]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #15557 from poettering/journal-zero-fix
authorAnita Zhang <the.anitazha@gmail.com>
Thu, 21 May 2020 01:14:51 +0000 (18:14 -0700)
committerGitHub <noreply@github.com>
Thu, 21 May 2020 01:14:51 +0000 (18:14 -0700)
journal: deal better with reading from zeroed out journal mmaps

571 files changed:
.clang-format
.github/workflows/main.yml [new file with mode: 0644]
.mkosi/mkosi.arch
.mkosi/mkosi.debian
.mkosi/mkosi.fedora
.mkosi/mkosi.opensuse
.mkosi/mkosi.ubuntu
NEWS
README
README.md
TODO
catalog/systemd.pl.catalog.in
docs/CODING_STYLE.md
docs/CONVERTING_TO_HOMED.md
docs/DESKTOP_ENVIRONMENTS.md
docs/HOME_DIRECTORY.md
docs/PASSWORD_AGENTS.md [new file with mode: 0644]
docs/PORTABILITY_AND_STABILITY.md
docs/SECURITY.md
docs/TRANSIENT-SETTINGS.md
docs/USERDB_AND_DESKTOPS.md
docs/USER_RECORD.md
hwdb.d/60-evdev.hwdb
hwdb.d/60-input-id.hwdb
hwdb.d/60-keyboard.hwdb
hwdb.d/60-sensor.hwdb
hwdb.d/70-mouse.hwdb
man/crypttab.xml
man/directives-template.xml [new file with mode: 0644]
man/homectl.xml
man/homed.conf.xml [new file with mode: 0644]
man/hostnamectl.xml
man/journalctl.xml
man/kernel-command-line.xml
man/machine-info.xml
man/machinectl.xml
man/meson.build
man/nss-resolve.xml
man/org.freedesktop.LogControl1.xml [new file with mode: 0644]
man/org.freedesktop.home1.xml [new file with mode: 0644]
man/org.freedesktop.hostname1.xml
man/org.freedesktop.import1.xml
man/org.freedesktop.locale1.xml
man/org.freedesktop.login1.xml
man/org.freedesktop.machine1.xml
man/org.freedesktop.resolve1.xml
man/org.freedesktop.systemd1.xml
man/org.freedesktop.timedate1.xml
man/pam_systemd.xml
man/pam_systemd_home.xml
man/resolvectl.xml
man/resolved.conf.xml
man/rules/meson.build
man/sd-bus-container-append.c [new file with mode: 0644]
man/sd-bus-container-read.c [new file with mode: 0644]
man/sd-bus.xml
man/sd-daemon.xml
man/sd_bus_add_match.xml
man/sd_bus_add_object.xml
man/sd_bus_call.xml
man/sd_bus_call_method.xml
man/sd_bus_get_current_handler.xml
man/sd_bus_get_name_creds.xml [new file with mode: 0644]
man/sd_bus_get_name_machine_id.xml [new file with mode: 0644]
man/sd_bus_message_append.xml
man/sd_bus_message_append_array.xml
man/sd_bus_message_get_type.xml
man/sd_bus_message_open_container.xml [new file with mode: 0644]
man/sd_bus_message_read.xml
man/sd_bus_negotiate_fds.xml
man/sd_bus_query_sender_creds.xml [new file with mode: 0644]
man/sd_bus_request_name.xml
man/sd_bus_send.xml
man/sd_bus_slot_get_bus.xml
man/sd_notify.xml
man/standard-specifiers.xml [new file with mode: 0644]
man/sysctl.d.xml
man/systemctl.xml
man/systemd-binfmt.service.xml
man/systemd-cryptsetup@.service.xml
man/systemd-firstboot.xml
man/systemd-homed.service.xml
man/systemd-hostnamed.service.xml
man/systemd-importd.service.xml
man/systemd-localed.service.xml
man/systemd-logind.service.xml
man/systemd-machined.service.xml
man/systemd-notify.xml
man/systemd-nspawn.xml
man/systemd-pstore.service.xml
man/systemd-repart.xml
man/systemd-resolved.service.xml
man/systemd-socket-proxyd.xml
man/systemd-timedated.service.xml
man/systemd-tmpfiles.xml
man/systemd-update-done.service.xml
man/systemd.automount.xml
man/systemd.dnssd.xml
man/systemd.exec.xml
man/systemd.journal-fields.xml
man/systemd.link.xml
man/systemd.mount.xml
man/systemd.netdev.xml
man/systemd.network.xml
man/systemd.service.xml
man/systemd.swap.xml
man/systemd.time.xml
man/systemd.unit.xml
man/systemd.xml
man/sysusers.d.xml
man/tmpfiles.d.xml
man/vtable-example.c
man/yubikey-crypttab.sh
meson.build
meson_options.txt
po/be.po
po/be@latin.po
po/bg.po
po/ca.po
po/cs.po
po/da.po
po/de.po
po/el.po
po/es.po
po/fr.po
po/gl.po
po/hr.po
po/hu.po
po/id.po
po/it.po
po/ja.po
po/ko.po
po/lt.po
po/pl.po
po/pt_BR.po
po/ro.po
po/ru.po
po/sk.po
po/sr.po
po/sv.po
po/tr.po
po/uk.po
po/zh_CN.po
po/zh_TW.po
semaphoreci/semaphore-runner.sh
shell-completion/zsh/_systemctl.in
shell-completion/zsh/_systemd-analyze
src/analyze/analyze-condition.c
src/analyze/analyze-security.c
src/analyze/analyze.c
src/basic/blockdev-util.c
src/basic/blockdev-util.h
src/basic/btrfs-util.c
src/basic/build.h
src/basic/cgroup-util.c
src/basic/cgroup-util.h
src/basic/conf-files.c
src/basic/efivars.c
src/basic/fd-util.c
src/basic/fileio.c
src/basic/fs-util.c
src/basic/fs-util.h
src/basic/glob-util.c
src/basic/glob-util.h
src/basic/hash-funcs.c
src/basic/hash-funcs.h
src/basic/hashmap.c
src/basic/hostname-util.c
src/basic/hostname-util.h
src/basic/limits-util.c
src/basic/locale-util.c
src/basic/locale-util.h
src/basic/missing_random.h
src/basic/parse-util.c
src/basic/path-util.c
src/basic/proc-cmdline.c
src/basic/proc-cmdline.h
src/basic/random-util.c
src/basic/random-util.h
src/basic/set.h
src/basic/socket-util.c
src/basic/socket-util.h
src/basic/stat-util.c
src/basic/stat-util.h
src/basic/strv.c
src/basic/strv.h
src/basic/terminal-util.h
src/basic/unit-def.c
src/basic/unit-def.h
src/basic/virt.c
src/binfmt/binfmt.c
src/boot/bootctl.c
src/busctl/busctl.c
src/core/automount.c
src/core/cgroup.c
src/core/cgroup.h
src/core/core-varlink.c
src/core/dbus-job.c
src/core/dbus-job.h
src/core/dbus-manager.c
src/core/dbus-mount.c
src/core/dbus-unit.c
src/core/dbus-unit.h
src/core/dbus.c
src/core/dbus.h
src/core/device.c
src/core/execute.c
src/core/execute.h
src/core/hostname-setup.c
src/core/load-fragment-gperf.gperf.m4
src/core/load-fragment.c
src/core/main.c
src/core/manager.c
src/core/manager.h
src/core/mount-setup.c
src/core/mount.c
src/core/mount.h
src/core/namespace.c
src/core/path.c
src/core/scope.c
src/core/selinux-access.c
src/core/selinux-access.h
src/core/service.c
src/core/service.h
src/core/slice.c
src/core/socket.c
src/core/swap.c
src/core/target.c
src/core/timer.c
src/core/unit-printf.c
src/core/unit.c
src/core/unit.h
src/coredump/coredump.c
src/coredump/coredumpctl.c
src/cryptsetup/cryptsetup-generator.c
src/cryptsetup/cryptsetup-pkcs11.c
src/cryptsetup/cryptsetup-pkcs11.h
src/cryptsetup/cryptsetup-util.c [new file with mode: 0644]
src/cryptsetup/cryptsetup-util.h [new file with mode: 0644]
src/cryptsetup/cryptsetup.c
src/firstboot/firstboot.c
src/fstab-generator/fstab-generator.c
src/home/home-util.c
src/home/home-util.h
src/home/homectl.c
src/home/homed-conf.c [new file with mode: 0644]
src/home/homed-conf.h [new file with mode: 0644]
src/home/homed-gperf.gperf [new file with mode: 0644]
src/home/homed-home-bus.c
src/home/homed-home-bus.h
src/home/homed-home.c
src/home/homed-manager-bus.c
src/home/homed-manager-bus.h
src/home/homed-manager.c
src/home/homed-manager.h
src/home/homed.c
src/home/homed.conf [new file with mode: 0644]
src/home/homework-luks.c
src/home/homework-luks.h
src/home/homework.c
src/home/homework.h
src/home/meson.build
src/home/pam_systemd_home.c
src/home/pwquality-util.c
src/home/user-record-util.c
src/hostname/hostnamed.c
src/hostname/org.freedesktop.hostname1.policy
src/import/import-fs.c
src/import/importd.c
src/initctl/initctl.c
src/journal-remote/journal-upload-journal.c
src/journal-remote/journal-upload.c
src/journal/compress.c
src/journal/compress.h
src/journal/fsprg.c
src/journal/journal-send.c
src/journal/journalctl.c
src/journal/journald-server.c
src/journal/journald-stream.c
src/journal/journald-syslog.c
src/journal/mmap-cache.c
src/journal/sd-journal.c
src/journal/test-audit-type.c
src/journal/test-compress.c
src/journal/test-journal-send.c
src/libsystemd-network/dhcp-identifier.c
src/libsystemd-network/dhcp-identifier.h
src/libsystemd-network/dhcp-server-internal.h
src/libsystemd-network/dhcp6-internal.h
src/libsystemd-network/dhcp6-option.c
src/libsystemd-network/icmp6-util.c
src/libsystemd-network/sd-dhcp-client.c
src/libsystemd-network/sd-dhcp-lease.c
src/libsystemd-network/sd-dhcp-server.c
src/libsystemd-network/sd-dhcp6-client.c
src/libsystemd-network/sd-radv.c
src/libsystemd-network/test-dhcp6-client.c
src/libsystemd-network/test-sd-dhcp-lease.c
src/libsystemd/sd-bus/bus-common-errors.h
src/libsystemd/sd-bus/bus-introspect.c
src/libsystemd/sd-bus/bus-introspect.h
src/libsystemd/sd-bus/bus-message.c
src/libsystemd/sd-bus/bus-objects.c
src/libsystemd/sd-bus/bus-protocol.h
src/libsystemd/sd-bus/bus-socket.c
src/libsystemd/sd-bus/test-bus-chat.c
src/libsystemd/sd-bus/test-bus-introspect.c
src/libsystemd/sd-daemon/sd-daemon.c
src/libsystemd/sd-device/device-enumerator.c
src/libsystemd/sd-device/device-monitor.c
src/libsystemd/sd-device/sd-device.c
src/libsystemd/sd-netlink/netlink-internal.h
src/libsystemd/sd-netlink/netlink-message.c
src/libsystemd/sd-netlink/netlink-socket.c
src/libsystemd/sd-netlink/test-netlink.c
src/locale/localectl.c
src/locale/localed.c
src/login/loginctl.c
src/login/logind-acl.c
src/login/logind-dbus.c
src/login/logind-dbus.h
src/login/logind-seat-dbus.c
src/login/logind-seat-dbus.h
src/login/logind-session-dbus.c
src/login/logind-session-dbus.h
src/login/logind-session.c
src/login/logind-session.h
src/login/logind-user-dbus.c
src/login/logind-user-dbus.h
src/login/logind.c
src/login/logind.h
src/login/org.freedesktop.login1.conf
src/login/pam_systemd.c
src/login/systemd-user.m4
src/machine/image-dbus.c
src/machine/image-dbus.h
src/machine/machine-dbus.c
src/machine/machine-dbus.h
src/machine/machinectl.c
src/machine/machined-dbus.c
src/machine/machined.c
src/machine/machined.h
src/mount/mount-tool.c
src/network/netdev/bond.c
src/network/netdev/bond.h
src/network/netdev/bridge.c
src/network/netdev/bridge.h
src/network/netdev/ipvlan.c
src/network/netdev/ipvlan.h
src/network/netdev/macsec.c
src/network/netdev/macvlan.c
src/network/netdev/macvlan.h
src/network/netdev/netdev-gperf.gperf
src/network/netdev/netdev.c
src/network/networkctl.c
src/network/networkd-dhcp-common.c
src/network/networkd-dhcp-common.h
src/network/networkd-dhcp-server.c
src/network/networkd-dhcp4.c
src/network/networkd-dhcp4.h
src/network/networkd-dhcp6.c
src/network/networkd-link-bus.c
src/network/networkd-link.c
src/network/networkd-lldp-rx.c
src/network/networkd-lldp-tx.c
src/network/networkd-manager.c
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h
src/network/networkd-util.c
src/network/test-network.c
src/notify/notify.c
src/nspawn/nspawn-cgroup.c
src/nspawn/nspawn-mount.c
src/nspawn/nspawn-mount.h
src/nspawn/nspawn-register.c
src/nspawn/nspawn.c
src/nss-myhostname/nss-myhostname.c
src/nss-mymachines/nss-mymachines.c
src/nss-resolve/nss-resolve.c
src/nss-systemd/nss-systemd.c
src/partition/makefs.c
src/partition/repart.c
src/partition/test-repart.sh
src/portable/portable.c
src/portable/portablectl.c
src/resolve/meson.build
src/resolve/resolvectl.c
src/resolve/resolved-bus.c
src/resolve/resolved-bus.h
src/resolve/resolved-conf.c
src/resolve/resolved-conf.h
src/resolve/resolved-dns-query.h
src/resolve/resolved-dns-scope.h
src/resolve/resolved-dns-search-domain.c
src/resolve/resolved-dns-search-domain.h
src/resolve/resolved-dns-server.c
src/resolve/resolved-dns-server.h
src/resolve/resolved-dns-stream.c
src/resolve/resolved-dns-stream.h
src/resolve/resolved-dns-transaction.h
src/resolve/resolved-dns-trust-anchor.c
src/resolve/resolved-dns-zone.c
src/resolve/resolved-dnssd-bus.c
src/resolve/resolved-dnssd-bus.h
src/resolve/resolved-dnssd.c
src/resolve/resolved-dnstls-gnutls.c
src/resolve/resolved-dnstls-openssl.c
src/resolve/resolved-dnstls.h
src/resolve/resolved-etc-hosts.c
src/resolve/resolved-gperf.gperf
src/resolve/resolved-link-bus.c
src/resolve/resolved-link-bus.h
src/resolve/resolved-link.c
src/resolve/resolved-link.h
src/resolve/resolved-manager.c
src/resolve/resolved-manager.h
src/resolve/resolved-resolv-conf.c
src/resolve/resolved-util.c [deleted file]
src/resolve/resolved-util.h [deleted file]
src/resolve/resolved.c
src/resolve/test-resolved-util.c [deleted file]
src/run/run.c
src/shared/acpi-fpdt.c
src/shared/ask-password-api.c
src/shared/binfmt-util.c [new file with mode: 0644]
src/shared/binfmt-util.h [new file with mode: 0644]
src/shared/bond-util.c [new file with mode: 0644]
src/shared/bond-util.h [new file with mode: 0644]
src/shared/bus-locator.c [new file with mode: 0644]
src/shared/bus-locator.h [new file with mode: 0644]
src/shared/bus-log-control-api.c
src/shared/bus-log-control-api.h
src/shared/bus-unit-util.c
src/shared/bus-util.c
src/shared/bus-util.h
src/shared/bus-wait-for-jobs.c
src/shared/bus-wait-for-units.c
src/shared/calendarspec.c
src/shared/calendarspec.h
src/shared/condition.c
src/shared/condition.h
src/shared/conf-parser.c
src/shared/conf-parser.h
src/shared/dissect-image.c
src/shared/ethtool-util.c
src/shared/ethtool-util.h
src/shared/format-table.c
src/shared/format-table.h
src/shared/fstab-util.c
src/shared/fstab-util.h
src/shared/generator.c
src/shared/install-printf.c
src/shared/install.c
src/shared/install.h
src/shared/ipvlan-util.c [new file with mode: 0644]
src/shared/ipvlan-util.h [new file with mode: 0644]
src/shared/json.c
src/shared/json.h
src/shared/logs-show.c
src/shared/macvlan-util.c [new file with mode: 0644]
src/shared/macvlan-util.h [new file with mode: 0644]
src/shared/meson.build
src/shared/mount-util.c
src/shared/mount-util.h
src/shared/resize-fs.c
src/shared/seccomp-util.c
src/shared/service-util.c [new file with mode: 0644]
src/shared/service-util.h [new file with mode: 0644]
src/shared/socket-netlink.c
src/shared/socket-netlink.h
src/shared/specifier.c
src/shared/specifier.h
src/shared/unit-file.c
src/shared/unit-file.h
src/shared/user-record-show.c
src/shared/user-record.c
src/shared/user-record.h
src/shared/verbs.c
src/shared/verbs.h
src/shutdown/shutdown.c
src/socket-proxy/socket-proxyd.c
src/sysctl/sysctl.c
src/systemctl/systemctl.c
src/systemd/sd-bus-vtable.h
src/systemd/sd-bus.h
src/systemd/sd-daemon.h
src/systemd/sd-dhcp-client.h
src/systemd/sd-dhcp-server.h
src/systemd/sd-dhcp6-client.h
src/systemd/sd-dhcp6-option.h [new file with mode: 0644]
src/sysusers/sysusers.c
src/test/meson.build
src/test/test-alloc-util.c
src/test/test-boot-timestamps.c
src/test/test-calendarspec.c
src/test/test-capability.c
src/test/test-cgroup-setup.c
src/test/test-cgroup-util.c
src/test/test-cgroup.c
src/test/test-clock.c
src/test/test-condition.c
src/test/test-copy.c
src/test/test-exec-util.c
src/test/test-execute.c
src/test/test-fd-util.c
src/test/test-fileio.c
src/test/test-fs-util.c
src/test/test-fstab-util.c
src/test/test-hashmap.c
src/test/test-hostname-util.c
src/test/test-install-root.c
src/test/test-locale-util.c
src/test/test-prioq.c
src/test/test-proc-cmdline.c
src/test/test-procfs-util.c
src/test/test-random-util.c
src/test/test-sd-hwdb.c
src/test/test-seccomp.c
src/test/test-set.c
src/test/test-sleep.c
src/test/test-socket-util.c
src/test/test-specifier.c
src/test/test-strv.c
src/test/test-time-util.c
src/test/test-umount.c
src/timedate/timedatectl.c
src/timedate/timedated.c
src/timesync/timesyncd-manager.c
src/tmpfiles/offline-passwd.c [new file with mode: 0644]
src/tmpfiles/offline-passwd.h [new file with mode: 0644]
src/tmpfiles/tmpfiles.c
src/udev/net/link-config-gperf.gperf
src/udev/net/link-config.c
src/udev/udev-ctrl.c
src/udev/udev-rules.c
src/udev/udevadm-trigger.c
src/udev/udevd.c
src/userdb/userdbctl.c
src/volatile-root/volatile-root.c
test/TEST-38-FREEZER/Makefile [new symlink]
test/TEST-38-FREEZER/test.sh [new file with mode: 0755]
test/fuzz/fuzz-bus-message/oss-fuzz-19446 [new file with mode: 0644]
test/fuzz/fuzz-calendarspec/oss-fuzz-22208 [new file with mode: 0644]
test/fuzz/fuzz-link-parser/directives.link
test/fuzz/fuzz-netdev-parser/directives.netdev
test/fuzz/fuzz-network-parser/directives.network
test/fuzz/fuzz-unit-file/directives.service
test/fuzz/meson.build
test/test-functions
test/units/testsuite-04.sh
test/units/testsuite-38-sleep.service [new file with mode: 0644]
test/units/testsuite-38.service [new file with mode: 0644]
test/units/testsuite-38.sh [new file with mode: 0755]
tmpfiles.d/meson.build
tmpfiles.d/systemd-pstore.conf [new file with mode: 0644]
tools/autosuspend-update.sh [moved from tools/meson-autosuspend-update.sh with 100% similarity]
tools/check-api-docs.sh [moved from tools/meson-check-api-docs.sh with 100% similarity]
tools/check-compilation.sh [moved from tools/meson-check-compilation.sh with 100% similarity]
tools/check-help.sh [moved from tools/meson-check-help.sh with 100% similarity]
tools/git-contrib.sh [moved from tools/meson-git-contrib.sh with 100% similarity]
tools/hwdb-update.sh [moved from tools/meson-hwdb-update.sh with 100% similarity]
tools/make-directive-index.py
tools/update-dbus-docs.py
tools/update-man-rules.py [moved from tools/make-man-rules.py with 98% similarity]
travis-ci/managers/debian.sh
travis-ci/managers/fuzzit.sh
units/meson.build
units/systemd-binfmt.service.in
units/systemd-logind.service.in
units/tmp.mount

index ef7c918d4e73f47434cdcb75911b01d78fdfdbee..2d412db269eb4fb984f7ed7c0015a4dadcf1f488 100644 (file)
@@ -3,10 +3,24 @@
 # result MUST NOT be committed indiscriminately, but each automated
 # change should be reviewed and only the appropriate ones commited.
 #
-# To apply the coding style you can run the following command (assuming you
-# installed clang-format on your system):
+# The easiest way to apply the formatting to your changes ONLY,
+# is to use the git-clang-format script (usually installed with clang-format).
 #
+# -  Fixup formatting before committing
+# 1. Edit and stage your files.
+# 2. Run `git clang-format`.
+# 3. Verify + correct + (un)stage changes.
+# 4. Commit.
+#
+# -  Fixup formatting after committing
+# 1. Commit your changes.
+# 2. Run `git clang-format HEAD~` - Refer the commit *before* your changes here.
+# 3. Verify + correct changes, `git difftool -d` can help here.
+# 4. Stage + commit, potentially with `--amend` (means to fixup the last commit).
+#
+# To run clang-format on all sourcefiles, use the following line:
 # $ git ls-files 'src/*.[ch]' 'src/*.cc' | xargs clang-format -i -style=file
+#
 # You can find more information on the different config parameters in this file here:
 # https://clang.llvm.org/docs/ClangFormatStyleOptions.html
 ---
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644 (file)
index 0000000..b46b1d6
--- /dev/null
@@ -0,0 +1,41 @@
+---
+# vi: ts=2 sw=2 et:
+# See: https://google.github.io/oss-fuzz/getting-started/continuous-integration/
+
+name: CIFuzz
+on:
+  pull_request:
+    paths:
+      - '**/meson.build'
+      - '.github/workflows/**'
+      - 'meson_options.txt'
+      - 'src/**'
+      - 'test/fuzz/**'
+      - 'tools/oss-fuzz.sh'
+  push:
+    branches:
+      - master
+jobs:
+ Fuzzing:
+   runs-on: ubuntu-latest
+   if: github.repository == 'systemd/systemd'
+   steps:
+   - name: Build Fuzzers
+     id: build
+     uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
+     with:
+       oss-fuzz-project-name: 'systemd'
+       dry-run: false
+       allowed-broken-targets-percentage: 0
+   - name: Run Fuzzers
+     uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
+     with:
+       oss-fuzz-project-name: 'systemd'
+       fuzz-seconds: 600
+       dry-run: false
+   - name: Upload Crash
+     uses: actions/upload-artifact@v1
+     if: failure() && steps.build.outcome == 'success'
+     with:
+       name: artifacts
+       path: ./out/artifacts
index 350d7cd2b8241e588dc1d803bd6ff095ea5765bc..965e26e411c16c06a8ac2e874e0a89bba2559925 100644 (file)
@@ -52,6 +52,7 @@ BuildPackages=
         python-lxml
         qrencode
         xz
+        zstd
 
 Packages=
         libidn2
index e85612bef1e50cc13cc935e29bfdfa2afa5c76be..ff0c8ffc07bdc90b32174c02fa1379d3d739d5ce 100644 (file)
@@ -50,6 +50,7 @@ BuildPackages=
         libsmartcols-dev
         libtool
         libxkbcommon-dev
+        libzstd-dev
         m4
         meson
         pkg-config
@@ -59,6 +60,7 @@ BuildPackages=
         uuid-dev
         xsltproc
         xz-utils
+        zstd
 
 Packages=
         libqrencode4
index 9769b0544741410bc6f21639d0a595fdd767d050..a26b36a163e7722dc8a47b17fe3e48743ae5a4e2 100644 (file)
@@ -47,6 +47,7 @@ BuildPackages=
         libselinux-devel
         libxkbcommon-devel
         libxslt
+        libzstd-devel
         lz4
         lz4-devel
         m4
@@ -62,16 +63,13 @@ BuildPackages=
         tree
         valgrind-devel
         xz-devel
+        zstd
 
 Packages=
-        coreutils
-        cryptsetup-libs
-        kmod-libs
-        e2fsprogs
-        libidn2
-        libseccomp
+        # libzstd can be dropped once the Fedora RPM gets a dependency on it
+        libzstd
+        # procps-ng provides a set of useful utilies (ps, free, etc)
         procps-ng
-        util-linux
 
 BuildDirectory=mkosi.builddir
 Cache=mkosi.cache
index 1faf9cc47633f7f15399beaca42c7517dd16fc60..57d13b274088a288caea5d241046fa6e12730c48 100644 (file)
@@ -48,11 +48,15 @@ BuildPackages=
         python3
         python3-lxml
         qrencode-devel
+        system-user-nobody
         zlib-devel
 # to satisfy tests
         acl
         glibc-locale
         system-group-obsolete
+        system-user-bin
+        system-user-daemon
+        system-user-root
         timezone
 
 Packages=
index 1e4005f0707a603acac75ff5b80d529bea88fc93..fc3192ccad322e3c94bf9ea4d38c0e1af5ec9a4d 100644 (file)
@@ -51,6 +51,7 @@ BuildPackages=
         libsmartcols-dev
         libtool
         libxkbcommon-dev
+        libzstd-dev
         m4
         meson
         pkg-config
@@ -61,6 +62,7 @@ BuildPackages=
         uuid-dev
         xsltproc
         xz-utils
+        zstd
 
 Packages=
         libqrencode3
diff --git a/NEWS b/NEWS
index 969efa6f41168219a5f51ea19d39284dbff0f5d6..4c4e92b763574ef833949d9a2d1aecc71394becb 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,10 @@ CHANGES WITH 246 in spe:
           their first output column with --no-legend. To hide the first column,
           use --plain.
 
+        * The service manager gained basic support for cgroup v2 freezer. Units
+          can now be suspended or resumed either using new systemctl verbs,
+          freeze and thaw respectively, or via D-Bus.
+
 CHANGES WITH 245:
 
         * A new tool "systemd-repart" has been added, that operates as an
@@ -280,7 +284,7 @@ CHANGES WITH 245:
           such files in version 243.
 
         * systemd-logind will now validate access to the operation of changing
-          the virtual terminal via a PolicyKit action. By default, only users
+          the virtual terminal via a polkit action. By default, only users
           with at least one session on a local VT are granted permission.
 
         * When systemd sets up PAM sessions that invoked service processes
@@ -815,6 +819,9 @@ CHANGES WITH 243:
         * systemd-networkd's TUN support gained a new setting VnetHeader= for
           tweaking Generic Segment Offload support.
 
+        * The address family for policy rules may be specified using the new
+          Family= option in the [RoutingPolicyRule] section.
+
         * networkctl gained a new "delete" command for removing virtual network
           devices, as well as a new "--stats" switch for showing device
           statistics.
@@ -2032,7 +2039,7 @@ CHANGES WITH 239:
           lookup is likely to trigger nss-ldap which in turn might use NSS to
           ask systemd-resolved for hostname lookups. This will hence result in
           a deadlock: a user name lookup in order to start
-          systemd-resolved.service will result in a host name lookup for which
+          systemd-resolved.service will result in a hostname lookup for which
           systemd-resolved.service needs to be started already. There are
           multiple ways to work around this problem: pre-allocate the
           "systemd-resolve" user on such systems, so that nss-ldap won't be
@@ -3001,7 +3008,7 @@ CHANGES WITH 235:
           A/AAAA resource record for the "_gateway" hostname, pointing to the
           current default IP gateway. Previously it did that for the "gateway"
           name, hampering adoption, as some distributions wanted to leave that
-          host name open for local use. The old behaviour may still be
+          hostname open for local use. The old behaviour may still be
           requested at build time.
 
         * systemd-networkd's [Address] section in .network files gained a new
@@ -4342,7 +4349,7 @@ CHANGES WITH 230:
           again don't consider turning this on in your stable, LTS or
           production release just yet. (Note that you have to enable
           nss-resolve in /etc/nsswitch.conf, to actually use systemd-resolved
-          and its DNSSEC mode for host name resolution from local
+          and its DNSSEC mode for hostname resolution from local
           applications.)
 
         * systemd-resolve conveniently resolves DANE records with the --tlsa
@@ -6160,14 +6167,14 @@ CHANGES WITH 218:
           for a unit, as declared in the (usually vendor-supplied)
           system preset files.
 
-        * nss-myhostname will now resolve the single-label host name
+        * nss-myhostname will now resolve the single-label hostname
           "gateway" to the locally configured default IP routing
           gateways, ordered by their metrics. This assigns a stable
           name to the used gateways, regardless which ones are
           currently configured. Note that the name will only be
           resolved after all other name sources (if nss-myhostname is
           configured properly) and should hence not negatively impact
-          systems that use the single-label host name "gateway" in
+          systems that use the single-label hostname "gateway" in
           other contexts.
 
         * systemd-inhibit now allows filtering by mode when listing
@@ -7595,7 +7602,7 @@ CHANGES WITH 210:
           reported by uname()'s "machine" field.
 
         * systemd-networkd now supports matching on the system
-          virtualization, architecture, kernel command line, host name
+          virtualization, architecture, kernel command line, hostname
           and machine ID.
 
         * logind is now a lot more aggressive when suspending the
@@ -7913,12 +7920,12 @@ CHANGES WITH 209:
           example, a line that creates /run/nologin).
 
         * A new API "sd-resolve.h" has been added which provides a simple
-          asynchronous wrapper around glibc NSS host name resolution
+          asynchronous wrapper around glibc NSS hostname resolution
           calls, such as getaddrinfo(). In contrast to glibc's
           getaddrinfo_a(), it does not use signals. In contrast to most
           other asynchronous name resolution libraries, this one does
           not reimplement DNS, but reuses NSS, so that alternate
-          host name resolution systems continue to work, such as mDNS,
+          hostname resolution systems continue to work, such as mDNS,
           LDAP, etc. This API is based on libasyncns, but it has been
           cleaned up for inclusion in systemd.
 
@@ -9702,7 +9709,7 @@ CHANGES WITH 190:
           when he over-mounts a non-empty directory.
 
         * There are new specifiers that are resolved in unit files,
-          for the host name (%H), the machine ID (%m) and the boot ID
+          for the hostname (%H), the machine ID (%m) and the boot ID
           (%b).
 
         Contributions from: Allin Cottrell, Auke Kok, Brandon Philips,
diff --git a/README b/README
index b2c8d28411f623ea4cdb5fa5416add16db8eeb43..4f4a21eeca7ea1e824542b3eda148d54ee88cfa8 100644 (file)
--- a/README
+++ b/README
@@ -150,6 +150,7 @@ REQUIREMENTS:
         libselinux (optional)
         liblzma (optional)
         liblz4 >= 1.3.0 / 130 (optional)
+        libzstd >= 1.4.0 (optional)
         libgcrypt (optional)
         libqrencode (optional)
         libmicrohttpd (optional)
index bfb2b3fbd40182460cbabc02dc198c8e390a50ba..8e72fbc2bef59476cc970fef914e0c8d099055b9 100644 (file)
--- a/README.md
+++ b/README.md
@@ -8,6 +8,7 @@ System and Service Manager
 [![Coverity Scan Status](https://scan.coverity.com/projects/350/badge.svg)](https://scan.coverity.com/projects/350)<br/>
 [![Fuzzit Status](https://app.fuzzit.dev/badge?org_id=systemd&branch=master)](https://app.fuzzit.dev/orgs/systemd/dashboard)<br/>
 [![OSS-Fuzz Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/systemd.svg)](https://oss-fuzz-build-logs.storage.googleapis.com/index.html#systemd)<br/>
+[![CIFuzz](https://github.com/systemd/systemd/workflows/CIFuzz/badge.svg)](https://github.com/systemd/systemd/actions)<br/>
 [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/1369/badge)](https://bestpractices.coreinfrastructure.org/projects/1369)<br/>
 [![Travis CI Build Status](https://travis-ci.org/systemd/systemd.svg?branch=master)](https://travis-ci.org/systemd/systemd)<br/>
 [![Language Grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/systemd/systemd.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/systemd/systemd/context:cpp)<br/>
diff --git a/TODO b/TODO
index 8838278072864523e1be03e61eaf4da6c6d25997..ee50452d040e1b22814ea618978eb75ed075843e 100644 (file)
--- a/TODO
+++ b/TODO
@@ -22,21 +22,82 @@ Janitorial Clean-ups:
 
 Features:
 
+* machined: add API to acquire UID range. add API to mount/dissect loopback
+  file. Both protected by PK. Then make nspawn use these APIs to run
+  unprivileged containers. i.e. push the truly privileged bits into machined,
+  so that the client side can remain entirely unprivileged, with SUID or
+  anything like that.
+
+* add "throttling" to sd-event event sources: optionally, when we wake up too
+  often for one, let's turn it off entirely for a while. Use that for the
+  /proc/self/mountinfo logic.
+
+* move our systemd-user PAM snippet to /usr/, which PAM appears to support
+  these days
+
+* nspawn: support time namespaces
+
+* pid1: Move to tracking of main pid/control pid of units per pidfd
+
+* pid1: support new clone3() fork-into-cgroup feature
+
+* pid1: also remove PID files of a service when the service starts, not just
+  when it exits
+
+* make "systemd-dissect" an official supported tool, i.e. move to /usr/bin/ and
+  provide man page. Given that we now have a tool that can generate images like
+  this, it's useful to have one that can dump contents of them, too.
+
+* All tools that support --root= should also learn --image= so that they can
+  operate on disk images directly. Specifically: bootctl, firstboot, tmpfiles,
+  sysusers, systemctl, repart, journalctl, coredumpctl.
+
+* per-service credential system. Specifically: add LoadCredential= (for loading
+  cred from file), AcquireCredential= (for asking user for cred, via
+  ask-password), PassCredential= (for passing on credential systemd itself
+  got). Then, place credentials in a per-service, immutable ramfs instance (so
+  that it cannot be swapped out), destroy after use. Also pass via keyring
+  (with graceful fallback to cover for containers). Define CredentialPath= for
+  defining subdir of /run/credentials/ where to place it. Set $CREDENTIAL_PATH
+  env var for services to the result. Also pass via fd passing (optionally).
+
+* homed: add native recovery key support. use 48 lowercase modhex characters
+  (192bit), show qr code of it, include pattern expression in user record.
+
+* homed: introduce "degraded" state for home directories that weren't cleanly
+  unmounted (use xattr we add and remove on the loop back file)
+
+* homed: during login resize fs automatically towards size goal. Specifically,
+  resize to diskSize if possible, but leave a certain amount (configured by a
+  new value diskLeaveFreeSize) of space free on the backing fs.
+
+* homed: permit multiple user record signing keys to be used locally, and pick
+  the right one for signing records automatically depending on a pre-existing
+  signature
+
+* homed: add a way to "adopt" a home directory, i.e. strip foreign signatures
+  and insert a local signature instead.
+
+* homed: as an extension to the directory+subvolume backend: if located on
+  especially marked fs, then sync down password into LUKS header of that fs,
+  and always verify passwords against it too. Bootstrapping is a problem
+  though: if noone is logged in (or no other user even exists yet), how do you
+  unlock the volume in order to create the first user and add the first pw.
+
+* homed: support new FS_IOC_ADD_ENCRYPTION_KEY ioctl for setting up fscrypt
+
+* busctl: maybe expose a verb "ping" for pinging a dbus service to see if it
+  exists and responds.
+
 * homed: maybe pre-create ~/.cache as subvol so that it can have separate quota
   easily?
 
-* journalctl --image= which is like --root= but operates on disk images
-
 * when systemd-nspawn and suchlike dissect an OS image, and there are multiple
   root partitions, do an strverscmp() on the partition label and boot
   first. That is inspired how sd-boot figures out which kernel to boot, and
   thus allows defining OS images which can be A/B updated and we default to the
   newest version automatically, both in nspawn and in sd-boot
 
-* drop sd_bus_message_set_priority() from sd-bus API and documentation as much
-  as we can, it's a kdbus left-over and unlikely to come back on AF_UNIX, since
-  it's not really implementable there.
-
 * cryptsetup/homed: also support FIDO2 HMAC password logic for unlocking
   devices. (see: https://github.com/mjec/fido2-hmac-secret)
 
@@ -56,9 +117,6 @@ Features:
 * by default, in systemd --user service bump the OOMAdjust to 100, as privs
   allow so that systemd survives
 
-* honour specifiers in unit files that resolve to some very basic
-  /etc/os-release data, such as ID, VERSION_ID, BUILD_ID, VARIANT_ID.
-
 * cryptsetup: allow encoding key directly in /etc/crypttab, maybe with a
   "base64:" prefix. Useful in particular for pkcs11 mode.
 
@@ -126,17 +184,16 @@ Features:
 * systemd-repart: make it a static checker during early boot for existence and
   absence of other partitions for trusted boot environments
 
-* systemd-repart: when no configuration is found, exit early do not check
-  partition table, so that it is safe to run in the initrd on any system
-
 * systemd-repart: allow config of partition uuid
 
 * userdb: allow username prefix searches in varlink API, allow realname and
   realname substr searches in varlink API
 
+* userdb: allow uid/gid range checks
+
 * userdb: allow existence checks
 
-* pid: activation by journal search expression
+* pid1: activation by journal search expression
 
 * when switching root from initrd to host, set the machine_id env var so that
   if the host has no machine ID set yet we continue to use the random one the
@@ -201,8 +258,7 @@ Features:
   that are linked to these places instead of copied. After all they are
   constant vendor data.
 
-* maybe add kernel cmdline params: 1) to force first-boot mode + 2) to force
-  random seed crediting
+* maybe add kernel cmdline params: to force random seed crediting
 
 * nspawn: on cgroupsv1 issue cgroup empty handler process based on host events,
   so that we make cgroup agent logic safe
@@ -220,7 +276,6 @@ Features:
   - rollback when resize fails mid-operation
   - GNOME's side for forget key on suspend (requires rework so that lock screen runs outside of uid)
   - resize on login?
-  - fstrim on logout?
   - shrink fs on logout?
   - update LUKS password on login if we find there's a password that unlocks the JSON record but not the LUKS device.
   - create on activate?
@@ -465,9 +520,6 @@ Features:
 
 * support projid-based quota in machinectl for containers
 
-* maybe use SOURCE_DATE_EPOCH (i.e. the env var the reproducible builds folks
-  introduced) as the RTC epoch, instead of the mtime of NEWS.
-
 * add a way to lock down cgroup migration: a boolean, which when set for a unit
   makes sure the processes in it can never migrate out of it
 
@@ -1157,18 +1209,15 @@ Features:
 * networkd:
    - add more keys to [Route] and [Address] sections
    - add support for more DHCPv4 options (and, longer term, other kinds of dynamic config)
-   - add proper initrd support (in particular generate .network/.link files based on /proc/cmdline)
    - add reduced [Link] support to .network files
-   - add Scope= parsing option for [Network]
    - properly handle routerless dhcp leases
    - work with non-Ethernet devices
-   - add support for more bond options
    - dhcp: do we allow configuring dhcp routes on interfaces that are not the one we got the dhcp info from?
    - the DHCP lease data (such as NTP/DNS) is still made available when
      a carrier is lost on a link. It should be removed instantly.
    - expose in the API the following bits:
-         - option 15, domain name and/or option 119, search list
-         - option 12, host name and/or option 81, fqdn
+         - option 15, domain name
+         - option 12, hostname and/or option 81, fqdn
          - option 123, 144, geolocation
          - option 252, configure http proxy (PAC/wpad)
    - provide a way to define a per-network interface default metric value
@@ -1176,12 +1225,8 @@ Features:
    - allow Name= to be specified repeatedly in the [Match] section. Maybe also
      support Name=foo*|bar*|baz ?
    - duplicate address check for static IPs (like ARPCHECK in network-scripts)
-   - allow DUID/IAID to be customized, see issue #394.
    - whenever uplink info changes, make DHCP server send out FORCERENEW
 
-* networkd-wait-online:
-   - make operstates to wait for configurable?
-
 * dhcp:
    - figure out how much we can increase Maximum Message Size
 
@@ -1205,20 +1250,14 @@ External:
    - natively watch for dbus-*.service symlinks (PENDING)
    - teach dbus to activate all services it finds in /etc/systemd/services/org-*.service
 
-* fix alsa mixer restore to not print error when no config is stored
-
 * make cryptsetup lower --iter-time
 
-* patch kernel for xattr support in /dev, /proc/, /sys?
-
 * kernel: add device_type = "fb", "fbcon" to class "graphics"
 
 * /usr/bin/service should actually show the new command line
 
 * fedora: suggest auto-restart on failure, but not on success and not on coredump. also, ask people to think about changing the start limit logic. Also point people to RestartPreventExitStatus=, SuccessExitStatus=
 
-* fedora: F20: go timer units all the way, leave cron.daily for cron
-
 * neither pkexec nor sudo initialize environ[] from the PAM environment?
 
 * fedora: update policy to declare access mode and ownership of unit files to root:root 0644, and add an rpmlint check for it
index 1a6c2546e67d30b2b7e700d1ddbf229ea4b0a675..5f3d41632266fc4058119966be271db5407d7873 100644 (file)
@@ -411,3 +411,26 @@ i jądro wymusiło zakończenie jego działania.
 
 Proszę zauważyć, że brak pamięci mógł nie zostać spowodowany
 przez jednostkę @UNIT@.
+
+-- b61fdac612e94b9182285b998843061f
+Subject: Przyjmowanie nazwy użytkownika/grupy @USER_GROUP_NAME@, która nie zgadza się ze ścisłymi regułami nazw użytkowników/grup.
+Defined-By: systemd
+Support: %SUPPORT_URL%
+
+Podano nazwę użytkownika/grupy @USER_GROUP_NAME@, co zostało przyjęte
+zgodnie z rozluźnionymi regułami nazw użytkowników/grup, ale nie spełnia
+ścisłych reguł.
+
+Ścisłe reguły nazw użytkowników/grup zapisane jako wyrażenie regularne to:
+
+^[a-zA-Z_][a-zA-Z0-9_-]{0,30}$
+
+Rozluźnione reguły nazw użytkowników/grup przyjmują wszystkie nazwy,
+oprócz pustego ciągu, nazw zawierających bajty NUL, znaki kontrolne,
+dwukropki lub ukośniki, nazw niebędących prawidłowym tekstem UTF-8,
+nazw z początkową lub końcową spacją, ciągów „.” lub „..”, ciągów
+zawierających tylko cyfry lub ciągów zaczynających się myślnikiem
+i zawierających oprócz niego tylko cyfry.
+
+https://systemd.io/USER_NAMES zawiera więcej informacji o ścisłych
+i rozluźnionych regułach nazw użytkowników/grup.
index c8ca8bfefcaa6e9df775359d75daaac68f2ff717..12a0c993fc99f37eb224458983d4adc48a25f078 100644 (file)
@@ -424,7 +424,7 @@ layout: default
 
 ## Deadlocks
 
-- Do not issue NSS requests (that includes user name and host name lookups)
+- Do not issue NSS requests (that includes user name and hostname lookups)
   from PID 1 as this might trigger deadlocks when those lookups involve
   synchronously talking to services that we would need to start up.
 
index a3a88be6c15995cb06a81ff18927373351b892ea..78b6c616317961b4bc2201891880d69484dd8490 100644 (file)
@@ -113,7 +113,7 @@ Here's the step-by-step guide:
    home directory temporarily and copy the data in.
 
     ```
-    homectl with foobar -- rsync -aHAXv --delete-during /home/foobar.saved/ .
+    homectl with foobar -- rsync -aHAXv --remove-source-files /home/foobar.saved/ .
     ```
 
    This mounts the home directory of the user, and then runs the specified
@@ -121,7 +121,7 @@ Here's the step-by-step guide:
    new. The new home directory is the working directory of the invoked `rsync`
    process. We are invoking this command as root, hence the `rsync` runs as
    root too. When the `rsync` command completes the home directory is
-   automatically unmounted again. Since we used `--delete-during` all files
+   automatically unmounted again. Since we used `--remove-source-files` all files
    copied are removed from the old home directory as the copy progresses. After
    the command completes the old home directory should be empty. Let's remove
    it hence:
index 6dbbbb10f2119be570fef6d2cd51bd24b85ca774..f8f0cb671f9fd007940b3e81dc07ecb640f44153 100644 (file)
@@ -28,11 +28,11 @@ Currently nothing like this is supported or even planned.
 [`systemd.special(7)`](https://www.freedesktop.org/software/systemd/man/systemd.special.html)
 defines the `graphical-session.target` and `graphical-session-pre.target` to
 allow cross-desktop integration. Furthermore, systemd defines the three base
-slices `background`, `apps` and `session`.
+slices `background`, `app` and `session`.
 All units should be placed into one of these slices depending on their purposes:
 
  * `session.slice`: Contains only processes essential to run the user's graphical session
- * `apps.slice`: Contains all normal applications that the user is running
+ * `app.slice`: Contains all normal applications that the user is running
  * `background.slice`: Useful for low-priority background tasks
 
 The purpose of this grouping is to assign different priorities to the
@@ -42,7 +42,7 @@ preferentially killing background tasks in out-of-memory situations
 or assigning different memory/CPU/IO priorities to ensure that the session
 runs smoothly under load.
 
-TODO: Will there be a default to place units into e.g. `apps.slice` by default
+TODO: Will there be a default to place units into e.g. `app.slice` by default
 rather than the root slice?
 
 ## XDG standardization for applications
@@ -50,9 +50,9 @@ rather than the root slice?
 To ensure cross-desktop compatibility and encourage sharing of good practices,
 desktop environments should adhere to the following conventions:
 
- * Application units should follow the scheme `apps-<launcher>-<ApplicationID>-<RANDOM>.service`,
-   e.g. `apps-gnome-org.gnome.Evince-12345.service`,
-   `apps-flatpak-org.telegram.desktop-12345.service` or `apps-KDE-org.kde.okular-12345.service`.
+ * Application units should follow the scheme `app-<launcher>-<ApplicationID>-<RANDOM>.service`,
+   e.g. `app-gnome-org.gnome.Evince-12345.service`,
+   `app-flatpak-org.telegram.desktop-12345.service` or `app-KDE-org.kde.okular-12345.service`.
  * Using `.service` units instead of `.scope` units, i.e. allowing systemd to
    start the process on behalf of the caller,
    instead of the caller starting the process and letting systemd know about it,
@@ -62,13 +62,13 @@ desktop environments should adhere to the following conventions:
    contain a `-` character.
 
 This has the following advantages:
- * Using the `apps-<launcher>-` prefix means that the unit defaults can be
+ * Using the `app-<launcher>-` prefix means that the unit defaults can be
    adjusted using desktop environment specific drop-in files.
  * The application ID can be retrieved by stripping the prefix and postfix.
    This in turn should map to the corresponding `.desktop` file when available
 
 TODO: Define the name of slices that should be used.
-This could be `apps-<launcher>-<ApplicationID>-<RANDOM>.slice`.
+This could be `app-<launcher>-<ApplicationID>-<RANDOM>.slice`.
 
 TODO: Does it really make sense to insert the `<launcher>`? In GNOME I am
 currently using a drop-in to configure `BindTo=graphical-session.target`,
@@ -78,7 +78,7 @@ global default for all (graphical) applications.
 
  * Should application lifetime be bound to the session?
  * May the user have applications that do not belong to the graphical session (e.g. launched from SSH)?
- * Could we maybe add a default `apps-.service.d` drop-in configuration?
+ * Could we maybe add a default `app-.service.d` drop-in configuration?
 
 ## XDG autostart integration
 
index c517cf573c15a291f0573b01e6d706d90bf10640..d82aca70653209531e0098c064aa7d0365980df8 100644 (file)
@@ -168,6 +168,10 @@ If the UID assigned to a user does not match the owner of the home directory in
 the file system, the home directory is automatically and recursively `chown()`ed
 to the correct UID.
 
-Depending on the `discard` setting of the user record either the backing
+Depending on the `luksDiscard` setting of the user record either the backing
 loopback file is `fallocate()`ed during activation, or the mounted file system
 is `FITRIM`ed after mounting, to ensure the setting is correctly enforced.
+
+When deactivating a home directory, the file system or block device is trimmed
+or extended as configured in the `luksOfflineDiscard` setting of the user
+record.
diff --git a/docs/PASSWORD_AGENTS.md b/docs/PASSWORD_AGENTS.md
new file mode 100644 (file)
index 0000000..75b10da
--- /dev/null
@@ -0,0 +1,40 @@
+---
+title: Password Agents
+category: Interfaces
+layout: default
+---
+
+# Password Agents
+
+systemd 12 and newer support lightweight password agents which can be used to query the user for system-level passwords or passphrases. These are passphrases that are not related to a specific user, but to some kind of hardware or service. Right now this is used exclusively for encrypted hard-disk passphrases but later on this is likely to be used to query passphrases of SSL certificates at Apache startup time as well. The basic idea is that a system component requesting a password entry can simply drop a simple .ini-style file into `/run/systemd/ask-password` which multiple different agents may watch via `inotify()`, and query the user as necessary. The answer is then sent back to the querier via an `AF_UNIX`/`SOCK_DGRAM` socket. Multiple agents might be running at the same time in which case they all should query the user and the agent which answers first wins. Right now systemd ships with the following passphrase agents:
+
+* A Plymouth agent used for querying passwords during boot-up
+* A console agent used in similar situations if Plymouth is not available
+* A GNOME agent which can be run as part of the normal user session which pops up a notification message and icon which when clicked receives the passphrase from the user. This is useful and necessary in case an encrypted system hard-disk is plugged in when the machine is already up.
+* A [`wall(1)`](http://man7.org/linux/man-pages/man1/wall.1.html) agent which sends wall messages as soon as a password shall be entered.
+* A simple tty agent which is built into "`systemctl start`" (and similar commands) and asks passwords to the user during manual startup of a service
+* A simple tty agent which can be run manually to respond to all queued passwords
+
+It is easy to write additional agents. The basic algorithm to follow looks like this:
+
+* Create an inotify watch on /run/systemd/ask-password, watch for `IN_CLOSE_WRITE|IN_MOVED_TO`
+* Ignore all events on files in that directory that do not start with "`ask.`"
+* As soon as a file named "`ask.xxxx`" shows up, read it. It's a simple `.ini` file that may be parsed with the usual parsers. The `xxxx` suffix is randomized.
+* Make sure to ignore unknown `.ini` file keys in those files, so that we can easily extend the format later on.
+* You'll find the question to ask the user in the `Message=` field in the `[Ask]` section. It is a single-line string in UTF-8, which might be internationalized (by the party that originally asks the question, not by the agent).
+* You'll find an icon name (following the XDG icon naming spec) to show next to the message in the `Icon=` field in the `[Ask]` section
+* You'll find the PID of the client asking the question in the `PID=` field in the `[Ask]` section (Before asking your question use `kill(PID, 0)` and ignore the file if this returns `ESRCH`; there's no need to show the data of this field but if you want to you may)
+* `Echo=` specifies whether the input should be obscured. If this field is missing or is `Echo=0`, the input should not be shown.
+* The socket to send the response to is configured via `Socket=` in the `[Ask]` section. It is a `AF_UNIX`/`SOCK_DGRAM` socket in the file system.
+* Ignore files where the time specified in the `NotAfter=` field in the `[Ask]` section is in the past. The time is specified in usecs, and refers to the `CLOCK_MONOTONIC` clock. If `NotAfter=` is `0`, no such check should take place.
+* Make sure to hide a password query dialog as soon as a) the `ask.xxxx` file is deleted, watch this with inotify. b) the `NotAfter=` time elapses, if it is set `!= 0`.
+* Access to the socket is restricted to privileged users. To acquire the necessary privileges to send the answer back, consider using PolicyKit. In fact, the GNOME agent we ship does that, and you may simply piggyback on that, by executing "`/usr/bin/pkexec /lib/systemd/systemd-reply-password 1 /path/to/socket`" or "`/usr/bin/pkexec /lib/systemd/systemd-reply-password 0 /path/to/socket`" and writing the password to its standard input. Use '`1`' as argument if a password was entered by the user, or '`0`' if the user canceled the request.
+* If you do not want to use PK ensure to acquire the necessary privileges in some other way and send a single datagram to the socket consisting of the password string either prefixed with "`+`" or with "`-`" depending on whether the password entry was successful or not. You may but don't have to include a final `NUL` byte in your message.
+
+Again, it is essential that you stop showing the password box/notification/status icon if the `ask.xxx` file is removed or when `NotAfter=` elapses (if it is set `!= 0`)!
+
+It may happen that multiple password entries are pending at the same time. Your agent needs to be able to deal with that. Depending on your environment you may either choose to show all outstanding passwords at the same time or instead only one and as soon as the user replied to that one go on to the next one.
+
+You may test this all with manually invoking the "`systemd-ask-password`" tool on the command line. Pass `--no-tty` to ensure the password is asked via the agent system. Note that only privileged users may use this tool (after all this is intended purely for system-level passwords).
+
+If you write a system level agent a smart way to activate it is using systemd `.path` units. This will ensure that systemd will watch the `/run/systemd/ask-password` directory and spawn the agent as soon as that directory becomes non-empty. In fact, the console, wall and Plymouth agents are started like this. If systemd is used to maintain user sessions as well you can use a similar scheme to automatically spawn your user password agent as well. (As of this moment we have not switched any DE over to use systemd for session management, however.)
index 95bfcb98d38b291e5d7828ad7c4c2185546418ec..064932970ffd64b43050c15363f6063ea5ca973c 100644 (file)
@@ -87,7 +87,7 @@ And now, here's the list of (hopefully) all APIs that we have introduced with sy
 | [Boot Loader interface](https://systemd.io/BOOT_LOADER_INTERFACE) | EFI variables | yes | yes | gummiboot | yes | - | no |
 | [Service bus API](https://www.freedesktop.org/wiki/Software/systemd/dbus) | D-Bus | yes | yes | system-config-services | no | - | no |
 | [logind](https://www.freedesktop.org/wiki/Software/systemd/logind) | D-Bus | yes | yes | GNOME | no | - | no |
-| [sd-login.h API](https://www.freedesktop.org/software/systemd/man/sd-login.html) | C Library | yes | yes | GNOME, PolicyKit, ... | no | - | no |
+| [sd-login.h API](https://www.freedesktop.org/software/systemd/man/sd-login.html) | C Library | yes | yes | GNOME, polkit, ... | no | - | no |
 | [sd-daemon.h API](https://www.freedesktop.org/software/systemd/man/sd-daemon.html) | C Library or Drop-in | yes | yes | numerous | yes | - | yes |
 | [sd-id128.h API](https://www.freedesktop.org/software/systemd/man/sd-id128.html) | C Library | yes | yes | - | yes | - | no |
 | [sd-journal.h API](https://www.freedesktop.org/software/systemd/man/sd-journal.html) | C Library | yes | yes | - | maybe | - | no |
index 0b34e5325fc87e6de8f10ceeb07e81a0e0f1b6ce..bd2915bab6095f569ed42d1ff71a447ff00d1a1c 100644 (file)
@@ -6,4 +6,8 @@ layout: default
 
 # Reporting of Security Vulnerabilities
 
-If you discover a security vulnerability, we'd appreciate a non-public disclosure. The [issue tracker](https://github.com/systemd/systemd/issues) and [systemd-devel mailing list](https://lists.freedesktop.org/mailman/listinfo/systemd-devel) are fully public. If you need to reach systemd developers in a non-public way, report the issue to the [systemd-security@redhat.com](mailto:systemd-security@redhat.com) mailing list. The disclosure will be coordinated with distributions.
+If you discover a security vulnerability, we'd appreciate a non-public disclosure. systemd developers can be contacted privately on the **[systemd-security@redhat.com](mailto:systemd-security@redhat.com) mailing list**. The disclosure will be coordinated with distributions.
+
+(The [issue tracker](https://github.com/systemd/systemd/issues) and [systemd-devel mailing list](https://lists.freedesktop.org/mailman/listinfo/systemd-devel) are fully public.)
+
+Subscription to the systemd-security mailing list is open to **regular systemd contributors and people working in the security teams of various distributions**. Those conditions should be backed by publicly accessible information (ideally, a track of posts and commits from the mail address in question). If you fall into one of those categories and wish to be subscribed, submit a **[subscription request](https://www.redhat.com/mailman/listinfo/systemd-security)**.
index d5a80466769841be47e77e173875713c0bfdd927..d9b1c20c77f3e1c0f42b62da1bf32d2e9b9d6e9c 100644 (file)
@@ -332,6 +332,7 @@ All mount unit settings are available to transient units:
 ✓ SloppyOptions=
 ✓ LazyUnmount=
 ✓ ForceUnmount=
+✓ ReadWriteOnly=
 ```
 
 ## Automount Unit Settings
index 6859c59da1319ef95b52eb1502635545076f64ba..a19f746a26f50a03c72574d0da9984ba4b825571 100644 (file)
@@ -77,7 +77,8 @@ supports is directly available in these JSON records. Hence it makes sense for
 any user management UI to expose them directly.
 
 `systemd-homed` exposes APIs to add, remove and make changes to local users via
-D-Bus, with full PolicyKit hook-up. On the command line this is exposed via the
+D-Bus, with full [polkit](https://www.freedesktop.org/software/polkit/docs/latest/)
+hook-up. On the command line this is exposed via the
 `homectl` command. A graphical UI that exposes similar functionality would be
 very useful, exposing the various new account settings, and in particular
 providing a stream-lined UI for enrolling new-style authentication tokens such
index 72acbcc026db6827677104aa0042a384a9fd36cb..6269b1e6ca5b3cd8b8ba9982987963e6c02ee58d 100644 (file)
@@ -455,6 +455,10 @@ storage. If false and `luks` storage is used turns this behavior off. In
 addition, depending on this setting an `FITRIM` or `fallocate()` operation is
 executed to make sure the image matches the selected option.
 
+`luksOfflineDiscard` → A boolean. Similar to `luksDiscard`, it controls whether
+to trim/allocate the file system/backing file when deactivating the home
+directory.
+
 `luksCipher` → A string, indicating the cipher to use for the LUKS storage mechanism.
 
 `luksCipherMode` → A string, selecting the cipher mode to use for the LUKS storage mechanism.
@@ -648,11 +652,12 @@ that may be used in this section are identical to the equally named ones in the
 `mountNoDevices`, `mountNoSuid`, `mountNoExecute`, `cifsDomain`,
 `cifsUserName`, `cifsService`, `imagePath`, `uid`, `gid`, `memberOf`,
 `fileSystemType`, `partitionUuid`, `luksUuid`, `fileSystemUuid`, `luksDiscard`,
-`luksCipher`, `luksCipherMode`, `luksVolumeKeySize`, `luksPbkdfHashAlgorithm`,
-`luksPbkdfType`, `luksPbkdfTimeCostUSec`, `luksPbkdfMemoryCost`,
-`luksPbkdfParallelThreads`, `rateLimitIntervalUSec`, `rateLimitBurst`,
-`enforcePasswordPolicy`, `autoLogin`, `stopDelayUSec`, `killProcesses`,
-`passwordChangeMinUSec`, `passwordChangeMaxUSec`, `passwordChangeWarnUSec`,
+`luksOfflineDiscard`, `luksOfflineDiscard`, `luksCipher`, `luksCipherMode`,
+`luksVolumeKeySize`, `luksPbkdfHashAlgorithm`, `luksPbkdfType`,
+`luksPbkdfTimeCostUSec`, `luksPbkdfMemoryCost`, `luksPbkdfParallelThreads`,
+`rateLimitIntervalUSec`, `rateLimitBurst`, `enforcePasswordPolicy`,
+`autoLogin`, `stopDelayUSec`, `killProcesses`, `passwordChangeMinUSec`,
+`passwordChangeMaxUSec`, `passwordChangeWarnUSec`,
 `passwordChangeInactiveUSec`, `passwordChangeNow`, `pkcs11TokenUri`.
 
 ## Fields in the `binding` section
index 1ab0f015840ab324fe64d4b1e9d3fb614883c6c4..2ee205a92f7465ef5cba86fee56db46ea6745848 100644 (file)
@@ -523,10 +523,10 @@ evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:*svnLENOVO:*pvrLenovoYoga500-14IBD*
 
 # Lenovo Thinkpad T490
 evdev:name:SynPS/2 Synaptics TouchPad:dmi:*:svnLENOVO:*pvrThinkPadT490:*
- EVDEV_ABS_00=::57
- EVDEV_ABS_01=::33
- EVDEV_ABS_35=::57
- EVDEV_ABS_36=::33
+ EVDEV_ABS_00=::44
+ EVDEV_ABS_01=::52
+ EVDEV_ABS_35=::44
+ EVDEV_ABS_36=::52
 
 # Lenovo Legion Y9000X2020
 evdev:name:MSFT0001:02 04F3:304B Touchpad:dmi:*svnLENOVO:*pvrLenovoLegionY9000X2020*
index 20c1e7ea0da26a6d80f5a4404a3e07e25d27c9f9..9e28db1e493d7576cfb4e505c7d805d7def24eda 100644 (file)
@@ -70,3 +70,7 @@ id-input:modalias:input:b0003v28bdp0078*
 # Lite-On Tech IBM USB Travel Keyboard with Ultra Nav Mouse
 id-input:modalias:input:b0003v04B3p301Ee0100-e0,1,2,4*
  ID_INPUT_POINTINGSTICK=1
+
+# Logitech Ultrathin Touch Mouse
+id-input:modalias:input:b0005v046DpB00De0700*
+ ID_INPUT_MOUSE=1
index ee335c8c1180878a25ff4547a4f47c78c1d8ac9c..51b7833f6033d9c8f605353326bf9ba2c897249c 100644 (file)
@@ -586,6 +586,8 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHDX9494NR:pvr*
 
 # HP EliteBook 725 G2
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPLicrice:pvr*
+# HP EliteBook 840 G1
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPEliteBook840G1:pvr*
 # HP ProBook 440 G2
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP440G2:pvr*
 # several HP ProBooks 4xx
@@ -1013,6 +1015,11 @@ evdev:input:b0005v046DpB30B*
  KEYBOARD_KEY_c103a=prog3      # Smartkey C → XF86Launch3
  KEYBOARD_KEY_c103b=prog4      # Smartkey D → XF86Launch4
 
+# Logitech K811
+evdev:input:b0005v046DpB317*
+ KEYBOARD_KEY_70047=brightnessdown
+ KEYBOARD_KEY_70048=brightnessup
+
 # iTouch
 evdev:input:b0003v046DpC308*
  KEYBOARD_KEY_90001=shop                                # Shopping
index c31acd4af3674fe67679f4fb9d833658e75d133e..0763f040f11ff238a7c6c9a12ad3ffc841bf670d 100644 (file)
@@ -193,6 +193,10 @@ sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd05/07/201
 sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd05/28/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnHampoo:rnCherryTrailCR:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:
  ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
 
+# Chuwi HiBook Pro (CWI526)
+sensor:modalias:acpi:BOSC0200*:dmi:*:svnHampoo*:pnP1D6_C109K:*
+ ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1 
+
 # Chuwi CoreBook
 # Chuwi CoreBook does not have its product name filled, so we
 # match the entire dmi-alias
@@ -297,6 +301,10 @@ sensor:modalias:acpi:KIOX010A*:dmi:*:svnGEO*:pnGeoFlex*:*
 sensor:modalias:platform:cros-ec-accel:dmi:*:svnGOOGLE*
  ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1
 
+# caroline board (Samsung Chromebook Pro) reports itself as svnGoogle
+sensor:modalias:platform:cros-ec-accel:dmi:*:svnGoogle:pnCaroline*
+ ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1
+
 #########################################
 # GP-electronic
 #########################################
@@ -465,6 +473,7 @@ sensor:modalias:acpi:SMO8500*:dmi:*:svnMEDION:pnAkoyaE2212TMD99720:*
  ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
 
 # Medion Akoya E2215T MD60198
+sensor:modalias:acpi:KIOX000A*:dmi:*svnMEDION:pnE2215TMD60198:*
 # Medion Akoya E3216 MD60900
 # Medion Akoya E3221 MD61237
 # Medion Akoya E2292 MD63390
index 7aeb6185aef7d76a177b4366fec14705c1efb13a..c759527e2a2ce4031ed792b1439949296dd05019 100644 (file)
@@ -756,3 +756,9 @@ mouse:usb:v3057p0001:*
  MOUSE_DPI=400@125 *800@125 1600@125 3200@125 400@500 800@500 1600@500 3200@500 400@1000 800@1000 1600@1000 3200@1000
  MOUSE_WHEEL_CLICK_COUNT=16
  MOUSE_WHEEL_CLICK_ANGLE=23
+
+# Zowie ZA12
+mouse:usb:v1af3p0001:name:Kingsis Peripherals ZOWIE Gaming mouse:
+ MOUSE_DPI=400@125 *800@125 1600@125 3200@125 400@500 800@500 1600@500 3200@500 400@1000 800@1000 1600@1000 3200@1000
+ MOUSE_WHEEL_CLICK_COUNT=16
+ MOUSE_WHEEL_CLICK_ANGLE=23
index 9b6fffd154ef9ad9f1779d6ce119432eb569439d..3942fe67f9b8eede6b080b5f249d0369435420d9 100644 (file)
@@ -41,7 +41,7 @@
     character are ignored. Each of the remaining lines describes one
     encrypted block device. Fields are delimited by white space.</para>
 
-    <para>Each line is in the form<programlisting><replaceable>name</replaceable> <replaceable>encrypted-device</replaceable> <replaceable>password</replaceable> <replaceable>options</replaceable></programlisting>
+    <para>Each line is in the form<programlisting><replaceable>volume-name</replaceable> <replaceable>encrypted-device</replaceable> <replaceable>key-file</replaceable> <replaceable>options</replaceable></programlisting>
     The first two fields are mandatory, the remaining two are
     optional.</para>
 
     it is opened as a LUKS device; otherwise, it is assumed to be in
     raw dm-crypt (plain mode) format.</para>
 
-    <para>The first field contains the name of the resulting encrypted
-    block device; the device is set up within
-    <filename>/dev/mapper/</filename>.</para>
+    <para>The first field contains the name of the resulting encrypted volume; its block device is set up
+    below <filename>/dev/mapper/</filename>.</para>
 
     <para>The second field contains a path to the underlying block
     device or file, or a specification of a block device via
     <literal>UUID=</literal> followed by the UUID.</para>
 
-    <para>The third field specifies the encryption password. If the
-    field is not present or the password is set to
-    <literal>none</literal> or <literal>-</literal>, the password has
-    to be manually entered during system boot. Otherwise, the field is
-    interpreted as an absolute path to a file containing the encryption
-    password. For swap encryption, <filename>/dev/urandom</filename>
-    or the hardware device <filename>/dev/hw_random</filename> can be
-    used as the password file; using <filename>/dev/random</filename>
-    may prevent boot completion if the system does not have enough
-    entropy to generate a truly random encryption key.</para>
+    <para>The third field specifies an absolute path to a file to read the encryption key from. If the field
+    is not present or set to <literal>none</literal> or <literal>-</literal>, a key file named after the
+    volume to unlock (i.e. the first column of the line), suffixed with <filename>.key</filename> is
+    automatically loaded from the <filename>/etc/cryptsetup-keys.d/</filename> and
+    <filename>/run/cryptsetup-keys.d/</filename> directories, if present. Otherwise, the password has to be
+    manually entered during system boot. For swap encryption, <filename>/dev/urandom</filename> may be used
+    as key file.</para>
 
     <para>The fourth field, if present, is a comma-delimited list of
     options. The following options are recognized:</para>
         size is then given by the key size.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>keyfile-erase</option></term>
+
+        <listitem><para>If enabled, the specified key file is erased after the volume is activated or when
+        activation fails. This is in particular useful when the key file is only acquired transiently before
+        activation (e.g. via a file in <filename>/run/</filename>, generated by a service running before
+        activation), and shall be removed after use. Defaults to off.</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><option>key-slot=</option></term>
 
         before it is used to unlock the LUKS volume.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>try-empty-password=</option></term>
+
+        <listitem><para>Takes a boolean argument. If enabled, right before asking the user for a password it
+        is first attempted to unlock the volume with an empty password. This is useful for systems that are
+        initialized with an encrypted volume with only an empty password set, which shall be replaced with a
+        suitable password during first boot, but after activation.</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><option>x-systemd.device-timeout=</option></term>
 
diff --git a/man/directives-template.xml b/man/directives-template.xml
new file mode 100644 (file)
index 0000000..5038061
--- /dev/null
@@ -0,0 +1,199 @@
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="systemd.directives" conditional="HAVE_PYTHON">
+  <refentryinfo>
+    <title>systemd.directives</title>
+    <productname>systemd</productname>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>systemd.directives</refentrytitle>
+    <manvolnum>7</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>systemd.directives</refname>
+    <refpurpose>Index of configuration directives</refpurpose>
+  </refnamediv>
+
+  <refsect1>
+    <title>Unit directives</title>
+
+    <para>Directives for configuring units, used in unit files.</para>
+
+    <variablelist id='unit-directives' />
+  </refsect1>
+
+  <refsect1>
+    <title>Options on the kernel command line</title>
+
+    <para>Kernel boot options for configuring the behaviour of the systemd process.</para>
+
+    <variablelist id='kernel-commandline-options' />
+  </refsect1>
+
+  <refsect1>
+    <title>Environment variables</title>
+
+    <para>Environment variables understood by the systemd manager and other programs and environment
+    variable-compatible settings.</para>
+
+    <variablelist id='environment-variables' />
+  </refsect1>
+
+  <refsect1>
+    <title>EFI variables</title>
+
+    <para>EFI variables understood by
+    <citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+    and other programs.</para>
+
+    <variablelist id='efi-variables' />
+  </refsect1>
+
+  <refsect1>
+    <title>Home Area/User Account directives</title>
+
+    <para>Directives for configuring home areas and user accounts via
+    <citerefentry><refentrytitle>systemd-homed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
+
+    <variablelist id='home-directives' />
+  </refsect1>
+
+  <refsect1>
+    <title>UDEV directives</title>
+
+    <para>Directives for configuring systemd units through the udev database.</para>
+
+    <variablelist id='udev-directives' />
+  </refsect1>
+
+  <refsect1>
+    <title>Network directives</title>
+
+    <para>Directives for configuring network links through the net-setup-link udev builtin and networks
+    through systemd-networkd.</para>
+
+    <variablelist id='network-directives' />
+  </refsect1>
+
+  <refsect1>
+    <title>Journal fields</title>
+
+    <para>Fields in the journal events with a well known meaning.</para>
+
+    <variablelist id='journal-directives' />
+  </refsect1>
+
+  <refsect1>
+    <title>PAM configuration directives</title>
+
+    <para>Directives for configuring PAM behaviour.</para>
+
+    <variablelist id='pam-directives' />
+  </refsect1>
+
+  <refsect1>
+    <title><filename>/etc/crypttab</filename> and
+    <filename>/etc/fstab</filename> options</title>
+
+    <para>Options which influence mounted filesystems and encrypted volumes.</para>
+
+    <variablelist id='fstab-options' />
+  </refsect1>
+
+  <refsect1>
+    <title><citerefentry><refentrytitle>systemd.nspawn</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+    directives</title>
+
+    <para>Directives for configuring systemd-nspawn containers.</para>
+
+    <variablelist id='nspawn-directives' />
+  </refsect1>
+
+  <refsect1>
+    <title>Program configuration options</title>
+
+    <para>Directives for configuring the behaviour of the systemd process and other tools through
+    configuration files.</para>
+
+    <variablelist id='config-directives' />
+  </refsect1>
+
+  <refsect1>
+    <title>Command line options</title>
+
+    <para>Command-line options accepted by programs in the systemd suite.</para>
+
+    <variablelist id='options' />
+  </refsect1>
+
+  <refsect1>
+    <title>Constants</title>
+
+    <para>Various constant used and/or defined by systemd.</para>
+
+    <variablelist id='constants' />
+  </refsect1>
+
+  <refsect1>
+    <title>Miscellaneous options and directives</title>
+
+    <para>Other configuration elements which don't fit in any of the above groups.</para>
+
+    <variablelist id='miscellaneous' />
+  </refsect1>
+
+  <refsect1>
+    <title>Specifiers</title>
+
+    <para>Short strings which are substituted in configuration directives.</para>
+
+    <variablelist id='specifiers' />
+  </refsect1>
+
+  <refsect1>
+    <title>Files and directories</title>
+
+    <para>Paths and file names referred to in the documentation.</para>
+
+    <variablelist id='filenames' />
+  </refsect1>
+
+  <refsect1>
+    <title>D-Bus interfaces</title>
+
+    <para>Interfaces exposed over D-Bus.</para>
+
+    <variablelist id='dbus-interface' />
+  </refsect1>
+
+  <refsect1>
+    <title>D-Bus methods</title>
+
+    <para>Methods exposed in the D-Bus interface.</para>
+
+    <variablelist id='dbus-method' />
+  </refsect1>
+
+  <refsect1>
+    <title>D-Bus properties</title>
+
+    <para>Properties exposed in the D-Bus interface.</para>
+
+    <variablelist id='dbus-property' />
+  </refsect1>
+
+  <refsect1>
+    <title>D-Bus signals</title>
+
+    <para>Signals emitted in the D-Bus interface.</para>
+
+    <variablelist id='dbus-signal' />
+  </refsect1>
+
+  <refsect1>
+    <title>Colophon</title>
+    <para id='colophon' />
+  </refsect1>
+</refentry>
index 6cec7a13c818b8d40b69efb2253b14eb7f7a8e8a..14877a0cde047e24265139e170443e624e671c8a 100644 (file)
         <listitem><para>Selects the storage mechanism to use for this home directory. Takes one of
         <literal>luks</literal>, <literal>fscrypt</literal>, <literal>directory</literal>,
         <literal>subvolume</literal>, <literal>cifs</literal>. For details about these mechanisms, see
-        above. If a new home directory is created and the storage type is not specifically specified defaults
-        to <literal>luks</literal> if supported, <literal>subvolume</literal> as first fallback if supported,
-        and <literal>directory</literal> if not.</para></listitem>
+        above. If a new home directory is created and the storage type is not specifically specified,
+        <citerefentry><refentrytitle>homed.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+        defines which default storage to use.</para></listitem>
       </varlistentry>
 
       <varlistentry>
 
         <listitem><para>When LUKS2 storage is used configures the file system type to use inside the home
         directory LUKS2 container. One of <literal>ext4</literal>, <literal>xfs</literal>,
-        <literal>btrfs</literal>. If not specified defaults to <literal>ext4</literal>. Note that
-        <literal>xfs</literal> is not recommended as its support for file system resizing is too
-        limited.</para></listitem>
+        <literal>btrfs</literal>. If not specified
+        <citerefentry><refentrytitle>homed.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+        defines which default file system type to use. Note that <literal>xfs</literal> is not recommended as
+        its support for file system resizing is too limited.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         loopback file) the discard logic defaults to on.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--luks-offline-discard=</option><replaceable>BOOL</replaceable></term>
+
+        <listitem><para>Similar to <option>--luks-discard=</option>, controls the trimming of the file
+        system. However, while <option>--luks-discard=</option> controls what happens when the home directory
+        is active, <option>--luks-offline-discard=</option> controls what happens when it becomes inactive,
+        i.e. whether to trim/allocate the storage when deactivating the home directory. This option defaults
+        to on, to ensure disk space is minimized while a user is not logged in.</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><option>--luks-cipher=</option><replaceable>CIPHER</replaceable></term>
         <term><option>--luks-cipher-mode=</option><replaceable>MODE</replaceable></term>
@@ -827,6 +838,7 @@ homectl update lafcadio --pkcs11-token-uri=…</programlisting>
     <para>
       <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>systemd-homed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>homed.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>userdbctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
       <citerefentry project='man-pages'><refentrytitle>useradd</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
       <citerefentry project='man-pages'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
diff --git a/man/homed.conf.xml b/man/homed.conf.xml
new file mode 100644 (file)
index 0000000..03590fe
--- /dev/null
@@ -0,0 +1,84 @@
+<?xml version='1.0'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="homed.conf" conditional='ENABLE_RESOLVE'
+    xmlns:xi="http://www.w3.org/2001/XInclude">
+  <refentryinfo>
+    <title>homed.conf</title>
+    <productname>systemd</productname>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>homed.conf</refentrytitle>
+    <manvolnum>5</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>homed.conf</refname>
+    <refname>homed.conf.d</refname>
+    <refpurpose>Home area/user account manager configuration files</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <para><filename>/etc/systemd/homed.conf</filename></para>
+    <para><filename>/etc/systemd/homed.conf.d/*.conf</filename></para>
+    <para><filename>/run/systemd/homed.conf.d/*.conf</filename></para>
+    <para><filename>/usr/lib/systemd/homed.conf.d/*.conf</filename></para>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>These configuration files control default parameters for home areas/user accounts created and
+    managed by
+    <citerefentry><refentrytitle>systemd-homed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
+
+  </refsect1>
+
+  <xi:include href="standard-conf.xml" xpointer="main-conf" />
+
+  <refsect1>
+    <title>Options</title>
+
+    <para>The following options are available in the <literal>[Home]</literal> section:</para>
+
+    <variablelist class='home-directives'>
+
+      <varlistentry>
+        <term><varname>DefaultStorage=</varname></term>
+        <listitem><para>The default storage to use for home areas. Takes one of <literal>luks</literal>,
+        <literal>fscrypt</literal>, <literal>directory</literal>, <literal>subvolume</literal>,
+        <literal>cifs</literal>. For details about these options, see
+        <citerefentry><refentrytitle>homectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>. If not
+        configured or assigned the empty string, the default storage is automatically determined: if not
+        running in a container enviroment and <filename>/home/</filename> is not itself encrypted, defaults
+        to <literal>luks</literal>. Otherwise defaults to <literal>subvolume</literal> if
+        <filename>/home/</filename> is on a btrfs file system, and <literal>directory</literal>
+        otherwise. Note that the storage selected on the <command>homectl</command> command line always takes
+        precedence.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>DefaultFileSystemType=</varname></term>
+        <listitem><para>When using <literal>luks</literal> as storage (see above), selects the default file
+        system to use inside the user's LUKS volume. Takes one of <literal>ext4</literal>,
+        <literal>xfs</literal> or <literal>btrfs</literal>. If not specified defaults to
+        <literal>ext4</literal>. This setting has no effect if a different storage mechanism is used. The
+        file system type selected on the <command>homectl</command> command line always takes
+        precedence.</para></listitem>
+      </varlistentry>
+
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+      <title>See Also</title>
+      <para>
+      <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>systemd-homed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      </para>
+  </refsect1>
+
+</refentry>
index 03293382e6e0b56fd748bac1c24a5a8e9e6f2ca3..7ca62f48105a7ab822e6807ac6c502118d33612f 100644 (file)
@@ -57,7 +57,7 @@
 
     <para>Use
     <citerefentry><refentrytitle>systemd-firstboot</refentrytitle><manvolnum>1</manvolnum></citerefentry>
-    to initialize the system host name for mounted (but not booted)
+    to initialize the system hostname for mounted (but not booted)
     system images.</para>
   </refsect1>
 
@@ -84,7 +84,7 @@
         simplified in regards to the character set used before the latter are updated. This is done by removing special
         characters and spaces. This ensures that the pretty and the static hostname are always closely related while
         still following the validity rules of the specific name. This simplification of the hostname string is not done
-        if only the transient and/or static host names are set, and the pretty host name is left untouched.</para>
+        if only the transient and/or static hostnames are set, and the pretty hostname is left untouched.</para>
 
         <para>Pass the empty string <literal></literal> as the
         hostname to reset the selected hostnames to their default
index d6d475ed9787dc2b696dac5971b631727c770c8e..6e4728b013425be52c9d57db01f089e0517371e2 100644 (file)
                 <option>cat</option>
               </term>
               <listitem>
-                <para>generates a very terse output, only showing the
-                actual message of each journal entry with no metadata,
-                not even a timestamp.</para>
+                <para>generates a very terse output, only showing the actual message of each journal entry
+                with no metadata, not even a timestamp. If combined with the
+                <option>--output-fields=</option> option will output the listed fields for each log record,
+                instead of the message.</para>
               </listitem>
             </varlistentry>
 
       <varlistentry>
         <term><option>--output-fields=</option></term>
 
-        <listitem><para>A comma separated list of the fields which should be included in the output. This has an
-        effect only for the output modes which would normally show all fields (<option>verbose</option>,
-        <option>export</option>, <option>json</option>, <option>json-pretty</option>, <option>json-sse</option> and
-        <option>json-seq</option>). The <literal>__CURSOR</literal>, <literal>__REALTIME_TIMESTAMP</literal>,
+        <listitem><para>A comma separated list of the fields which should be included in the output. This has
+        an effect only for the output modes which would normally show all fields (<option>verbose</option>,
+        <option>export</option>, <option>json</option>, <option>json-pretty</option>,
+        <option>json-sse</option> and <option>json-seq</option>), as well as on <option>cat</option>. For the
+        former, the <literal>__CURSOR</literal>, <literal>__REALTIME_TIMESTAMP</literal>,
         <literal>__MONOTONIC_TIMESTAMP</literal>, and <literal>_BOOT_ID</literal> fields are always
         printed.</para></listitem>
       </varlistentry>
index 4aac14ea180c8bf39961b3dc231ea6606888350b..0f2972a0b6840346228a56198f3e8d6b8d85eddc 100644 (file)
 
         <listitem><para>Takes a boolean argument, defaults to on. If off,
         <citerefentry><refentrytitle>systemd-firstboot.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-        will not query the user for basic system settings, even if the system boots up for the first time and the
-        relevant settings are not initialized yet.</para></listitem>
+        will not query the user for basic system settings, even if the system boots up for the first time and
+        the relevant settings are not initialized yet. Not to be confused with
+        <varname>systemd.condition-first-boot=</varname> (see below), which overrides the result of the
+        <varname>ConditionFirstBoot=</varname> unit file condition, and thus controls more than just
+        <filename>systemd-firstboot.service</filename> behaviour.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>systemd.condition-needs-update=</varname></term>
+
+        <listitem><para>Takes a boolean argument. If specified, overrides the result of
+        <varname>ConditionNeedsUpdate=</varname> unit condition checks. See
+        <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
+        details.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>systemd.condition-first-boot=</varname></term>
+
+        <listitem><para>Takes a boolean argument. If specified, overrides the result of
+        <varname>ConditionFirstBoot=</varname> unit condition checks. See
+        <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
+        details. Not to be confused with <varname>systemd.firstboot=</varname> which only controls behaviour
+        of the <filename>systemd-firstboot.service</filename> system service but has no effect on the
+        condition check (see above).</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>systemd.clock-usec=</varname></term>
+
+        <listitem><para>Takes a decimal, numeric timestamp in µs since January 1st 1970, 00:00am, to set the
+        system clock to. The system time is set to the specified timestamp early during
+        boot. It is not propagated to the hardware clock (RTC).</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>systemd.hostname=</varname></term>
+
+        <listitem><para>Accepts a hostname to set during early boot. If specified takes precedence over what
+        is set in <filename>/etc/hostname</filename>. Note that this does not bar later runtime changes to
+        the hostname, it simply controls the initial hostname set during early boot.</para></listitem>
       </varlistentry>
     </variablelist>
 
index 4fb27abe0a32f73d93dc85835e225acab0946139..7a0a396a1ebabcbe4387d9cba7773e12b9d4e482 100644 (file)
@@ -70,7 +70,7 @@
         <literal>Lennart's Computer</literal> an Internet hostname of
         <literal>lennarts-computer</literal> might be a good choice.
         If this parameter is not set, an application should fall back
-        to the Internet host name for presentation
+        to the Internet hostname for presentation
         purposes.</para></listitem>
       </varlistentry>
 
index c211ca02a94cea9d6fb84115d4884cff8a64ad38..e903eca7214aea2a83af521ba390212e569b60e5 100644 (file)
@@ -56,7 +56,7 @@
     </itemizedlist>
 
     <para>Machines are identified by names that follow the same rules
-    as UNIX and DNS host names. For details, see below.</para>
+    as UNIX and DNS hostnames. For details, see below.</para>
 
     <para>Machines are instantiated from disk or file system images that
     frequently — but not necessarily — carry the same name as machines running
         image is optimized for file systems that support copy-on-write, and might not be efficient on others, due to
         file system limitations.</para>
 
-        <para>Note that this command leaves host name, machine ID and
+        <para>Note that this command leaves hostname, machine ID and
         all other settings that could identify the instance
         unmodified. The original image and the cloned copy will hence
         share these credentials, and it might be necessary to manually
 
     <para>The <command>machinectl</command> tool operates on machines
     and images whose names must be chosen following strict
-    rules. Machine names must be suitable for use as host names
+    rules. Machine names must be suitable for use as hostnames
     following a conservative subset of DNS and UNIX/Linux
     semantics. Specifically, they must consist of one or more
     non-empty label strings, separated by dots. No leading or trailing
index 8021adedec8d088708566dade8db51327a49a8ba..3a7143a4b6a7377a71326af8cf80a291e31d0f72 100644 (file)
@@ -34,6 +34,7 @@ custom_entities_ent = configure_file(
 man_pages = []
 html_pages = []
 source_xml_files = []
+dbus_docs = []
 foreach tuple : xsltproc.found() ? manpages : []
         stem = tuple[0]
         section = tuple[1]
@@ -90,7 +91,11 @@ foreach tuple : xsltproc.found() ? manpages : []
                         install_dir : join_paths(docdir, 'html'))
                 html_pages += p3
 
-                source_xml_files += files(tuple[0] + '.xml')
+                file = files(tuple[0] + '.xml')
+                source_xml_files += file
+                if tuple[0].startswith('org.freedesktop.')
+                        dbus_docs += file
+                endif
         else
                 message('Skipping @0@.@1@ because @2@ is false'.format(stem, section, condition))
         endif
@@ -105,9 +110,9 @@ endif
 
 systemd_directives_xml = custom_target(
         'systemd.directives.xml',
-        input : source_xml_files,
+        input : ['directives-template.xml', source_xml_files],
         output : 'systemd.directives.xml',
-        command : [make_directive_index_py, '@OUTPUT@'] + source_xml_files)
+        command : [make_directive_index_py, '@OUTPUT@', '@INPUT@'])
 
 nonindex_xml_files = source_xml_files + [systemd_directives_xml]
 systemd_index_xml = custom_target(
@@ -193,13 +198,26 @@ run_target(
 
 ############################################################
 
+if dbus_docs.length() > 0
+        custom_target(
+                'update-dbus-docs',
+                output : 'update-dbus-docs',
+                command : ['python3',
+                           '@0@/tools/update-dbus-docs.py'.format(project_source_root),
+                           '--build-dir=@0@'.format(project_build_root),
+                           '@INPUT@'],
+                input : dbus_docs)
+endif
+
+############################################################
+
 if git.found()
         custom_target(
                 'update-man-rules',
                 output : 'update-man-rules',
                 command : ['sh', '-c',
                            'cd @0@ && '.format(meson.build_root()) +
-                           'python3 @0@/tools/make-man-rules.py $(git ls-files ":/man/*.xml") >t && '.format(project_source_root) +
+                           'python3 @0@/tools/update-man-rules.py $(git ls-files ":/man/*.xml") >t && '.format(project_source_root) +
                            'mv t @0@/rules/meson.build'.format(meson.current_source_dir())],
                 depend_files : custom_entities_ent)
 endif
index cc33b2c08228dd030b20d80b17c39e67389afee9..8bc75b1316038901311fc7ab86b14561e66e5d47 100644 (file)
@@ -29,7 +29,7 @@
     <title>Description</title>
 
     <para><command>nss-resolve</command> is a plug-in module for the GNU Name Service Switch (NSS) functionality of the
-    GNU C Library (<command>glibc</command>) enabling it to resolve host names via the
+    GNU C Library (<command>glibc</command>) enabling it to resolve hostnames via the
     <citerefentry><refentrytitle>systemd-resolved</refentrytitle><manvolnum>8</manvolnum></citerefentry> local network
     name resolution service. It replaces the <command>nss-dns</command> plug-in module that traditionally resolves
     hostnames via DNS.</para>
diff --git a/man/org.freedesktop.LogControl1.xml b/man/org.freedesktop.LogControl1.xml
new file mode 100644 (file)
index 0000000..125a008
--- /dev/null
@@ -0,0 +1,106 @@
+<?xml version='1.0'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" >
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="org.freedesktop.LogControl1"
+    xmlns:xi="http://www.w3.org/2001/XInclude">
+  <refentryinfo>
+    <title>org.freedesktop.LogControl1</title>
+    <productname>systemd</productname>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>org.freedesktop.LogControl1</refentrytitle>
+    <manvolnum>5</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>org.freedesktop.LogControl1</refname>
+    <refpurpose>D-Bus interface to query and set logging configuration</refpurpose>
+  </refnamediv>
+
+  <refsect1>
+    <title>Introduction</title>
+
+    <para><interfacename>org.freedesktop.LogControl1</interfacename> is a generic interface that is intended
+    to be used by any daemon which should allow setting the log level and target over D-Bus. It is implemented
+    by various daemons that are part of the
+    <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry> suite.</para>
+
+    <para>It is assumed that those settings are global for the whole program, so a fixed object path is
+    used. The interface should always be available under the path
+    <filename>/org/freedesktop/LogControl1</filename>.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>The following interface is exposed:</para>
+
+    <programlisting executable="systemd" node="/org/freedesktop/LogControl1" interface="org.freedesktop.LogControl1">
+node /org/freedesktop/LogControl1 {
+  interface org.freedesktop.LogControl1 {
+    properties:
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      @org.freedesktop.systemd1.Privileged("true")
+      readwrite s LogLevel = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      @org.freedesktop.systemd1.Privileged("true")
+      readwrite s LogTarget = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly s SyslogIdentifier = '...';
+  };
+  interface org.freedesktop.DBus.Peer { ... };
+  interface org.freedesktop.DBus.Introspectable { ... };
+  interface org.freedesktop.DBus.Properties { ... };
+};
+    </programlisting>
+
+    <!--Autogenerated cross-references for systemd.directives, do not edit-->
+
+    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.LogControl1"/>
+
+    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.LogControl1"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="LogLevel"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="LogTarget"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="SyslogIdentifier"/>
+
+    <!--End of Autogenerated section-->
+
+    <refsect2>
+      <title>Properties</title>
+
+      <para><varname>LogLevel</varname> describes the
+      <citerefentry><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>-style
+      log-level, and should be one of <literal>emerg</literal>, <literal>alert</literal>,
+      <literal>crit</literal>, <literal>err</literal>, <literal>warning</literal>, <literal>notice</literal>,
+      <literal>info</literal>, <literal>debug</literal>, in order of increasing verbosity.</para>
+
+      <para><varname>LogTarget</varname> describes the log target (mechanism). It should be one of
+      <literal>console</literal> (log to the console or standard output),
+      <literal>kmsg</literal> (log to the kernel ring buffer),
+      <literal>journal</literal> (log the the journal natively, see
+      <citerefentry><refentrytitle>systemd-journald.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>),
+      <literal>syslog</literal> (log using the
+      <citerefentry><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry> call).
+      </para>
+
+      <para>Those two properties are writable, so they may be set by sufficiently privileged users.</para>
+
+      <para><varname>SyslogIdentifier</varname> is a read-only property that shows the "syslog identifier".
+      It is a short string that identifies the program that is the source of log messages that is passed to
+      the <citerefentry><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry> call.
+      </para>
+
+      <para>Note: <command>journalctl</command> option <option>-p</option>/<option>--priority=</option> may
+      be used to filter log messages by log level, option <option>-t</option>/<option>--identifier=</option>
+      may be used to by the syslog identifier, and filters like <literal>_TRANSPORT=syslog</literal>,
+      <literal>_TRANSPORT=journal</literal>, and <literal>_TRANSPORT=kernel</literal> may be used to filter
+      messages by the mechanism through which they reached <command>systemd-journald</command>.</para>
+    </refsect2>
+  </refsect1>
+</refentry>
diff --git a/man/org.freedesktop.home1.xml b/man/org.freedesktop.home1.xml
new file mode 100644 (file)
index 0000000..e7d12a0
--- /dev/null
@@ -0,0 +1,502 @@
+<?xml version='1.0'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" >
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="org.freedesktop.home1" conditional='ENABLE_HOMED'
+    xmlns:xi="http://www.w3.org/2001/XInclude">
+  <refentryinfo>
+    <title>org.freedesktop.home1</title>
+    <productname>systemd</productname>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>org.freedesktop.home1</refentrytitle>
+    <manvolnum>5</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>org.freedesktop.home1</refname>
+    <refpurpose>The D-Bus interface of systemd-homed</refpurpose>
+  </refnamediv>
+
+  <refsect1>
+    <title>Introduction</title>
+
+    <para><citerefentry><refentrytitle>systemd-homed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+    is a system service which may be used to to create, remove, change or inspect home areas. This page
+    describes the D-Bus interface.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>The Manager Object</title>
+
+    <para>The service exposes the following interfaces on the Manager object on the bus:</para>
+
+    <programlisting executable="systemd-homed" node="/org/freedesktop/home1" interface="org.freedesktop.home1.Manager">
+node /org/freedesktop/home1 {
+  interface org.freedesktop.home1.Manager {
+    methods:
+      GetHomeByName(in  s user_name,
+                    out u uid,
+                    out s home_state,
+                    out u gid,
+                    out s real_name,
+                    out s home_directory,
+                    out s shell,
+                    out o bus_path);
+      GetHomeByUID(in  u uid,
+                   out s user_name,
+                   out s home_state,
+                   out u gid,
+                   out s real_name,
+                   out s home_directory,
+                   out s shell,
+                   out o bus_path);
+      GetUserRecordByName(in  s user_name,
+                          out s user_record,
+                          out b incomplete,
+                          out o bus_path);
+      GetUserRecordByUID(in  u uid,
+                         out s user_record,
+                         out b incomplete,
+                         out o bus_path);
+      ListHomes(out a(susussso) home_areas);
+      ActivateHome(in  s user_name,
+                   in  s secret);
+      DeactivateHome(in  s user_name);
+      RegisterHome(in  s user_record);
+      UnregisterHome(in  s user_name);
+      CreateHome(in  s user_record);
+      RealizeHome(in  s user_name,
+                  in  s secret);
+      RemoveHome(in  s user_name);
+      FixateHome(in  s user_name,
+                 in  s secret);
+      AuthenticateHome(in  s user_name,
+                       in  s secret);
+      UpdateHome(in  s user_record);
+      ResizeHome(in  s user_name,
+                 in  t size,
+                 in  s secret);
+      ChangePasswordHome(in  s user_name,
+                         in  s new_secret,
+                         in  s old_secret);
+      LockHome(in  s user_name);
+      UnlockHome(in  s user_name,
+                 in  s secret);
+      AcquireHome(in  s user_name,
+                  in  s secret,
+                  in  b please_suspend,
+                  out h send_fd);
+      RefHome(in  s user_name,
+              in  b please_suspend,
+              out h send_fd);
+      ReleaseHome(in  s user_name);
+      LockAllHomes();
+    properties:
+      readonly a(sso) AutoLogin = [...];
+  };
+  interface org.freedesktop.DBus.Peer { ... };
+  interface org.freedesktop.DBus.Introspectable { ... };
+  interface org.freedesktop.DBus.Properties { ... };
+};
+    </programlisting>
+
+    <!--Autogenerated cross-references for systemd.directives, do not edit-->
+
+    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.home1.Manager"/>
+
+    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.home1.Manager"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="GetHomeByName()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="GetHomeByUID()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="GetUserRecordByName()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="GetUserRecordByUID()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="ListHomes()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="ActivateHome()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="DeactivateHome()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="RegisterHome()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="UnregisterHome()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="CreateHome()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="RealizeHome()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="RemoveHome()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="FixateHome()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="AuthenticateHome()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="UpdateHome()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="ResizeHome()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="ChangePasswordHome()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="LockHome()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="UnlockHome()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="AcquireHome()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="RefHome()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="ReleaseHome()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="LockAllHomes()"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="AutoLogin"/>
+
+    <!--End of Autogenerated section-->
+
+    <refsect2>
+      <title>Methods</title>
+
+      <para><function>GetHomeByName()</function> returns basic user information (a minimal subset of the full
+      user record), provided a user name. The information supplied more or less matches what
+      <citerefentry><refentrytitle>getpwnam</refentrytitle><manvolnum>3</manvolnum></citerefentry> returns:
+      the numeric UID and GID, the real name, home directory and shell. In addition it returns a state
+      identifier describing the state the user's home directory is in, as well as a bus path referring to the
+      bus object encapsulating the user record and home directory. This object implements the
+      <classname>org.freedesktop.home1.Home</classname> interface documented below.</para>
+
+      <para><function>GetHomeByUID()</function> is similar to <function>GetHomeByName()</function> but
+      acquires the information based on the numeric UID of the user.</para>
+
+      <para><function>GetUserRecordByName()</function> is also similar to
+      <function>GetHomeByName()</function> but returns the full JSON user record data instead of the broken
+      down records. An additional returned boolean indicates whether the record is complete or not. A record
+      is considered complete when its <literal>privileged</literal> section is included, and incomplete if it
+      was removed (see <ulink url="https://systemd.io/USER_RECORD">JSON User Records</ulink> for details
+      about the various sections of a user record). Generally, only privileged clients and clients running
+      under the identity of the user itself get access to the <literal>privileged</literal> section and will
+      thus see complete records.</para>
+
+      <para><function>GetUserRecordByUID()</function> is similar to <function>GetUserRecordByName()</function>
+      but returns the user record matching the specified numeric UID.</para>
+
+      <para><function>ListHomes()</function> returns an array of all locally managed users. The array
+      contains the same fields <function>GetHomeByName()</function> returns: user name, numeric UID, state,
+      numeric GID, real name, home directory, shell and bus path of the matching bus object.</para>
+
+      <para><function>ActivateHome()</function> activates (i.e. mounts) the home directory of the specified
+      user. The second argument shall contain a user record consisting only of a <literal>secret</literal>
+      section (all other sections should be stripped, see <ulink url="https://systemd.io/USER_RECORD">JSON
+      User Records</ulink> for details), and should contain only the secret credentials necessary for
+      unlocking the home directory. Typically a client would invoke this function first with an entirely
+      empty record (which is possibly sufficient if single-factor authentication with a plugged-in security
+      token is configured), and would then retry with a record populated with more information, depending on
+      the returned error code, in case more credentials are necessary. This function is synchronous and
+      returns only after the home directory was fully activated (or the operation failed), which might take
+      some time. Clients must be prepared for that, and typically should extend the D-Bus method call
+      time-out accordingly. This method is equivalent to the <function>Activate()</function> method on the
+      <classname>org.freedesktop.home1.Home</classname> interface documented below, but may be called on the
+      manager object and takes a user name as additional argument, instead.</para>
+
+      <para><function>DeactivateHome()</function> deactivates (i.e. unmounts) the home directory of the
+      specified user. It is equivalent to the <function>Deactivate()</function> method on the
+      <classname>org.freedesktop.home1.Home</classname> interface documented below.</para>
+
+      <para><function>RegisterHome()</function> registers a new home directory locally. It receives the JSON
+      user record as only argument (which typically excludes the <literal>secret</literal>
+      section). Registering a home directory just makes the user record known to the system, it does not
+      create a home directory or such (which is expected to exist already, or created later). This operation
+      is useful to register home directories locally that are not located where
+      <filename>systemd-homed.service</filename> would find them automatically.</para>
+
+      <para><function>UnregisterHome()</function> unregisters an existing home directory. It takes a user
+      name as argument and undoes what <function>RegisterHome()</function> does. It does not attempt to
+      remove the home directory itself, it just unregisters it with the local system. Note that if the home
+      directory is placed where <filename>systemd-homed.service</filename> looks for home directories anyway
+      this call will only undo fixation (see below), but the record will remain known to
+      <filename>systemd-homed.service</filename> and be listed among known records. Since the user record is
+      embedded into the home directory this operation generally does not discard data belonging to the user
+      or their record. This method is equivalent to
+      <function>Unregister()</function> on the <classname>org.freedesktop.home1.Home</classname>
+      interface.</para>
+
+      <para><function>CreateHome()</function> registers and creates a new home directory. This takes a fully
+      specified JSON user record as argument (including the <literal>secret</literal> section. This registers
+      the user record locally and creates a home directory matching it, depending on the settings specified
+      in the record in combination with local configuration.</para>
+
+      <para><function>RealizeHome()</function> creates a home directory whose user record is already
+      registered locally. This takes a user name plus a user record consisting only of the
+      <literal>secret</literal> section. Invoking <function>RegisterHome()</function> followed by
+      <function>RealizeHome()</function> is mostly equivalent to calling <function>CreateHome()</function>,
+      except that the latter combines the two in atomic fashion. This method is equivalent to
+      <function>Realize()</function> on the <classname>org.freedesktop.home1.Home</classname>
+      interface.</para>
+
+      <para><function>RemoveHome()</function> unregisters a user record locally, and removes the home
+      directory belonging to it, if it is accessible. It takes a user name as argument. This method is equivalent to
+      <function>Remove()</function> on the <classname>org.freedesktop.home1.Home</classname>
+      interface.</para>
+
+      <para><function>FixateHome()</function> <literal>fixates</literal> an automatically discovered home
+      directory. <filename>systemd-homed.service</filename> automatically discovers home directories dropped
+      in our plugged in and adds them to the runtime list of user records it manages. A user record
+      discovered that way may be <literal>fixated</literal>, in which case it is copied out of the home
+      directory, onto persistent storage, to fixate the UID/GID assignment of the record, and extract
+      additional (typically previously encrypted) user record data from the home directory. A home directory
+      mus be fixated before it can be logged into. This method call takes a user name and a JSON user record
+      consisting only of the <literal>secret</literal> section as argument. This method is equivalent to
+      <function>Fixate()</function> on the <classname>org.freedesktop.home1.Home</classname> interface.</para>
+
+      <para><function>AuthenticateHome()</function> checks passwords or other authentication credentials
+      associated with the home directory. It takes a user name and a JSON user record consisting only of the
+      <literal>secret</literal> section as argument. Note that many of the other method calls authenticate
+      the user first, in order to execute some other operation. This method call only authenticates and
+      executes no further operation. Like <function>ActivateHome()</function> it is usually first invoked
+      with an empty JSON user record, which is then populated for subsequent tries with additional
+      authentication data supplied. This method is equivalent to
+      <function>Authenticate()</function> on the <classname>org.freedesktop.home1.Home</classname>
+      interface.</para>
+
+      <para><function>UpdateHome()</function> updates a locally registered user record. Takes a fully
+      specified JSON user record as argument (including the <literal>secret</literal> section). A user with a
+      matching name and realm must be registered locally already, and the last change timestamp of the newly
+      supplied record must be newer than the previously existing user record. Note this operation updates the
+      user record only, it does not propagate passwords/authentication tokens from the user record to the
+      storage back-end, or resizes the storage back-end. Typically a home directory is first updated, and then
+      the password of the underlying storage updated using <function>ChangePasswordHome()</function> as well
+      as the storage resized using <function>ResizeHome()</function>. This method is equivalent to
+      <function>Update()</function> on the <classname>org.freedesktop.home1.Home</classname> interface.</para>
+
+      <para><function>ResizeHome()</function> resizes the storage associated with a user record. Takes a user
+      name, a disk size in bytes and a user record consisting only of the <literal>secret</literal> section
+      as argument. If the size is specified as <constant>UINT64_MAX</constant> the storage is resized to the
+      size already specified in the user record. Typically, if the user record is updated using
+      <function>UpdateHome()</function> above this is used to propagate the size configured there-in down to
+      the underlying storage back-end. This method is equivalent to
+      <function>Resize()</function> on the <classname>org.freedesktop.home1.Home</classname>
+      interface.</para>
+
+      <para><function>ChangePasswordHome()</function> changes the passwords/authentication tokens of a home
+      directory. Takes a user name, and two JSON user record objects, each consisting only of the
+      <literal>secret</literal> section, for the old and for the new passwords/authentication tokens. If the
+      user record with the new passwords/authentication token data is specified as empty the existing user
+      record's settings are propagated down to the home directory storage. This is typically used after a
+      user record is updated using <function>UpdateHome()</function> in order to propagate the
+      secrets/authentication tokens down to the storage. This method is equivalent to
+      <function>ChangePassword()</function> on the <classname>org.freedesktop.home1.Home</classname>
+      interface.</para>
+
+      <para><function>LockHome()</function> temporarily suspends access to a home directory, flushing out any
+      cryptographic keys from memory. This is only supported on some back-ends, and usually done during system
+      suspend, in order to effectively secure home directories while the system is sleeping. Takes a user
+      name as single argument. If an application attempts to access a home directory while it is locked it
+      will typically freeze until the home directory is unlocked again. This method is equivalent to
+      <function>Lock()</function> on the <classname>org.freedesktop.home1.Home</classname> interface.</para>
+
+      <para><function>UnlockHome()</function> undoes the effect of <function>LockHome()</function>. Takes a
+      user name and a user record consisting only of the <literal>secret</literal> section as arguments. This
+      method is equivalent to <function>Unlock()</function> on the
+      <classname>org.freedesktop.home1.Home</classname> interface.</para>
+
+      <para><function>AcquireHome()</function> activates or unlocks a home directory in a reference counted
+      mode of operation. Takes a user name and user record consisting only of <literal>secret</literal>
+      section as argument. If the home directory is not active yet, it is activated. If it is currently
+      locked it is unlocked. After completion a reference to the activation/unlocking of the home directory
+      is returned via a file descriptor. When the last client which acquired such a file descriptor closes it
+      the home directory is automatically deactivated again. This method is typically invoked when a user
+      logs in, and the file descriptor is held until the user logs out again, thus ensuring the user's home
+      directory can be unmounted automatically again in a robust fashion, when the user logs out. The third
+      argument is a boolean which indicates whether the client invoking the call is able to automatically
+      re-authenticate when the system comes back from suspending. It should be set by all clients that
+      implement a secure lock screen running outside of the user's context, that is brought up when the
+      system comes back from suspend and can be used to re-acquire the credentials to unlock the user's home
+      directory. If a home directory has at least one client with an open reference to the home directory
+      that does not support this it is not suspended automatically at system suspend, otherwise it is. This
+      method is equivalent to <function>Acquire()</function> on the
+      <classname>org.freedesktop.home1.Home</classname> interface.</para>
+
+      <para><function>RefHome()</function> is similar to <function>AcquireHome()</function> but takes no user
+      record with <literal>secret</literal> section, i.e. will take an additional reference to an already
+      activated/unlocked home directory without attempting to activate/unlock it itself. It will fail if the
+      home directory is not already activated. This method is equivalent to
+      <function>Ref()</function> on the <classname>org.freedesktop.home1.Home</classname>
+      interface.</para>
+
+      <para><function>ReleaseHome()</function> releases a home directory again, if all file descriptors
+      referencing it are already closed, that where acquired through <function>AcquireHome()</function> or
+      <function>RefHome()</function>. Note that this call does not actually cause the deactivation of the
+      home directory (which happens automatically when the last referencing file descriptor is closed), but
+      is simply a synchronization mechanism that allows delaying of the user session's termination until any
+      triggered deactivation is completed. This method is equivalent to <function>Release()</function> on the
+      <classname>org.freedesktop.home1.Home</classname> interface.</para>
+
+      <para><function>LockAllHomes()</function> locks all active home directories that only have references
+      that opted into automatic suspending during system suspend. This is usually invoked automatically
+      shortly before system suspend.</para>
+    </refsect2>
+
+    <refsect2>
+      <title>Properties</title>
+
+      <para><varname>AutoLogin</varname> exposes an array of structures consisting of user name, seat name
+      and object path of an home directory object. All locally managed users that have the
+      <literal>autoLogin</literal> field set are listed here, with the seat name they are associated with. A
+      display manager may watch this property and pre-fill the login screen with the users exposed this
+      way.</para>
+    </refsect2>
+  </refsect1>
+
+  <refsect1>
+    <title>The Home Object</title>
+
+    <programlisting executable="systemd-homed" node="/org/freedesktop/home1/home" interface="org.freedesktop.home1.Home">
+node /org/freedesktop/home1/home {
+  interface org.freedesktop.home1.Home {
+    methods:
+      Activate(in  s secret);
+      Deactivate();
+      Unregister();
+      Realize(in  s secret);
+      Remove();
+      Fixate(in  s secret);
+      Authenticate(in  s secret);
+      Update(in  s user_record);
+      Resize(in  t size,
+             in  s secret);
+      ChangePassword(in  s new_secret,
+                     in  s old_secret);
+      Lock();
+      Unlock(in  s secret);
+      Acquire(in  s secret,
+              in  b please_suspend,
+              out h send_fd);
+      Ref(in  b please_suspend,
+          out h send_fd);
+      Release();
+    properties:
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+      readonly s UserName = '...';
+      readonly u UID = ...;
+      readonly (suusss) UnixRecord = ...;
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly s State = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("invalidates")
+      readonly (sb) UserRecord = ...;
+  };
+  interface org.freedesktop.DBus.Peer { ... };
+  interface org.freedesktop.DBus.Introspectable { ... };
+  interface org.freedesktop.DBus.Properties { ... };
+  interface org.freedesktop.DBus.ObjectManager { ... };
+};
+    </programlisting>
+
+    <!--Autogenerated cross-references for systemd.directives, do not edit-->
+
+    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.DBus.ObjectManager"/>
+
+    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.home1.Home"/>
+
+    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.DBus.ObjectManager"/>
+
+    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.home1.Home"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="Activate()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="Deactivate()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="Unregister()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="Realize()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="Remove()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="Fixate()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="Authenticate()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="Update()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="Resize()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="ChangePassword()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="Lock()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="Unlock()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="Acquire()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="Ref()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="Release()"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="UserName"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="UID"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="UnixRecord"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="State"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="UserRecord"/>
+
+    <!--End of Autogenerated section-->
+
+    <refsect2>
+      <title>Methods</title>
+
+      <para><function>Activate()</function>, <function>Deactivate()</function>,
+      <function>Unregister()</function>, <function>Realize()</function>, <function>Remove()</function>,
+      <function>Fixate()</function>, <function>Authenticate()</function>, <function>Update()</function>,
+      <function>Resize()</function>, <function>ChangePassword()</function>, <function>Lock()</function>,
+      <function>Unlock()</function>, <function>Acquire()</function>, <function>Ref()</function>,
+      <function>Release()</function> operate like their matching counterparts on the
+      <classname>org.freedesktop.home1.Manager</classname> interface (see above). The main difference is that
+      they are methods of the home directory objects, and hence carry no additional user name
+      parameter. Which of the two flavors of methods to call depends on the handles to the user known on the
+      client side: if only the user name is known, it's preferable to use the methods on the manager object
+      since they operate with user names only. If however the home object path was already acquired some way
+      it is preferable to operate on the <classname>org.freedesktop.home1.Home</classname> objects
+      instead.</para>
+    </refsect2>
+
+    <refsect2>
+      <title>Properties</title>
+
+      <para><varname>UserName</varname> contains the user name of the user account/home directory.</para>
+
+      <para><varname>UID</varname> contains the numeric UNIX UID of the user account.</para>
+
+      <para><varname>UnixRecord</varname> contains a structure encapsulating the six fields a
+      <structname>struct passwd</structname> typically contains (the password field is suppressed).</para>
+
+      <para><varname>State</varname> exposes the current state home the home directory.</para>
+
+      <para><varname>UserRecord</varname> contains the full JSON user record string of the user account.</para>
+    </refsect2>
+  </refsect1>
+
+  <refsect1>
+    <title>Versioning</title>
+
+    <para>These D-Bus interfaces follow <ulink url="http://0pointer.de/blog/projects/versioning-dbus.html">
+    the usual interface versioning guidelines</ulink>.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>See Also</title>
+    <para>
+      <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>systemd-homed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>homectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+    </para>
+  </refsect1>
+
+</refentry>
index c852bed6de9b315f93d86392df47898efd60bcea..d17d9a55213d3549c0e4ecaf82a8e935cbbf8284 100644 (file)
 
     <para>The service exposes the following interfaces on the bus:</para>
 
-    <programlisting>
-$ gdbus introspect --system \
-        --dest org.freedesktop.hostname1 \
-        --object-path /org/freedesktop/hostname1
-
+    <programlisting executable="systemd-hostnamed" node="/org/freedesktop/hostname1" interface="org.freedesktop.hostname1">
 node /org/freedesktop/hostname1 {
   interface org.freedesktop.hostname1 {
     methods:
@@ -89,38 +85,6 @@ node /org/freedesktop/hostname1 {
 };
     </programlisting>
 
-    <!--method SetDeployment is not documented!-->
-
-    <!--method SetLocation is not documented!-->
-
-    <!--method GetProductUUID is not documented!-->
-
-    <!--property Hostname is not documented!-->
-
-    <!--property StaticHostname is not documented!-->
-
-    <!--property PrettyHostname is not documented!-->
-
-    <!--property IconName is not documented!-->
-
-    <!--property Chassis is not documented!-->
-
-    <!--property Deployment is not documented!-->
-
-    <!--property Location is not documented!-->
-
-    <!--property KernelName is not documented!-->
-
-    <!--property KernelRelease is not documented!-->
-
-    <!--property KernelVersion is not documented!-->
-
-    <!--property OperatingSystemPrettyName is not documented!-->
-
-    <!--property OperatingSystemCPEName is not documented!-->
-
-    <!--property HomeURL is not documented!-->
-
     <!--Autogenerated cross-references for systemd.directives, do not edit-->
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.hostname1"/>
@@ -173,7 +137,8 @@ node /org/freedesktop/hostname1 {
 
     <para>Whenever the hostname or other metadata is changed via the daemon,
     <function>PropertyChanged</function> signals are sent out to subscribed clients. Changing a hostname
-    using this interface is authenticated via PolicyKit.</para>
+    using this interface is authenticated via
+    <ulink url="https://www.freedesktop.org/software/polkit/docs/latest/">polkit</ulink>.</para>
   </refsect1>
 
   <refsect1>
@@ -219,10 +184,6 @@ node /org/freedesktop/hostname1 {
     it could not be auto-detected. Set this property to the empty string to reenable the automatic detection of
     the chassis type from firmware information.</para>
 
-    <para>A client that wants to change the local hostname for DHCP/mDNS should invoke
-    <code>SetHostname("newname", false)</code> as soon as the name is available and afterwards reset it via
-    <code>SetHostname("")</code>.</para>
-
     <para>Note that <filename>systemd-hostnamed</filename> starts only on request and terminates after a
     short idle period. This effectively means that <function>PropertyChanged</function> messages are not sent
     out for changes made directly on the files (as in: administrator edits the files with vi). This is
@@ -244,33 +205,91 @@ node /org/freedesktop/hostname1 {
     <citerefentry><refentrytitle>machine-info</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     for that. For more information on these files and syscalls see the respective man pages.</para>
 
-    <para>The <varname>user_interaction</varname> boolean parameters can be used to control whether PolicyKit
-    should interactively ask the user for authentication credentials if required.</para>
+    <refsect2>
+      <title>Methods and Properties</title>
+
+      <para><function>SetHostname()</function> sets the transient (dynamic) hostname which is exposed by the
+      <varname>Hostname</varname> property. If empty, the transient hostname is set to the static hostname.
+      </para>
+
+      <para><function>SetStaticHostname()</function> sets the static hostname which is exposed by the
+      <varname>StaticHostname</varname> property. If empty, the built-in default of
+      <literal>&FALLBACK_HOSTNAME;</literal> is used.</para>
+
+      <para><function>SetPrettyHostname()</function> sets the pretty hostname which is exposed by the
+      <varname>PrettyHostname</varname> property.</para>
+
+      <para><function>SetIconName()</function>, <function>SetChassis()</function>,
+      <function>SetDeployment()</function>, and <function>SetLocation()</function> set the properties
+      <varname>IconName</varname> (the name of the icon representing for the machine),
+      <varname>Chassis</varname> (the machine form factor), <varname>Deployment</varname> (the system
+      deployment environment), and <varname>Location</varname> (physical system location), respectively.
+      </para>
+
+      <para><varname>PrettyHostname</varname>, <varname>IconName</varname>, <varname>Chassis</varname>,
+      <varname>Deployment</varname>, and <varname>Location</varname> are stored in
+      <filename>/etc/machine-info</filename>. See
+      <citerefentry><refentrytitle>machine-info</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
+      the semantics of those settings.</para>
+
+      <para><function>GetProductUUID()</function> returns the "product uuid" as exposed by the kernel based
+      on DMI information in <filename>/sys/class/dmi/id/product_uuid</filename>. Reading the file directly
+      requires root privileges, and this method allows access to unprivileged clients through the polkit
+      framework.</para>
+
+      <para><varname>KernelName</varname>, <varname>KernelRelease</varname>, and
+      <varname>KernelVersion</varname> expose the kernel name (e.g. <literal>Linux</literal>), release
+      (e.g. <literal>5.0.0-11</literal>, and version (i.e. the build number, e.g. <literal>#11</literal>) as
+      reported by
+      <citerefentry project="man-pages"><refentrytitle>uname</refentrytitle><manvolnum>2</manvolnum></citerefentry>.
+      <varname>OperatingSystemPrettyName</varname>, <varname>OperatingSystemCPEName</varname>, and
+      <varname>HomeURL</varname> expose the <varname>PRETTY_NAME=</varname>, <varname>CPE_NAME=</varname> and
+      <varname>HOME_URL=</varname> fields from
+      <citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry>. The
+      purpose of those properties is to allow remote clients to access this information over D-Bus. Local
+      clients can access the information directly.</para>
+    </refsect2>
+
+    <refsect2>
+      <title>Security</title>
+
+      <para>The <varname>interactive</varname> boolean parameters can be used to control whether polkit
+      should interactively ask the user for authentication credentials if required.</para>
+
+      <para>The polkit action for <function>SetHostname()</function> is
+      <interfacename>org.freedesktop.hostname1.set-hostname</interfacename>. For
+      <function>SetStaticHostname()</function> and <function>SetPrettyHostname()</function> it is
+      <interfacename>org.freedesktop.hostname1.set-static-hostname</interfacename>. For
+      <function>SetIconName()</function> and <function>SetChassis()</function> it is
+      <interfacename>org.freedesktop.hostname1.set-machine-info</interfacename>.</para>
+    </refsect2>
+  </refsect1>
 
-    <para>The PolicyKit action for <function>SetHostname()</function> is
-    <interfacename>org.freedesktop.hostname1.set-hostname</interfacename>. For
-    <function>SetStaticHostname()</function> and <function>SetPrettyHostname()</function> it is
-    <interfacename>org.freedesktop.hostname1.set-static-hostname</interfacename>. For
-    <function>SetIconName()</function> and <function>SetChassis()</function> it is
-    <interfacename>org.freedesktop.hostname1.set-machine-info</interfacename>.</para>
+  <refsect1>
+    <title>Recommendations</title>
 
-    <para>Here are three examples show how the pretty hostname and the icon name should be used:
+    <para>Here are three examples that show how the pretty hostname and the icon name should be used:
     <itemizedlist>
-      <listitem><para>When registering DNS-SD services: use the pretty hostname in the service name, and
-      pass the icon name in the TXT data, if there is an icon name. Browsing clients can then show the server
-      icon on each service. This is especially useful for WebDAV applications or UPnP media sharing.
+      <listitem><para>When registering DNS-SD services: use the pretty hostname in the service name, and pass
+      the icon name in the TXT data, if there is an icon name. Browsing clients can then show the server icon
+      on each service. This is especially useful for WebDAV applications or UPnP media sharing.
       </para></listitem>
 
       <listitem><para>Set the bluetooth name to the pretty hostname.</para></listitem>
 
-      <listitem><para>When your file browser has a "Computer" icon, replace the name with the pretty hostname if set, and the icon with the icon name, if it is set.</para></listitem>
+      <listitem><para>When your file browser has a "Computer" icon, replace the name with the pretty hostname
+      if set, and the icon with the icon name, if it is set.</para></listitem>
     </itemizedlist></para>
 
     <para>To properly handle name lookups with changing local hostnames without having to edit
-    <filename>/etc/hosts</filename>, we recommend using <filename>systemd-hostnamed</filename> in
-    combination with <citerefentry><refentrytitle>nss-myhostname</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+    <filename>/etc/hosts</filename>, we recommend using <filename>systemd-hostnamed</filename> in combination
+    with <citerefentry><refentrytitle>nss-myhostname</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
     </para>
 
+    <para>A client that wants to change the local hostname for DHCP/mDNS should invoke
+    <code>SetHostname("newname", false)</code> as soon as the name is available and afterwards reset it via
+    <code>SetHostname("")</code>.</para>
+
     <para>Here are some recommendations to follow when generating a static (internet) hostname from a pretty
     name:
     <itemizedlist>
@@ -314,7 +333,7 @@ node /org/freedesktop/hostname1 {
     </itemizedlist></para>
 
     <para>Of course, an already valid internet hostname label you enter and pass through this
-    conversion should stay unmodified, so that users have direct control of it, if they want -- by simply
+    conversion should stay unmodified, so that users have direct control of it, if they want  by simply
     ignoring the fact that the pretty hostname is pretty and just edit it as if it was the normal internet
     name.</para>
   </refsect1>
@@ -326,6 +345,19 @@ node /org/freedesktop/hostname1 {
     the usual interface versioning guidelines</ulink>.</para>
   </refsect1>
 
+  <refsect1>
+    <title>Examples</title>
+
+    <example>
+      <title>Introspect <interfacename>org.freedesktop.hostname1</interfacename> on the bus</title>
+
+      <programlisting>$ gdbus introspect --system \
+  --dest org.freedesktop.hostname1 \
+  --object-path /org/freedesktop/hostname1
+      </programlisting>
+    </example>
+  </refsect1>
+
   <refsect1>
     <title>See also</title>
 
index 4a425f1ac3d5ff2f1055387210796f34111b2ce2..1414cc15d794eb00380359f0bc2fad84ae03f2b3 100644 (file)
 
     <para>The service exposes the following interfaces on the Manager object on the bus:</para>
 
-    <programlisting>
-$ gdbus introspect --system \
-        --dest org.freedesktop.import1 \
-        --object-path /org/freedesktop/import1
-
+    <programlisting executable="systemd-importd" node="/org/freedesktop/import1" interface="org.freedesktop.import1.Manager">
 node /org/freedesktop/import1 {
   interface org.freedesktop.import1.Manager {
     methods:
@@ -238,11 +234,7 @@ node /org/freedesktop/import1 {
   <refsect1>
     <title>The Transfer Object</title>
 
-    <programlisting>
-$ gdbus introspect --system \
-        --dest org.freedesktop.import1 \
-        --object-path /org/freedesktop/import1/transfer/_1
-
+    <programlisting executable="systemd-importd" node="/org/freedesktop/import1/transfer/_1" interface="org.freedesktop.import1.Transfer">
 node /org/freedesktop/import1/transfer/_1 {
   interface org.freedesktop.import1.Transfer {
     methods:
@@ -325,6 +317,28 @@ node /org/freedesktop/import1/transfer/_1 {
     </refsect2>
   </refsect1>
 
+  <refsect1>
+    <title>Examples</title>
+
+    <example>
+      <title>Introspect <interfacename>org.freedesktop.import1.Manager</interfacename> on the bus</title>
+
+      <programlisting>$ gdbus introspect --system \
+  --dest org.freedesktop.import1 \
+  --object-path /org/freedesktop/import1
+      </programlisting>
+    </example>
+
+    <example>
+      <title>Introspect <interfacename>org.freedesktop.import1.Transfer</interfacename> on the bus</title>
+
+      <programlisting>$ gdbus introspect --system \
+  --dest org.freedesktop.import1 \
+  --object-path /org/freedesktop/import1/transfer/_1
+      </programlisting>
+    </example>
+  </refsect1>
+
   <refsect1>
     <title>Versioning</title>
 
index 52f9abcf9d7f46a5fd746d556c1baa18a79a9e19..3956eaf8a7b8c1f58189a4bb3d2461f3562ba1e4 100644 (file)
 
     <para>The service exposes the following interfaces on the bus:</para>
 
-    <programlisting>
-$ gdbus introspect --system \
-        --dest org.freedesktop.locale1 \
-        --object-path /org/freedesktop/locale1
-
+    <programlisting executable="systemd-localed" node="/org/freedesktop/locale1" interface="org.freedesktop.locale1">
 node /org/freedesktop/locale1 {
   interface org.freedesktop.locale1 {
     methods:
@@ -126,7 +122,8 @@ node /org/freedesktop/locale1 {
 
       <para>Use the empty string for the keymap parameters you wish not to set.</para>
 
-      <para>The <varname>interactive</varname> boolean parameters can be used to control whether PolicyKit
+      <para>The <varname>interactive</varname> boolean parameters can be used to control whether
+      <ulink url="https://www.freedesktop.org/software/polkit/docs/latest/">polkit</ulink>
       should interactively ask the user for authentication credentials if required.</para>
     </refsect2>
 
@@ -160,14 +157,28 @@ node /org/freedesktop/locale1 {
     <refsect2>
       <title>Security</title>
 
-      <para>Changing the system locale or keymap using this interface is authenticated via PolicyKit. The
-      PolicyKit action for <function>SetLocale()</function> is
-      <constant>org.freedesktop.locale1.set-locale</constant>. The PolicyKit action for
+      <para>Changing the system locale or keymap using this interface is authenticated via polkit. The
+      polkit action for <function>SetLocale()</function> is
+      <constant>org.freedesktop.locale1.set-locale</constant>. The polkit action for
       <function>SetX11Keyboard()</function> and <function>SetVConsoleKeyboard()</function> is
       <constant>org.freedesktop.locale1.set-keyboard</constant>.</para>
     </refsect2>
   </refsect1>
 
+  <refsect1>
+    <title>Examples</title>
+
+    <example>
+      <title>Introspect <interfacename>org.freedesktop.locale1</interfacename> on the bus</title>
+
+      <programlisting>
+$ gdbus introspect --system \
+  --dest org.freedesktop.locale1 \
+  --object-path /org/freedesktop/locale1
+      </programlisting>
+    </example>
+  </refsect1>
+
   <refsect1>
     <title>Versioning</title>
 
index cd4925b19458b33fdbe1cd632673c02e79f02af7..44ad033752d526b56c36640415a684fa919ff807 100644 (file)
 
     <para>The service exposes the following interfaces on the Manager object on the bus:</para>
 
-    <programlisting>
-$ gdbus introspect --system \
-        --dest org.freedesktop.login1 \
-        --object-path /org/freedesktop/login1
-
+    <programlisting executable="systemd-logind" node="/org/freedesktop/login1" interface="org.freedesktop.login1.Manager">
 node /org/freedesktop/login1 {
   interface org.freedesktop.login1.Manager {
     methods:
@@ -496,22 +492,24 @@ node /org/freedesktop/login1 {
       and seat are identified by their respective IDs.</para>
 
       <para><function>SetUserLinger()</function> enables or disables user lingering. If enabled, the runtime
-      directory of a user is kept around and he may continue to run processes while he is logged out. If
+      directory of a user is kept around and they may continue to run processes while logged out. If
       disabled, the runtime directory goes away as soon as they log out. <function>SetUserLinger()</function>
       expects three arguments: the UID, a boolean whether to enable/disable and a boolean controlling the
-      PolicyKit authorization interactivity (see below). Note that the user linger state is persistently
+      <ulink url="https://www.freedesktop.org/software/polkit/docs/latest/">polkit</ulink>
+      authorization interactivity (see below). Note that the user linger state is persistently
       stored on disk.</para>
 
       <para><function>AttachDevice()</function> may be used to assign a specific device to a specific
-      seat. The device is identified by its /sys path and must be eligible for seat assignments. <function>AttachDevice()</function> takes three
-      arguments: the seat id, the sysfs path, and a boolean for controlling PolicyKit interactivity (see
-      below). Device assignments are persistently stored on disk. To create a new seat, simply specify a
-      previously unused seat id. For more information about the seat assignment logic see
+      seat. The device is identified by its <filename>/sys</filename> path and must be eligible for seat
+      assignments. <function>AttachDevice()</function> takes three arguments: the seat id, the sysfs path,
+      and a boolean for controlling polkit interactivity (see below). Device assignments are persistently
+      stored on disk. To create a new seat, simply specify a previously unused seat id. For more information
+      about the seat assignment logic see
       <ulink url="https://www.freedesktop.org/wiki/Software/systemd/multiseat">Multi-Seat for Linux</ulink>.
       </para>
 
       <para><function>FlushDevices()</function> removes all explicit seat assignments for devices, resetting
-      all assignments to the automatic defaults. The only argument it takes is the PolicyKit interactivity
+      all assignments to the automatic defaults. The only argument it takes is the polkit interactivity
       boolean (see below).</para>
 
       <para><function>PowerOff()</function>, <function>Reboot()</function>, <function>Halt()</function>,
@@ -521,9 +519,9 @@ node /org/freedesktop/login1 {
       the machine is powered down). <function>HybridSleep()</function> results in the system entering a
       hybrid-sleep mode, i.e. the system is both hibernated and suspended.
       <function>SuspendThenHibernate()</function> results in the system being suspended, then later woken
-      using an RTC timer and hibernated. The only argument is the PolicyKit interactivity boolean
+      using an RTC timer and hibernated. The only argument is the polkit interactivity boolean
       <varname>interactive</varname> (see below). The main purpose of these calls is that they enforce
-      PolicyKit policy and hence allow powering off/rebooting/suspending/hibernating even by unprivileged
+      polkit policy and hence allow powering off/rebooting/suspending/hibernating even by unprivileged
       users. They also enforce inhibition locks. UIs should expose these calls as the primary mechanism to
       poweroff/reboot/suspend/hibernate the machine.</para>
 
@@ -678,7 +676,7 @@ node /org/freedesktop/login1 {
     <refsect2>
       <title>Security</title>
 
-      <para>A number of operations are protected via the PolicyKit privilege
+      <para>A number of operations are protected via the polkit privilege
       system. <function>SetUserLinger()</function> requires the
       <interfacename>org.freedesktop.login1.set-user-linger</interfacename>
       privilege. <function>AttachDevice()</function> requires
@@ -731,7 +729,7 @@ node /org/freedesktop/login1 {
       <interfacename>org.freedesktop.login1.inhibit-handle-lid-switch</interfacename> depending on the lock
       type and mode taken.</para>
 
-      <para>The <varname>interactive</varname> boolean parameters can be used to control whether PolicyKit
+      <para>The <varname>interactive</varname> boolean parameters can be used to control whether polkit
       should interactively ask the user for authentication credentials if required.</para>
     </refsect2>
   </refsect1>
@@ -739,10 +737,7 @@ node /org/freedesktop/login1 {
   <refsect1>
     <title>Seat Objects</title>
 
-    <programlisting>
-$ gdbus introspect --system --dest org.freedesktop.login1 \
-      --object-path /org/freedesktop/login1/seat/seat0
-
+    <programlisting executable="systemd-logind" node="/org/freedesktop/login1/seat/seat0" interface="org.freedesktop.login1.Seat">
 node /org/freedesktop/login1/seat/seat0 {
   interface org.freedesktop.login1.Seat {
     methods:
@@ -756,8 +751,6 @@ node /org/freedesktop/login1/seat/seat0 {
       readonly s Id = '...';
       readonly (so) ActiveSession = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
-      readonly b CanMultiSession = ...;
-      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly b CanTTY = ...;
       readonly b CanGraphical = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
@@ -792,8 +785,6 @@ node /org/freedesktop/login1/seat/seat0 {
 
     <variablelist class="dbus-property" generated="True" extra-ref="ActiveSession"/>
 
-    <variablelist class="dbus-property" generated="True" extra-ref="CanMultiSession"/>
-
     <variablelist class="dbus-property" generated="True" extra-ref="CanTTY"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="CanGraphical"/>
@@ -825,7 +816,7 @@ node /org/freedesktop/login1/seat/seat0 {
       <title>Signals</title>
 
       <para>Whenever <function>ActiveSession</function>, <function>Sessions</function>,
-      <function>CanGraphical</function>, <function>CanMultiSession</function> and <function>CanTTY</function>
+      <function>CanGraphical</function>, <function>CanTTY</function>,
       or the idle state changes, <function>PropertyChanged</function> signals are sent out to which clients
       can subscribe.</para>
     </refsect2>
@@ -838,26 +829,22 @@ node /org/freedesktop/login1/seat/seat0 {
       <para><varname>ActiveSession</varname> encodes the currently active session if there is one. It is a
       structure consisting of the session id and the object path.</para>
 
-      <para><varname>CanMultiSession</varname> encodes whether the session is multi-session capable,
-      <varname>CanTTY</varname> whether it is suitable for text logins, <varname>CanGraphical</varname>
-      whether it is suitable for graphical sessions.</para>
+      <para><varname>CanTTY</varname> encodes whether the session is suitable for text logins, and
+      <varname>CanGraphical</varname> whether it is suitable for graphical sessions.</para>
 
       <para>The <varname>Sessions</varname> property is an array of all current sessions of this seat, each
       encoded in a structure consisting of the ID and the object path.</para>
 
       <para>The <varname>IdleHint</varname>, <varname>IdleSinceHint</varname>, and
-      <varname>IdleSinceHint</varname> properties encode the idle state, similar to the one exposed on the
-      Manager object, but specific for this seat.</para>
+      <varname>IdleSinceHintMonotonic</varname> properties encode the idle state, similar to the ones exposed
+      on the <interfacename>Manager</interfacename> object, but specific for this seat.</para>
     </refsect2>
   </refsect1>
 
   <refsect1>
     <title>User Objects</title>
 
-    <programlisting>
-$ gdbus introspect --system --dest org.freedesktop.login1 \
-        --object-path /org/freedesktop/login1/user/_1000
-
+    <programlisting executable="systemd-logind" node="/org/freedesktop/login1/user/_1000" interface="org.freedesktop.login1.User">
 node /org/freedesktop/login1/user/_1000 {
   interface org.freedesktop.login1.User {
     methods:
@@ -1002,11 +989,8 @@ node /org/freedesktop/login1/user/_1000 {
   <refsect1>
     <title>Session Objects</title>
 
-    <programlisting>
-$ gdbus introspect --system --dest org.freedesktop.login1 \
-        --object-path /org/freedesktop/login1/session/45
-
-node /org/freedesktop/login1/session/45 {
+    <programlisting executable="systemd-logind" node="/org/freedesktop/login1/session/1" interface="org.freedesktop.login1.Session">
+node /org/freedesktop/login1/session/1 {
   interface org.freedesktop.login1.Session {
     methods:
       Terminate();
@@ -1019,6 +1003,7 @@ node /org/freedesktop/login1/session/45 {
            in  i signal_number);
       TakeControl(in  b force);
       ReleaseControl();
+      SetType(in  s type);
       TakeDevice(in  u major,
                  in  u minor,
                  out h fd,
@@ -1074,7 +1059,6 @@ node /org/freedesktop/login1/session/45 {
       readonly u Leader = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly u Audit = ...;
-      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s Type = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s Class = '...';
@@ -1091,6 +1075,100 @@ node /org/freedesktop/login1/session/45 {
 };
     </programlisting>
 
+    <!--Autogenerated cross-references for systemd.directives, do not edit-->
+
+    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.login1.Session"/>
+
+    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.login1.Session"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="Terminate()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="Activate()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="Lock()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="Unlock()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="SetIdleHint()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="SetLockedHint()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="Kill()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="TakeControl()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="ReleaseControl()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="SetType()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="TakeDevice()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="ReleaseDevice()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="PauseDeviceComplete()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="SetBrightness()"/>
+
+    <variablelist class="dbus-signal" generated="True" extra-ref="PauseDevice"/>
+
+    <variablelist class="dbus-signal" generated="True" extra-ref="ResumeDevice"/>
+
+    <variablelist class="dbus-signal" generated="True" extra-ref="Lock"/>
+
+    <variablelist class="dbus-signal" generated="True" extra-ref="Unlock"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="Id"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="User"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="Name"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="Timestamp"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="TimestampMonotonic"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="VTNr"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="Seat"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="TTY"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="Display"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="Remote"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="RemoteHost"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="RemoteUser"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="Service"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="Desktop"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="Scope"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="Leader"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="Audit"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="Type"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="Class"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="Active"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="State"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="IdleHint"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="IdleSinceHint"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="IdleSinceHintMonotonic"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="LockedHint"/>
+
+    <!--End of Autogenerated section-->
+
     <refsect2>
       <title>Methods</title>
 
@@ -1107,10 +1185,17 @@ node /org/freedesktop/login1/session/45 {
       out and replaced. Otherwise, this method fails if there is already a controller. Note that this method is
       limited to D-Bus users with the effective UID set to the user of the session or root.</para>
 
-      <para><function>ReleaseControl()</function> drops control of a given session. Closing the
-      D-Bus connection implicitly releases control as well. See <function>TakeControl()</function> for more information. This
-      method also releases all devices for which the controller requested ownership via <function>TakeDevice()</function>.
-      </para>
+      <para><function>ReleaseControl()</function> drops control of a given session. Closing the D-Bus
+      connection implicitly releases control as well. See <function>TakeControl()</function> for more
+      information. This method also releases all devices for which the controller requested ownership via
+      <function>TakeDevice()</function>.</para>
+
+      <para><function>SetType()</function> allows the type of the session to be changed dynamically.  It can
+      only be called by session's current controller. If <function>TakeControl()</function> has not been
+      called, this method will fail. In addition, the session type will be reset to its original value once
+      control is released, either by calling <function>ReleaseControl()</function> or closing the D-Bus
+      connection. This should help prevent a session from entering an inconsistent state, for example if the
+      controller crashes. The only argument <varname>type</varname> is the new session type.</para>
 
       <para><function>TakeDevice()</function> allows a session controller to get a file descriptor for a
       specific device. Pass in the major and minor numbers of the character device and
@@ -1255,6 +1340,42 @@ node /org/freedesktop/login1/session/45 {
     </refsect2>
   </refsect1>
 
+  <refsect1>
+    <title>Examples</title>
+
+    <example>
+      <title>Introspect <interfacename>org.freedesktop.login1.Manager</interfacename> on the bus</title>
+
+      <programlisting>$ gdbus introspect --system --dest org.freedesktop.login1 \
+  --object-path /org/freedesktop/login1
+      </programlisting>
+    </example>
+
+    <example>
+      <title>Introspect <interfacename>org.freedesktop.login1.Seat</interfacename> on the bus</title>
+
+      <programlisting>$ gdbus introspect --system --dest org.freedesktop.login1 \
+ --object-path /org/freedesktop/login1/seat/seat0
+      </programlisting>
+    </example>
+
+    <example>
+      <title>Introspect <interfacename>org.freedesktop.login1.User</interfacename> on the bus</title>
+
+      <programlisting>$ gdbus introspect --system --dest org.freedesktop.login1 \
+  --object-path /org/freedesktop/login1/user/_1000
+      </programlisting>
+    </example>
+
+    <example>
+      <title>Introspect <interfacename>org.freedesktop.login1.Session</interfacename> on the bus</title>
+
+      <programlisting>$ gdbus introspect --system --dest org.freedesktop.login1 \
+  --object-path /org/freedesktop/login1/session/45
+      </programlisting>
+    </example>
+  </refsect1>
+
   <refsect1>
     <title>Versioning</title>
 
index bc9779c5212431a8027536fad216b7205c7d53f5..c18e133e7cbc6ff1a0b340b4ced3612110330eca 100644 (file)
 
     <para>The service exposes the following interfaces on the Manager object on the bus:</para>
 
-    <programlisting>
-$ gdbus introspect --system \
-        --dest org.freedesktop.machine1 \
-        --object-path /org/freedesktop/machine1
-
+    <programlisting executable="systemd-machined" node="/org/freedesktop/machine1" interface="org.freedesktop.machine1.Manager">
 node /org/freedesktop/machine1 {
   interface org.freedesktop.machine1.Manager {
     methods:
@@ -435,11 +431,7 @@ node /org/freedesktop/machine1 {
   <refsect1>
     <title>Machine Objects</title>
 
-    <programlisting>
-$ gdbus introspect --system \
-        --dest org.freedesktop.machine1 \
-        --object-path /org/freedesktop/machine1/machine/rawhide
-
+    <programlisting executable="systemd-machined" node="/org/freedesktop/machine1/machine/rawhide" interface="org.freedesktop.machine1.Machine">
 node /org/freedesktop/machine1/machine/rawhide {
   interface org.freedesktop.machine1.Machine {
     methods:
@@ -617,6 +609,30 @@ node /org/freedesktop/machine1/machine/rawhide {
     </refsect2>
   </refsect1>
 
+  <refsect1>
+    <title>Examples</title>
+
+    <example>
+      <title>Introspect <interfacename>org.freedesktop.machine1.Manager</interfacename> on the bus</title>
+
+      <programlisting>
+$ gdbus introspect --system \
+  --dest org.freedesktop.machine1 \
+  --object-path /org/freedesktop/machine1
+      </programlisting>
+    </example>
+
+    <example>
+      <title>Introspect <interfacename>org.freedesktop.machine1.Machine</interfacename> on the bus</title>
+
+      <programlisting>
+$ gdbus introspect --system \
+  --dest org.freedesktop.machine1 \
+  --object-path /org/freedesktop/machine1/machine/rawhide
+      </programlisting>
+    </example>
+  </refsect1>
+
   <refsect1>
     <title>Versioning</title>
 
index ad7b6e20fb62d8499b84def807cf66c095f022c2..96e22c65591ba568880b6a7a3ed0c7934126208b 100644 (file)
 
     <para>The service exposes the following interfaces on the Manager object on the bus:</para>
 
-    <programlisting>
-$ gdbus introspect --system \
-        --dest org.freedesktop.resolve1 \
-        --object-path /org/freedesktop/resolve1
-
+    <programlisting executable="systemd-resolved" node="/org/freedesktop/resolve1" interface="org.freedesktop.resolve1.Manager">
 node /org/freedesktop/resolve1 {
   interface org.freedesktop.resolve1.Manager {
     methods:
@@ -110,7 +106,7 @@ node /org/freedesktop/resolve1 {
                       in  s type,
                       in  q service_port,
                       in  q service_priority,
-                      in  q serwise_weight,
+                      in  q service_weight,
                       in  aa{say} txt_datas,
                       out o service_path);
       UnregisterService(in  o service_path);
@@ -145,9 +141,6 @@ node /org/freedesktop/resolve1 {
       readonly as DNSSECNegativeTrustAnchors = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly s DNSStubListener = '...';
-      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
-      @org.freedesktop.systemd1.Privileged("true")
-      readwrite s LogLevel = '...';
   };
   interface org.freedesktop.DBus.Peer { ... };
   interface org.freedesktop.DBus.Introspectable { ... };
@@ -257,8 +250,6 @@ node /org/freedesktop/resolve1 {
 
     <variablelist class="dbus-property" generated="True" extra-ref="DNSStubListener"/>
 
-    <variablelist class="dbus-property" generated="True" extra-ref="LogLevel"/>
-
     <!--End of Autogenerated section-->
 
     <refsect2>
@@ -394,7 +385,7 @@ node /org/freedesktop/resolve1 {
       default LLMNR setting is used. If <literal>yes</literal>, LLMNR is used for resolution of single-label
       names and the local hostname is registered on all local LANs for LLMNR resolution by peers. If
       <literal>no</literal>, LLMNR is turned off fully on this interface. If <literal>resolve</literal>, LLMNR
-      is only enabled for resolving names, but the local host name is not registered for other peers to
+      is only enabled for resolving names, but the local hostname is not registered for other peers to
       use.</para>
 
       <para>Similarly, the <function>SetLinkMulticastDNS()</function> method enables or disables MulticastDNS
@@ -551,12 +542,8 @@ node /org/freedesktop/resolve1 {
   <refsect1>
     <title>Link Object</title>
 
-    <programlisting>
-$ gdbus introspect --system \
-        --dest org.freedesktop.resolve1 \
-        --object-path /org/freedesktop/resolve1/link/_34
-
-node /org/freedesktop/resolve1/link/_34 {
+    <programlisting executable="systemd-resolved" node="/org/freedesktop/resolve1/link/_1" interface="org.freedesktop.resolve1.Link">
+node /org/freedesktop/resolve1/link/_1 {
   interface org.freedesktop.resolve1.Link {
     methods:
       SetDNS(in  a(iay) addresses);
@@ -790,6 +777,30 @@ node /org/freedesktop/resolve1/link/_34 {
     </variablelist>
   </refsect1>
 
+  <refsect1>
+    <title>Examples</title>
+
+    <example>
+      <title>Introspect <interfacename>org.freedesktop.resolve1.Manager</interfacename> on the bus</title>
+
+      <programlisting>
+$ gdbus introspect --system \
+  --dest org.freedesktop.resolve1 \
+  --object-path /org/freedesktop/resolve1
+      </programlisting>
+    </example>
+
+    <example>
+      <title>Introspect <interfacename>org.freedesktop.resolve1.Link</interfacename> on the bus</title>
+
+      <programlisting>
+$ gdbus introspect --system \
+  --dest org.freedesktop.resolve1 \
+  --object-path /org/freedesktop/resolve1/link/_11
+      </programlisting>
+    </example>
+  </refsect1>
+
   <refsect1>
     <title>Versioning</title>
 
index 996c7179048c6208cf40394c2db1a393a13fb415..9a8b788982a0a6a06c95d00e390285515d1554c7 100644 (file)
     <para>Properties exposing time values are usually encoded in microseconds (usec) on the bus, even if
     their corresponding settings in the unit files are in seconds.</para>
 
-    <para>In contrast to most of the other services of the systemd suite, PID 1 does not use PolicyKit for
-    controlling access to privileged operations, but relies exclusively on the low-level D-Bus policy
-    language. (This is done in order to avoid a cyclic dependency between PolicyKit and systemd/PID 1.) This
+    <para>In contrast to most of the other services of the systemd suite, PID 1 does not use
+    <ulink url="https://www.freedesktop.org/software/polkit/docs/latest/">polkit</ulink>
+    for controlling access to privileged operations, but relies exclusively on the low-level D-Bus policy
+    language. (This is done in order to avoid a cyclic dependency between polkit and systemd/PID 1.) This
     means that sensitive operations exposed by PID 1 on the bus are generally not available to unprivileged
     processes directly. However, some operations (such as shutdown/reboot/suspend) are made available through the D-Bus
     API of logind, see
     <para>The main entry point object is available on the fixed
     <constant>/org/freedesktop/systemd1</constant> object path:</para>
 
-    <programlisting>
-$ gdbus introspect --system \
-        --dest org.freedesktop.systemd1 \
-        --object-path /org/freedesktop/systemd1
-
+    <programlisting executable="systemd" node="/org/freedesktop/systemd1" interface="org.freedesktop.systemd1.Manager">
 node /org/freedesktop/systemd1 {
   interface org.freedesktop.systemd1.Manager {
     methods:
@@ -113,6 +110,8 @@ node /org/freedesktop/systemd1 {
                in  i signal);
       CleanUnit(in  s name,
                 in  as mask);
+      FreezeUnit(in  s name);
+      ThawUnit(in  s name);
       ResetFailedUnit(in  s name);
       SetUnitProperties(in  s name,
                         in  b runtime,
@@ -488,6 +487,10 @@ node /org/freedesktop/systemd1 {
 
     <!--method CleanUnit is not documented!-->
 
+    <!--method FreezeUnit is not documented!-->
+
+    <!--method ThawUnit is not documented!-->
+
     <!--method RefUnit is not documented!-->
 
     <!--method UnrefUnit is not documented!-->
@@ -746,6 +749,10 @@ node /org/freedesktop/systemd1 {
 
     <variablelist class="dbus-method" generated="True" extra-ref="CleanUnit()"/>
 
+    <variablelist class="dbus-method" generated="True" extra-ref="FreezeUnit()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="ThawUnit()"/>
+
     <variablelist class="dbus-method" generated="True" extra-ref="ResetFailedUnit()"/>
 
     <variablelist class="dbus-method" generated="True" extra-ref="SetUnitProperties()"/>
@@ -1463,7 +1470,7 @@ node /org/freedesktop/systemd1 {
       <title>Security</title>
 
       <para>Read access is generally granted to all clients. Additionally, for unprivileged clients, some
-      operations are allowed through the PolicyKit privilege system. Operations which modify unit state
+      operations are allowed through the polkit privilege system. Operations which modify unit state
       (<function>StartUnit()</function>, <function>StopUnit()</function>, <function>KillUnit()</function>,
       <function>RestartUnit()</function> and similar, <function>SetProperty</function>) require
       <interfacename>org.freedesktop.systemd1.manage-units</interfacename>. Operations which modify unit file
@@ -1483,10 +1490,7 @@ node /org/freedesktop/systemd1 {
   <refsect1>
     <title>Unit Objects</title>
 
-    <programlisting interface="org.freedesktop.systemd1.Unit">
-$ gdbus introspect --system --dest org.freedesktop.systemd1 \
-      --object-path /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice
-
+    <programlisting executable="systemd" node="/org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice" interface="org.freedesktop.systemd1.Unit">
 node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
   interface org.freedesktop.systemd1.Unit {
     methods:
@@ -1520,6 +1524,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
       Ref();
       Unref();
       Clean(in  as mask);
+      Freeze();
+      Thaw();
     properties:
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s Id = '...';
@@ -1576,6 +1582,7 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s LoadState = '...';
       readonly s ActiveState = '...';
+      readonly s FreezerState = '...';
       readonly s SubState = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s FragmentPath = '...';
@@ -1607,6 +1614,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
       readonly b CanIsolate = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly as CanClean = ['...', ...];
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+      readonly b CanFreeze = ...;
       readonly (uo) Job = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly b StopWhenUnneeded = ...;
@@ -1673,7 +1682,6 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
   interface org.freedesktop.DBus.Peer { ... };
   interface org.freedesktop.DBus.Introspectable { ... };
   interface org.freedesktop.DBus.Properties { ... };
-  interface org.freedesktop.systemd1.Service { ... };
 };
     </programlisting>
 
@@ -1685,6 +1693,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <!--method Clean is not documented!-->
 
+    <!--method Freeze is not documented!-->
+
+    <!--method Thaw is not documented!-->
+
     <!--property PartOf is not documented!-->
 
     <!--property RequisiteOf is not documented!-->
@@ -1695,6 +1707,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <!--property JoinsNamespaceOf is not documented!-->
 
+    <!--property FreezerState is not documented!-->
+
     <!--property DropInPaths is not documented!-->
 
     <!--property UnitFilePreset is not documented!-->
@@ -1705,6 +1719,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <!--property CanClean is not documented!-->
 
+    <!--property CanFreeze is not documented!-->
+
     <!--property OnFailureJobMode is not documented!-->
 
     <!--property JobRunningTimeoutUSec is not documented!-->
@@ -1745,12 +1761,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <!--Autogenerated cross-references for systemd.directives, do not edit-->
 
-    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Service"/>
-
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
 
-    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Service"/>
-
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
 
     <variablelist class="dbus-method" generated="True" extra-ref="Start()"/>
@@ -1781,6 +1793,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <variablelist class="dbus-method" generated="True" extra-ref="Clean()"/>
 
+    <variablelist class="dbus-method" generated="True" extra-ref="Freeze()"/>
+
+    <variablelist class="dbus-method" generated="True" extra-ref="Thaw()"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="Id"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="Names"/>
@@ -1837,6 +1853,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <variablelist class="dbus-property" generated="True" extra-ref="ActiveState"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="FreezerState"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="SubState"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="FragmentPath"/>
@@ -1879,6 +1897,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <variablelist class="dbus-property" generated="True" extra-ref="CanClean"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="CanFreeze"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="Job"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="StopWhenUnneeded"/>
@@ -2127,7 +2147,7 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
       allowed for everyone. All operations are allowed for clients with the
       <constant>CAP_SYS_ADMIN</constant> capability or when the
       <interfacename>org.freedesktop.systemd1.manage-units</interfacename> privilege is granted by
-      PolicyKit.</para>
+      polkit.</para>
     </refsect2>
   </refsect1>
 
@@ -2138,10 +2158,7 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
     <interfacename>org.freedesktop.systemd1.Service</interfacename> interface (described here) in addition to
     the generic <interfacename>org.freedesktop.systemd1.Unit</interfacename> interface (see above).</para>
 
-    <programlisting interface="org.freedesktop.systemd1.Service">
-$ gdbus introspect --system --dest org.freedesktop.systemd1 \
-      --object-path /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice
-
+    <programlisting executable="systemd" node="/org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice" interface="org.freedesktop.systemd1.Service">
 node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
   interface org.freedesktop.systemd1.Service {
     methods:
@@ -3134,14 +3151,14 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <!--Autogenerated cross-references for systemd.directives, do not edit-->
 
-    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Service"/>
-
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Service"/>
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
 
+    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Service"/>
+
     <variablelist class="dbus-method" generated="True" extra-ref="GetProcesses()"/>
 
     <variablelist class="dbus-method" generated="True" extra-ref="AttachProcesses()"/>
@@ -3745,10 +3762,7 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
   <refsect1>
     <title>Socket Unit Objects</title>
 
-    <programlisting interface="org.freedesktop.systemd1.Socket">
-$ gdbus introspect --system --dest org.freedesktop.systemd1 \
-      --object-path /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket
-
+    <programlisting executable="systemd" node="/org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket" interface="org.freedesktop.systemd1.Socket">
 node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
   interface org.freedesktop.systemd1.Socket {
     methods:
@@ -4776,14 +4790,14 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
 
     <!--Autogenerated cross-references for systemd.directives, do not edit-->
 
-    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Socket"/>
-
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Socket"/>
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
 
+    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Socket"/>
+
     <variablelist class="dbus-method" generated="True" extra-ref="GetProcesses()"/>
 
     <variablelist class="dbus-method" generated="True" extra-ref="AttachProcesses()"/>
@@ -5339,10 +5353,7 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
   <refsect1>
     <title>Target Unit Objects</title>
 
-    <programlisting interface="org.freedesktop.systemd1.Target">
-$ gdbus introspect --system --dest org.freedesktop.systemd1 \
-      --object-path /org/freedesktop/systemd1/unit/basic_2etarget
-
+    <programlisting executable="systemd" node="/org/freedesktop/systemd1/unit/basic_2etarget" interface="org.freedesktop.systemd1.Target">
 node /org/freedesktop/systemd1/unit/basic_2etarget {
   interface org.freedesktop.systemd1.Target {
   };
@@ -5363,11 +5374,8 @@ node /org/freedesktop/systemd1/unit/basic_2etarget {
     <para>All device unit objects implement the <interfacename>org.freedesktop.systemd1.Device</interfacename> interface (described here)
     in addition to the generic <interfacename>org.freedesktop.systemd1.Unit</interfacename> interface (see above).</para>
 
-    <programlisting interface="org.freedesktop.systemd1.Device">
-$ gdbus introspect --system --dest org.freedesktop.systemd1 \
-      --object-path /org/freedesktop/systemd1/unit/dev_2dfoo_2edevice
-
-node /org/freedesktop/systemd1/unit/dev_2dfoo_2edevice {
+    <programlisting executable="systemd" node="/org/freedesktop/systemd1/unit/dev_2dttyS0_2edevice" interface="org.freedesktop.systemd1.Device">
+node /org/freedesktop/systemd1/unit/dev_2dttyS0_2edevice {
   interface org.freedesktop.systemd1.Device {
     properties:
       readonly s SysFSPath = '...';
@@ -5381,14 +5389,14 @@ node /org/freedesktop/systemd1/unit/dev_2dfoo_2edevice {
 
     <!--Autogenerated cross-references for systemd.directives, do not edit-->
 
-    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Device"/>
-
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Device"/>
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
 
+    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Device"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="SysFSPath"/>
 
     <!--End of Autogenerated section-->
@@ -5410,10 +5418,7 @@ node /org/freedesktop/systemd1/unit/dev_2dfoo_2edevice {
     interface (described here) in addition to the generic
     <interfacename>org.freedesktop.systemd1.Unit</interfacename> interface (see above).</para>
 
-    <programlisting interface="org.freedesktop.systemd1.Mount">
-$ gdbus introspect --system --dest org.freedesktop.systemd1 \
-      --object-path /org/freedesktop/systemd1/unit/home_2emount
-
+    <programlisting executable="systemd" node="/org/freedesktop/systemd1/unit/home_2emount" interface="org.freedesktop.systemd1.Mount">
 node /org/freedesktop/systemd1/unit/home_2emount {
   interface org.freedesktop.systemd1.Mount {
     methods:
@@ -6290,14 +6295,14 @@ node /org/freedesktop/systemd1/unit/home_2emount {
 
     <!--Autogenerated cross-references for systemd.directives, do not edit-->
 
-    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Mount"/>
-
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Mount"/>
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
 
+    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Mount"/>
+
     <variablelist class="dbus-method" generated="True" extra-ref="GetProcesses()"/>
 
     <variablelist class="dbus-method" generated="True" extra-ref="AttachProcesses()"/>
@@ -6772,10 +6777,7 @@ node /org/freedesktop/systemd1/unit/home_2emount {
     <interfacename>org.freedesktop.systemd1.Automount</interfacename> interface (described here) in addition
     to the generic <interfacename>org.freedesktop.systemd1.Unit</interfacename> interface (see above).</para>
 
-    <programlisting interface="org.freedesktop.systemd1.Automount">
-$ gdbus introspect --system --dest org.freedesktop.systemd1 \
-      --object-path /org/freedesktop/systemd1/unit/proc_2dsys_2dfs_2dbinfmt_5fmisc_2eautomount
-
+    <programlisting executable="systemd" node="/org/freedesktop/systemd1/unit/proc_2dsys_2dfs_2dbinfmt_5fmisc_2eautomount" interface="org.freedesktop.systemd1.Automount">
 node /org/freedesktop/systemd1/unit/proc_2dsys_2dfs_2dbinfmt_5fmisc_2eautomount {
   interface org.freedesktop.systemd1.Automount {
     properties:
@@ -6802,14 +6804,14 @@ node /org/freedesktop/systemd1/unit/proc_2dsys_2dfs_2dbinfmt_5fmisc_2eautomount
 
     <!--Autogenerated cross-references for systemd.directives, do not edit-->
 
-    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Automount"/>
-
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Automount"/>
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
 
+    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Automount"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="Where"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="DirectoryMode"/>
@@ -6840,10 +6842,7 @@ node /org/freedesktop/systemd1/unit/proc_2dsys_2dfs_2dbinfmt_5fmisc_2eautomount
     interface (described here) in addition to the generic
     <interfacename>org.freedesktop.systemd1.Unit</interfacename> interface (see above).</para>
 
-    <programlisting interface="org.freedesktop.systemd1.Timer">
-$ gdbus introspect --system --dest org.freedesktop.systemd1 \
-      --object-path /org/freedesktop/systemd1/unit/systemd_2dtmpfiles_2dclean_2etimer
-
+    <programlisting executable="systemd" node="/org/freedesktop/systemd1/unit/systemd_2dtmpfiles_2dclean_2etimer" interface="org.freedesktop.systemd1.Timer">
 node /org/freedesktop/systemd1/unit/systemd_2dtmpfiles_2dclean_2etimer {
   interface org.freedesktop.systemd1.Timer {
     properties:
@@ -6900,14 +6899,14 @@ node /org/freedesktop/systemd1/unit/systemd_2dtmpfiles_2dclean_2etimer {
 
     <!--Autogenerated cross-references for systemd.directives, do not edit-->
 
-    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Timer"/>
-
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Timer"/>
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
 
+    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Timer"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="Unit"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="TimersMonotonic"/>
@@ -6979,10 +6978,7 @@ node /org/freedesktop/systemd1/unit/systemd_2dtmpfiles_2dclean_2etimer {
     interface (described here) in addition to the generic
     <interfacename>org.freedesktop.systemd1.Unit</interfacename> interface (see above).</para>
 
-    <programlisting interface="org.freedesktop.systemd1.Swap">
-$ gdbus introspect --system --dest org.freedesktop.systemd1 \
-      --object-path /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap
-
+    <programlisting executable="systemd" node="/org/freedesktop/systemd1/unit/dev_2dsda3_2eswap" interface="org.freedesktop.systemd1.Swap">
 node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
   interface org.freedesktop.systemd1.Swap {
     methods:
@@ -7835,14 +7831,14 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
 
     <!--Autogenerated cross-references for systemd.directives, do not edit-->
 
-    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Swap"/>
-
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Swap"/>
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
 
+    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Swap"/>
+
     <variablelist class="dbus-method" generated="True" extra-ref="GetProcesses()"/>
 
     <variablelist class="dbus-method" generated="True" extra-ref="AttachProcesses()"/>
@@ -8305,10 +8301,7 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
   <refsect1>
     <title>Path Unit Objects</title>
 
-    <programlisting interface="org.freedesktop.systemd1.Path">
-$ gdbus introspect --system --dest org.freedesktop.systemd1 \
-      --object-path /org/freedesktop/systemd1/unit/cups_2epath
-
+    <programlisting executable="systemd" node="/org/freedesktop/systemd1/unit/cups_2epath" interface="org.freedesktop.systemd1.Path">
 node /org/freedesktop/systemd1/unit/cups_2epath {
   interface org.freedesktop.systemd1.Path {
     properties:
@@ -8335,14 +8328,14 @@ node /org/freedesktop/systemd1/unit/cups_2epath {
 
     <!--Autogenerated cross-references for systemd.directives, do not edit-->
 
-    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Path"/>
-
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Path"/>
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
 
+    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Path"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="Unit"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="Paths"/>
@@ -8381,10 +8374,7 @@ node /org/freedesktop/systemd1/unit/cups_2epath {
     interface (described here) in addition to the generic
     <interfacename>org.freedesktop.systemd1.Unit</interfacename> interface (see above).</para>
 
-    <programlisting interface="org.freedesktop.systemd1.Slice">
-$ gdbus introspect --system --dest org.freedesktop.systemd1 \
-      --object-path /org/freedesktop/systemd1/unit/system_2eslice
-
+    <programlisting executable="systemd" node="/org/freedesktop/systemd1/unit/system_2eslice" interface="org.freedesktop.systemd1.Slice">
 node /org/freedesktop/systemd1/unit/system_2eslice {
   interface org.freedesktop.systemd1.Slice {
     methods:
@@ -8644,14 +8634,14 @@ node /org/freedesktop/systemd1/unit/system_2eslice {
 
     <!--Autogenerated cross-references for systemd.directives, do not edit-->
 
-    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Slice"/>
-
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Slice"/>
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
 
+    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Slice"/>
+
     <variablelist class="dbus-method" generated="True" extra-ref="GetProcesses()"/>
 
     <variablelist class="dbus-method" generated="True" extra-ref="AttachProcesses()"/>
@@ -8792,10 +8782,7 @@ node /org/freedesktop/systemd1/unit/system_2eslice {
     interface (described here) in addition to the generic
     <interfacename>org.freedesktop.systemd1.Unit</interfacename> interface (see above).</para>
 
-    <programlisting interface="org.freedesktop.systemd1.Scope">
-$ gdbus introspect --system --dest org.freedesktop.systemd1 \
-      --object-path /org/freedesktop/systemd1/unit/session_2d1_2escope
-
+    <programlisting executable="systemd" node="/org/freedesktop/systemd1/unit/session_2d1_2escope" interface="org.freedesktop.systemd1.Scope">
 node /org/freedesktop/systemd1/unit/session_2d1_2escope {
   interface org.freedesktop.systemd1.Scope {
     methods:
@@ -9096,14 +9083,14 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
 
     <!--Autogenerated cross-references for systemd.directives, do not edit-->
 
-    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Scope"/>
-
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Scope"/>
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
 
+    <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Scope"/>
+
     <variablelist class="dbus-method" generated="True" extra-ref="Abandon()"/>
 
     <variablelist class="dbus-method" generated="True" extra-ref="GetProcesses()"/>
@@ -9292,11 +9279,8 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
     <para>Job objects encapsulate scheduled or running jobs. Each unit can have none or one jobs in the
     execution queue. Each job is attached to exactly one unit.</para>
 
-    <programlisting>
-$ gdbus introspect --system --dest org.freedesktop.systemd1 \
-      --object-path /org/freedesktop/systemd1/job/1292
-
-node /org/freedesktop/systemd1/job/1292 {
+    <programlisting executable="systemd" node="/org/freedesktop/systemd1/job/666" interface="org.freedesktop.systemd1.Job">
+node /org/freedesktop/systemd1/job/666 {
   interface org.freedesktop.systemd1.Job {
     methods:
       Cancel();
@@ -9372,6 +9356,41 @@ node /org/freedesktop/systemd1/job/1292 {
     </refsect2>
   </refsect1>
 
+  <refsect1>
+    <title>Examples</title>
+
+    <example>
+      <title>Introspect <interfacename>org.freedesktop.systemd1.Manager</interfacename> on the bus</title>
+
+      <programlisting>
+$ gdbus introspect --system \
+        --dest org.freedesktop.systemd1 \
+        --object-path /org/freedesktop/systemd1
+      </programlisting>
+    </example>
+
+    <example>
+      <title>Introspect a unit on the bus</title>
+
+      <programlisting>
+$ busctl introspect org.freedesktop.systemd1 \
+  $(busctl call org.freedesktop.systemd1 \
+     /org/freedesktop/systemd1 \
+     org.freedesktop.systemd1.Manager \
+     GetUnit s systemd-resolved.service | cut -d'"' -f2)
+      </programlisting>
+    </example>
+
+    <example>
+      <title>Introspect <interfacename>org.freedesktop.systemd1.Job</interfacename> on the bus</title>
+
+      <programlisting>
+$ gdbus introspect --system --dest org.freedesktop.systemd1 \
+  --object-path /org/freedesktop/systemd1/job/1292
+      </programlisting>
+    </example>
+  </refsect1>
+
   <refsect1>
     <title>Versioning</title>
 
index 000c0ca03e664ef74d9df6dbbe21102b193387bf..325c3acfb1e078bc8634281c9a5864ccb4165048 100644 (file)
 
     <para>The service exposes the following interfaces on the bus:</para>
 
-    <programlisting>
-$ gdbus introspect --system \
-        --dest org.freedesktop.timedate1 \
-        --object-path /org/freedesktop/timedate1
-
+    <programlisting executable="systemd-timedated" node="/org/freedesktop/timedate1" interface="org.freedesktop.timedate1">
 node /org/freedesktop/timedate1 {
   interface org.freedesktop.timedate1 {
     methods:
@@ -72,22 +68,6 @@ node /org/freedesktop/timedate1 {
 };
     </programlisting>
 
-    <!--method ListTimezones is not documented!-->
-
-    <!--property Timezone is not documented!-->
-
-    <!--property LocalRTC is not documented!-->
-
-    <!--property CanNTP is not documented!-->
-
-    <!--property NTP is not documented!-->
-
-    <!--property NTPSynchronized is not documented!-->
-
-    <!--property TimeUSec is not documented!-->
-
-    <!--property RTCTimeUSec is not documented!-->
-
     <!--Autogenerated cross-references for systemd.directives, do not edit-->
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.timedate1"/>
@@ -148,28 +128,68 @@ node /org/freedesktop/timedate1 {
       network using <filename>systemd-timesyncd</filename>. This will enable and start or disable and stop
       the chosen time synchronization service.</para>
 
-      <para>Whenever the timezone and local_rtc settings are changed via the daemon,
-      <function>PropertyChanged</function> signals are sent out to which clients can subscribe. Changing the
-      time settings using this interface is authenticated via PolicyKit.</para>
+      <para><function>ListTimezones()</function> returns a list of time zones known on the local system as an
+      array of names (<literal>["Africa/Abidjan", "Africa/Accra", ..., "UTC"]</literal>).</para>
+    </refsect2>
+
+    <refsect2>
+      <title>Properties</title>
+
+      <para><varname>Timezone</varname> shows the currently configured time zone.
+      <varname>LocalRTC</varname> shows whether the RTC is configured to use UTC (false), or the local time
+      zone (true). <varname>CanNTP</varname> shows whether a service to perform time synchronization over the
+      network is available, and <varname>NTP</varname> shows whether such a service is enabled.</para>
+
+      <para><varname>NTPSynchronized</varname> shows whether the kernel reports the time as synchronized
+      (c.f.
+      <citerefentry project="man-pages"><refentrytitle>adjtimex</refentrytitle><manvolnum>3</manvolnum></citerefentry>).
+      <varname>TimeUSec</varname> and <varname>RTCTimeUSec</varname> show the current time on the system and
+      in the RTC. The purpose of those three properties is to allow remote clients to access this information
+      over D-Bus. Local clients can access the information directly.</para>
+
+      <para>Whenever the <varname>Timezone</varname> and <varname>LocalRTC</varname> settings are changed via
+      the daemon, <function>PropertyChanged</function> signals are sent out to which clients can subscribe.
+      </para>
 
       <para>Note that this service will not inform you about system time changes. Use
       <citerefentry project="man-pages"><refentrytitle>timerfd</refentrytitle><manvolnum>3</manvolnum></citerefentry>
       with <constant>CLOCK_REALTIME</constant> and <constant>TFD_TIMER_CANCEL_ON_SET</constant> for that.
       </para>
+    </refsect2>
 
-      <para>The <varname>user_interaction</varname> boolean parameters can be used to control whether
-      PolicyKit should interactively ask the user for authentication credentials if required.</para>
+    <refsect2>
+      <title>Security</title>
+
+      <para>The <varname>interactive</varname> boolean parameters can be used to control whether
+      <ulink url="https://www.freedesktop.org/software/polkit/docs/latest/">polkit</ulink>
+      should interactively ask the user for authentication credentials if required.</para>
 
-      <para>The PolicyKit action for <function>SetTimezone()</function> is
+      <para>The polkit action for <function>SetTimezone()</function> is
       <interfacename>org.freedesktop.timedate1.set-timezone</interfacename>. For
       <function>SetLocalRTC()</function> it is
       <interfacename>org.freedesktop.timedate1.set-local-rtc</interfacename>, for
       <function>SetTime()</function> it is <interfacename>org.freedesktop.timedate1.set-time</interfacename>
       and for <function>SetNTP()</function> it is
-      <interfacename>org.freedesktop.timedate1.set-ntp</interfacename>.</para>
+      <interfacename>org.freedesktop.timedate1.set-ntp</interfacename>.
+      <function>ListTimezones()</function> does not require any privileges.
+      </para>
     </refsect2>
   </refsect1>
 
+  <refsect1>
+    <title>Examples</title>
+
+    <example>
+      <title>Introspect <interfacename>org.freedesktop.timedate1</interfacename> on the bus</title>
+
+      <programlisting>
+$ gdbus introspect --system \
+  --dest org.freedesktop.timedate1 \
+  --object-path /org/freedesktop/timedate1
+      </programlisting>
+    </example>
+  </refsect1>
+
   <refsect1>
     <title>Versioning</title>
 
index 694371c2c47aeb3cf4c0fdc138266cd92fe777b4..70927d737423c278e4b48bcc256717c812a029fc 100644 (file)
 
     <variablelist class='pam-directives'>
       <varlistentry>
-        <term><varname>systemd.memory_max</varname></term>
+        <term><varname>systemd.memory_max=</varname></term>
 
         <listitem><para>Sets unit <varname>MemoryMax=</varname>.</para></listitem>
       </varlistentry>
 
       <varlistentry>
-        <term><varname>systemd.tasks_max</varname></term>
+        <term><varname>systemd.tasks_max=</varname></term>
 
         <listitem><para>Sets unit <varname>TasksMax=</varname>.</para></listitem>
       </varlistentry>
 
       <varlistentry>
-        <term><varname>systemd.cpu_weight</varname></term>
+        <term><varname>systemd.cpu_weight=</varname></term>
 
         <listitem><para>Sets unit <varname>CPUWeight=</varname>.</para></listitem>
       </varlistentry>
 
       <varlistentry>
-        <term><varname>systemd.io_weight</varname></term>
+        <term><varname>systemd.io_weight=</varname></term>
 
         <listitem><para>Sets unit <varname>IOWeight=</varname>.</para></listitem>
       </varlistentry>
 
       <varlistentry>
-        <term><varname>systemd.runtime_max_sec</varname></term>
+        <term><varname>systemd.runtime_max_sec=</varname></term>
 
         <listitem><para>Sets unit <varname>RuntimeMaxSec=</varname>.</para></listitem>
       </varlistentry>
@@ -308,19 +308,24 @@ pam_set_data(handle, "systemd.runtime_max_sec", (void *)"3600", cleanup);
     <filename>systemd-logind.service</filename>:</para>
 
     <programlisting>#%PAM-1.0
-auth     sufficient pam_unix.so
-auth     required   pam_deny.so
-
-account  required   pam_nologin.so
-account  sufficient pam_unix.so
-account  required   pam_permit.so
-
-password sufficient pam_unix.so sha512 shadow try_first_pass try_authtok
-password required   pam_deny.so
-
--session optional   pam_loginuid.so
--session optional   pam_systemd.so
-session  required   pam_unix.so</programlisting>
+auth      sufficient pam_unix.so
+-auth     sufficient pam_systemd_home.so
+auth      required   pam_deny.so
+
+account   required   pam_nologin.so
+-account  sufficient pam_systemd_home.so
+account   sufficient pam_unix.so
+account   required   pam_permit.so
+
+-password sufficient pam_systemd_home.so
+password  sufficient pam_unix.so sha512 shadow try_first_pass try_authtok
+password  required   pam_deny.so
+
+-session  optional   pam_keyinit.so revoke
+-session  optional   pam_loginuid.so
+-session  optional   pam_systemd_home.so
+<command>-session  optional   pam_systemd.so</command>
+session   required   pam_unix.so</programlisting>
   </refsect1>
 
   <refsect1>
index d952c98dc1418072fafdf77916a6d47116c506dd..ab02f98337202e60dbc21d42e27de819796e3c9b 100644 (file)
         the re-authentication must take place from a component running outside of the user's context, so that
         it does not require access to the user's home directory for operation. Traditionally, most desktop
         environments do not implement screen locking this way, and need to be updated
-        accordingly.</para></listitem>
+        accordingly.</para>
+
+        <para>This setting may also be controlled via the <varname>$SYSTEMD_HOME_SUSPEND</varname>
+        environment variable (see below), which <command>pam_systemd_home</command> reads during initialization and sets
+        for sessions. If both the environment variable is set and the module parameter specified the latter
+        takes precedence.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <listitem><para>Indicates that the user's home directory is managed by <filename>systemd-homed.service</filename>.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>$SYSTEMD_HOME_SUSPEND=</varname></term>
+
+        <listitem><para>Indicates whether the session has been registered with the suspend mechanism enabled
+        or disabled (see above). The variable's value is either <literal>0</literal> or
+        <literal>1</literal>. Note that the module both reads the variable when initializing, and sets it for
+        sessions.</para></listitem>
+      </varlistentry>
+
     </variablelist>
   </refsect1>
 
 
     <programlisting>#%PAM-1.0
 auth      sufficient pam_unix.so
--auth     sufficient pam_systemd_home.so
+<command>-auth     sufficient pam_systemd_home.so</command>
 auth      required   pam_deny.so
 
 account   required   pam_nologin.so
--account  sufficient pam_systemd_home.so
+<command>-account  sufficient pam_systemd_home.so</command>
 account   sufficient pam_unix.so
 account   required   pam_permit.so
 
--password sufficient pam_systemd_home.so
+<command>-password sufficient pam_systemd_home.so</command>
 password  sufficient pam_unix.so sha512 shadow try_first_pass try_authtok
 password  required   pam_deny.so
 
 -session  optional   pam_keyinit.so revoke
 -session  optional   pam_loginuid.so
--session  optional   pam_systemd_home.so
+<command>-session  optional   pam_systemd_home.so</command>
 -session  optional   pam_systemd.so
 session   required   pam_unix.so</programlisting>
   </refsect1>
index cc049945941d3ae9b5a2789758d6d1d12e27ca49..e2d00b9cf08c250598bb6138606c61b96ce50c2f 100644 (file)
@@ -45,7 +45,7 @@
     interface the data was discovered. It also contains information on whether the information could be
     authenticated. All data for which local DNSSEC validation succeeds is considered authenticated. Moreover all data
     originating from local, trusted sources is also reported authenticated, including resolution of the local host
-    name, the <literal>localhost</literal> host name or all data from <filename>/etc/hosts</filename>.</para>
+    name, the <literal>localhost</literal> hostname or all data from <filename>/etc/hosts</filename>.</para>
   </refsect1>
 
   <refsect1>
index 81d156b8e3bf7642c272e11026989a61209d2c7e..9be41baaa5a5fb03f79dfa072f00d48ff088f5a9 100644 (file)
@@ -68,7 +68,7 @@
       <varlistentry>
         <term><varname>Domains=</varname></term>
         <listitem><para>A space-separated list of domains. These domains are used as search suffixes when resolving
-        single-label host names (domain names which contain no dot), in order to qualify them into fully-qualified
+        single-label hostnames (domain names which contain no dot), in order to qualify them into fully-qualified
         domain names (FQDNs). Search domains are strictly processed in the order they are specified, until the name
         with the suffix appended is found. For compatibility reasons, if this setting is not specified, the search
         domains listed in <filename>/etc/resolv.conf</filename> are used instead, if that file exists and any domains
index 1405c95b61a7da2450913650b67354dcf68add62..941e248d72acadedfc9513248d574503b2f7bc45 100644 (file)
@@ -1,4 +1,4 @@
-# Do not edit. Generated by make-man-rules.py.
+# Do not edit. Generated by update-man-rules.py.
 # Update with:
 #     ninja -C build man/update-man-rules
 manpages = [
@@ -18,6 +18,7 @@ manpages = [
  ['file-hierarchy', '7', [], ''],
  ['halt', '8', ['poweroff', 'reboot'], ''],
  ['homectl', '1', [], 'ENABLE_HOMED'],
+ ['homed.conf', '5', ['homed.conf.d'], 'ENABLE_RESOLVE'],
  ['hostname', '5', [], ''],
  ['hostnamectl', '1', [], 'ENABLE_HOSTNAMED'],
  ['hwdb', '7', [], 'ENABLE_HWDB'],
@@ -44,6 +45,8 @@ manpages = [
  ['nss-mymachines', '8', ['libnss_mymachines.so.2'], 'ENABLE_NSS_MYMACHINES'],
  ['nss-resolve', '8', ['libnss_resolve.so.2'], 'ENABLE_NSS_RESOLVE'],
  ['nss-systemd', '8', ['libnss_systemd.so.2'], 'ENABLE_NSS_SYSTEMD'],
+ ['org.freedesktop.LogControl1', '5', [], ''],
+ ['org.freedesktop.home1', '5', [], 'ENABLE_HOMED'],
  ['org.freedesktop.hostname1', '5', [], 'ENABLE_HOSTNAMED'],
  ['org.freedesktop.import1', '5', [], 'ENABLE_IMPORTD'],
  ['org.freedesktop.locale1', '5', [], 'ENABLE_LOCALED'],
@@ -262,6 +265,8 @@ manpages = [
   ['sd_bus_get_events', 'sd_bus_get_timeout', 'sd_bus_set_fd'],
   ''],
  ['sd_bus_get_n_queued_read', '3', ['sd_bus_get_n_queued_write'], ''],
+ ['sd_bus_get_name_creds', '3', ['sd_bus_get_owner_creds'], ''],
+ ['sd_bus_get_name_machine_id', '3', [], ''],
  ['sd_bus_is_open', '3', ['sd_bus_is_ready'], ''],
  ['sd_bus_list_names', '3', [], ''],
  ['sd_bus_message_append', '3', ['sd_bus_message_appendv'], ''],
@@ -291,7 +296,8 @@ manpages = [
   ''],
  ['sd_bus_message_get_type',
   '3',
-  ['sd_bus_message_get_errno',
+  ['sd_bus_message_get_creds',
+   'sd_bus_message_get_errno',
    'sd_bus_message_get_error',
    'sd_bus_message_is_method_call',
    'sd_bus_message_is_method_error',
@@ -319,7 +325,16 @@ manpages = [
    'sd_bus_message_new_method_errorf'],
   ''],
  ['sd_bus_message_new_signal', '3', [], ''],
- ['sd_bus_message_read', '3', ['sd_bus_message_readv'], ''],
+ ['sd_bus_message_open_container',
+  '3',
+  ['sd_bus_message_close_container',
+   'sd_bus_message_enter_container',
+   'sd_bus_message_exit_container'],
+  ''],
+ ['sd_bus_message_read',
+  '3',
+  ['sd_bus_message_peek_type', 'sd_bus_message_readv'],
+  ''],
  ['sd_bus_message_read_array', '3', [], ''],
  ['sd_bus_message_read_basic', '3', [], ''],
  ['sd_bus_message_read_strv', '3', [], ''],
@@ -347,7 +362,9 @@ manpages = [
  ['sd_bus_message_verify_type', '3', [], ''],
  ['sd_bus_negotiate_fds',
   '3',
-  ['sd_bus_negotiate_creds', 'sd_bus_negotiate_timestamp'],
+  ['sd_bus_get_creds_mask',
+   'sd_bus_negotiate_creds',
+   'sd_bus_negotiate_timestamp'],
   ''],
  ['sd_bus_new',
   '3',
@@ -364,6 +381,7 @@ manpages = [
   ['sd_bus_path_decode', 'sd_bus_path_decode_many', 'sd_bus_path_encode_many'],
   ''],
  ['sd_bus_process', '3', [], ''],
+ ['sd_bus_query_sender_creds', '3', ['sd_bus_query_sender_privilege'], ''],
  ['sd_bus_reply_method_error',
   '3',
   ['sd_bus_reply_method_errno',
@@ -379,7 +397,7 @@ manpages = [
    'sd_bus_release_name_async',
    'sd_bus_request_name_async'],
   ''],
- ['sd_bus_send', '3', [], ''],
+ ['sd_bus_send', '3', ['sd_bus_send_to'], ''],
  ['sd_bus_set_address', '3', ['sd_bus_get_address', 'sd_bus_set_exec'], ''],
  ['sd_bus_set_close_on_exit', '3', ['sd_bus_get_close_on_exit'], ''],
  ['sd_bus_set_connected_signal', '3', ['sd_bus_get_connected_signal'], ''],
@@ -703,7 +721,11 @@ manpages = [
  ['sd_machine_get_class', '3', ['sd_machine_get_ifindices'], ''],
  ['sd_notify',
   '3',
-  ['sd_notifyf', 'sd_pid_notify', 'sd_pid_notify_with_fds', 'sd_pid_notifyf'],
+  ['sd_notify_barrier',
+   'sd_notifyf',
+   'sd_pid_notify',
+   'sd_pid_notify_with_fds',
+   'sd_pid_notifyf'],
   ''],
  ['sd_path_lookup', '3', ['sd_path_lookup_strv'], ''],
  ['sd_pid_get_owner_uid',
diff --git a/man/sd-bus-container-append.c b/man/sd-bus-container-append.c
new file mode 100644 (file)
index 0000000..e350ea0
--- /dev/null
@@ -0,0 +1,17 @@
+#include <systemd/sd-bus.h>
+
+int append_strings_to_message(sd_bus_message *m, const char *const *arr) {
+  int r;
+
+  r = sd_bus_message_open_container(m, 'a', "s");
+  if (r < 0)
+    return r;
+
+  for (const char *s = *arr; *s; s++) {
+    r = sd_bus_message_append(m, "s", s);
+    if (r < 0)
+      return r;
+  }
+
+  return sd_bus_message_close_container(m);
+}
diff --git a/man/sd-bus-container-read.c b/man/sd-bus-container-read.c
new file mode 100644 (file)
index 0000000..b6c95f4
--- /dev/null
@@ -0,0 +1,25 @@
+#include <stdio.h>
+
+#include <systemd/sd-bus.h>
+
+int read_strings_from_message(sd_bus_message *m) {
+  int r;
+
+  r = sd_bus_message_enter_container(m, 'a', "s");
+  if (r < 0)
+    return r;
+
+  for (;;) {
+    const char *s;
+
+    r = sd_bus_message_read(m, "s", &s);
+    if (r < 0)
+      return r;
+    if (r == 0)
+      break;
+
+    printf("%s\n", s);
+  }
+
+  return sd_bus_message_exit_container(m);
+}
index 6b14474f7923a09f945db2f2710cc8ce685fe8bf..24999337c8f74cd2fa7969696e9952c2c7651870 100644 (file)
@@ -74,6 +74,7 @@
 <citerefentry><refentrytitle>sd_bus_get_address</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_get_allow_interactive_authorization</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_get_bus_id</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_get_creds_mask</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_get_current_handler</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_get_current_message</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_get_current_slot</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
@@ -82,6 +83,9 @@
 <citerefentry><refentrytitle>sd_bus_get_fd</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_get_method_call_timeout</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_get_n_queued_read</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_get_name_machine_id</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_get_name_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_get_owner_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_get_scope</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_get_tid</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_get_unique_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_message_append_string_memfd</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_message_append_strv</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_message_at_end</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_message_close_container</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_message_copy</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_message_dump</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_message_enter_container</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_message_exit_container</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_message_get_allow_interactive_authorization</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_message_get_cookie</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_message_get_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_message_get_errno</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_message_get_error</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_message_get_monotonic_usec</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_message_new_method_call</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_message_new_method_error</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_message_new_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_message_open_container</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_message_peek_type</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_message_read</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_message_read_array</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_message_read_basic</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_path_encode</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_process</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_query_sender_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_query_sender_privilege</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_reply_method_return</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_reply_method_error</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_request_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_send</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_send_to</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_set_address</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_set_allow_interactive_authorization</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
 <citerefentry><refentrytitle>sd_bus_set_bus_client</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
index 64ed5f3779c73ac71a87d7b4a552b88f13e4b62f..a01ec5878690ca5a30d18028c022c7c41fe1816d 100644 (file)
 
     <para>These prefixes are intended to be used in conjunction with stderr-based logging (or stdout-based
     logging) as implemented by systemd. If a systemd service definition file is configured with
-    <varname>StandardError=journal</varname>, <varname>StandardError=syslog</varname> or
-    <varname>StandardError=kmsg</varname> (and similar with <varname>StandardOutput=</varname>), these
-    prefixes can be used to encode a log level in lines printed. This is similar to the kernel
-    <function>printk()</function>-style logging. See
+    <varname>StandardError=journal</varname> or <varname>StandardError=kmsg</varname> (and similar with
+    <varname>StandardOutput=</varname>), these prefixes can be used to encode a log level in lines
+    printed. This is similar to the kernel <function>printk()</function>-style logging. See
     <citerefentry><refentrytitle>klogctl</refentrytitle><manvolnum>2</manvolnum></citerefentry> for more
     information.</para>
 
index a1065443869ceee9c582b3038bdbbb6ed37fb869..071060dde6987d98e3fb459858b61065c35c12f5 100644 (file)
@@ -33,7 +33,7 @@
     <funcsynopsis>
       <funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
 
-      <funcprototype>
+      <funcprototype id="sd_bus_message_handler_t">
         <funcdef>typedef int (*<function>sd_bus_message_handler_t</function>)</funcdef>
         <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
         <paramdef>void *<parameter>userdata</parameter></paramdef>
index a747df62ca90dd8d4216853ff31f2947e09b11b7..bce71bd11a121d0954dc9b5dd1a8cb8838cad256 100644 (file)
     <funcsynopsis>
       <funcsynopsisinfo>#include &lt;systemd/sd-bus-vtable.h&gt;</funcsynopsisinfo>
 
-      <funcprototype>
-        <funcdef>typedef int (*<function>sd_bus_message_handler_t</function>)</funcdef>
-        <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
-        <paramdef>void *<parameter>userdata</parameter></paramdef>
-        <paramdef>sd_bus_error *<parameter>ret_error</parameter></paramdef>
-      </funcprototype>
+      <xi:include href="sd_bus_add_match.xml" xpointer="sd_bus_message_handler_t"/>
 
       <funcprototype>
         <funcdef>typedef int (*<function>sd_bus_property_get_t</function>)</funcdef>
       <para>
         <constant>SD_BUS_VTABLE_END</constant>
       </para>
+      <para>
+        <constant>SD_BUS_METHOD_WITH_ARGS_OFFSET(
+        <replaceable>member</replaceable>,
+        <replaceable>args</replaceable>,
+        <replaceable>result</replaceable>,
+        <replaceable>handler</replaceable>,
+        <replaceable>offset</replaceable>,
+        <replaceable>flags</replaceable>)
+        </constant>
+      </para>
+      <para>
+        <constant>SD_BUS_METHOD_WITH_ARGS(
+        <replaceable>member</replaceable>,
+        <replaceable>args</replaceable>,
+        <replaceable>result</replaceable>,
+        <replaceable>handler</replaceable>,
+        <replaceable>flags</replaceable>)
+        </constant>
+      </para>
       <para>
         <constant>SD_BUS_METHOD_WITH_NAMES_OFFSET(
         <replaceable>member</replaceable>,
         <replaceable>flags</replaceable>)
         </constant>
       </para>
+      <para>
+        <constant>SD_BUS_SIGNAL_WITH_ARGS(
+        <replaceable>member</replaceable>,
+        <replaceable>args</replaceable>,
+        <replaceable>flags</replaceable>)
+        </constant>
+      </para>
       <para>
         <constant>SD_BUS_SIGNAL_WITH_NAMES(
         <replaceable>member</replaceable>,
       </para>
       <para>
         <constant>SD_BUS_PARAM(<replaceable>name</replaceable>)</constant>
+        <constant>SD_BUS_ARGS(<replaceable>...</replaceable>)</constant>
+        <constant>SD_BUS_RESULT(<replaceable>...</replaceable>)</constant>
+        <constant>SD_BUS_NO_ARGS</constant>
+        <constant>SD_BUS_NO_RESULT</constant>
       </para>
     </funcsynopsis>
   </refsynopsisdiv>
           <listitem><para>Those must always be the first and last element.</para></listitem>
         </varlistentry>
 
+        <varlistentry>
+          <term><constant>SD_BUS_METHOD_WITH_ARGS_OFFSET()</constant></term>
+          <term><constant>SD_BUS_METHOD_WITH_ARGS()</constant></term>
+
+          <listitem><para>Declare a D-Bus method with the name <replaceable>member</replaceable>,
+          arguments <replaceable>args</replaceable> and result <replaceable>result</replaceable>.
+          <replaceable>args</replaceable> expects a sequence of argument type/name pairs wrapped in the
+          <constant>SD_BUS_ARGS()</constant> macro. The elements at even indices in this list describe the
+          types of the method's arguments. The method's parameter signature is the concatenation of all the
+          string literals at even indices in <replaceable>args</replaceable>. If a method has no parameters,
+          pass <constant>SD_BUS_NO_ARGS</constant> to <replaceable>args</replaceable>. The elements at uneven
+          indices describe the names of the method's arguments. <replaceable>result</replaceable> expects a
+          sequence of type/name pairs wrapped in the <constant>SD_BUS_RESULT()</constant> macro in the same
+          format as <constant>SD_BUS_ARGS()</constant>. The method's result signature is the concatenation of
+          all the string literals at even indices in <replaceable>result</replaceable>. If a method has no
+          result, pass <constant>SD_BUS_NO_RESULT</constant> to <replaceable>result</replaceable>. Note that
+          argument types are expected to be quoted string literals and argument names are expected to be
+          unquoted string literals. See below for a complete example.</para>
+
+          <para>The handler function <replaceable>handler</replaceable> must be of type
+          <function>sd_bus_message_handler_t</function>. It will be called to handle the incoming messages
+          that call this method. It receives a pointer that is the <replaceable>userdata</replaceable>
+          parameter passed to the registration function offset by <replaceable>offset</replaceable> bytes.
+          This may be used to pass pointers to different fields in the same data structure to different
+          methods in the same vtable. To send a reply from <parameter>handler</parameter>, call
+          <citerefentry><refentrytitle>sd_bus_reply_method_return</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+          with the message the callback was invoked with. Parameter <replaceable>flags</replaceable> is a
+          combination of flags, see below.</para>
+
+          <constant>SD_BUS_METHOD_WITH_ARGS()</constant> is a shorthand for calling
+          <constant>SD_BUS_METHOD_WITH_ARGS_OFFSET()</constant> with an offset of zero.
+          </listitem>
+        </varlistentry>
+
         <varlistentry>
           <term><constant>SD_BUS_METHOD_WITH_NAMES_OFFSET()</constant></term>
           <term><constant>SD_BUS_METHOD_WITH_NAMES()</constant></term>
           parameter signature <replaceable>signature</replaceable>, result signature
           <replaceable>result</replaceable>. Parameters <replaceable>in_names</replaceable> and
           <replaceable>out_names</replaceable> specify the argument names of the input and output
-          arguments in the function signature. The handler function
-          <replaceable>handler</replaceable> must be of type
-          <function>sd_bus_message_handler_t</function>. It will be called to handle the incoming
-          messages that call this method. It receives a pointer that is the
-          <replaceable>userdata</replaceable> parameter passed to the registration function offset
-          by <replaceable>offset</replaceable> bytes. This may be used to pass pointers to different
-          fields in the same data structure to different methods in the same vtable. To send a reply
-          from <parameter>handler</parameter>, call
-          <citerefentry><refentrytitle>sd_bus_reply_method_return</refentrytitle><manvolnum>3</manvolnum></citerefentry>
-          with the message the callback was invoked with. <replaceable>in_names</replaceable> and
+          arguments in the function signature. <replaceable>in_names</replaceable> and
           <replaceable>out_names</replaceable> should be created using the
-          <constant>SD_BUS_PARAM()</constant> macro, see below. Parameter
-          <replaceable>flags</replaceable> is a combination of flags, see below.</para>
+          <constant>SD_BUS_PARAM()</constant> macro, see below. In all other regards, this macro behaves
+          exactly the same as <constant>SD_BUS_METHOD_WITH_ARGS_OFFSET()</constant>.</para>
 
           <para><constant>SD_BUS_METHOD_WITH_NAMES()</constant>,
           <constant>SD_BUS_METHOD_WITH_OFFSET()</constant>, and <constant>SD_BUS_METHOD()</constant>
           are variants which specify zero offset (<replaceable>userdata</replaceable> parameter is
           passed with no change), leave the names unset (i.e. no parameter names), or both.</para>
+
+          <para>Prefer using <constant>SD_BUS_METHOD_WITH_ARGS_OFFSET()</constant> and
+          <constant>SD_BUS_METHOD_WITH_ARGS()</constant> over these macros as they allow specifying argument
+          types and names next to each other which is less error-prone than first specifying all argument
+          types followed by specifying all argument names.</para>
           </listitem>
         </varlistentry>
 
+        <varlistentry>
+          <term><constant>SD_BUS_SIGNAL_WITH_ARGS()</constant></term>
+
+          <listitem><para>>Declare a D-Bus signal with the name <replaceable>member</replaceable> and
+          arguments <replaceable>args</replaceable>. <replaceable>args</replaceable> expects a sequence of
+          argument type/name pairs wrapped in the <constant>SD_BUS_ARGS()</constant> macro. The elements at
+          even indices in this list describe the types of the signal's arguments. The signal's parameter
+          signature is the concatenation of all the string literals at even indices in
+          <replaceable>args</replaceable>. If a signal has no parameters, pass
+          <constant>SD_BUS_NO_ARGS</constant> to <replaceable>args</replaceable>. The elements at uneven
+          indices describe the names of the signal's arguments. Parameter <replaceable>flags</replaceable> is
+          a combination of flags. See below for a complete example.</para></listitem>
+        </varlistentry>
+
         <varlistentry>
           <term><constant>SD_BUS_SIGNAL_WITH_NAMES()</constant></term>
           <term><constant>SD_BUS_SIGNAL()</constant></term>
           Parameter <replaceable>flags</replaceable> is a combination of flags, see below.
           </para>
 
-          <para>Equivalent to <constant>SD_BUS_SIGNAL_WITH_NAMES()</constant> with the
-          <replaceable>names</replaceable> parameter unset (i.e. no parameter names).</para>
+          <para><constant>SD_BUS_SIGNAL()</constant> is equivalent to
+          <constant>SD_BUS_SIGNAL_WITH_NAMES()</constant> with the <replaceable>names</replaceable> parameter
+          unset (i.e. no parameter names).</para>
+
+          <para>Prefer using <constant>SD_BUS_SIGNAL_WITH_ARGS()</constant> over these macros as it allows
+          specifying argument types and names next to each other which is less error-prone than first
+          specifying all argument types followed by specifying all argument names.</para>
           </listitem>
         </varlistentry>
 
           This corresponds to the <constant>org.freedesktop.systemd1.Explicit</constant> annotation
           in introspection data.</para></listitem>
         </varlistentry>
+
+        <varlistentry>
+          <term><constant>SD_BUS_VTABLE_SENSITIVE</constant></term>
+
+          <listitem><para>Mark this vtable method entry as processing sensitive data. When set,
+          incoming method call messages and their outgoing reply messages are marked as sensitive using
+          <citerefentry><refentrytitle>sd_bus_message_sensitive</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+          so that they are erased from memory when freed.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>SD_BUS_VTABLE_ABSOLUTE_OFFSET</constant></term>
+
+          <listitem><para>Mark this vtable method or property entry so that the user data pointer passed to
+          its associated handler functions is determined slightly differently: instead of adding the offset
+          parameter of the entry to the user data pointer specified during vtable registration, the offset is
+          passed directly, converted to a pointer, without taking the user data pointer specified during
+          vtable registration into account.</para></listitem>
+        </varlistentry>
       </variablelist>
     </refsect2>
   </refsect1>
index 93462f24b594fa42eb15ff3dc39efdddc91769e9..f47f9c8526e57032e52594801860f6219c5c6896 100644 (file)
@@ -27,6 +27,8 @@
     <funcsynopsis>
       <funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
 
+      <xi:include href="sd_bus_add_match.xml" xpointer="sd_bus_message_handler_t"/>
+
       <funcprototype>
         <funcdef>int <function>sd_bus_call</function></funcdef>
         <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
     received a D-Bus error reply), <parameter>ret_error</parameter> is initialized to an instance of
     <structname>sd_bus_error</structname> describing the error.</para>
 
-    <para><function>sd_bus_call_async()</function> is like <function>sd_bus_call()</function> but
-    works asynchronously. The <parameter>callback</parameter> indicates the function to call when
-    the response arrives. The <parameter>userdata</parameter> pointer will be passed to the callback
-    function, and may be chosen freely by the caller. If <parameter>slot</parameter> is not
-    <constant>NULL</constant> and <function>sd_bus_call_async()</function> succeeds,
-    <parameter>slot</parameter> is set to a slot object which can be used to cancel the method call
-    at a later time using
+    <para><function>sd_bus_call_async()</function> is like <function>sd_bus_call()</function> but works
+    asynchronously. The <parameter>callback</parameter> indicates the function to call when the response
+    arrives. The <parameter>userdata</parameter> pointer will be passed to the callback function, and may be
+    chosen freely by the caller. If <parameter>slot</parameter> is not <constant>NULL</constant> and
+    <function>sd_bus_call_async()</function> succeeds, <parameter>slot</parameter> is set to a slot object
+    which can be used to cancel the method call at a later time using
     <citerefentry><refentrytitle>sd_bus_slot_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
-    If <parameter>slot</parameter> is <constant>NULL</constant>, the lifetime of the method call is
-    bound to the lifetime of the bus object itself, and it cannot be cancelled independently. See
+    If <parameter>slot</parameter> is <constant>NULL</constant>, the lifetime of the method call is bound to
+    the lifetime of the bus object itself, and it cannot be cancelled independently. See
     <citerefentry><refentrytitle>sd_bus_slot_set_floating</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     for details. <parameter>callback</parameter> is called when a reply arrives with the reply,
-    <parameter>userdata</parameter> and an <structname>sd_bus_error</structname> output
-    parameter as its arguments. Unlike <function>sd_bus_call()</function>, the
-    <structname>sd_bus_error</structname> output parameter passed to the callback will be empty. To
-    determine whether the method call succeeded, use
+    <parameter>userdata</parameter> and an <structname>sd_bus_error</structname> output parameter as its
+    arguments. Unlike <function>sd_bus_call()</function>, the <structname>sd_bus_error</structname> output
+    parameter passed to the callback will be empty. To determine whether the method call succeeded, use
     <citerefentry><refentrytitle>sd_bus_message_is_method_error</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     on the reply message passed to the callback instead. If the callback returns zero and the
-    <structname>sd_bus_error</structname> output parameter is still empty when the callback
-    inishes, other handlers registered with functions such as
+    <structname>sd_bus_error</structname> output parameter is still empty when the callback finishes, other
+    handlers registered with functions such as
     <citerefentry><refentrytitle>sd_bus_add_filter</refentrytitle><manvolnum>3</manvolnum></citerefentry> or
-    <citerefentry><refentrytitle>sd_bus_add_match</refentrytitle><manvolnum>3</manvolnum></citerefentry>
-    are given a chance to process the message. If the callback returns a non-zero value or the
-    <structname>sd_bus_error</structname> output parameter is not empty when the callback finishes,
-    no further processing of the message is done. Generally, you want to return zero from the
-    callback to give other registered handlers a chance to process the reply as well.</para>
+    <citerefentry><refentrytitle>sd_bus_add_match</refentrytitle><manvolnum>3</manvolnum></citerefentry> are
+    given a chance to process the message. If the callback returns a non-zero value or the
+    <structname>sd_bus_error</structname> output parameter is not empty when the callback finishes, no
+    further processing of the message is done. Generally, you want to return zero from the callback to give
+    other registered handlers a chance to process the reply as well. (Note that the
+    <structname>sd_bus_error</structname> parameter is an output parameter of the callback function, not an
+    input parameter; it can be used to propagate errors from the callback handler, it will not receive any
+    error that was received as method reply.)</para>
 
     <para>If <parameter>usec</parameter> is zero, the default D-Bus method call timeout is used. See
     <citerefentry><refentrytitle>sd_bus_get_method_call_timeout</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
index 6348a4ce7725bf9252f983e036a32ded223e63fa..ac9cf143ad18ae92271ae1e38c6a7ef41a275c61 100644 (file)
@@ -30,6 +30,8 @@
     <funcsynopsis>
       <funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
 
+      <xi:include href="sd_bus_add_match.xml" xpointer="sd_bus_message_handler_t"/>
+
       <funcprototype>
         <funcdef>int <function>sd_bus_call_method</function></funcdef>
         <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
index 07c61cd416405a421ffc4c8cac6e4896c06308c4..0a1843a849c7c4da21ae0c7ad767f6cdc0d2d7ef 100644 (file)
@@ -28,6 +28,8 @@
     <funcsynopsis>
       <funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
 
+      <xi:include href="sd_bus_add_match.xml" xpointer="sd_bus_message_handler_t"/>
+
       <funcprototype>
         <funcdef>sd_bus_message_handler_t <function>sd_bus_get_current_handler</function></funcdef>
         <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
diff --git a/man/sd_bus_get_name_creds.xml b/man/sd_bus_get_name_creds.xml
new file mode 100644 (file)
index 0000000..3731336
--- /dev/null
@@ -0,0 +1,121 @@
+<?xml version='1.0'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="sd_bus_get_name_creds" xmlns:xi="http://www.w3.org/2001/XInclude">
+
+  <refentryinfo>
+    <title>sd_bus_get_name_creds</title>
+    <productname>systemd</productname>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>sd_bus_get_name_creds</refentrytitle>
+    <manvolnum>3</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>sd_bus_get_name_creds</refname>
+    <refname>sd_bus_get_owner_creds</refname>
+
+    <refpurpose>Query bus client credentials</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
+
+      <funcprototype>
+        <funcdef>int <function>sd_bus_get_name_creds</function></funcdef>
+        <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+        <paramdef>const char *<parameter>name</parameter></paramdef>
+        <paramdef>uint64_t <parameter>mask</parameter></paramdef>
+        <paramdef>sd_bus_creds **<parameter>creds</parameter></paramdef>
+      </funcprototype>
+
+      <funcprototype>
+        <funcdef>int <function>sd_bus_get_owner_creds</function></funcdef>
+        <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+        <paramdef>uint64_t <parameter>mask</parameter></paramdef>
+        <paramdef>sd_bus_creds **<parameter>creds</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para><function>sd_bus_get_name_creds()</function> queries the credentials of the bus client
+    identified by <parameter>name</parameter>. The <parameter>mask</parameter> parameter is a combo of
+    <constant index='false'>SD_BUS_CREDS_*</constant> flags that indicate which credential info the caller is
+    interested in. See
+    <citerefentry><refentrytitle>sd_bus_creds_new_from_pid</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+    for a list of possible flags. On success, <parameter>creds</parameter> contains a new
+    <structname>sd_bus_creds</structname> instance with the requested information. Ownership of this instance
+    belongs to the caller and it should be freed once no longer needed by calling
+    <citerefentry><refentrytitle>sd_bus_creds_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+    </para>
+
+    <para><function>sd_bus_get_owner_creds()</function> queries the credentials of the creator of the given
+    bus. The <parameter>mask</parameter> and <parameter>creds</parameter> parameters behave the same as in
+    <function>sd_bus_get_name_creds()</function>.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Return Value</title>
+
+    <para>On success, these functions return a non-negative integer. On failure, they return a negative
+    errno-style error code.</para>
+
+    <refsect2>
+      <title>Errors</title>
+
+      <para>Returned errors may indicate the following problems:</para>
+
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
+
+          <listitem><para>An argument is invalid.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-ENOPKG</constant></term>
+
+          <listitem><para>The bus cannot be resolved.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-EPERM</constant></term>
+
+          <listitem><para>The bus has already been started.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
+
+          <listitem><para>The bus was created in a different process.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
+
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+  </refsect1>
+
+  <xi:include href="libsystemd-pkgconfig.xml" />
+
+  <refsect1>
+    <title>See Also</title>
+
+    <para>
+      <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_bus_creds_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+    </para>
+  </refsect1>
+</refentry>
diff --git a/man/sd_bus_get_name_machine_id.xml b/man/sd_bus_get_name_machine_id.xml
new file mode 100644 (file)
index 0000000..8f3ce64
--- /dev/null
@@ -0,0 +1,98 @@
+<?xml version='1.0'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="sd_bus_get_name_machine_id" xmlns:xi="http://www.w3.org/2001/XInclude">
+
+  <refentryinfo>
+    <title>sd_bus_get_name_machine_id</title>
+    <productname>systemd</productname>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>sd_bus_get_name_machine_id</refentrytitle>
+    <manvolnum>3</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>sd_bus_get_name_machine_id</refname>
+
+    <refpurpose>Retrieve a bus client's machine identity</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
+
+      <funcprototype>
+        <funcdef>int <function>sd_bus_get_name_machine_id</function></funcdef>
+        <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+        <paramdef>const char *<parameter>name</parameter></paramdef>
+        <paramdef>sd_id128_t *<parameter>machine</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para><function>sd_bus_get_name_machine_id()</function> retrieves the D-Bus machine identity of the
+    machine that the bus client identified by <parameter>name</parameter> is running on. Internally, it calls
+    the <function>GetMachineId</function> method of the <constant>org.freedesktop.DBus.Peer</constant>
+    interface. The D-Bus machine identity is a 128-bit UUID. On Linux systems running systemd, this
+    corresponds to the contents of <filename>/etc/machine-id</filename>. On success, the machine identity is
+    stored in <parameter>machine</parameter>.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Return Value</title>
+
+    <para>On success, this function returns a non-negative integer. On failure, it returns a negative
+    errno-style error code.</para>
+
+    <refsect2>
+      <title>Errors</title>
+
+      <para>Returned errors may indicate the following problems:</para>
+
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
+
+          <listitem><para>An argument is invalid.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-ENOPKG</constant></term>
+
+          <listitem><para>The bus cannot be resolved.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
+
+          <listitem><para>The bus was created in a different process.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
+
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+  </refsect1>
+
+  <xi:include href="libsystemd-pkgconfig.xml" />
+
+  <refsect1>
+    <title>See Also</title>
+
+    <para>
+      <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+    </para>
+  </refsect1>
+
+</refentry>
index 6ebcc8d9ea6f07c3ce1ac77884d6b7a71447b089..5faadd603a123cfd915e7fe998307826b90e3407 100644 (file)
@@ -229,7 +229,8 @@ sd_bus_message_append(m, "ynqiuxtd", y, n, q, i, u, x, t, d);</programlisting>
       <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>sd_bus_message_append_basic</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
-      <citerefentry><refentrytitle>sd_bus_message_append_array</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+      <citerefentry><refentrytitle>sd_bus_message_append_array</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_bus_message_open_container</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     </para>
   </refsect1>
 
index b9595d6a0a224f7dd9aada88304476e5928a9503..d81ddc558f0ddff107a21b0260e6235969b4650a 100644 (file)
@@ -34,7 +34,7 @@
         <funcdef>int sd_bus_message_append_array</funcdef>
         <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
         <paramdef>char <parameter>type</parameter></paramdef>
-        <paramdef>char void *<parameter>ptr</parameter></paramdef>
+        <paramdef>void *<parameter>ptr</parameter></paramdef>
         <paramdef>size_t <parameter>size</parameter></paramdef>
       </funcprototype>
 
index 7c5e0df61757e15af529e510d47e05a7d4ae81fa..2b962413d2a4334c2c4157cef0137bdde294ccc4 100644 (file)
     <refname>sd_bus_message_get_type</refname>
     <refname>sd_bus_message_get_error</refname>
     <refname>sd_bus_message_get_errno</refname>
+    <refname>sd_bus_message_get_creds</refname>
     <refname>sd_bus_message_is_signal</refname>
     <refname>sd_bus_message_is_method_call</refname>
     <refname>sd_bus_message_is_method_error</refname>
 
-    <refpurpose>Query bus message addressing metadata</refpurpose>
+    <refpurpose>Query bus message addressing/credentials metadata</refpurpose>
   </refnamediv>
 
   <refsynopsisdiv>
         <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
       </funcprototype>
 
+      <funcprototype>
+        <funcdef>sd_bus_creds* <function>sd_bus_message_get_creds</function></funcdef>
+        <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
+      </funcprototype>
+
       <funcprototype>
         <funcdef>int <function>sd_bus_message_is_signal</function></funcdef>
         <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
     <citerefentry><refentrytitle>sd_bus_error_add_map</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
     </para>
 
+    <para><function>sd_bus_message_get_creds()</function> returns the message credentials attached to the
+    message <parameter>m</parameter>. If no credentials are attached to the message, it returns
+    <constant>NULL</constant>. Ownership of the credentials instance is not transferred to the caller and
+    hence should not be freed.</para>
+
     <para><function>sd_bus_message_is_signal()</function> checks if message <parameter>m</parameter> is a
     signal message. If <parameter>interface</parameter> is non-null, it also checks if the message has the
     same interface set. If <parameter>member</parameter> is non-null, it also checks if the message has the
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success, these functions return a non-negative integer. On failure, they return a negative
-    errno-style error code. <function>sd_bus_message_get_errno()</function> always returns a non-negative
-    integer, even on failure.</para>
+    <para>On success, these functions (except <function>sd_bus_message_get_error()</function> and
+    <function>sd_bus_message_get_creds()</function>) return a non-negative integer. On failure, they return a
+    negative errno-style error code. <function>sd_bus_message_get_errno()</function> always returns a
+    non-negative integer, even on failure.</para>
 
     <refsect2>
       <title>Errors</title>
diff --git a/man/sd_bus_message_open_container.xml b/man/sd_bus_message_open_container.xml
new file mode 100644 (file)
index 0000000..5a65518
--- /dev/null
@@ -0,0 +1,165 @@
+<?xml version='1.0'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="sd_bus_message_open_container"
+          xmlns:xi="http://www.w3.org/2001/XInclude">
+
+  <refentryinfo>
+    <title>sd_bus_message_open_container</title>
+    <productname>systemd</productname>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>sd_bus_message_open_container</refentrytitle>
+    <manvolnum>3</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>sd_bus_message_open_container</refname>
+    <refname>sd_bus_message_close_container</refname>
+    <refname>sd_bus_message_enter_container</refname>
+    <refname>sd_bus_message_exit_container</refname>
+
+    <refpurpose>Create and move between containers in D-Bus messages</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
+
+      <funcprototype>
+        <funcdef>int sd_bus_message_open_container</funcdef>
+        <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
+        <paramdef>char <parameter>type</parameter></paramdef>
+        <paramdef>const char *<parameter>contents</parameter></paramdef>
+      </funcprototype>
+
+      <funcprototype>
+        <funcdef>int sd_bus_message_close_container</funcdef>
+        <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
+      </funcprototype>
+
+      <funcprototype>
+        <funcdef>int sd_bus_message_enter_container</funcdef>
+        <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
+        <paramdef>char <parameter>type</parameter></paramdef>
+        <paramdef>const char *<parameter>contents</parameter></paramdef>
+      </funcprototype>
+
+      <funcprototype>
+        <funcdef>int sd_bus_message_exit_container</funcdef>
+        <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para><function>sd_bus_message_open_container()</function> appends a new container to the message
+    <parameter>m</parameter>. After opening a new container, it can be filled with content using
+    <citerefentry><refentrytitle>sd_bus_message_append</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+    and similar functions. Containers behave like a stack. To nest containers inside each other, call
+    <function>sd_bus_message_open_container()</function> multiple times without calling
+    <function>sd_bus_message_close_container()</function> in between. Each container will be nested inside the
+    previous container. <parameter>type</parameter> represents the container type and should be one of
+    <literal>r</literal>, <literal>a</literal>, <literal>v</literal> or <literal>e</literal> as described in
+    <citerefentry><refentrytitle>sd_bus_message_append</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+    Instead of literals, the corresponding constants <constant>SD_BUS_TYPE_STRUCT</constant>,
+    <constant>SD_BUS_TYPE_ARRAY</constant>, <constant>SD_BUS_TYPE_VARIANT</constant> or
+    <constant>SD_BUS_TYPE_DICT_ENTRY</constant> can also be used. <parameter>contents</parameter> describes
+    the type of the container's elements and should be a D-Bus type string following the rules described in
+    <citerefentry><refentrytitle>sd_bus_message_append</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+    </para>
+
+    <para><function>sd_bus_message_close_container()</function> closes the last container opened with
+    <function>sd_bus_message_open_container()</function>. On success, the write pointer of the message
+    <parameter>m</parameter> is positioned after the closed container in its parent container or in
+    <parameter>m</parameter> itself if there is no parent container.</para>
+
+    <para><function>sd_bus_message_enter_container()</function> enters the next container of the message
+    <parameter>m</parameter>. It behaves mostly the same as
+    <function>sd_bus_message_open_container()</function>. Entering a container allows reading its contents
+    with
+    <citerefentry><refentrytitle>sd_bus_message_read</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+    and similar functions. <parameter>type</parameter> and <parameter>contents</parameter> are the same as in
+    <function>sd_bus_message_open_container()</function>.</para>
+
+    <para><function>sd_bus_message_exit_container()</function> exits the scope of the last container entered
+    with <function>sd_bus_message_enter_container()</function>. It behaves mostly the same as
+    <function>sd_bus_message_close_container()</function>.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Return Value</title>
+
+    <para>On success, these functions return a non-negative integer. On failure, they return a negative
+    errno-style error code.</para>
+
+    <refsect2>
+      <title>Errors</title>
+
+      <para>Returned errors may indicate the following problems:</para>
+
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
+
+          <listitem><para><parameter>m</parameter> or <parameter>contents</parameter> are
+          <constant>NULL</constant> or <parameter>type</parameter> is invalid.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-EPERM</constant></term>
+
+          <listitem><para>The message <parameter>m</parameter> is already sealed.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-ESTALE</constant></term>
+
+          <listitem><para>The message <parameter>m</parameter> is in an invalid state.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
+
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+  </refsect1>
+
+  <xi:include href="libsystemd-pkgconfig.xml" />
+
+  <refsect1>
+    <title>Examples</title>
+
+    <example>
+      <title>Append an array of strings to a message</title>
+
+      <programlisting><xi:include href="sd-bus-container-append.c" parse="text" /></programlisting>
+    </example>
+
+    <example>
+      <title>Read an array of strings from a message</title>
+
+      <programlisting><xi:include href="sd-bus-container-read.c" parse="text" /></programlisting>
+    </example>
+  </refsect1>
+
+  <refsect1>
+    <title>See Also</title>
+
+    <para>
+      <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_bus_message_append</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_bus_message_read</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <ulink url="https://dbus.freedesktop.org/doc/dbus-specification.html">The D-Bus specification</ulink>
+    </para>
+  </refsect1>
+
+</refentry>
index 53cda9f32937b9883a3b7ce706ec9d78ed22ca6b..1b9f36cd84ed8f2a55672e5bacd1f6db1213af6b 100644 (file)
@@ -19,6 +19,7 @@
   <refnamediv>
     <refname>sd_bus_message_read</refname>
     <refname>sd_bus_message_readv</refname>
+    <refname>sd_bus_message_peek_type</refname>
 
     <refpurpose>Read a sequence of values from a message</refpurpose>
   </refnamediv>
         <paramdef>const char *<parameter>types</parameter></paramdef>
         <paramdef>va_list <parameter>ap</parameter></paramdef>
       </funcprototype>
+
+      <funcprototype>
+        <funcdef>int <function>sd_bus_message_peek_type</function></funcdef>
+        <paramdef>char *<parameter>type</parameter></paramdef>
+        <paramdef>const char **<parameter>contents</parameter></paramdef>
+      </funcprototype>
     </funcsynopsis>
   </refsynopsisdiv>
 
   <refsect1>
     <title>Description</title>
 
-    <para><function>sd_bus_message_read()</function> reads a sequence of fields from
-    the D-Bus message object <parameter>m</parameter> and advances the read position
-    in the message. The type string <parameter>types</parameter> describes the types
-    of items expected in the message and the field arguments that follow. The type
-    string may be <constant>NULL</constant> or empty, in which case nothing is
-    read.</para>
+    <para><function>sd_bus_message_read()</function> reads a sequence of fields from the D-Bus message object
+    <parameter>m</parameter> and advances the read position in the message. The type string
+    <parameter>types</parameter> describes the types of items expected in the message and the field arguments
+    that follow. The type string may be <constant>NULL</constant> or empty, in which case nothing is read.
+    </para>
 
     <para>The type string is composed of the elements described in
     <citerefentry><refentrytitle>sd_bus_message_append</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
-    i.e. basic and container types. It must contain zero or more single "complete
-    types". The type string is <constant>NUL</constant>-terminated.</para>
-
-    <para>For each type specified in the type string, one or more arguments need to be specified
-    after the <parameter>types</parameter> parameter, in the same order. The arguments must be
-    pointers to appropriate types (a pointer to <type>int8_t</type> for a <literal>y</literal> in
-    the type string, a pointer to <type>int32_t</type> for an <literal>i</literal>, a pointer to
-    <type>const char*</type> for an <literal>s</literal>, ...)  which are set based on the values in
-    the message. As an exception, in case of array and variant types, the first argument is an
-    "input" argument that further specifies how the message should be read. See the table below for
-    a complete list of allowed arguments and their types. Note that, if the basic type is a pointer
-    (e.g., <type>const char *</type> in the case of a string), the argument is a pointer to a
-    pointer, and also the pointer value that is written is only borrowed and the contents must be
-    copied if they are to be used after the end of the messages lifetime.</para>
-
-    <para>Each argument may also be <constant>NULL</constant>, in which case the value is read and
-    ignored.</para>
+    i.e. basic and container types. It must contain zero or more single "complete types". The type string is
+    <constant>NUL</constant>-terminated.</para>
+
+    <para>For each type specified in the type string, one or more arguments need to be specified after the
+    <parameter>types</parameter> parameter, in the same order. The arguments must be pointers to appropriate
+    types (a pointer to <type>int8_t</type> for a <literal>y</literal> in the type string, a pointer to
+    <type>int32_t</type> for an <literal>i</literal>, a pointer to <type>const char*</type> for an
+    <literal>s</literal>, ...)  which are set based on the values in the message. As an exception, in case of
+    array and variant types, the first argument is an "input" argument that further specifies how the message
+    should be read. See the table below for a complete list of allowed arguments and their types. Note that,
+    if the basic type is a pointer (e.g., <type>const char *</type> in the case of a string), the argument is
+    a pointer to a pointer, and also the pointer value that is written is only borrowed and the contents must
+    be copied if they are to be used after the end of the messages lifetime.</para>
+
+    <para>Each argument may also be <constant>NULL</constant>, in which case the value is read and ignored.
+    </para>
 
     <table>
       <title>Item type specifiers</title>
       </tgroup>
     </table>
 
-    <para>If objects of the specified types are not present at the current position
-    in the message, an error is returned.
-    </para>
+    <para>If objects of the specified types are not present at the current position in the message, an error
+    is returned.</para>
 
     <para>The <function>sd_bus_message_readv()</function> is equivalent to the
-    <function>sd_bus_message_read()</function>, except that it is called with a
-    <literal>va_list</literal> instead of a variable number of arguments. This
-    function does not call the <function>va_end()</function> macro. Because it
-    invokes the <function>va_arg()</function> macro, the value of
-    <parameter>ap</parameter> is undefined after the call.</para>
+    <function>sd_bus_message_read()</function>, except that it is called with a <literal>va_list</literal>
+    instead of a variable number of arguments. This function does not call the <function>va_end()</function>
+    macro. Because it invokes the <function>va_arg()</function> macro, the value of <parameter>ap</parameter>
+    is undefined after the call.</para>
+
+    <para><function>sd_bus_message_peek_type()</function> determines the type of the next element in
+    <parameter>m</parameter> to be read by <function>sd_bus_message_read()</function> or similar functions.
+    On success, the type is stored in <parameter>type</parameter>, if it is not <constant>NULL</constant>.
+    If the type is a container type, the type of its elements is stored in <parameter>contents</parameter>,
+    if it is not <constant>NULL</constant>. If this function successfully determines the type of the next
+    element in <parameter>m</parameter>, it returns a positive integer. If there are no more elements to be
+    read, it returns zero.</para>
   </refsect1>
 
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success, <function>sd_bus_message_read()</function> and
-    <function>sd_bus_message_readv()</function> return 0 or a positive integer. On failure, they return a
-    negative errno-style error code.</para>
+    <para>On success, these functions return a non-negative integer. On failure, they return a negative
+    errno-style error code.</para>
 
     <xi:include href="sd_bus_message_read_basic.xml" xpointer="errors" />
   </refsect1>
@@ -228,7 +238,8 @@ sd_bus_message_read(m, "a{is}", 3, &amp;i, &amp;s, &amp;j, &amp;t, &amp;k, &amp;
       <citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>sd_bus_message_read_basic</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>sd_bus_message_skip</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
-      <citerefentry><refentrytitle>sd_bus_message_append</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+      <citerefentry><refentrytitle>sd_bus_message_append</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_bus_message_enter_container</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     </para>
   </refsect1>
 
index c12b65c983994249b4aec4f0eab478025f2cb660..f17a54f26941aded576f64fcfc7a482d3e63902f 100644 (file)
@@ -19,6 +19,7 @@
     <refname>sd_bus_negotiate_fds</refname>
     <refname>sd_bus_negotiate_timestamp</refname>
     <refname>sd_bus_negotiate_creds</refname>
+    <refname>sd_bus_get_creds_mask</refname>
 
     <refpurpose>Control feature negotiation on bus connections</refpurpose>
   </refnamediv>
         <paramdef>int <parameter>b</parameter></paramdef>
         <paramdef>uint64_t <parameter>mask</parameter></paramdef>
       </funcprototype>
+
+      <funcprototype>
+        <funcdef>int <function>sd_bus_get_creds_mask</function></funcdef>
+        <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+        <paramdef>uint64_t *<parameter>mask</parameter></paramdef>
+      </funcprototype>
     </funcsynopsis>
   </refsynopsisdiv>
 
   <refsect1>
     <title>Description</title>
 
-    <para><function>sd_bus_negotiate_fds()</function> controls whether
-    file descriptor passing shall be negotiated for the specified bus
-    connection. It takes a bus object and a boolean, which, when true,
-    enables file descriptor passing, and, when false, disables
-    it. Note that not all transports and servers support file
-    descriptor passing. In particular, networked transports generally
-    do not support file descriptor passing. To find out whether file
-    descriptor passing is available after negotiation, use
+    <para><function>sd_bus_negotiate_fds()</function> controls whether file descriptor passing shall be
+    negotiated for the specified bus connection. It takes a bus object and a boolean, which, when true,
+    enables file descriptor passing, and, when false, disables it. Note that not all transports and servers
+    support file descriptor passing. In particular, networked transports generally do not support file
+    descriptor passing. To find out whether file descriptor passing is available after negotiation, use
     <citerefentry><refentrytitle>sd_bus_can_send</refentrytitle><manvolnum>3</manvolnum></citerefentry>
-    and pass <constant>SD_BUS_TYPE_UNIX_FD</constant>. Note that file
-    descriptor passing is always enabled for both sending and
-    receiving or for neither, but never only in one direction. By
-    default, file descriptor passing is negotiated for all
-    connections.</para>
-
-    <para><function>sd_bus_negotiate_timestamp()</function> controls whether implicit sender
-    timestamps shall be attached automatically to all incoming messages. Takes a bus object and a
-    boolean, which, when true, enables timestamping, and, when false, disables it.  Use
+    and pass <constant>SD_BUS_TYPE_UNIX_FD</constant>. Note that file descriptor passing is always enabled
+    for both sending and receiving or for neither, but never only in one direction. By default, file
+    descriptor passing is negotiated for all connections.</para>
+
+    <para><function>sd_bus_negotiate_timestamp()</function> controls whether implicit sender timestamps shall
+    be attached automatically to all incoming messages. Takes a bus object and a boolean, which, when true,
+    enables timestamping, and, when false, disables it.  Use
     <citerefentry><refentrytitle>sd_bus_message_get_monotonic_usec</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
     <citerefentry><refentrytitle>sd_bus_message_get_realtime_usec</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
     <citerefentry><refentrytitle>sd_bus_message_get_seqnum</refentrytitle><manvolnum>3</manvolnum></citerefentry>
-    to query the timestamps of incoming messages. If negotiation is disabled or not supported, these
-    calls will fail with <constant>-ENODATA</constant>. Note that currently no transports support
-    timestamping of messages. By default, message timestamping is not negotiated for
-    connections.</para>
+    to query the timestamps of incoming messages. If negotiation is disabled or not supported, these calls
+    will fail with <constant>-ENODATA</constant>. Note that currently no transports support timestamping of
+    messages. By default, message timestamping is not negotiated for connections.</para>
 
     <para><function>sd_bus_negotiate_creds()</function> controls whether and which implicit sender
-    credentials shall be attached automatically to all incoming messages. Takes a bus object and a
-    boolean indicating whether to enable or disable the credential parts encoded in the bit mask
-    value argument. Note that not all transports support attaching sender credentials to messages,
-    or do not support all types of sender credential parameters, or might suppress them under
-    certain circumstances for individual messages. Specifically, dbus1 only supports
-    <constant>SD_BUS_CREDS_UNIQUE_NAME</constant>. The sender credentials are suitable for
-    authorization decisions. By default, only <constant>SD_BUS_CREDS_WELL_KNOWN_NAMES</constant> and
-    <constant>SD_BUS_CREDS_UNIQUE_NAME</constant> are enabled. In fact, these two credential fields
-    are always sent along and cannot be turned off.</para>
-
-    <para>The <function>sd_bus_negotiate_fds()</function> function may
-    be called only before the connection has been started with
+    credentials shall be attached automatically to all incoming messages. Takes a bus object and a boolean
+    indicating whether to enable or disable the credential parts encoded in the bit mask value argument. Note
+    that not all transports support attaching sender credentials to messages, or do not support all types of
+    sender credential parameters, or might suppress them under certain circumstances for individual messages.
+    Specifically, dbus1 only supports <constant>SD_BUS_CREDS_UNIQUE_NAME</constant>. The sender credentials
+    are suitable for authorization decisions. By default, only
+    <constant>SD_BUS_CREDS_WELL_KNOWN_NAMES</constant> and <constant>SD_BUS_CREDS_UNIQUE_NAME</constant> are
+    enabled. In fact, these two credential fields are always sent along and cannot be turned off.</para>
+
+    <para><function>sd_bus_get_creds_mask()</function> returns the set of sender credentials that was
+    negotiated to be attached to all incoming messages in <parameter>mask</parameter>. This value is an
+    upper boundary only. Hence, always make sure to explicitly check which credentials are attached to a
+    specific message before using it.</para>
+
+    <para>The <function>sd_bus_negotiate_fds()</function> function may be called only before the connection
+    has been started with
     <citerefentry><refentrytitle>sd_bus_start</refentrytitle><manvolnum>3</manvolnum></citerefentry>. Both
-    <function>sd_bus_negotiate_timestamp()</function> and
-    <function>sd_bus_negotiate_creds()</function> may also be called
-    after a connection has been set up. Note that, when operating on a
-    connection that is shared between multiple components of the same
-    program (for example via
-    <citerefentry><refentrytitle>sd_bus_default</refentrytitle><manvolnum>3</manvolnum></citerefentry>),
-    it is highly recommended to only enable additional per message
-    metadata fields, but never disable them again, in order not to
-    disable functionality needed by other components.</para>
+    <function>sd_bus_negotiate_timestamp()</function> and <function>sd_bus_negotiate_creds()</function> may
+    also be called after a connection has been set up. Note that, when operating on a connection that is
+    shared between multiple components of the same program (for example via
+    <citerefentry><refentrytitle>sd_bus_default</refentrytitle><manvolnum>3</manvolnum></citerefentry>), it
+    is highly recommended to only enable additional per message metadata fields, but never disable them
+    again, in order not to disable functionality needed by other components.</para>
   </refsect1>
 
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success, these functions return 0 or a
-    positive integer. On failure, they return a negative errno-style
-    error code.</para>
+    <para>On success, these functions return a non-negative integer. On failure, they return a negative
+    errno-style error code.</para>
 
     <refsect2>
       <title>Errors</title>
 
           <listitem><para>The bus connection has already been started.</para></listitem>
         </varlistentry>
+
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
+
+          <listitem><para>An argument is invalid.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-ENOPKG</constant></term>
+
+          <listitem><para>The bus cannot be resolved.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
+
+          <listitem><para>The bus was created in a different process.</para></listitem>
+        </varlistentry>
       </variablelist>
     </refsect2>
   </refsect1>
diff --git a/man/sd_bus_query_sender_creds.xml b/man/sd_bus_query_sender_creds.xml
new file mode 100644 (file)
index 0000000..54cd817
--- /dev/null
@@ -0,0 +1,133 @@
+<?xml version='1.0'?> <!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="sd_bus_query_sender_creds" xmlns:xi="http://www.w3.org/2001/XInclude">
+
+  <refentryinfo>
+    <title>sd_bus_query_sender_creds</title>
+    <productname>systemd</productname>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>sd_bus_query_sender_creds</refentrytitle>
+    <manvolnum>3</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>sd_bus_query_sender_creds</refname>
+    <refname>sd_bus_query_sender_privilege</refname>
+
+    <refpurpose>Query bus message sender credentials/privileges</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
+
+      <funcprototype>
+        <funcdef>int <function>sd_bus_query_sender_creds</function></funcdef>
+        <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
+        <paramdef>uint64_t <parameter>mask</parameter></paramdef>
+        <paramdef>sd_bus_creds **<parameter>creds</parameter></paramdef>
+      </funcprototype>
+
+      <funcprototype>
+        <funcdef>sd_bus_error* <function>sd_bus_query_sender_privilege</function></funcdef>
+        <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
+        <paramdef>int <parameter>capability</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para><function>sd_bus_query_sender_creds()</function> returns the credentials of the message
+    <parameter>m</parameter>. The <parameter>mask</parameter> parameter is a combo of
+    <constant index='false'>SD_BUS_CREDS_*</constant> flags that indicate which credential info the caller is
+    interested in. See
+    <citerefentry><refentrytitle>sd_bus_creds_new_from_pid</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+    for a list of possible flags. First, this message checks if the requested credentials are attached to the
+    message itself. If not but the message contains the pid of the sender, this function tries to figure out
+    the missing credentials via other means (starting from the pid). If the pid isn't available but the
+    message has a sender, this function calls
+    <citerefentry><refentrytitle>sd_bus_get_name_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+    to get the requested credentials. If the message has no sender (when a direct connection is used), this
+    function calls
+    <citerefentry><refentrytitle>sd_bus_get_owner_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+    to get the requested credentials. On success, the requested credentials are stored in
+    <parameter>creds</parameter>. Ownership of the credentials object in <parameter>creds</parameter> is
+    transferred to the caller and should be freed by calling
+    <citerefentry><refentrytitle>sd_bus_creds_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+    </para>
+
+    <para><function>sd_bus_query_sender_privilege()</function> checks if the message <parameter>m</parameter>
+    has the requested privileges. If <parameter>capability</parameter> is a non-negative integer, this
+    function checks if the message has the capability with the same value. See
+    <citerefentry project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+    for a list of capabilities. If <parameter>capability</parameter> is a negative integer, this function
+    returns whether the sender of the message runs as the same user as the receiver of the message, or if the
+    sender of the message runs as root and the receiver of the message does not run as root. On success and
+    if the message has the requested privileges, this function returns a positive integer. If the message
+    does not have the requested privileges, this function returns zero.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Return Value</title>
+
+    <para>On success, these functions return a non-negative integer. On failure, they return a negative
+    errno-style error code.</para>
+
+    <refsect2>
+      <title>Errors</title>
+
+      <para>Returned errors may indicate the following problems:</para>
+
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
+
+          <listitem><para>The message <parameter>m</parameter> or an output parameter is
+          <constant>NULL</constant>.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-ENOTCONN</constant></term>
+
+          <listitem><para>The bus of <parameter>m</parameter> is not connected.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
+
+          <listitem><para>The bus of <parameter>m</parameter> was created in a different process.
+          </para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-EPERM</constant></term>
+
+          <listitem><para>The message <parameter>m</parameter> is not sealed.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
+  </refsect1>
+
+  <xi:include href="libsystemd-pkgconfig.xml" />
+
+  <refsect1>
+    <title>See Also</title>
+
+    <para>
+      <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_bus_creds_new_from_pid</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_bus_get_name_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_bus_get_owner_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_bus_creds_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+    </para>
+  </refsect1>
+</refentry>
index 7229ef517a577051b5bfeaf78e107de75b6f1117..f8a49c006b242900886302050b24c8784c0da0fa 100644 (file)
@@ -28,6 +28,8 @@
     <funcsynopsis>
       <funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
 
+      <xi:include href="sd_bus_add_match.xml" xpointer="sd_bus_message_handler_t"/>
+
       <funcprototype>
         <funcdef>int <function>sd_bus_request_name</function></funcdef>
         <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
index 659fa2a86ce7c5b2fb676f06d2844b6d50787f4b..2cdf436db2bc981857f798cbbd3e4c45322f9ce6 100644 (file)
@@ -18,6 +18,7 @@
 
   <refnamediv>
     <refname>sd_bus_send</refname>
+    <refname>sd_bus_send_to</refname>
 
     <refpurpose>Queue a D-Bus message for transfer</refpurpose>
   </refnamediv>
         <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
         <paramdef>uint64_t *<parameter>cookie</parameter></paramdef>
       </funcprototype>
+
+      <funcprototype>
+        <funcdef>int <function>sd_bus_send_to</function></funcdef>
+        <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+        <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
+        <paramdef>const char *<parameter>destination</parameter></paramdef>
+        <paramdef>uint64_t *<parameter>cookie</parameter></paramdef>
+      </funcprototype>
     </funcsynopsis>
   </refsynopsisdiv>
 
   <refsect1>
     <title>Description</title>
 
-    <para><function>sd_bus_send()</function> queues the bus message object <parameter>m</parameter>
-    for transfer. If <parameter>bus</parameter> is <constant>NULL</constant>, the bus that
-    <parameter>m</parameter> is attached to is used. <parameter>bus</parameter> only needs to be set
-    when the message is sent to a different bus than the one it's attached to, for example when
-    forwarding messages. If the output parameter <parameter>cookie</parameter> is not
-    <constant>NULL</constant>, it is set to the message identifier. This value can later be used to
-    match incoming replies to their corresponding messages. If <parameter>cookie</parameter> is set
-    to <constant>NULL</constant> and the message is not sealed, <function>sd_bus_send()</function>
-    assumes the message <parameter>m</parameter> doesn't expect a reply and adds the necessary
-    headers to indicate this.</para>
+    <para><function>sd_bus_send()</function> queues the bus message object <parameter>m</parameter> for
+    transfer. If <parameter>bus</parameter> is <constant>NULL</constant>, the bus that
+    <parameter>m</parameter> is attached to is used. <parameter>bus</parameter> only needs to be set when the
+    message is sent to a different bus than the one it's attached to, for example when forwarding messages.
+    If the output parameter <parameter>cookie</parameter> is not <constant>NULL</constant>, it is set to the
+    message identifier. This value can later be used to match incoming replies to their corresponding
+    messages. If <parameter>cookie</parameter> is set to <constant>NULL</constant> and the message is not
+    sealed, <function>sd_bus_send()</function> assumes the message <parameter>m</parameter> doesn't expect a
+    reply and adds the necessary headers to indicate this.</para>
 
     <para>Note that in most scenarios, <function>sd_bus_send()</function> should not be called
     directly. Instead, use higher level functions such as
     <citerefentry><refentrytitle>sd_bus_call_method</refentrytitle><manvolnum>3</manvolnum></citerefentry> and
     <citerefentry><refentrytitle>sd_bus_reply_method_return</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     which call <function>sd_bus_send()</function> internally.</para>
+
+    <para><function>sd_bus_send_to()</function> is a shorthand for sending a message to a specific
+    destination. It's main use case is to simplify sending unicast signal messages (signals that only have a
+    single receiver). It's behavior is similar to calling
+    <citerefentry><refentrytitle>sd_bus_message_set_destination</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+    followed by calling <function>sd_bus_send()</function>.</para>
   </refsect1>
 
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success, this function returns a non-negative integer. On failure, it returns a
-    negative errno-style error code.</para>
+    <para>On success, these functions return a non-negative integer. On failure, they return a negative
+    errno-style error code.</para>
 
     <refsect2 id='errors'>
       <title>Errors</title>
@@ -85,8 +99,8 @@
         <varlistentry>
           <term><constant>-ECHILD</constant></term>
 
-          <listitem><para>The bus connection was allocated in a parent process and is being reused
-          in a child process after <function>fork()</function>.</para></listitem>
+          <listitem><para>The bus connection was allocated in a parent process and is being reused in a child
+          process after <function>fork()</function>.</para></listitem>
         </varlistentry>
 
         <varlistentry>
       <citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>sd_bus_call_method</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>sd_bus_message_set_destination</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
-      <citerefentry><refentrytitle>sd_bus_reply_method_return</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
-      <citerefentry><refentrytitle>sd_bus_send_to</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+      <citerefentry><refentrytitle>sd_bus_reply_method_return</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     </para>
   </refsect1>
 
index ed3e55b0574e5a510830195eabadd6e823c195ce..26541a9d97b410b188f6ac2fe7561de6f6099048 100644 (file)
@@ -27,6 +27,8 @@
     <funcsynopsis>
       <funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
 
+      <xi:include href="sd_bus_add_match.xml" xpointer="sd_bus_message_handler_t"/>
+
       <funcprototype>
         <funcdef>sd_bus *<function>sd_bus_slot_get_bus</function></funcdef>
         <paramdef>sd_bus_slot *<parameter>slot</parameter></paramdef>
index 3046ca88ee728c703d7b411406db05b92c564ecd..87b12c4bdff8b16ac28ffb67ac00a4421e371f75 100644 (file)
@@ -22,6 +22,7 @@
     <refname>sd_pid_notify</refname>
     <refname>sd_pid_notifyf</refname>
     <refname>sd_pid_notify_with_fds</refname>
+    <refname>sd_notify_barrier</refname>
     <refpurpose>Notify service manager about start-up completion and other service status changes</refpurpose>
   </refnamediv>
 
         <paramdef>const int *<parameter>fds</parameter></paramdef>
         <paramdef>unsigned <parameter>n_fds</parameter></paramdef>
       </funcprototype>
+
+      <funcprototype>
+        <funcdef>int <function>sd_notify_barrier</function></funcdef>
+        <paramdef>int <parameter>unset_environment</parameter></paramdef>
+        <paramdef>uint64_t <parameter>timeout</parameter></paramdef>
+      </funcprototype>
     </funcsynopsis>
   </refsynopsisdiv>
 
         in a <citerefentry><refentrytitle>memfd_create</refentrytitle><manvolnum>2</manvolnum></citerefentry> memory
         file descriptor. Note that the service manager will accept messages for a service only if its
         <varname>FileDescriptorStoreMax=</varname> setting is non-zero (defaults to zero, see
-        <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>). If file
-        descriptors sent are pollable (see
+        <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>). If
+        <varname>FDPOLL=0</varname> is not set and the file descriptors sent are pollable (see
         <citerefentry><refentrytitle>epoll_ctl</refentrytitle><manvolnum>2</manvolnum></citerefentry>), then any
         <constant>EPOLLHUP</constant> or <constant>EPOLLERR</constant> event seen on them will result in their
         automatic removal from the store. Multiple arrays of file descriptors may be sent in separate messages, in
         submitted name does not follow these restrictions, it is ignored.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term>FDPOLL=0</term>
+
+        <listitem><para>When used in combination with <varname>FDSTORE=1</varname>, disables polling of the stored
+        file descriptors regardless of whether or not they are pollable. As this option disables automatic cleanup
+        of the stored file descriptors on EPOLLERR and EPOLLHUP, care must be taken to ensure proper manual cleanup.
+        Use of this option is not generally recommended except for when automatic cleanup has unwanted behavior such
+        as prematurely discarding file descriptors from the store.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>BARRIER=1</term>
+
+        <listitem><para>Tells the service manager that the client is explicitly requesting synchronization by means of
+        closing the file descriptor sent with this command. The service manager guarantees that the processing of a <varname>
+        BARRIER=1</varname> command will only happen after all previous notification messages sent before this command
+        have been processed. Hence, this command accompanied with a single file descriptor can be used to synchronize
+        against reception of all previous status messages. Note that this command cannot be mixed with other notifications,
+        and has to be sent in a separate message to the service manager, otherwise all assignments will be ignored. Note that
+        sending 0 or more than 1 file descriptor with this command is a violation of the protocol.</para></listitem>
+      </varlistentry>
     </variablelist>
 
     <para>It is recommended to prefix variable names that are not
     attribute the message to the unit, and thus will ignore it, even if
     <varname>NotifyAccess=</varname><option>all</option> is set for it.</para>
 
+    <para>Hence, to eliminate all race conditions involving lookup of the client's unit and attribution of notifications
+    to units correctly, <function>sd_notify_barrier()</function> may be used. This call acts as a synchronization point
+    and ensures all notifications sent before this call have been picked up by the service manager when it returns
+    successfully. Use of <function>sd_notify_barrier()</function> is needed for clients which are not invoked by the
+    service manager, otherwise this synchronization mechanism is unnecessary for attribution of notifications to the
+    unit.</para>
+
     <para><function>sd_notifyf()</function> is similar to
     <function>sd_notify()</function> but takes a
     <function>printf()</function>-like format string plus
     to the service manager on messages that do not expect them (i.e.
     without <literal>FDSTORE=1</literal>) they are immediately closed
     on reception.</para>
+
+    <para><function>sd_notify_barrier()</function> allows the caller to
+    synchronize against reception of previously sent notification messages
+    and uses the <literal>BARRIER=1</literal> command. It takes a relative
+    <varname>timeout</varname> value in microseconds which is passed to
+    <citerefentry><refentrytitle>ppoll</refentrytitle><manvolnum>2</manvolnum>
+    </citerefentry>. A value of UINT64_MAX is interpreted as infinite timeout.
+    </para>
   </refsect1>
 
   <refsect1>
 
       <programlisting>sd_pid_notify_with_fds(0, 0, "FDSTORE=1\nFDNAME=foobar", &amp;fd, 1);</programlisting>
     </example>
+
+    <example>
+      <title>Eliminating race conditions</title>
+
+      <para>When the client sending the notifications is not spawned
+      by the service manager, it may exit too quickly and the service
+      manager may fail to attribute them correctly to the unit. To
+      prevent such races, use <function>sd_notify_barrier()</function>
+      to synchronize against reception of all notifications sent before
+      this call is made.</para>
+
+      <programlisting>sd_notify(0, "READY=1");
+      /* set timeout to 5 seconds */
+      sd_notify_barrier(0, 5 * 1000000);
+      </programlisting>
+    </example>
   </refsect1>
 
   <refsect1>
diff --git a/man/standard-specifiers.xml b/man/standard-specifiers.xml
new file mode 100644 (file)
index 0000000..3efbb6d
--- /dev/null
@@ -0,0 +1,62 @@
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<tbody>
+  <row id='b'>
+    <entry><literal>%b</literal></entry>
+    <entry>Boot ID</entry>
+    <entry>The boot ID of the running system, formatted as string. See <citerefentry><refentrytitle>random</refentrytitle><manvolnum>4</manvolnum></citerefentry> for more information.</entry>
+  </row>
+  <row id='a'>
+    <entry><literal>%a</literal></entry>
+    <entry>Architecture</entry>
+    <entry>A short string identifying the architecture of the local system. A string such as <constant>x86</constant>, <constant>x86-64</constant> or <constant>arm64</constant>. See the architectures defined for <varname>ConditionArchitecture=</varname> in <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for a full list.</entry>
+  </row>
+  <row id='B'>
+    <entry><literal>%B</literal></entry>
+    <entry>Operating system build ID</entry>
+    <entry>The operating system build identifier of the running system, as read from the <varname>BUILD_ID=</varname> field of <filename>/etc/os-release</filename>. If not set, resolves to an empty string. See <citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
+  </row>
+  <row id='H'>
+    <entry><literal>%H</literal></entry>
+    <entry>Host name</entry>
+    <entry>The hostname of the running system.</entry>
+  </row>
+  <row id='l'>
+    <entry><literal>%l</literal></entry>
+    <entry>Short host name</entry>
+    <entry>The hostname of the running system, truncated at the first dot to remove any domain component.</entry>
+  </row>
+  <row id='m'>
+    <entry><literal>%m</literal></entry>
+    <entry>Machine ID</entry>
+    <entry>The machine ID of the running system, formatted as string. See <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
+  </row>
+  <row id='o'>
+    <entry><literal>%o</literal></entry>
+    <entry>Operating system ID</entry>
+    <entry>The operating system identifier of the running system, as read from the <varname>ID=</varname> field of <filename>/etc/os-release</filename>. See <citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
+  </row>
+  <row id='v'>
+    <entry><literal>%v</literal></entry>
+    <entry>Kernel release</entry>
+    <entry>Identical to <command>uname -r</command> output.</entry>
+  </row>
+  <row id='w'>
+    <entry><literal>%w</literal></entry>
+    <entry>Operating system version ID</entry>
+    <entry>The operating system version identifier of the running system, as read from the <varname>VERSION_ID=</varname> field of <filename>/etc/os-release</filename>. If not set, resolves to an empty string. See <citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
+  </row>
+  <row id='W'>
+    <entry><literal>%W</literal></entry>
+    <entry>Operating system variant ID</entry>
+    <entry>The operating system variant identifier of the running system, as read from the <varname>VARIANT_ID=</varname> field of <filename>/etc/os-release</filename>. If not set, resolves to an empty string. See <citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
+  </row>
+  <row id='percent'>
+    <entry><literal>%%</literal></entry>
+    <entry>Single percent sign</entry>
+    <entry>Use <literal>%%</literal> in place of <literal>%</literal> to specify a single percent sign.</entry>
+  </row>
+</tbody>
index 2735cb10dd01dbc12a8ea37d3d45d4df7526ccd4..dc10776e9968a022a9beb916b4e006b537bb5c92 100644 (file)
@@ -159,7 +159,7 @@ net.bridge.bridge-nf-call-arptables = 0
 
     <example>
       <title>Set network routing properties for all interfaces</title>
-      <para><filename>/etc/systemd/20-rp_filter.conf</filename>:</para>
+      <para><filename>/etc/sysctl.d/20-rp_filter.conf</filename>:</para>
 
       <programlisting>net.ipv4.conf.default.rp_filter = 2
 net.ipv4.conf.*.rp_filter = 2
index 30880b41102f3e109f51794689729e8388bba91c..36495cbd3352731fa6d9a51895d0f9dc8d8fe340 100644 (file)
@@ -303,6 +303,30 @@ Sun 2017-02-26 20:57:49 EST  2h 3min left  Sun 2017-02-26 11:56:36 EST  6h ago
             generally redundant and reproducible on the next invocation of the unit).</para>
           </listitem>
         </varlistentry>
+        <varlistentry>
+          <term><command>freeze <replaceable>PATTERN</replaceable>…</command></term>
+
+          <listitem>
+            <para>Freeze one or more units specified on the
+            command line using cgroup freezer</para>
+
+            <para>Freezing the unit will cause all processes contained within the cgroup corresponding to the unit
+            to be suspended. Being suspended means that unit's processes won't be scheduled to run on CPU until thawed.
+            Note that this command is supported only on systems that use unified cgroup hierarchy. Unit is automatically
+            thawed just before we execute a job against the unit, e.g. before the unit is stopped.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><command>thaw <replaceable>PATTERN</replaceable>…</command></term>
+
+          <listitem>
+            <para>Thaw (unfreeze) one or more units specified on the
+            command line.</para>
+
+            <para>This is the inverse operation to the <command>freeze</command> command and resumes the execution of
+            processes in the unit's cgroup.</para>
+          </listitem>
+        </varlistentry>
         <varlistentry>
           <term><command>is-active <replaceable>PATTERN</replaceable>…</command></term>
 
@@ -729,6 +753,11 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
                   <row>
                     <entry><literal>linked-runtime</literal></entry>
                   </row>
+                  <row>
+                    <entry><literal>alias</literal></entry>
+                    <entry>The name is an alias (symlink to another unit file).</entry>
+                    <entry>0</entry>
+                  </row>
                   <row>
                     <entry><literal>masked</literal></entry>
                     <entry morerows='1'>Completely disabled, so that any start operation on it fails (permanently in <filename>/etc/systemd/system/</filename> or transiently in <filename>/run/systemd/systemd/</filename>).</entry>
index 27e34195afeec0548dd3e711544d6358fc6316d6..41a8247c5f400b5c46a508a333093eb056b86ad0 100644 (file)
 
   <refsect1><title>Options</title>
     <variablelist>
+
+      <varlistentry>
+        <term><option>--unregister</option></term>
+        <listitem><para>If passed, instead of registering configured binary formats in the kernel, the
+        reverse operation is executed: all currently registered binary formats are unregistered from the
+        kernel.</para></listitem>
+      </varlistentry>
+
       <xi:include href="standard-options.xml" xpointer="cat-config" />
       <xi:include href="standard-options.xml" xpointer="no-pager" />
       <xi:include href="standard-options.xml" xpointer="help" />
index 0324a6744097f77fe6d4e047019481368d69012b..47051b9cef307d7cc62e0ef12c17723fab538489 100644 (file)
     <para>At early boot and when the system manager configuration is reloaded, <filename>/etc/crypttab</filename> is
     translated into <filename>systemd-cryptsetup@.service</filename> units by
     <citerefentry><refentrytitle>systemd-cryptsetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
+
+    <para>In order to unlock a volume a password or binary key is
+    required. <filename>systemd-cryptsetup@.service</filename> tries to acquire a suitable password or binary
+    key via the following mechanisms, tried in order:</para>
+
+    <orderedlist>
+      <listitem><para>If a key file is explicitly configured (via the third column in
+      <filename>/etc/crypttab</filename>), a key read from it is used. If a PKCS#11 token is configured
+      (using the <varname>pkcs11-uri=</varname> option) the key is decrypted before use.</para></listitem>
+
+      <listitem><para>If no key file is configured explicitly this way, a key file is automatically loaded
+      from <filename>/etc/cryptsetup-keys.d/<replaceable>volume</replaceable>.key</filename> and
+      <filename>/run/cryptsetup-keys.d/<replaceable>volume</replaceable>.key</filename>, if present. Here
+      too, if a PKCS#11 token is configured, any key found this way is decrypted before
+      use.</para></listitem>
+
+      <listitem><para>If the <varname>try-empty-password</varname> option is specified it is then attempted
+      to unlock the volume with an empty password.</para></listitem>
+
+      <listitem><para>The kernel keyring is then checked for a suitable cached password from previous
+      attempts.</para></listitem>
+
+      <listitem><para>Finally, the user is queried for a password, possibly multiple times.</para></listitem>
+    </orderedlist>
+
+    <para>If no suitable key may be acquired via any of the mechanisms describes above, volume activation fails.</para>
   </refsect1>
 
   <refsect1>
index 560649f22c4b2ea49cf6161c10d3c402778711ca..0eb212341f6cd1547180b7ef6f37eb613636bbf4 100644 (file)
@@ -54,7 +54,7 @@
 
       <listitem><para>The system time zone</para></listitem>
 
-      <listitem><para>The system host name</para></listitem>
+      <listitem><para>The system hostname</para></listitem>
 
       <listitem><para>The machine ID of the system</para></listitem>
 
         <term><option>--hostname=<replaceable>HOSTNAME</replaceable></option></term>
 
         <listitem><para>Sets the system hostname. The argument should
-        be a host name, compatible with DNS. This controls the
+        be a hostname, compatible with DNS. This controls the
         <citerefentry><refentrytitle>hostname</refentrytitle><manvolnum>5</manvolnum></citerefentry>
         configuration file.</para></listitem>
       </varlistentry>
index e4c520ff2fabab914e1e5c4022f72f4ca7b70fc0..ab8bcab8cb852a5ecb5f5dfbd762b9666e3b99f8 100644 (file)
     <citerefentry><refentrytitle>userdbctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
   </refsect1>
 
+  <refsect1>
+    <title>Key Management</title>
+
+    <para>User records are cryptographically signed with a public/private key pair (the signature is part of
+    the JSON record itself). For a user to be permitted to log in locally the public key matching the
+    signature of their user record must be installed. For a user record to be modified locally the private
+    key matching the signature must be installed locally, too. The keys are stored in the
+    <filename>/var/lib/systemd/home/</filename> directory:</para>
+
+    <variablelist>
+
+      <varlistentry>
+        <term><filename>/var/lib/systemd/home/local.private</filename></term>
+
+        <listitem><para>The private key of the public/private key pair used for local records. Currently,
+        only a single such key may be installed.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><filename>/var/lib/systemd/home/local.public</filename></term>
+
+        <listitem><para>The public key of the public/private key pair used for local records. Currently,
+        only a single such key may be installed.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><filename>/var/lib/systemd/home/*.public</filename></term>
+
+        <listitem><para>Additional public keys. Any users whose user records are signed with any of these keys
+        are permitted to log in locally. An arbitrary number of keys may be installed this
+        way.</para></listitem>
+      </varlistentry>
+    </variablelist>
+
+    <para>All key files listed above are in PEM format.</para>
+
+    <para>In order to migrate a home directory from a host <literal>foobar</literal> to another host
+    <literal>quux</literal> it is hence sufficient to copy
+    <filename>/var/lib/systemd/home/local.public</filename> from the host <literal>foobar</literal> to
+    <literal>quux</literal>, maybe calling the file on the destination
+    <filename>/var/lib/systemd/home/foobar.public</filename>, reflecting the origin of the key. If the user
+    record should be modifiable on <literal>quux</literal> the pair
+    <filename>/var/lib/systemd/home/local.public</filename> and
+    <filename>/var/lib/systemd/home/local.private</filename> need to be copied from <literal>foobar</literal>
+    to <literal>quux</literal>, and placed under the identical paths there, as currently only a single
+    private key is supported per host. Note of course that the latter means that user records
+    generated/signed before the key pair is copied in, lose their validity.</para>
+  </refsect1>
+
   <refsect1>
     <title>See Also</title>
     <para>
       <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>homed.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>homectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>pam_systemd_home</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
-      <citerefentry><refentrytitle>userdbctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+      <citerefentry><refentrytitle>userdbctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>org.freedesktop.home1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
     </para>
   </refsect1>
 </refentry>
index 699316a09a2eadf447043be5b0e9174a86a66b1d..1aa32a61cedc3b9a0291d2349e482fed407d1b3f 100644 (file)
@@ -56,7 +56,9 @@
     is a command line client to this service.</para>
 
     <para>See
-    <citerefentry><refentrytitle>org.freedesktop.hostname1</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+    <citerefentry><refentrytitle>org.freedesktop.hostname1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+    and
+    <citerefentry><refentrytitle>org.freedesktop.LogControl1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
     for a description of the D-Bus API.</para>
   </refsect1>
 
index 355e5b0b98190a2a0fb53380a84b4e32b38d25cd..fa3c3a812f05e035fad9c5c80d1d67194c8b249d 100644 (file)
     <command>pull-raw</command>, <command>pull-tar</command>, <command>import-raw</command>,
     <command>import-tar</command>, <command>export-raw</command>, and <command>export-tar</command> commands.</para>
 
-    <para>See the
-    <ulink url="https://www.freedesktop.org/wiki/Software/systemd/importd">
-    importd D-Bus API Documentation</ulink> for information about the
-    APIs <filename>systemd-importd</filename> provides.</para>
+    <para>See
+    <citerefentry><refentrytitle>org.freedesktop.import1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+    and
+    <citerefentry><refentrytitle>org.freedesktop.LogControl1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+    for a description of the D-Bus API.</para>
   </refsect1>
 
   <refsect1>
index e5f6b78d218acd10b98a1b22b10973e2a226afb8..49eeeffee6e368e55c977d2dfc07eb06f50ef418 100644 (file)
@@ -41,7 +41,9 @@
     is a command line client to this service.</para>
 
     <para>See
-    <citerefentry><refentrytitle>org.freedesktop.locale1</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+    <citerefentry><refentrytitle>org.freedesktop.locale1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+    and
+    <citerefentry><refentrytitle>org.freedesktop.LogControl1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
     for a description of the D-Bus API.</para>
   </refsect1>
 
index 12f9f7a0f683af827c21d47c44392f6ee0c570e3..c602b2e42fe800fcac5a0dd420a01180d3e2f36b 100644 (file)
@@ -79,7 +79,9 @@
     such as users, sessions and seats.</para>
 
     <para>See
-    <citerefentry><refentrytitle>org.freedesktop.login1</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+    <citerefentry><refentrytitle>org.freedesktop.login1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+    and
+    <citerefentry><refentrytitle>org.freedesktop.LogControl1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
     for information about the D-Bus APIs <filename>systemd-logind</filename> provides.</para>
 
     <para>For more information on the inhibition logic see the <ulink
index e15cc963b407c565e8c0131407061cf764ef2ae4..ab58d8fd3f76fd35f141c234a801f829ad050489 100644 (file)
     For more information please consult
     <citerefentry><refentrytitle>sd-login</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     and
-    <citerefentry><refentrytitle>org.freedesktop.machine1</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+    <citerefentry><refentrytitle>org.freedesktop.machine1</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+    and
+    <citerefentry><refentrytitle>org.freedesktop.LogControl1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
     </para>
 
     <para>A small companion daemon
index 89060680f5efa1132446b4442d4fbb4a01b1ecea..6d583003baca6c1e531da3e91011f17ac0b446f7 100644 (file)
     off the process, i.e. on all processes that match <varname>NotifyAccess=</varname><option>main</option> or
     <varname>NotifyAccess=</varname><option>exec</option>. Conversely, if an auxiliary process of the unit sends an
     <function>sd_notify()</function> message and immediately exits, the service manager might not be able to properly
-    attribute the message to the unit, and thus will ignore it, even if
-    <varname>NotifyAccess=</varname><option>all</option> is set for it.</para>
-
-    <para><command>systemd-notify</command> will first attempt to invoke <function>sd_notify()</function> pretending to
-    have the PID of the invoking process. This will only succeed when invoked with sufficient privileges. On failure,
-    it will then fall back to invoking it under its own PID. This behaviour is useful in order that when the tool is
-    invoked from a shell script the shell process — and not the <command>systemd-notify</command> process — appears as
-    sender of the message, which in turn is helpful if the shell process is the main process of a service, due to the
-    limitations of <varname>NotifyAccess=</varname><option>all</option> described above.</para>
+    attribute the message to the unit, and thus will ignore it, even if <varname>NotifyAccess=</varname><option>all
+    </option> is set for it. When <option>--no-block</option> is used, all synchronization for reception of notifications
+    is disabled, and hence the aforementioned race may occur if the invoking process is not the service manager or spawned
+    by the service manager.</para>
+
+    <para>Hence, <command>systemd-notify</command> will first attempt to invoke <function>sd_notify()</function>
+    pretending to have the PID of the invoking process. This will only succeed when invoked with sufficient privileges.
+    On failure, it will then fall back to invoking it under its own PID. This behaviour is useful in order that when
+    the tool is invoked from a shell script the shell process — and not the <command>systemd-notify</command> process
+    — appears as sender of the message, which in turn is helpful if the shell process is the main process of a service,
+    due to the limitations of <varname>NotifyAccess=</varname><option>all</option>. Use the <option>--pid=</option>
+    switch to tweak this behaviour.</para>
+
   </refsect1>
 
   <refsect1>
       <varlistentry>
         <term><option>--pid=</option></term>
 
-        <listitem><para>Inform the init system about the main PID of
-        the daemon. Takes a PID as argument. If the argument is
-        omitted, the PID of the process that invoked
-        <command>systemd-notify</command> is used. This is equivalent
-        to <command>systemd-notify MAINPID=$PID</command>. For details
-        about the semantics of this option see
+        <listitem><para>Inform the service manager about the main PID of the daemon. Takes a PID as
+        argument. If the argument is specified as <literal>auto</literal> or omitted, the PID of the process
+        that invoked <command>systemd-notify</command> is used, except if that's the service manager. If the
+        argument is specified as <literal>self</literal>, the PID of the <command>systemd-notify</command>
+        command itself is used, and if <literal>parent</literal> is specified the calling process' PID is
+        used — even if it is the service manager. This is equivalent to <command>systemd-notify
+        MAINPID=$PID</command>. For details about the semantics of this option see
         <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
       </varlistentry>
 
         with systemd.  </para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--no-block</option></term>
+
+        <listitem><para>Do not synchronously wait for the requested operation to finish.
+        Use of this option is only recommended when <command>systemd-notify</command>
+        is spawned by the service manager, or when the invoking process is directly spawned
+        by the service manager and has enough privileges to allow <command>systemd-notify
+        </command> to send the notification on its behalf. Sending notifications with
+        this option set is prone to race conditions in all other cases.</para></listitem>
+      </varlistentry>
+
       <xi:include href="standard-options.xml" xpointer="help" />
       <xi:include href="standard-options.xml" xpointer="version" />
     </variablelist>
index 8c9dbe52ef595f3453ee6fa201c2da29c0397399..8c7d5a20048e0bc09e6e184c1b21f5233a3ea3ef 100644 (file)
         all subdirectories and subvolumes below it, but excluding any sub-mounts. May not be specified
         together with <option>--image=</option> or <option>--ephemeral</option>.</para>
 
-        <para>Note that this switch leaves host name, machine ID and
+        <para>Note that this switch leaves hostname, machine ID and
         all other settings that could identify the instance
         unmodified.</para></listitem>
       </varlistentry>
         <listitem><para>If specified, the container is run with a temporary snapshot of its file system that is removed
         immediately when the container terminates. May not be specified together with
         <option>--template=</option>.</para>
-        <para>Note that this switch leaves host name, machine ID and all other settings that could identify
+        <para>Note that this switch leaves hostname, machine ID and all other settings that could identify
         the instance unmodified. Please note that — as with <option>--template=</option> — taking the
         temporary snapshot is more efficient on file systems that support subvolume snapshots or 'reflinks'
         natively (<literal>btrfs</literal> or new <literal>xfs</literal>) than on more traditional file
index 47916da5219d6e658eb55b5d135dcf36d78249e3..335a3b3d183e1b67d3e14cebb6140e61390ef8c5 100644 (file)
       <citerefentry><refentrytitle>pstore.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
       </para>
     </refsect2>
+
+    <refsect2>
+      <title>Controlling kernel parameters</title>
+
+      <para> The kernel has two parameters,
+      <filename>/sys/module/kernel/parameters/crash_kexec_post_notifiers</filename> and
+      <filename>/sys/module/printk/parameters/always_kmsg_dump</filename>,
+      that control writes into pstore.
+      The crash_kexec_post_notifiers parameter enables the kernel to write
+      dmesg (including stack trace) into pstore upon a panic or crash, and
+      printk.always_kmsg_dump parameter enables the kernel to write dmesg
+      upon a normal shutdown (shutdown, reboot, halt). These kernel
+      parameters are managed via the
+      <citerefentry><refentrytitle>tmpfiles.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+      mechanism, specifically the file <filename>/usr/lib/tmpfiles/systemd-pstore.conf</filename>.
+      </para>
+    </refsect2>
+
   </refsect1>
 
   <refsect1>
index f55be4f32803c7e33a197c876c3a59239d5b2461..74c6ba95b1400fd36f0696fcd747182fc29b3491 100644 (file)
@@ -58,7 +58,7 @@
 
     <itemizedlist>
       <listitem><para>The root partition may be grown to cover the whole available disk space</para></listitem>
-      <listitem><para>A <filename>/home/</filename>, swap or <filename>/srv</filename> partition can be added in</para></listitem>
+      <listitem><para>A <filename>/home/</filename>, swap or <filename>/srv/</filename> partition can be added in</para></listitem>
       <listitem><para>A second (or third, …) root partition may be added in, to cover A/B style setups
       where a second version of the root file system is alternatingly used for implementing update
       schemes. The deployed image would carry only a single partition ("A") but on first boot a second
     also be set explicitly, formatted as UUID via the <option>--seed=</option> option. By hashing these UUIDs
     from a common seed images prepared with this tool become reproducible and the result of the algorithm
     above deterministic.</para>
+
+    <para>The positional argument should specify the block device to operate on. Instead of a block device
+    node path a regular file may be specified too, in which case the command operates on it like it would if
+    a loopback block device node was specified with the file attached. If <option>--empty=create</option> is
+    specified the specified path is created as regular file, which is useful for generating disk images from
+    scratch.</para>
   </refsect1>
 
   <refsect1>
       <varlistentry>
         <term><option>--empty=</option></term>
         <listitem><para>Takes one of <literal>refuse</literal>, <literal>allow</literal>,
-        <literal>require</literal> or <literal>force</literal>. Controls how to operate on block devices that
-        are entirely empty, i.e. carry no partition table/disk label yet. If this switch is not specified the
-        implied default is <literal>refuse</literal>.</para>
+        <literal>require</literal>, <literal>force</literal> or <literal>create</literal>. Controls how to
+        operate on block devices that are entirely empty, i.e. carry no partition table/disk label yet. If
+        this switch is not specified the implied default is <literal>refuse</literal>.</para>
 
         <para>If <literal>refuse</literal> <command>systemd-repart</command> requires that the block device
         it shall operate on already carries a partition table and refuses operation if none is found. If
         exists so far, and refuse operation if one already exists. If <literal>force</literal> it will create
         a fresh partition table unconditionally, erasing the disk fully in effect. If
         <literal>force</literal> no existing partitions will be taken into account or survive the
-        operation. Hence: use with care, this is a great way to lose all your data.</para></listitem>
+        operation. Hence: use with care, this is a great way to lose all your data. If
+        <literal>create</literal> a new loopback file is create under the path passed via the device node
+        parameter, of the size indicated with <option>--size=</option>, see below.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         the implied default. Controls whether to issue the <constant>BLKDISCARD</constant> I/O control
         command on the space taken up by any added partitions or on the space in between them. Usually, it's
         a good idea to issue this request since it tells the underlying hardware that the covered blocks
-        shall be considered empty, improving performance.</para></listitem>
+        shall be considered empty, improving performance. If operating on a regular file instead of a block
+        device node, a sparse file is generated.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--size=</option></term>
+
+        <listitem><para>Takes a size in bytes, using the usual K, M, G, T suffixes. If used the specified
+        device node path must refer to a regular file, which is then grown to the specified size if smaller,
+        before any change is made to the partition table. This is not supported if the specified node is a
+        block device. This switch has no effect if the file is already as large as the specified size or
+        larger. The specified size is implicitly rounded up to multiples of 4096. When used with
+        <option>--empty=create</option> this specifies the initial size of the loopback file to
+        create.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index a30c5f72b8114f57f76d7f48055e5b3dab395128..6e1ee9f4a5158229561b579277944d10ce90d49a 100644 (file)
@@ -38,6 +38,8 @@
       <listitem><para>The native, fully-featured API <command>systemd-resolved</command> exposes on the bus,
       see
       <citerefentry><refentrytitle>org.freedesktop.resolve1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+      and
+      <citerefentry><refentrytitle>org.freedesktop.LogControl1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
       for details. Usage of this API is generally recommended to clients as it is asynchronous and fully
       featured (for example, properly returns DNSSEC validation status and interface scope for addresses as
       necessary for supporting link-local networking).</para></listitem>
@@ -53,7 +55,7 @@
       (<citerefentry project='man-pages'><refentrytitle>nss</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
       Usage of the glibc NSS module
       <citerefentry><refentrytitle>nss-resolve</refentrytitle><manvolnum>8</manvolnum></citerefentry> is
-      required in order to allow glibc's NSS resolver functions to resolve host names via
+      required in order to allow glibc's NSS resolver functions to resolve hostnames via
       <command>systemd-resolved</command>.</para></listitem>
 
       <listitem><para>Additionally, <command>systemd-resolved</command> provides a local DNS stub listener on
@@ -69,7 +71,7 @@
     <filename>/etc/systemd/resolved.conf</filename>, the per-link static settings in
     <filename>/etc/systemd/network/*.network</filename> files (in case
     <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-    is used), the per-link dynamic settings received over DHCP, user request made via
+    is used), the per-link dynamic settings received over DHCP, information provided via
     <citerefentry><refentrytitle>resolvectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>, and any
     DNS server information made available by other system services. See
     <citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry> and
 
       <listitem><para>The mappings defined in <filename>/etc/hosts</filename> are resolved to their
       configured addresses and back, but they will not affect lookups for non-address types (like MX).
+      Support for <filename>/etc/hosts</filename> may be disabled with <varname>ReadEtcHosts=no</varname>,
+      see <citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
       </para></listitem>
     </itemizedlist>
   </refsect1>
   <refsect1>
     <title>Protocols and Routing</title>
 
-    <para>Lookup requests are routed to the available DNS servers, LLMNR and MulticastDNS interfaces
+    <para>Lookup requests are routed to the available DNS servers, LLMNR, and MulticastDNS interfaces
     according to the following rules:</para>
 
     <itemizedlist>
-      <listitem><para>Lookups for the special hostname <literal>localhost</literal> are never routed to the
-      network. (A few other, special domains are handled the same way.)</para></listitem>
-
-      <listitem><para>Single-label names are routed to all local interfaces capable of IP multicasting, using
-      the LLMNR protocol. Lookups for IPv4 addresses are only sent via LLMNR on IPv4, and lookups for IPv6
-      addresses are only sent via LLMNR on IPv6. Lookups for the locally configured host name and the
-      <literal>_gateway</literal> host name are never routed to LLMNR.</para></listitem>
+      <listitem><para>Names for which synthetic records are generated (as listed in the previous section) are
+      never routed to the network and a reply is sent immediately. In particular this means that lookups for
+      <literal>localhost</literal> are never routed to the network.</para></listitem>
+
+      <listitem><para>Single-label names are routed to all local interfaces capable of IP multicasting, where
+      LLMNR is not disabled, using the LLMNR protocol. Lookups for IPv4 addresses are only sent via LLMNR on
+      IPv4, and lookups for IPv6 addresses are only sent via LLMNR on IPv6. Lookups for the locally
+      configured hostname and the <literal>_gateway</literal> hostname are never routed to LLMNR.
+      </para></listitem>
 
       <listitem><para>Multi-label names with the domain suffix <literal>.local</literal> are routed to all
-      local interfaces capable of IP multicasting, using the MulticastDNS protocol. As with LLMNR IPv4
-      address lookups are sent via IPv4 and IPv6 address lookups are sent via IPv6.</para></listitem>
+      local interfaces capable of IP multicasting, where MulticastDNS is not disabled, using the MulticastDNS
+      protocol. As with LLMNR, IPv4 address lookups are sent via IPv4 and IPv6 address lookups are sent via
+      IPv6.</para></listitem>
+
+      <listitem><para>Resolution of address records (A and AAAA) via unicast DNS (i.e. not LLMNR or
+      MulticastDNS) for non-synthesized single-label names is only allowed for non-top-level domains. This
+      means that such records can only be resolved when search domains are defined. For any interface which
+      defines search domains, such look-ups are routed to that interface, suffixed with each of the search
+      domains defined on that interface in turn. When global search domains are defined, such look-ups are
+      routed to all interfaces, suffixed by each of the global search domains in turn. The details of which
+      servers are queried and how the final reply is chosen are described below. Note that this means that
+      address queries for single-label names are never sent out to remote DNS servers, and if no search
+      domains are defined, resolution will fail.</para></listitem>
 
       <listitem><para>Other multi-label names are routed to all local interfaces that have a DNS server
-      configured, plus the globally configured DNS server if there is one. Address lookups from the
-      link-local address range are never routed to DNS. Note that by default lookups for domains with the
-      <literal>.local</literal> suffix are not routed to DNS servers, unless the domain is specified
-      explicitly as routing or search domain for the DNS server and interface. This means that on networks
-      where the <literal>.local</literal> domain is defined in a site-specific DNS server, explicit search or
-      routing domains need to be configured to make lookups within this DNS domain work. Note that today it's
-      generally recommended to avoid defining <literal>.local</literal> in a DNS server, as <ulink
-      url="https://tools.ietf.org/html/rfc6762">RFC6762</ulink> reserves this domain for exclusive
+      configured, plus the globally configured DNS servers if there are any. Note that by default, lookups for
+      domains with the <literal>.local</literal> suffix are not routed to DNS servers, unless the domain is
+      specified explicitly as routing or search domain for the DNS server and interface. This means that on
+      networks where the <literal>.local</literal> domain is defined in a site-specific DNS server, explicit
+      search or routing domains need to be configured to make lookups within this DNS domain work. Note that
+      these days, it's generally recommended to avoid defining <literal>.local</literal> in a DNS server, as
+      <ulink url="https://tools.ietf.org/html/rfc6762">RFC6762</ulink> reserves this domain for exclusive
       MulticastDNS use.</para></listitem>
+
+      <listitem><para>Address lookups are routed similarly to multi-label names, with the exception that
+      addresses from the link-local address range are never routed to unicast DNS and are only resolved using
+      LLMNR and MulticastDNS (when enabled).</para></listitem>
     </itemizedlist>
 
     <para>If lookups are routed to multiple interfaces, the first successful response is returned (thus
 
     <itemizedlist>
       <listitem><para>If a name to look up matches (that is: is equal to or has as suffix) any of the
-      configured search or route-only domains of any link (or the globally configured DNS settings), the
+      configured search or route-only domains of any link (see
+      <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>),
+      or the globally configured DNS settings (see the discussion of <varname>Domains=</varname> in
+      <citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>),
       "best matching" search/route-only domain is determined: the matching one with the most labels. The
       query is then sent to all DNS servers of any links or the globally configured DNS servers associated
       with this "best matching" search/route-only domain. (Note that more than one link might have this same
       "best matching" search/route-only domain configured, in which case the query is sent to all of them in
-      parallel).</para></listitem>
+      parallel).</para>
+
+      <para>In case of single-label names, when search domains are defined, the same logic applies, except
+      that the name is first suffixed by the search domain.</para></listitem>
 
       <listitem><para>If a query does not match any configured search/route-only domain (neither per-link nor
       global), it is sent to all DNS servers that are configured on links with the "DNS default route" option
     configured DNS domains for a link: if there's any route-only domain (not matching <literal>~.</literal>)
     it defaults to false, otherwise to true.</para>
 
-    <para>Effectively this means: in order to preferably route all DNS queries not explicitly matched by
-    search/route-only domain configuration to a specific link, configure a <literal>~.</literal> route-only
-    domain on it. This will ensure that other links will not be considered for the queries (unless they too
-    carry such a route-only domain). In order to route all such DNS queries to a specific link only in case
-    no other link is preferable, then set the "DNS default route" option for the link to true, and do not
-    configure a <literal>~.</literal> route-only domain on it. Finally, in order to ensure that a specific
-    link never receives any DNS traffic not matching any of its configured search/route-only domains, set the
-    "DNS default route" option for it to false.</para>
+    <para>Effectively this means: in order to support single-label non-synthetized names, define appropriate
+    search domains. In order to preferably route all DNS queries not explicitly matched by search/route-only
+    domain configuration to a specific link, configure a <literal>~.</literal> route-only domain on it. This
+    will ensure that other links will not be considered for these queries (unless they too carry such a
+    route-only domain). In order to route all such DNS queries to a specific link only if no other link
+    is preferable, set the "DNS default route" option for the link to true and do not configure a
+    <literal>~.</literal> route-only domain on it. Finally, in order to ensure that a specific link never
+    receives any DNS traffic not matching any of its configured search/route-only domains, set the "DNS
+    default route" option for it to false.</para>
 
     <para>See the <ulink url="https://www.freedesktop.org/wiki/Software/systemd/resolved">resolved D-Bus API
     Documentation</ulink> for information about the APIs <filename>systemd-resolved</filename> provides.
index a72ac1bbc66fcf2276d9a215897834c48894aec4..58b26aad87f4e785de9e5f6d4710f808ecf85a0b 100644 (file)
         <listitem><para>Sets the maximum number of simultaneous connections, defaults to 256.
         If the limit of concurrent connections is reached further connections will be refused.</para></listitem>
       </varlistentry>
+      <varlistentry>
+        <term><option>--exit-idle-time=</option></term>
+
+        <listitem><para>Sets the time before exiting when there are no connections, defaults to
+        <constant>infinity</constant>. Takes a unit-less value in seconds, or a time span value such
+        as <literal>5min 20s</literal>.</para></listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
   <refsect1>
@@ -115,6 +122,9 @@ server {
         <programlisting><![CDATA[# systemctl enable --now proxy-to-nginx.socket
 $ curl http://localhost:80/]]></programlisting>
       </example>
+      <para>If <filename>nginx.service</filename> has <varname>StopWhenUnneeded=</varname> set, then
+      passing <option>--exit-idle-time=</option> to <command>systemd-socket-proxyd</command> allows
+      both services to stop during idle periods.</para>
     </refsect2>
     <refsect2>
       <title>Namespace Example</title>
index b722b33115ff78ef54c4570d61e410990eebefc3..93cfdf511803a06c109101e6450aa8b0905f1fc3 100644 (file)
@@ -55,6 +55,8 @@
 
     <para>See
     <citerefentry><refentrytitle>org.freedesktop.timedate1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+    and
+    <citerefentry><refentrytitle>org.freedesktop.LogControl1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
     for information about the D-Bus API.</para>
   </refsect1>
 
index 7720ef53fa19fb2ba73dbb83299d365faeb6b56b..998fd0911baa5ba35df16e3a64d81ca51d81b53b 100644 (file)
         <listitem><para>Takes a directory path as an argument. All paths will be prefixed with the given alternate
         <replaceable>root</replaceable> path, including config search paths.</para>
 
-        <para>Note that this option does not alter how the users and groups specified in the configuration files are
-        resolved. With or without this option, users and groups are always resolved according to the host's user and
-        group databases, any such databases stored under the specified root directories are not
-        consulted.</para></listitem>
+        <para>When this option is used, the libc Name Service Switch (NSS) is bypassed for resolving users
+        and groups. Instead the files <filename>/etc/passwd</filename> and <filename>/etc/group</filename>
+        inside the alternate root are read directly. This means that users/groups not listed in these files
+        will not be resolved, i.e. LDAP NIS and other complex databases are not considered.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index ad412691a946847c39d1ae09cc501969aed5d3be..91196dff301fb92ce9cab3b2a82ac8a627b82495 100644 (file)
     <citerefentry project='man-pages'><refentrytitle>touch</refentrytitle><manvolnum>1</manvolnum></citerefentry>
     on it.</para>
 
+    <para>Note that if the <varname>systemd.condition-needs-update=</varname> kernel command line option is
+    used it overrides the <varname>ConditionNeedsUpdate=</varname> unit condition checks. In that case
+    <filename>systemd-update-done.service</filename> will not reset the condition state until a follow-up
+    reboot where the kernel switch is not specified anymore.</para>
   </refsect1>
 
   <refsect1>
index f2ed7610216bdd4bb8c0d3dbeecef2bf23df19ec..35690fd22a7539527ffb69a01b0d0650c2098dee 100644 (file)
         <listitem><para>Automount units acquire automatic <varname>Before=</varname> and
         <varname>Conflicts=</varname> on <filename>umount.target</filename> in order to be stopped during
         shutdown.</para></listitem>
+
+        <listitem><para>Automount units automatically gain an <varname>After=</varname> dependency
+        on <filename>local-fs-pre.target</filename>, and a <varname>Before=</varname> dependency on
+        <filename>local-fs.target</filename>.</para></listitem>
       </itemizedlist>
     </refsect2>
   </refsect1>
index 1ac760eec744af1d29470c56d66ba703f41266e5..2fb0a8ee7067b2924adfa876fca8a94f64375a9a 100644 (file)
@@ -3,7 +3,9 @@
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
-<refentry id="systemd.dnssd" conditional='ENABLE_RESOLVE'>
+<refentry id="systemd.dnssd"
+          xmlns:xi="http://www.w3.org/2001/XInclude"
+          conditional='ENABLE_RESOLVE'>
 
   <refentryinfo>
     <title>systemd.dnssd</title>
@@ -73,7 +75,7 @@
             <para>An instance name of the network service as defined in the section 4.1.1 of <ulink
             url="https://tools.ietf.org/html/rfc6763">RFC 6763</ulink>, e.g. <literal>webserver</literal>.</para>
             <para>The option supports simple specifier expansion. The following expansions are understood:</para>
-            <table>
+            <table class='specifiers'>
               <title>Specifiers available</title>
               <tgroup cols='3' align='left' colsep='1' rowsep='1'>
                 <colspec colname="spec" />
                   </row>
                 </thead>
                 <tbody>
-                  <row>
-                    <entry><literal>%m</literal></entry>
-                    <entry>Machine ID</entry>
-                    <entry>The machine ID of the running system, formatted as string. See <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
-                  </row>
-                  <row>
-                    <entry><literal>%b</literal></entry>
-                    <entry>Boot ID</entry>
-                    <entry>The boot ID of the running system, formatted as string. See <citerefentry><refentrytitle>random</refentrytitle><manvolnum>4</manvolnum></citerefentry> for more information.</entry>
-                  </row>
-                  <row>
-                    <entry><literal>%H</literal></entry>
-                    <entry>Host name</entry>
-                    <entry>The hostname of the running system.</entry>
-                  </row>
-                  <row>
-                    <entry><literal>%v</literal></entry>
-                    <entry>Kernel release</entry>
-                    <entry>Identical to <command>uname -r</command> output.</entry>
-                  </row>
+                  <xi:include href="standard-specifiers.xml" xpointer="a"/>
+                  <xi:include href="standard-specifiers.xml" xpointer="b"/>
+                  <xi:include href="standard-specifiers.xml" xpointer="B"/>
+                  <xi:include href="standard-specifiers.xml" xpointer="H"/>
+                  <xi:include href="standard-specifiers.xml" xpointer="m"/>
+                  <xi:include href="standard-specifiers.xml" xpointer="o"/>
+                  <xi:include href="standard-specifiers.xml" xpointer="v"/>
+                  <xi:include href="standard-specifiers.xml" xpointer="w"/>
+                  <xi:include href="standard-specifiers.xml" xpointer="W"/>
+                  <xi:include href="standard-specifiers.xml" xpointer="percent"/>
                 </tbody>
               </tgroup>
             </table>
index 3e2ae93bf0e60d857a347710b979b73710d1d97d..8f57cc8bfb964fe31a7d34063f9acac2efe98c34 100644 (file)
@@ -66,9 +66,9 @@
       will also gain an automatic <varname>After=</varname> dependency on
       <citerefentry><refentrytitle>systemd-tmpfiles-setup.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para></listitem>
 
-      <listitem><para>Units whose standard output or error output is connected to <option>journal</option>,
-      <option>syslog</option> or <option>kmsg</option> (or their combinations with console output, see below)
-      automatically acquire dependencies of type <varname>After=</varname> on
+      <listitem><para>Units whose standard output or error output is connected to <option>journal</option> or
+      <option>kmsg</option> (or their combinations with console output, see below) automatically acquire
+      dependencies of type <varname>After=</varname> on
       <filename>systemd-journald.socket</filename>.</para></listitem>
 
       <listitem><para>Units using <varname>LogNamespace=</varname> will automatically gain ordering and
@@ -891,10 +891,11 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
         <term><varname>ProtectSystem=</varname></term>
 
         <listitem><para>Takes a boolean argument or the special values <literal>full</literal> or
-        <literal>strict</literal>. If true, mounts the <filename>/usr</filename> and <filename>/boot</filename>
-        directories read-only for processes invoked by this unit. If set to <literal>full</literal>, the
-        <filename>/etc</filename> directory is mounted read-only, too. If set to <literal>strict</literal> the entire
-        file system hierarchy is mounted read-only, except for the API file system subtrees <filename>/dev</filename>,
+        <literal>strict</literal>. If true, mounts the <filename>/usr</filename> and the boot loader
+        directories (<filename>/boot</filename> and <filename>/efi</filename>) read-only for processes
+        invoked by this unit. If set to <literal>full</literal>, the <filename>/etc</filename> directory is
+        mounted read-only, too. If set to <literal>strict</literal> the entire file system hierarchy is
+        mounted read-only, except for the API file system subtrees <filename>/dev</filename>,
         <filename>/proc</filename> and <filename>/sys</filename> (protect these directories using
         <varname>PrivateDevices=</varname>, <varname>ProtectKernelTunables=</varname>,
         <varname>ProtectControlGroups=</varname>). This setting ensures that any modification of the vendor-supplied
@@ -2627,6 +2628,13 @@ StandardInputData=SWNrIHNpdHplIGRhIHVuJyBlc3NlIEtsb3BzLAp1ZmYgZWVtYWwga2xvcHAncy
         </para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>$LOG_NAMESPACE</varname></term>
+
+        <listitem><para>If the <varname>LogNamespace=</varname> service setting is used, contains name of the
+        selected logging namespace.</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><varname>$JOURNAL_STREAM</varname></term>
 
index a0771f3c135a2504fdec1a2e9d5f4311396aaefd..4d35cfb6dc5cbe27ec0280a7175a04795ed2c923 100644 (file)
       <varlistentry>
         <term><varname>_LINE_BREAK=</varname></term>
         <listitem>
-          <para>Only applies to <literal>_TRANSPORT=stdout</literal> records: indicates that the log message in the
-          standard output/error stream was not terminated with a normal newline character (<literal>\n</literal>,
-          i.e. ASCII 10). Specifically, when set this field is one of <option>nul</option> (in case the line was
-          terminated by a NUL byte), <option>line-max</option> (in case the maximum log line length was reached, as
-          configured with <varname>LineMax=</varname> in
-          <citerefentry><refentrytitle>journald.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>) or
-          <option>eof</option> (if this was the last log record of a stream and the stream ended without a final
-          newline character). Note that this record is not generated when a normal newline character was used for
-          marking the log line end.</para>
+          <para>Only applies to <literal>_TRANSPORT=stdout</literal> records: indicates that the log message
+          in the standard output/error stream was not terminated with a normal newline character
+          (<literal>\n</literal>, i.e. ASCII 10). Specifically, when set this field is one of
+          <option>nul</option> (in case the line was terminated by a NUL byte), <option>line-max</option> (in
+          case the maximum log line length was reached, as configured with <varname>LineMax=</varname> in
+          <citerefentry><refentrytitle>journald.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>),
+          <option>eof</option> (if this was the last log record of a stream and the stream ended without a
+          final newline character), or <option>pid-change</option> (if the process which generated the log
+          output changed in the middle of a line). Note that this record is not generated when a normal
+          newline character was used for marking the log line end.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
index e04618340bd2cdcb3dbd2418e9be3927ecdf8593..7e17bf095fe8432e2a9ead034fb1988fb4dd56fa 100644 (file)
       <varlistentry>
         <term><varname>RxBufferSize=</varname></term>
         <listitem>
-          <para>Takes a integer. Specifies the NIC receive ring buffer size. When unset, the kernel's default will be used.</para>
+          <para>Takes an integer. Specifies the maximum number of pending packets in the NIC receive buffer.
+          When unset, the kernel's default will be used.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>RxMiniBufferSize=</varname></term>
+        <listitem>
+          <para>Takes an integer. Specifies the maximum number of pending packets in the NIC mini receive buffer.
+          When unset, the kernel's default will be used.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>RxJumboBufferSize=</varname></term>
+        <listitem>
+          <para>Takes an integer. Specifies the maximum number of pending packets in the NIC jumbo receive buffer.
+          When unset, the kernel's default will be used.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>TxBufferSize=</varname></term>
         <listitem>
-          <para>Takes a integer. Specifies the NIC transmit ring buffer size. When unset, the kernel's default will be used.</para>
+          <para>Takes an integer. Specifies the maximum number of pending packets in the NIC transmit buffer.
+          When unset, the kernel's default will be used.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
index d775d74053fdf14180a05453f3d8381ce8e6c7b8..07feccb54a06a38869c754888e2dc61f3a8c9634 100644 (file)
         <varname>Options=</varname> setting in a unit file.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>x-systemd.rw-only</option></term>
+
+        <listitem><para>If a mount operation fails to mount the file system
+        read-write, it normally tries mounting the file system read-only instead.
+        This option disables that behaviour, and causes the mount to fail
+        immediately instead. This option is translated into the
+        <varname>ReadWriteOnly=</varname> setting in a unit file.</para>
+        </listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><option>_netdev</option></term>
 
         created. (See
         <citerefentry><refentrytitle>systemd.device</refentrytitle><manvolnum>5</manvolnum></citerefentry>
         for more information.) This option is mandatory. Note that the usual specifier expansion is applied
-        to this setting, literal percent characters should hence be written as <literal>%%</literal>. If this
-        mount is a bind mount and the specified path does not exist yet it is created as
-        directory.</para></listitem>
+        to this setting, literal percent characters should hence be written as <literal
+        class='specifiers'>%%</literal>. If this mount is a bind mount and the specified path does not exist
+        yet it is created as directory.</para></listitem>
       </varlistentry>
 
       <varlistentry>
 
         <listitem><para>Mount options to use when mounting. This takes a comma-separated list of options. This setting
         is optional. Note that the usual specifier expansion is applied to this setting, literal percent characters
-        should hence be written as <literal>%%</literal>.</para></listitem>
+        should hence be written as <literal class='specifiers'>%%</literal>.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         off.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>ReadWriteOnly=</varname></term>
+
+        <listitem><para>Takes a boolean argument. If false, a mount
+        point that shall be mounted read-write but cannot be mounted
+        so is retried to be mounted read-only. If true the operation
+        will fail immediately after the read-write mount attempt did
+        not succeed. This corresponds with
+        <citerefentry project='man-pages'><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>'s
+        <parameter>-w</parameter> switch. Defaults to
+        off.</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><varname>ForceUnmount=</varname></term>
 
index 6ad1dc9e73714598fa1bdec079bbec7d5a9969e2..026fae089f24a248185ef90fd02fb0297187956e 100644 (file)
           </para>
         </listitem>
       </varlistentry>
+      <varlistentry>
+        <term><varname>VLANProtocol=</varname></term>
+        <listitem>
+          <para>Allows setting the protocol used for VLAN filtering. Takes
+          <option>802.1q</option> or,
+          <option>802.1ad</option>, and defaults to unset and kernel's default is used.
+          </para>
+        </listitem>
+      </varlistentry>
       <varlistentry>
         <term><varname>STP=</varname></term>
         <listitem>
index 43fc7efb74b9bf6ab8f10e4c1543b089659a0824..1aa9b132df71efe677fabc0dacb35f9e6bf05a76 100644 (file)
           controlled by other applications.</para>
         </listitem>
       </varlistentry>
+      <varlistentry>
+        <term><varname>Group=</varname></term>
+        <listitem>
+          <para>Link groups are similar to port ranges found in managed switches.
+          When network interfaces are added to a numbered group, operations on
+          all the interfaces from that group can be performed at once. An unsigned
+          integer ranges 0 to 4294967294. Default to unset.</para>
+        </listitem>
+      </varlistentry>
       <varlistentry>
         <term><varname>RequiredForOnline=</varname></term>
         <listitem>
             <literal>nearest-bridge</literal>, <literal>non-tpmr-bridge</literal> and
             <literal>customer-bridge</literal>.  Defaults to false, which turns off LLDP packet emission. If not false,
             a short LLDP packet with information about the local system is sent out in regular intervals on the
-            link. The LLDP packet will contain information about the local host name, the local machine ID (as stored
+            link. The LLDP packet will contain information about the local hostname, the local machine ID (as stored
             in <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>) and the
             local interface name, as well as the pretty hostname of the system (as set in
             <citerefentry><refentrytitle>machine-info</refentrytitle><manvolnum>5</manvolnum></citerefentry>). LLDP
             this link. Each item in the list should be a domain name, optionally prefixed with a tilde
             (<literal>~</literal>). The domains with the prefix are called "routing-only domains". The
             domains without the prefix are called "search domains" and are first used as search suffixes for
-            extending single-label host names (host names containing no dots) to become fully qualified
-            domain names (FQDNs). If a single-label host name is resolved on this interface, each of the
+            extending single-label hostnames (hostnames containing no dots) to become fully qualified
+            domain names (FQDNs). If a single-label hostname is resolved on this interface, each of the
             specified search domains are appended to it in turn, converting it into a fully qualified domain
             name, until one of them may be successfully resolved.</para>
 
-            <para>Both "search" and "routing-only" domains are used for routing of DNS queries: look-ups for host names
+            <para>Both "search" and "routing-only" domains are used for routing of DNS queries: look-ups for hostnames
             ending in those domains (hence also single label names, if any "search domains" are listed), are routed to
             the DNS servers configured for this interface. The domain routing logic is particularly useful on
             multi-homed hosts with DNS servers serving particular private DNS zones on each interface.</para>
             false.</para>
 
             <para>It is recommended to enable this option only on trusted networks, as setting this affects resolution
-            of all host names, in particular of single-label names. It is generally safer to use the supplied domain
+            of all hostnames, in particular of single-label names. It is generally safer to use the supplied domain
             only as routing domain, rather than as search domain, in order to not have it affect local resolution of
             single-label names.</para>
 
           </listitem>
         </varlistentry>
 
+         <varlistentry>
+          <term><varname>FallbackLeaseLifetimeSec=</varname></term>
+          <listitem>
+            <para>Allows to set DHCPv4 lease lifetime when DHCPv4 server does not send the lease lifetime.
+            Takes one of <literal>forever</literal> or <literal>infinity</literal> means that the address
+            never expires. Defaults to unset.</para>
+          </listitem>
+        </varlistentry>
+
         <varlistentry>
           <term><varname>SendRelease=</varname></term>
           <listitem>
         <varlistentry>
           <term><varname>RequestOptions=</varname></term>
           <listitem>
-            <para>A whitespace-separated list of integers in the range 1–254.</para>
+            <para>When configured, allows to set arbitrary request options in the DHCPv4 request options list and will be
+            sent to the DHCPV4 server. A whitespace-separated list of integers in the range 1..254. Defaults to unset.</para>
           </listitem>
         </varlistentry>
 
           </listitem>
         </varlistentry>
 
+        <varlistentry>
+          <term><varname>RequestOptions=</varname></term>
+          <listitem>
+            <para>When configured, allows to set arbitrary request options in the DHCPv6 request options list and will
+            sent to the DHCPV6 server. A whitespace-separated list of integers in the range 1..254. Defaults to unset.</para>
+          </listitem>
+        </varlistentry>
+
         <varlistentry>
           <term><varname>ForceDHCPv6PDOtherInformation=</varname></term>
           <listitem>
           <listitem>
             <para>Takes an IPv6 address with prefix length as <varname>Address=</varname> in
             the "[Network]" section. Specifies the DHCPv6 client for the requesting router to include
-            a prefix-hint in the DHCPv6 solicitation. Prefix ranges 1-128. Defaults to unset.</para>
+            a prefix-hint in the DHCPv6 solicitation. Prefix ranges 1..128. Defaults to unset.</para>
           </listitem>
         </varlistentry>
 
             Defaults to false.</para>
           </listitem>
         </varlistentry>
+
+        <varlistentry>
+          <term><varname>SendOption=</varname></term>
+          <listitem>
+            <para>As in the <literal>[DHCPv4]</literal> section, however because DHCPv6 uses 16-bit fields to store
+            option numbers, the option number is an integer in the range 1..65536.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>UserClass=</varname></term>
+          <listitem>
+            <para>A DHCPv6 client can use User Class option to identify the type or category of user or applications
+            it represents. The information contained in this option is a string that represents the user class of which
+            the client is a member. Each class sets an identifying string of information to be used by the DHCP
+            service to classify clients. Special characters in the data string may be escaped using
+            <ulink url="https://en.wikipedia.org/wiki/Escape_sequences_in_C#Table_of_escape_sequences">C-style
+            escapes</ulink>. This setting can be specified multiple times. If an empty string is specified,
+            then all options specified earlier are cleared. Takes a whitespace-separated list of strings. Note that
+            currently NUL bytes are not allowed.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>VendorClass=</varname></term>
+          <listitem>
+            <para>A DHCPv6 client can use VendorClass option to identify the vendor that
+            manufactured the hardware on which the client is running. The information
+            contained in the data area of this option is contained in one or more opaque
+            fields that identify details of the hardware configuration. Takes a
+            whitespace-separated list of strings.</para>
+          </listitem>
+        </varlistentry>
       </variablelist>
   </refsect1>
 
             <literal>~</literal>. Defaults to false.</para>
 
             <para>It is recommended to enable this option only on trusted networks, as setting this affects resolution
-            of all host names, in particular of single-label names. It is generally safer to use the supplied domain
+            of all hostnames, in particular of single-label names. It is generally safer to use the supplied domain
             only as routing domain, rather than as search domain, in order to not have it affect local resolution of
             single-label names.</para>
 
           <para>Send a raw option with value via DHCPv4 server. Takes a DHCP option number, data type
           and data (<literal><replaceable>option</replaceable>:<replaceable>type</replaceable>:<replaceable>value</replaceable></literal>).
           The option number is an integer in the range 1..254. The type takes one of <literal>uint8</literal>,
-          <literal>uint16</literal>, <literal>uint32</literal>, <literal>ipv4address</literal>, or
+          <literal>uint16</literal>, <literal>uint32</literal>, <literal>ipv4address</literal>, <literal>ipv6address</literal>, or
           <literal>string</literal>. Special characters in the data string may be escaped using
           <ulink url="https://en.wikipedia.org/wiki/Escape_sequences_in_C#Table_of_escape_sequences">C-style
           escapes</ulink>. This setting can be specified multiple times. If an empty string is specified,
index 398fd69b46979c39624df559cf319e887e01e677..0cfd0853c6b29711115669146adcec7327bc8cf9 100644 (file)
 
       <varlistentry>
         <term><varname>SuccessExitStatus=</varname></term>
+
         <listitem><para>Takes a list of exit status definitions that, when returned by the main service
-        process, will be considered successful termination, in addition to the normal successful exit code 0
-        and the signals <constant>SIGHUP</constant>, <constant>SIGINT</constant>,
+        process, will be considered successful termination, in addition to the normal successful exit status
+        and the signals <constant>SIGHUP</constant>, <constant>SIGINT</constant>,
         <constant>SIGTERM</constant>, and <constant>SIGPIPE</constant>. Exit status definitions can be
-        numeric exit codes, termination code names, or termination signal names, separated by spaces. See the
-        Process Exit Codes section in
+        numeric termination statuses, termination status names, or termination signal names, separated by
+        spaces. See the Process Exit Codes section in
         <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
-        a list of termination codes names (for this setting only the part without the
-        <literal>EXIT_</literal> or <literal>EX_</literal> prefix should be used). See
-        <citerefentry project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
+        a list of termination status names (for this setting only the part without the
+        <literal>EXIT_</literal> or <literal>EX_</literal> prefix should be used). See <citerefentry
+        project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
         a list of signal names.</para>
 
-        <para>This option may appear more than once, in which case the
-        list of successful exit statuses is merged. If the empty
-        string is assigned to this option, the list is reset, all
-        prior assignments of this option will have no
-        effect.</para>
+        <para>Note that this setting does not change the the mapping between numeric exit statuses and their
+        names, i.e. regardless how this setting is used 0 will still be mapped to <literal>SUCCESS</literal>
+        (and thus typically shown as <literal>0/SUCCESS</literal> in tool outputs) and 1 to
+        <literal>FAILURE</literal> (and thus typically shown as <literal>1/FAILURE</literal>), and so on. It
+        only controls what happens as effect of these exit statuses, and how it propagates to the state of
+        the service as a whole.</para>
+
+        <para>This option may appear more than once, in which case the list of successful exit statuses is
+        merged. If the empty string is assigned to this option, the list is reset, all prior assignments of
+        this option will have no effect.</para>
 
         <example>
           <title>A service with with the <varname>SuccessExitStatus=</varname> setting</title>
 
           <programlisting>SuccessExitStatus=TEMPFAIL 250 SIGUSR1</programlisting>
 
-          <para>Exit codes 75 (<constant>TEMPFAIL</constant>), 250, and the termination signal
+          <para>Exit status 75 (<constant>TEMPFAIL</constant>), 250, and the termination signal
           <constant>SIGKILL</constant> are considered clean service terminations.</para>
         </example>
 
-        <para>Note: <command>systemd-analyze exit-codes</command> may be used to list exit
-        codes and translate between numerical code values and names.</para></listitem>
+        <para>Note: <command>systemd-analyze exit-status</command> may be used to list exit statuses and
+        translate between numerical status values and names.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <option>exec</option>. Conversely, if an auxiliary process of the unit sends an
         <function>sd_notify()</function> message and immediately exits, the service manager might not be able to
         properly attribute the message to the unit, and thus will ignore it, even if
-        <varname>NotifyAccess=</varname><option>all</option> is set for it.</para></listitem>
+        <varname>NotifyAccess=</varname><option>all</option> is set for it.</para>
+
+        <para>Hence, to eliminate all race conditions involving lookup of the client's unit and attribution of notifications
+        to units correctly, <function>sd_notify_barrier()</function> may be used. This call acts as a synchronization point
+        and ensures all notifications sent before this call have been picked up by the service manager when it returns
+        successfully. Use of <function>sd_notify_barrier()</function> is needed for clients which are not invoked by the
+        service manager, otherwise this synchronization mechanism is unnecessary for attribution of notifications to the
+        unit.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index 190fc388c0911a5d64a7520ba9d5e659553ad5ad..c4160290a5142787f38c00cf9c95c7a0fa0d8efc 100644 (file)
         project='man-pages'><refentrytitle>swapon</refentrytitle><manvolnum>8</manvolnum></citerefentry> for
         details. If this refers to a device node, a dependency on the respective device unit is automatically
         created. (See
-        <citerefentry><refentrytitle>systemd.device</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more
-        information.) If this refers to a file, a dependency on the respective mount unit is automatically
-        created. (See <citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-        for more information.) This option is mandatory. Note that the usual specifier expansion is applied to this
-        setting, literal percent characters should hence be written as <literal>%%</literal>.</para></listitem>
+        <citerefentry><refentrytitle>systemd.device</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+        for more information.) If this refers to a file, a dependency on the respective mount unit is
+        automatically created. (See
+        <citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
+        more information.) This option is mandatory. Note that the usual specifier expansion is applied to
+        this setting, literal percent characters should hence be written as
+        <literal class='specifiers'>%%</literal>.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index dc1e78a18752b7cf7c9ce6918df2d5152f8e2227..b4656b05d10ba07e108cd3023e75f0410ff82206 100644 (file)
@@ -199,15 +199,14 @@ tomorrow Pacific/Auckland → Thu 2012-11-23 19:00:00
     continuous weekdays. <literal>,</literal> and <literal>..</literal>
     may be combined freely.</para>
 
-    <para>In the date and time specifications, any component may be
-    specified as <literal>*</literal> in which case any value will
-    match. Alternatively, each component can be specified as a list of
-    values separated by commas. Values may be suffixed with
-    <literal>/</literal> and a repetition value, which indicates that
-    the value itself and the value plus all multiples of the repetition value
-    are matched.  Two values separated by <literal>..</literal> may be used
-    to indicate a range of values; ranges may also be followed with
-    <literal>/</literal> and a repetition value.</para>
+    <para>In the date and time specifications, any component may be specified as <literal>*</literal> in
+    which case any value will match. Alternatively, each component can be specified as a list of values
+    separated by commas. Values may be suffixed with <literal>/</literal> and a repetition value, which
+    indicates that the value itself and the value plus all multiples of the repetition value are matched.
+    Two values separated by <literal>..</literal> may be used to indicate a range of values; ranges may also
+    be followed with <literal>/</literal> and a repetition value, in which case the expression matches all
+    times starting with the start value, and continuing with all multiples of the repetition value relative
+    to the start value, ending at the end value the latest.</para>
 
     <para>A date specification may use <literal>~</literal> to indicate the
     last day(s) in a month. For example, <literal>*-02~03</literal> means
index c26937e752f506428fe9c39658a028db36480019..fa8ed1b47bbeb89d113bdbb8779f4b269b9371e9 100644 (file)
@@ -6,7 +6,8 @@
 ]>
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
-<refentry id="systemd.unit">
+<refentry id="systemd.unit"
+          xmlns:xi="http://www.w3.org/2001/XInclude">
 
   <refentryinfo>
     <title>systemd.unit</title>
           </listitem>
         </varlistentry>
 
+        <varlistentry>
+          <term><varname>ConditionEnvironment=</varname></term>
+
+          <listitem><para><varname>ConditionEnvironment=</varname> may be used to check whether a specific
+          environment variable is set (or if prefixed with the exclamation mark — unset) in the service
+          manager's environment block.
+
+          The argument may be a single word, to check if the variable with this name is defined in the
+          environment block, or an assignment
+          (<literal><replaceable>name</replaceable>=<replaceable>value</replaceable></literal>), to check if
+          the variable with this exact value is defined. Note that the environment block of the service
+          manager itself is checked, i.e. not any variables defined with <varname>Environment=</varname> or
+          <varname>EnvironmentFile=</varname>, as described above. This is particularly useful when the
+          service manager runs inside a containerized environment or as per-user service manager, in order to
+          check for variables passed in by the enclosing container manager or PAM.</para>
+          </listitem>
+        </varlistentry>
+
         <varlistentry>
           <term><varname>ConditionSecurity=</varname></term>
 
           <citerefentry><refentrytitle>systemd-update-done.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
           to make sure they run before the stamp file's modification time gets reset indicating a completed
           update.</para>
+
+          <para>If the <varname>systemd.condition-needs-update=</varname> option is specified on the kernel
+          command line (taking a boolean), it will override the result of this condition check, taking
+          precedence over any file modification time checks. If it is used
+          <filename>systemd-update-done.service</filename> will not have immediate effect on any following
+          <varname>ConditionNeedsUpdate=</varname> checks, until the system is rebooted where the kernel
+          command line option is not specified anymore.</para>
           </listitem>
         </varlistentry>
 
           (specifically: an <filename>/etc</filename> with no <filename>/etc/machine-id</filename>). This may
           be used to populate <filename>/etc</filename> on the first boot after factory reset, or when a new
           system instance boots up for the first time.</para>
+
+          <para>If the <varname>systemd.condition-first-boot=</varname> option is specified on the kernel
+          command line (taking a boolean), it will override the result of this condition check, taking
+          precedence over <filename>/etc/machine-id</filename> existence checks.</para>
           </listitem>
         </varlistentry>
 
           </listitem>
         </varlistentry>
 
+        <varlistentry>
+          <term><varname>ConditionPathIsEncrypted=</varname></term>
+
+          <listitem><para><varname>ConditionPathIsEncrypted=</varname> is similar to
+          <varname>ConditionPathExists=</varname> but verifies that the underlying file system's backing
+          block device is encrypted using dm-crypt/LUKS. Note that this check does not cover ext4
+          per-directory encryption, and only detects block level encryption. Moreover, if the specified path
+          resides on a file system on top of a loopback block device, only encryption above the loopback device is
+          detected. It is not detected whether the file system backing the loopback block device is encrypted.</para>
+          </listitem>
+        </varlistentry>
+
         <varlistentry>
           <term><varname>ConditionDirectoryNotEmpty=</varname></term>
 
     and resolvable for the setting to be valid. The following
     specifiers are understood:</para>
 
-    <table>
+    <table class='specifiers'>
       <title>Specifiers available in unit files</title>
       <tgroup cols='3' align='left' colsep='1' rowsep='1'>
         <colspec colname="spec" />
         </thead>
         <tbody>
           <row>
-            <entry><literal>%b</literal></entry>
-            <entry>Boot ID</entry>
-            <entry>The boot ID of the running system, formatted as string. See <citerefentry><refentrytitle>random</refentrytitle><manvolnum>4</manvolnum></citerefentry> for more information.</entry>
+            <!-- We do not use the common definition from standard-specifiers.xml here since it includes a
+                 reference onto our own man page, which would make the rendered version self-referential. -->
+            <entry><literal>%a</literal></entry>
+            <entry>Architecture</entry>
+            <entry>A short string identifying the architecture of the local system. A string such as <constant>x86</constant>, <constant>x86-64</constant> or <constant>arm64</constant>. See the architectures defined for <varname>ConditionArchitecture=</varname> above for a full list.</entry>
           </row>
+          <xi:include href="standard-specifiers.xml" xpointer="b"/>
+          <xi:include href="standard-specifiers.xml" xpointer="B"/>
           <row>
             <entry><literal>%C</literal></entry>
             <entry>Cache directory root</entry>
 Note that this setting is <emphasis>not</emphasis> influenced by the <varname>User=</varname> setting configurable in the [Service] section of the service unit.</entry>
           </row>
           <row>
+            <!-- We do not use the common definition from standard-specifiers.xml here since we want a
+                 slightly more verbose explanation here, referring to the reload cycle. -->
             <entry><literal>%H</literal></entry>
             <entry>Host name</entry>
             <entry>The hostname of the running system at the point in time the unit configuration is loaded.</entry>
           </row>
+          <row>
+            <entry><literal>%l</literal></entry>
+            <entry>Short host name</entry>
+            <entry>The hostname of the running system at the point in time the unit configuration is loaded, truncated at the first dot to remove any domain component.</entry>
+          </row>
           <row>
             <entry><literal>%i</literal></entry>
             <entry>Instance name</entry>
@@ -1765,11 +1818,8 @@ Note that this setting is <emphasis>not</emphasis> influenced by the <varname>Us
             <entry>Log directory root</entry>
             <entry>This is either <filename>/var/log</filename> (for the system manager) or the path <literal>$XDG_CONFIG_HOME</literal> resolves to with <filename index="false">/log</filename> appended (for user managers).</entry>
           </row>
-          <row>
-            <entry><literal>%m</literal></entry>
-            <entry>Machine ID</entry>
-            <entry>The machine ID of the running system, formatted as string. See <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
-          </row>
+          <xi:include href="standard-specifiers.xml" xpointer="m"/>
+          <xi:include href="standard-specifiers.xml" xpointer="o"/>
           <row>
             <entry><literal>%n</literal></entry>
             <entry>Full unit name</entry>
@@ -1834,21 +1884,15 @@ Note that this setting is <emphasis>not</emphasis> influenced by the <varname>Us
 
 Note that this setting is <emphasis>not</emphasis> influenced by the <varname>User=</varname> setting configurable in the [Service] section of the service unit.</entry>
           </row>
-          <row>
-            <entry><literal>%v</literal></entry>
-            <entry>Kernel release</entry>
-            <entry>Identical to <command>uname -r</command> output</entry>
-          </row>
+          <xi:include href="standard-specifiers.xml" xpointer="v"/>
           <row>
             <entry><literal>%V</literal></entry>
             <entry>Directory for larger and persistent temporary files</entry>
             <entry>This is either <filename>/var/tmp</filename> or the path <literal>$TMPDIR</literal>, <literal>$TEMP</literal> or <literal>$TMP</literal> are set to.</entry>
           </row>
-          <row>
-            <entry><literal>%%</literal></entry>
-            <entry>Single percent sign</entry>
-            <entry>Use <literal>%%</literal> in place of <literal>%</literal> to specify a single percent sign.</entry>
-          </row>
+          <xi:include href="standard-specifiers.xml" xpointer="w"/>
+          <xi:include href="standard-specifiers.xml" xpointer="W"/>
+          <xi:include href="standard-specifiers.xml" xpointer="percent"/>
         </tbody>
       </tgroup>
     </table>
index 1534027d927b1f068e74d2e66c1214c57705e0cc..11954a78da8ed2ef14686298245dd50ee78b0ad0 100644 (file)
     execution compared to the target unit's state and is marked successful and
     complete when both satisfy. However, this job also pulls in other
     dependencies due to the defined relationships and thus leads to, in our
-    our example, start jobs for any of those inactive units getting queued as
+    example, start jobs for any of those inactive units getting queued as
     well.</para>
 
     <para>systemd contains native implementations of various tasks
     <citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
 
     <para>The D-Bus API of <command>systemd</command> is described in
-    <citerefentry><refentrytitle>org.freedesktop.systemd1</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+    <citerefentry><refentrytitle>org.freedesktop.systemd1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+    and
+    <citerefentry><refentrytitle>org.freedesktop.LogControl1</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+    </para>
 
     <para>Systems which invoke systemd in a container or initrd environment should implement the <ulink
     url="https://systemd.io/CONTAINER_INTERFACE">Container Interface</ulink> or <ulink
index f0e0f2bedc1606f38de928da2fa5ed54b0bc64ef..38a95d6e1fcdc280f241dcfdd876a0c572a622ef 100644 (file)
@@ -234,61 +234,49 @@ r     -        500-900
   <refsect1>
     <title>Specifiers</title>
 
-    <para>Specifiers can be used in the "Name", "ID", "GECOS", "Home directory", and "Shell" fields.
-    An unknown or unresolvable specifier is treated as invalid configuration.
-    The following expansions are understood:</para>
-      <table>
-        <title>Specifiers available</title>
-        <tgroup cols='3' align='left' colsep='1' rowsep='1'>
-          <colspec colname="spec" />
-          <colspec colname="mean" />
-          <colspec colname="detail" />
-          <thead>
-            <row>
-              <entry>Specifier</entry>
-              <entry>Meaning</entry>
-              <entry>Details</entry>
-            </row>
-          </thead>
-          <tbody>
-            <row>
-              <entry><literal>%b</literal></entry>
-              <entry>Boot ID</entry>
-              <entry>The boot ID of the running system, formatted as string. See <citerefentry><refentrytitle>random</refentrytitle><manvolnum>4</manvolnum></citerefentry> for more information.</entry>
-            </row>
-            <row>
-              <entry><literal>%H</literal></entry>
-              <entry>Host name</entry>
-              <entry>The hostname of the running system.</entry>
-            </row>
-            <row>
-              <entry><literal>%m</literal></entry>
-              <entry>Machine ID</entry>
-              <entry>The machine ID of the running system, formatted as string. See <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
-            </row>
-            <row>
-              <entry><literal>%T</literal></entry>
-              <entry>Directory for temporary files</entry>
-              <entry>This is either <filename>/tmp</filename> or the path <literal>$TMPDIR</literal>, <literal>$TEMP</literal> or <literal>$TMP</literal> are set to.</entry>
-            </row>
-            <row>
-              <entry><literal>%v</literal></entry>
-              <entry>Kernel release</entry>
-              <entry>Identical to <command>uname -r</command> output.</entry>
-            </row>
-            <row>
-              <entry><literal>%V</literal></entry>
-              <entry>Directory for larger and persistent temporary files</entry>
-              <entry>This is either <filename>/var/tmp</filename> or the path <literal>$TMPDIR</literal>, <literal>$TEMP</literal> or <literal>$TMP</literal> are set to.</entry>
-            </row>
-            <row>
-              <entry><literal>%%</literal></entry>
-              <entry>Escaped <literal>%</literal></entry>
-              <entry>Single percent sign.</entry>
-            </row>
-          </tbody>
-        </tgroup>
-      </table>
+    <para>Specifiers can be used in the <literal>Name</literal>, <literal>ID</literal>,
+    <literal>GECOS</literal>, <literal>Home directory</literal>, and <literal>Shell</literal> fields. An
+    unknown or unresolvable specifier is treated as invalid configuration. The following expansions are
+    understood:</para>
+
+    <table class='specifiers'>
+      <title>Specifiers available</title>
+      <tgroup cols='3' align='left' colsep='1' rowsep='1'>
+        <colspec colname="spec" />
+        <colspec colname="mean" />
+        <colspec colname="detail" />
+        <thead>
+          <row>
+            <entry>Specifier</entry>
+            <entry>Meaning</entry>
+            <entry>Details</entry>
+          </row>
+        </thead>
+        <tbody>
+          <xi:include href="standard-specifiers.xml" xpointer="a"/>
+          <xi:include href="standard-specifiers.xml" xpointer="b"/>
+          <xi:include href="standard-specifiers.xml" xpointer="B"/>
+          <xi:include href="standard-specifiers.xml" xpointer="H"/>
+          <xi:include href="standard-specifiers.xml" xpointer="l"/>
+          <xi:include href="standard-specifiers.xml" xpointer="m"/>
+          <xi:include href="standard-specifiers.xml" xpointer="o"/>
+          <row>
+            <entry><literal>%T</literal></entry>
+            <entry>Directory for temporary files</entry>
+            <entry>This is either <filename>/tmp</filename> or the path <literal>$TMPDIR</literal>, <literal>$TEMP</literal> or <literal>$TMP</literal> are set to.</entry>
+          </row>
+          <xi:include href="standard-specifiers.xml" xpointer="v"/>
+          <row>
+            <entry><literal>%V</literal></entry>
+            <entry>Directory for larger and persistent temporary files</entry>
+            <entry>This is either <filename>/var/tmp</filename> or the path <literal>$TMPDIR</literal>, <literal>$TEMP</literal> or <literal>$TMP</literal> are set to.</entry>
+          </row>
+          <xi:include href="standard-specifiers.xml" xpointer="w"/>
+          <xi:include href="standard-specifiers.xml" xpointer="W"/>
+          <xi:include href="standard-specifiers.xml" xpointer="percent"/>
+        </tbody>
+      </tgroup>
+    </table>
   </refsect1>
 
   <refsect1>
index a29c913ff078c682b8ce7932c866fb00bcbe63b3..b9e9eee96c8a7330f1855238941cb149113257d0 100644 (file)
@@ -6,7 +6,8 @@
 
   Copyright © 2010 Brandon Philips
 -->
-<refentry id="tmpfiles.d">
+<refentry id="tmpfiles.d"
+          xmlns:xi="http://www.w3.org/2001/XInclude">
 
   <refentryinfo>
     <title>tmpfiles.d</title>
@@ -120,16 +121,19 @@ A+    /path-or-glob/to/append/acls/recursively -    -    -     -           POSIX
     <filename>/usr/lib/tmpfiles.d</filename> and <filename>/run/tmpfiles.d</filename>. Files in
     <filename>/run/tmpfiles.d</filename> override files with the same name in
     <filename>/usr/lib/tmpfiles.d</filename>. Packages should install their configuration files in
-    <filename>/usr/lib/tmpfiles.d</filename>. Files in <filename>/etc/tmpfiles.d</filename> are reserved for the local
-    administrator, who may use this logic to override the configuration files installed by vendor packages. All
-    configuration files are sorted by their filename in lexicographic order, regardless of which of the directories
-    they reside in. If multiple files specify the same path, the entry in the file with the lexicographically earliest
-    name will be applied.  All other conflicting entries will be logged as errors. When two lines are prefix path and
-    suffix path of each other, then the prefix line is always created first, the suffix later (and if removal applies
-    to the line, the order is reversed: the suffix is removed first, the prefix later). Lines that take globs are
-    applied after those accepting no globs. If multiple operations shall be applied on the same file (such as ACL,
-    xattr, file attribute adjustments), these are always done in the same fixed order. Except for those cases, the
-    files/directories are processed in the order they are listed.</para>
+    <filename>/usr/lib/tmpfiles.d</filename>. Files in <filename>/etc/tmpfiles.d</filename> are reserved for
+    the local administrator, who may use this logic to override the configuration files installed by vendor
+    packages. All configuration files are sorted by their filename in lexicographic order, regardless of
+    which of the directories they reside in. If multiple files specify the same path, the entry in the file
+    with the lexicographically earliest name will be applied (note that lines suppressed due to the
+    <literal>!</literal> are filtered before application, meaning that if an early line carries the
+    exclamation mark and is suppressed because of that, a later line matching in path will be applied).  All
+    other conflicting entries will be logged as errors. When two lines are prefix path and suffix path of
+    each other, then the prefix line is always created first, the suffix later (and if removal applies to the
+    line, the order is reversed: the suffix is removed first, the prefix later). Lines that take globs are
+    applied after those accepting no globs. If multiple operations shall be applied on the same file (such as
+    ACL, xattr, file attribute adjustments), these are always done in the same fixed order. Except for those
+    cases, the files/directories are processed in the order they are listed.</para>
 
     <para>If the administrator wants to disable a configuration file
     supplied by the vendor, the recommended way is to place a symlink
@@ -153,8 +157,8 @@ L     /tmp/foobar -    -    -     -   /dev/null</programlisting>
     <refsect2>
       <title>Type</title>
 
-      <para>The type consists of a single letter and optionally an
-      exclamation mark and/or minus sign.</para>
+      <para>The type consists of a single letter and optionally an exclamation mark (<literal>!</literal>)
+      and/or minus sign (<literal>-</literal>).</para>
 
       <para>The following line types are understood:</para>
 
@@ -452,13 +456,10 @@ L     /tmp/foobar -    -    -     -   /dev/null</programlisting>
         </varlistentry>
       </variablelist>
 
-      <para>If the exclamation mark is used, this line is only safe to
-      execute during boot, and can break a running system. Lines
-      without the exclamation mark are presumed to be safe to execute
-      at any time, e.g. on package upgrades.
-      <command>systemd-tmpfiles</command> will execute line with an
-      exclamation mark only if option <option>--boot</option> is
-      given.</para>
+      <para>If the exclamation mark (<literal>!</literal>) is used, this line is only safe to execute during
+      boot, and can break a running system. Lines without the exclamation mark are presumed to be safe to
+      execute at any time, e.g. on package upgrades. <command>systemd-tmpfiles</command> will take lines with
+      an exclamation mark only into consideration, if the <option>--boot</option> option is given.</para>
 
       <para>For example:
       <programlisting># Make sure these are created by default so that nobody else can
@@ -470,9 +471,8 @@ r! /tmp/.X[0-9]*-lock</programlisting>
       running system, and will only be executed with
       <option>--boot</option>.</para>
 
-      <para>If the minus sign is used, this line failing to run
-      successfully during create (and only create) will not cause
-      the execution of <command>systemd-tmpfiles</command> to return
+      <para>If the minus sign (<literal>-</literal>) is used, this line failing to run successfully during
+      create (and only create) will not cause the execution of <command>systemd-tmpfiles</command> to return
       an error.</para>
 
       <para>For example:
@@ -617,7 +617,7 @@ w- /proc/sys/vm/swappiness - - - - 10</programlisting></para>
     <para>Specifiers can be used in the "path" and "argument" fields.
     An unknown or unresolvable specifier is treated as invalid configuration.
     The following expansions are understood:</para>
-      <table>
+      <table class='specifiers'>
         <title>Specifiers available</title>
         <tgroup cols='3' align='left' colsep='1' rowsep='1'>
           <colspec colname="spec" />
@@ -631,11 +631,9 @@ w- /proc/sys/vm/swappiness - - - - 10</programlisting></para>
             </row>
           </thead>
           <tbody>
-            <row>
-              <entry><literal>%b</literal></entry>
-              <entry>Boot ID</entry>
-              <entry>The boot ID of the running system, formatted as string. See <citerefentry><refentrytitle>random</refentrytitle><manvolnum>4</manvolnum></citerefentry> for more information.</entry>
-            </row>
+            <xi:include href="standard-specifiers.xml" xpointer="a"/>
+            <xi:include href="standard-specifiers.xml" xpointer="b"/>
+            <xi:include href="standard-specifiers.xml" xpointer="B"/>
             <row>
               <entry><literal>%C</literal></entry>
               <entry>System or user cache directory</entry>
@@ -646,21 +644,15 @@ w- /proc/sys/vm/swappiness - - - - 10</programlisting></para>
               <entry>User home directory</entry>
               <entry>This is the home directory of the user running the command. In case of the system instance this resolves to <literal>/root</literal>.</entry>
             </row>
-            <row>
-              <entry><literal>%H</literal></entry>
-              <entry>Host name</entry>
-              <entry>The hostname of the running system.</entry>
-            </row>
+            <xi:include href="standard-specifiers.xml" xpointer="H"/>
+            <xi:include href="standard-specifiers.xml" xpointer="l"/>
             <row>
               <entry><literal>%L</literal></entry>
               <entry>System or user log directory</entry>
               <entry>In <option>--user</option> mode, this is the same as <varname>$XDG_CONFIG_HOME</varname> with <filename index="false">/log</filename> appended, and <filename>/var/log</filename> otherwise.</entry>
             </row>
-            <row>
-              <entry><literal>%m</literal></entry>
-              <entry>Machine ID</entry>
-              <entry>The machine ID of the running system, formatted as string. See <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
-            </row>
+            <xi:include href="standard-specifiers.xml" xpointer="m"/>
+            <xi:include href="standard-specifiers.xml" xpointer="o"/>
             <row>
               <entry><literal>%S</literal></entry>
               <entry>System or user state directory</entry>
@@ -696,21 +688,15 @@ w- /proc/sys/vm/swappiness - - - - 10</programlisting></para>
               <entry>User UID</entry>
               <entry>This is the numeric UID of the user running the command. In case of the system instance this resolves to <constant>0</constant>.</entry>
             </row>
-            <row>
-              <entry><literal>%v</literal></entry>
-              <entry>Kernel release</entry>
-              <entry>Identical to <command>uname -r</command> output.</entry>
-            </row>
+            <xi:include href="standard-specifiers.xml" xpointer="v"/>
             <row>
               <entry><literal>%V</literal></entry>
               <entry>Directory for larger and persistent temporary files</entry>
               <entry>This is either <filename>/var/tmp</filename> or the path <literal>$TMPDIR</literal>, <literal>$TEMP</literal> or <literal>$TMP</literal> are set to.</entry>
             </row>
-            <row>
-              <entry><literal>%%</literal></entry>
-              <entry>Escaped <literal>%</literal></entry>
-              <entry>Single percent sign.</entry>
-            </row>
+            <xi:include href="standard-specifiers.xml" xpointer="w"/>
+            <xi:include href="standard-specifiers.xml" xpointer="W"/>
+            <xi:include href="standard-specifiers.xml" xpointer="percent"/>
           </tbody>
         </tgroup>
       </table>
index 98c20eec5227d191fe974a1728dc250725900493..dede12befdfbc83a24b01dd45085fe28430967a3 100644 (file)
@@ -27,6 +27,30 @@ static const sd_bus_vtable vtable[] = {
             "s", SD_BUS_PARAM(returnstring),
             method, offsetof(object, number),
             SD_BUS_VTABLE_DEPRECATED),
+        SD_BUS_METHOD_WITH_ARGS_OFFSET(
+            "Method3",
+            SD_BUS_ARGS("s", string, "o", path),
+            SD_BUS_RESULT("s", returnstring),
+            method, offsetof(object, number),
+            SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS(
+            "Method4",
+            SD_BUS_NO_ARGS,
+            SD_BUS_NO_RESULT,
+            method,
+            SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_SIGNAL(
+            "Signal1",
+            "so",
+            0),
+        SD_BUS_SIGNAL_WITH_NAMES(
+            "Signal2",
+            "so", SD_BUS_PARAM(string) SD_BUS_PARAM(path),
+            0),
+        SD_BUS_SIGNAL_WITH_ARGS(
+            "Signal3",
+            SD_BUS_ARGS("s", string, "o", path),
+            0),
         SD_BUS_WRITABLE_PROPERTY(
             "AutomaticStringProperty", "s", NULL, NULL,
             offsetof(object, name),
index c0717b364ecbd87bec29bdb9080f6cfd428959cd..651246d6a1e464ffb5e38d593bcdd6be19a2d247 100644 (file)
@@ -23,8 +23,9 @@ dd if=/dev/urandom of=plaintext.bin bs=128 count=1
 base64 < plaintext.bin | tr -d '\n\r\t ' > plaintext.base64
 
 # Encrypt this newly generated (binary) LUKS decryption key using the public key whose private key is on the
-# Yubikey, store the result in /etc/encrypted-luks-key.bin, where we'll look for it during boot.
-sudo openssl rsautl -encrypt -pubin -inkey pubkey.pem -in plaintext.bin -out /etc/encrypted-luks-key.bin
+# Yubikey, store the result in /etc/cryptsetup-keys.d/mytest.key, where we'll look for it during boot.
+mkdir -p /etc/cryptsetup-keys.d
+sudo openssl rsautl -encrypt -pubin -inkey pubkey.pem -in plaintext.bin -out /etc/cryptsetup-keys.d/mytest.key
 
 # Configure the LUKS decryption key on the LUKS device. We use very low pbkdf settings since the key already
 # has quite a high quality (it comes directly from /dev/urandom after all), and thus we don't need to do much
@@ -40,8 +41,10 @@ shred -u plaintext.bin plaintext.base64
 rm pubkey.pem
 
 # Test: Let's run systemd-cryptsetup to test if this all worked. The option string should contain the full
-# PKCS#11 URI we have in the clipboard, it tells the tool how to decipher the encrypted LUKS key.
-sudo systemd-cryptsetup attach mytest /dev/sdXn /etc/encrypted-luks-key.bin 'pkcs11-uri=pkcs11:…'
+# PKCS#11 URI we have in the clipboard; it tells the tool how to decipher the encrypted LUKS key. Note that
+# systemd-cryptsetup automatically searches for the encrypted key in /etc/cryptsetup-keys.d/, hence we do
+# not need to specify the key file path explicitly here.
+sudo systemd-cryptsetup attach mytest /dev/sdXn - 'pkcs11-uri=pkcs11:…'
 
 # If that worked, let's now add the same line persistently to /etc/crypttab, for the future.
-sudo bash -c 'echo "mytest /dev/sdXn /etc/encrypted-luks-key \'pkcs11-uri=pkcs11:…\'" >> /etc/crypttab'
+sudo bash -c 'echo "mytest /dev/sdXn - \'pkcs11-uri=pkcs11:…\'" >> /etc/crypttab'
index 209971cc100fa9b423d208f594d9aa7f491d9946..20cb2b88a21d2ea3525c2738f52deae8a2edd505 100644 (file)
@@ -32,8 +32,9 @@ substs.set('PROJECT_VERSION',      meson.project_version(),
 # This is to be used instead of meson.source_root(), as the latter will return
 # the wrong result when systemd is being built as a meson subproject
 project_source_root = meson.current_source_dir()
+project_build_root = meson.current_build_dir()
 relative_source_path = run_command('realpath',
-                                   '--relative-to=@0@'.format(meson.current_build_dir()),
+                                   '--relative-to=@0@'.format(project_build_root),
                                    project_source_root).stdout().strip()
 conf.set_quoted('RELATIVE_SOURCE_PATH', relative_source_path)
 
@@ -89,6 +90,10 @@ sysvrcnd_path = get_option('sysvrcnd-path')
 conf.set10('HAVE_SYSV_COMPAT', sysvinit_path != '' and sysvrcnd_path != '',
            description : 'SysV init scripts and rcN.d links are supported')
 
+if get_option('hibernate') and not get_option('initrd')
+        error('hibernate depends on initrd')
+endif
+
 conf.set10('BUMP_PROC_SYS_FS_FILE_MAX', get_option('bump-proc-sys-fs-file-max'))
 conf.set10('BUMP_PROC_SYS_FS_NR_OPEN',  get_option('bump-proc-sys-fs-nr-open'))
 conf.set('HIGH_RLIMIT_NOFILE',          512*1024)
@@ -292,13 +297,13 @@ substs.set('RC_LOCAL_SCRIPT_PATH_START',                      get_option('rc-loc
 substs.set('MEMORY_ACCOUNTING_DEFAULT',                       memory_accounting_default ? 'yes' : 'no')
 substs.set('STATUS_UNIT_FORMAT_DEFAULT',                      status_unit_format_default)
 substs.set('HIGH_RLIMIT_NOFILE',                              conf.get('HIGH_RLIMIT_NOFILE'))
-substs.set('BUILD_ROOT',                                      meson.current_build_dir())
+substs.set('BUILD_ROOT',                                      project_build_root)
 
 #####################################################################
 
 cc = meson.get_compiler('c')
 pkgconfig = import('pkgconfig')
-check_compilation_sh = find_program('tools/meson-check-compilation.sh')
+check_compilation_sh = find_program('tools/check-compilation.sh')
 meson_build_sh = find_program('tools/meson-build.sh')
 
 want_tests = get_option('tests')
@@ -334,15 +339,6 @@ basic_disabled_warnings = [
         '-Wno-unused-result',
         '-Wno-format-signedness',
 ]
-if get_option('b_ndebug') == 'true'
-        # With asserts disabled with get a bunch of warnings about variables which
-        # are used only in the asserts. This is not useful at all, so let's just silence
-        # those warnings.
-        basic_disabled_warnings += [
-                '-Wno-unused-variable',
-                '-Wno-unused-but-set-variable',
-        ]
-endif
 
 possible_cc_flags = [
         '-Werror=undef',
@@ -377,9 +373,6 @@ possible_cc_flags = [
         '-Wno-error=#warnings',  # clang
         '-Wno-string-plus-int',  # clang
 
-        # work-around for gcc 7.1 turning this on on its own.
-        '-Wno-error=nonnull',
-
         # Disable -Wmaybe-uninitialized, since it's noisy on gcc 8 with
         # optimizations enabled, producing essentially false positives.
         '-Wno-maybe-uninitialized',
@@ -422,6 +415,9 @@ add_project_arguments(cc.get_supported_arguments(basic_disabled_warnings), langu
 add_project_arguments(cc.get_supported_arguments(possible_cc_flags), language : 'c')
 add_project_link_arguments(cc.get_supported_link_arguments(possible_link_flags), language : 'c')
 
+have = cc.has_argument('-Wzero-length-bounds')
+conf.set10('HAVE_ZERO_LENGTH_BOUNDS', have)
+
 if cc.compiles('''
    #include <time.h>
    #include <inttypes.h>
@@ -650,7 +646,14 @@ endforeach
 
 ############################################################
 
-conf.set_quoted('FALLBACK_HOSTNAME', get_option('fallback-hostname'))
+fallback_hostname = get_option('fallback-hostname')
+if fallback_hostname == '' or fallback_hostname[0] == '.' or fallback_hostname[0] == '-'
+        error('Invalid fallback-hostname configuration')
+        # A more extensive test is done in test-hostname-util. Let's catch
+        # the most obvious errors here so we don't fail with an assert later.
+endif
+conf.set_quoted('FALLBACK_HOSTNAME', fallback_hostname)
+
 conf.set10('ENABLE_COMPAT_GATEWAY_HOSTNAME', get_option('compat-gateway-hostname'))
 gateway_hostnames = ['_gateway'] + (conf.get('ENABLE_COMPAT_GATEWAY_HOSTNAME') == 1 ? ['gateway'] : [])
 
@@ -670,8 +673,13 @@ conf.set_quoted('DEFAULT_NET_NAMING_SCHEME', default_net_naming_scheme)
 
 time_epoch = get_option('time-epoch')
 if time_epoch == -1
-        NEWS = files('NEWS')
-        time_epoch = run_command(stat, '-c', '%Y', NEWS).stdout().to_int()
+        source_date_epoch = run_command('sh', ['-c', 'echo "$SOURCE_DATE_EPOCH"']).stdout().strip()
+        if source_date_epoch != ''
+                time_epoch = source_date_epoch.to_int()
+        else
+                NEWS = files('NEWS')
+                time_epoch = run_command(stat, '-c', '%Y', NEWS).stdout().to_int()
+        endif
 endif
 conf.set('TIME_EPOCH', time_epoch)
 
@@ -1130,8 +1138,8 @@ conf.set10('HAVE_OPENSSL', have)
 want_p11kit = get_option('p11kit')
 if want_p11kit != 'false' and not skip_deps
         libp11kit = dependency('p11-kit-1',
-                                version : '>= 0.23.3',
-                                required : want_p11kit == 'true')
+                               version : '>= 0.23.3',
+                               required : want_p11kit == 'true')
         have = libp11kit.found()
 else
         have = false
@@ -1195,6 +1203,18 @@ else
 endif
 conf.set10('HAVE_LZ4', have)
 
+want_zstd = get_option('zstd')
+if want_zstd != 'false' and not skip_deps
+        libzstd = dependency('libzstd',
+                             required : want_zstd == 'true',
+                             version : '>= 1.4.0')
+        have = libzstd.found()
+else
+        have = false
+        libzstd = []
+endif
+conf.set10('HAVE_ZSTD', have)
+
 want_xkbcommon = get_option('xkbcommon')
 if want_xkbcommon != 'false' and not skip_deps
         libxkbcommon = dependency('xkbcommon',
@@ -1403,6 +1423,7 @@ foreach term : ['utmp',
                 'smack',
                 'gshadow',
                 'idn',
+                'initrd',
                 'nss-myhostname',
                 'nss-systemd']
         have = get_option(term)
@@ -1484,6 +1505,7 @@ meson_apply_m4 = find_program('tools/meson-apply-m4.sh')
 
 includes = include_directories('src/basic',
                                'src/boot',
+                               'src/home',
                                'src/shared',
                                'src/systemd',
                                'src/journal',
@@ -1543,6 +1565,7 @@ libsystemd = shared_library(
         dependencies : [threads,
                         librt,
                         libxz,
+                        libzstd,
                         liblz4],
         link_depends : libsystemd_sym,
         install : true,
@@ -1566,6 +1589,7 @@ install_libsystemd_static = static_library(
         dependencies : [threads,
                         librt,
                         libxz,
+                        libzstd,
                         liblz4,
                         libcap,
                         libblkid,
@@ -1574,7 +1598,7 @@ install_libsystemd_static = static_library(
                         libgcrypt],
         c_args : libsystemd_c_args + (static_libsystemd_pic ? [] : ['-fno-PIC']))
 
-#Generate autosuspend rules
+# Generate autosuspend rules
 make_autosuspend_rules_py = find_program('tools/make-autosuspend-rules.py')
 
 ############################################################
@@ -1681,120 +1705,129 @@ endforeach
 
 ############################################################
 
-executable('systemd',
-           systemd_sources,
-           include_directories : includes,
-           link_with : [libcore,
-                        libshared],
-           dependencies : [versiondep,
-                           threads,
-                           librt,
-                           libseccomp,
-                           libselinux,
-                           libmount,
-                           libblkid],
-           install_rpath : rootlibexecdir,
-           install : true,
-           install_dir : rootlibexecdir)
+executable(
+        'systemd',
+        systemd_sources,
+        include_directories : includes,
+        link_with : [libcore,
+                     libshared],
+        dependencies : [versiondep,
+                        threads,
+                        librt,
+                        libseccomp,
+                        libselinux,
+                        libmount,
+                        libblkid],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : rootlibexecdir)
 
 meson.add_install_script(meson_make_symlink,
                          join_paths(rootlibexecdir, 'systemd'),
                          join_paths(rootsbindir, 'init'))
 
-exe = executable('systemd-analyze',
-                 systemd_analyze_sources,
-                 include_directories : includes,
-                 link_with : [libcore,
-                              libshared],
-                 dependencies : [versiondep,
-                                 threads,
-                                 librt,
-                                 libseccomp,
-                                 libselinux,
-                                 libmount,
-                                 libblkid],
-                 install_rpath : rootlibexecdir,
-                 install : get_option('analyze'))
-public_programs += exe
-
-executable('systemd-journald',
-           systemd_journald_sources,
-           include_directories : includes,
-           link_with : [libjournal_core,
-                        libshared],
-           dependencies : [threads,
-                           libxz,
-                           liblz4,
-                           libselinux],
-           install_rpath : rootlibexecdir,
-           install : true,
-           install_dir : rootlibexecdir)
+public_programs += executable(
+        'systemd-analyze',
+        systemd_analyze_sources,
+        include_directories : includes,
+        link_with : [libcore,
+                     libshared],
+        dependencies : [versiondep,
+                        threads,
+                        librt,
+                        libseccomp,
+                        libselinux,
+                        libmount,
+                        libblkid],
+        install_rpath : rootlibexecdir,
+        install : get_option('analyze'))
 
-exe = executable('systemd-cat',
-                 systemd_cat_sources,
-                 include_directories : includes,
-                 link_with : [libjournal_core,
-                              libshared],
-                 dependencies : [threads],
-                 install_rpath : rootlibexecdir,
-                 install : true)
-public_programs += exe
-
-exe = executable('journalctl',
-                 journalctl_sources,
-                 include_directories : includes,
-                 link_with : [libshared],
-                 dependencies : [threads,
-                                 libqrencode,
-                                 libxz,
-                                 liblz4,
-                                 libpcre2],
-                 install_rpath : rootlibexecdir,
-                 install : true,
-                 install_dir : rootbindir)
-public_programs += exe
-
-executable('systemd-getty-generator',
-           'src/getty-generator/getty-generator.c',
-           include_directories : includes,
-           link_with : [libshared],
-           install_rpath : rootlibexecdir,
-           install : true,
-           install_dir : systemgeneratordir)
+executable(
+        'systemd-journald',
+        systemd_journald_sources,
+        include_directories : includes,
+        link_with : [libjournal_core,
+                     libshared],
+        dependencies : [threads,
+                        libxz,
+                        liblz4,
+                        libselinux,
+                        libzstd],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : rootlibexecdir)
 
-executable('systemd-debug-generator',
-           'src/debug-generator/debug-generator.c',
-           include_directories : includes,
-           link_with : [libshared],
-           install_rpath : rootlibexecdir,
-           install : true,
-           install_dir : systemgeneratordir)
+public_programs += executable(
+        'systemd-cat',
+        systemd_cat_sources,
+        include_directories : includes,
+        link_with : [libjournal_core,
+                     libshared],
+        dependencies : [threads],
+        install_rpath : rootlibexecdir,
+        install : true)
+
+public_programs += executable(
+        'journalctl',
+        journalctl_sources,
+        include_directories : includes,
+        link_with : [libshared],
+        dependencies : [threads,
+                        libqrencode,
+                        libxz,
+                        liblz4,
+                        libpcre2,
+                        libzstd],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : rootbindir)
 
-executable('systemd-run-generator',
-           'src/run-generator/run-generator.c',
-           include_directories : includes,
-           link_with : [libshared],
-           install_rpath : rootlibexecdir,
-           install : true,
-           install_dir : systemgeneratordir)
+executable(
+        'systemd-getty-generator',
+        'src/getty-generator/getty-generator.c',
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : systemgeneratordir)
 
-executable('systemd-fstab-generator',
-           'src/fstab-generator/fstab-generator.c',
-           include_directories : includes,
-           link_with : [libcore_shared,
-                        libshared],
-           install_rpath : rootlibexecdir,
-           install : true,
-           install_dir : systemgeneratordir)
+executable(
+        'systemd-debug-generator',
+        'src/debug-generator/debug-generator.c',
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : systemgeneratordir)
+
+executable(
+        'systemd-run-generator',
+        'src/run-generator/run-generator.c',
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : systemgeneratordir)
+
+executable(
+        'systemd-fstab-generator',
+        'src/fstab-generator/fstab-generator.c',
+        include_directories : includes,
+        link_with : [libcore_shared,
+                     libshared],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : systemgeneratordir)
 
 if conf.get('ENABLE_ENVIRONMENT_D') == 1
-        executable('30-systemd-environment-d-generator',
-                   'src/environment-d-generator/environment-d-generator.c',
-                   include_directories : includes,
-                   link_with : [libshared],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : userenvgeneratordir)
+        executable(
+                '30-systemd-environment-d-generator',
+                'src/environment-d-generator/environment-d-generator.c',
+                include_directories : includes,
+                link_with : [libshared],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : userenvgeneratordir)
 
         meson.add_install_script(meson_make_symlink,
                                  join_paths(sysconfdir, 'environment'),
@@ -1802,111 +1835,117 @@ if conf.get('ENABLE_ENVIRONMENT_D') == 1
 endif
 
 if conf.get('ENABLE_HIBERNATE') == 1
-        executable('systemd-hibernate-resume-generator',
-                   'src/hibernate-resume/hibernate-resume-generator.c',
-                   include_directories : includes,
-                   link_with : [libshared],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : systemgeneratordir)
-
-        executable('systemd-hibernate-resume',
-                   'src/hibernate-resume/hibernate-resume.c',
-                   include_directories : includes,
-                   link_with : [libshared],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
+        executable(
+                'systemd-hibernate-resume-generator',
+                'src/hibernate-resume/hibernate-resume-generator.c',
+                include_directories : includes,
+                link_with : [libshared],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : systemgeneratordir)
+
+        executable(
+                'systemd-hibernate-resume',
+                'src/hibernate-resume/hibernate-resume.c',
+                include_directories : includes,
+                link_with : [libshared],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
 endif
 
 if conf.get('HAVE_BLKID') == 1
-        executable('systemd-gpt-auto-generator',
-                   'src/gpt-auto-generator/gpt-auto-generator.c',
-                   'src/shared/blkid-util.h',
-                   include_directories : includes,
-                   link_with : [libshared],
-                   dependencies : libblkid,
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : systemgeneratordir)
-
-        exe = executable('systemd-dissect',
-                         'src/dissect/dissect.c',
-                         include_directories : includes,
-                         link_with : [libshared],
-                         install_rpath : rootlibexecdir,
-                         install : true,
-                         install_dir : rootlibexecdir)
-        public_programs += exe
+        executable(
+                'systemd-gpt-auto-generator',
+                'src/gpt-auto-generator/gpt-auto-generator.c',
+                'src/shared/blkid-util.h',
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : libblkid,
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : systemgeneratordir)
+
+        public_programs += executable(
+                'systemd-dissect',
+                'src/dissect/dissect.c',
+                include_directories : includes,
+                link_with : [libshared],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
 endif
 
 if conf.get('ENABLE_RESOLVE') == 1
-        executable('systemd-resolved',
-                   systemd_resolved_sources,
-                   include_directories : includes,
-                   link_with : [libshared,
-                                libbasic_gcrypt,
-                                libsystemd_resolve_core],
-                   dependencies : systemd_resolved_dependencies,
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
-
-        exe = executable('resolvectl',
-                         resolvectl_sources,
-                         include_directories : includes,
-                         link_with : [libshared,
-                                      libbasic_gcrypt,
-                                      libsystemd_resolve_core],
-                         dependencies : [threads,
-                                         libgpg_error,
-                                         libm,
-                                         libidn],
-                         install_rpath : rootlibexecdir,
-                         install : true)
-        public_programs += exe
+        executable(
+                'systemd-resolved',
+                systemd_resolved_sources,
+                include_directories : includes,
+                link_with : [libshared,
+                             libbasic_gcrypt,
+                             libsystemd_resolve_core],
+                dependencies : systemd_resolved_dependencies,
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
+
+        public_programs += executable(
+                'resolvectl',
+                resolvectl_sources,
+                include_directories : includes,
+                link_with : [libshared,
+                             libbasic_gcrypt,
+                             libsystemd_resolve_core],
+                dependencies : [threads,
+                                libgpg_error,
+                                libm,
+                                libidn],
+                install_rpath : rootlibexecdir,
+                install : true)
 
         meson.add_install_script(meson_make_symlink,
-                         join_paths(bindir, 'resolvectl'),
-                         join_paths(rootsbindir, 'resolvconf'))
+                                 join_paths(bindir, 'resolvectl'),
+                                 join_paths(rootsbindir, 'resolvconf'))
 
         meson.add_install_script(meson_make_symlink,
-                         join_paths(bindir, 'resolvectl'),
-                         join_paths(bindir, 'systemd-resolve'))
+                                 join_paths(bindir, 'resolvectl'),
+                                 join_paths(bindir, 'systemd-resolve'))
 endif
 
 if conf.get('ENABLE_LOGIND') == 1
-        executable('systemd-logind',
-                   systemd_logind_sources,
-                   include_directories : includes,
-                   link_with : [liblogind_core,
-                                libshared],
-                   dependencies : [threads,
-                                   libacl],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
-
-        exe = executable('loginctl',
-                         loginctl_sources,
-                         include_directories : includes,
-                         link_with : [libshared],
-                         dependencies : [threads,
-                                         liblz4,
-                                         libxz],
-                         install_rpath : rootlibexecdir,
-                         install : true,
-                         install_dir : rootbindir)
-        public_programs += exe
-
-        exe = executable('systemd-inhibit',
-                         'src/login/inhibit.c',
-                         include_directories : includes,
-                         link_with : [libshared],
-                         install_rpath : rootlibexecdir,
-                         install : true,
-                         install_dir : rootbindir)
-        public_programs += exe
+        executable(
+                'systemd-logind',
+                systemd_logind_sources,
+                include_directories : includes,
+                link_with : [liblogind_core,
+                             libshared],
+                dependencies : [threads,
+                                libacl],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
+
+        public_programs += executable(
+                'loginctl',
+                loginctl_sources,
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [threads,
+                                liblz4,
+                                libxz,
+                                libzstd],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootbindir)
+
+        public_programs += executable(
+                'systemd-inhibit',
+                'src/login/inhibit.c',
+                include_directories : includes,
+                link_with : [libshared],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootbindir)
 
         if conf.get('HAVE_PAM') == 1
                 version_script_arg = join_paths(project_source_root, pam_systemd_sym)
@@ -1934,70 +1973,75 @@ if conf.get('ENABLE_LOGIND') == 1
                 endif
         endif
 
-        executable('systemd-user-runtime-dir',
-                   user_runtime_dir_sources,
-                   include_directories : includes,
-                   link_with : [libshared],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
+        executable(
+                'systemd-user-runtime-dir',
+                user_runtime_dir_sources,
+                include_directories : includes,
+                link_with : [libshared],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
 endif
 
 if conf.get('HAVE_PAM') == 1
-        executable('systemd-user-sessions',
-                   'src/user-sessions/user-sessions.c',
-                   include_directories : includes,
-                   link_with : [libshared],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
+        executable(
+                'systemd-user-sessions',
+                'src/user-sessions/user-sessions.c',
+                include_directories : includes,
+                link_with : [libshared],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
 endif
 
 if conf.get('ENABLE_EFI') == 1 and conf.get('HAVE_BLKID') == 1
-        exe = executable('bootctl',
-                         'src/boot/bootctl.c',
-                         include_directories : includes,
-                         link_with : [libshared],
-                         dependencies : [libblkid],
-                         install_rpath : rootlibexecdir,
-                         install : true)
-        public_programs += exe
-
-        executable('systemd-bless-boot',
-                   'src/boot/bless-boot.c',
-                   include_directories : includes,
-                   link_with : [libshared],
-                   dependencies : [libblkid],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
-
-        executable('systemd-bless-boot-generator',
-                   'src/boot/bless-boot-generator.c',
-                   include_directories : includes,
-                   link_with : [libshared],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : systemgeneratordir)
-endif
-
-executable('systemd-boot-check-no-failures',
-           'src/boot/boot-check-no-failures.c',
-           include_directories : includes,
-           link_with : [libshared],
-           dependencies : [libblkid],
-           install_rpath : rootlibexecdir,
-           install : true,
-           install_dir : rootlibexecdir)
-
-exe = executable('systemd-socket-activate', 'src/activate/activate.c',
-                 include_directories : includes,
-                 link_with : [libshared],
-                 dependencies : [threads],
-                 install_rpath : rootlibexecdir,
-                 install : true)
-public_programs += exe
+        public_programs += executable(
+                'bootctl',
+                'src/boot/bootctl.c',
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [libblkid],
+                install_rpath : rootlibexecdir,
+                install : true)
+
+        public_programs += executable(
+                'systemd-bless-boot',
+                'src/boot/bless-boot.c',
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [libblkid],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
+
+        executable(
+                'systemd-bless-boot-generator',
+                'src/boot/bless-boot-generator.c',
+                include_directories : includes,
+                link_with : [libshared],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : systemgeneratordir)
+endif
+
+executable(
+        'systemd-boot-check-no-failures',
+        'src/boot/boot-check-no-failures.c',
+        include_directories : includes,
+        link_with : [libshared],
+        dependencies : [libblkid],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : rootlibexecdir)
 
+public_programs += executable(
+        'systemd-socket-activate',
+        'src/activate/activate.c',
+        include_directories : includes,
+        link_with : [libshared],
+        dependencies : [threads],
+        install_rpath : rootlibexecdir,
+        install : true)
 
 if get_option('link-systemctl-shared')
         systemctl_link_with = [libshared]
@@ -2008,111 +2052,120 @@ else
                                libbasic_gcrypt]
 endif
 
-exe = executable('systemctl',
-                 'src/systemctl/systemctl.c',
-                 'src/systemctl/sysv-compat.h',
-                 'src/systemctl/sysv-compat.c',
-                 include_directories : includes,
-                 link_with : systemctl_link_with,
-                 dependencies : [threads,
-                                 libcap,
-                                 libselinux,
-                                 libxz,
-                                 liblz4],
-                 install_rpath : rootlibexecdir,
-                 install : true,
-                 install_dir : rootbindir)
-public_programs += exe
+public_programs += executable(
+        'systemctl',
+        'src/systemctl/systemctl.c',
+        'src/systemctl/sysv-compat.h',
+        'src/systemctl/sysv-compat.c',
+        include_directories : includes,
+        link_with : systemctl_link_with,
+        dependencies : [threads,
+                        libcap,
+                        libselinux,
+                        libxz,
+                        liblz4,
+                        libzstd],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : rootbindir)
 
 if conf.get('ENABLE_PORTABLED') == 1
-        executable('systemd-portabled',
-                   systemd_portabled_sources,
-                   include_directories : includes,
-                   link_with : [libshared],
-                   dependencies : [threads],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
-
-        exe = executable('portablectl', 'src/portable/portablectl.c',
-                         include_directories : includes,
-                         link_with : [libshared],
-                         dependencies : [threads],
-                         install_rpath : rootlibexecdir,
-                         install : true,
-                         install_dir : rootbindir)
-        public_programs += exe
+        executable(
+                'systemd-portabled',
+                systemd_portabled_sources,
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [threads],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
+
+        public_programs += executable(
+                'portablectl',
+                'src/portable/portablectl.c',
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [threads],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootbindir)
 endif
 
 if conf.get('ENABLE_USERDB') == 1
-        executable('systemd-userwork',
-                   systemd_userwork_sources,
-                   include_directories : includes,
-                   link_with : [libshared],
-                   dependencies : [threads],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
-
-        executable('systemd-userdbd',
-                   systemd_userdbd_sources,
-                   include_directories : includes,
-                   link_with : [libshared],
-                   dependencies : [threads],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
-
-        executable('userdbctl',
-                   userdbctl_sources,
-                   include_directories : includes,
-                   link_with : [libshared],
-                   dependencies : [threads],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootbindir)
+        executable(
+                'systemd-userwork',
+                systemd_userwork_sources,
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [threads],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
+
+        executable(
+                'systemd-userdbd',
+                systemd_userdbd_sources,
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [threads],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
+
+        public_programs += executable(
+                'userdbctl',
+                userdbctl_sources,
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [threads],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootbindir)
 endif
 
 if conf.get('ENABLE_HOMED') == 1
-        executable('systemd-homework',
-                   systemd_homework_sources,
-                   include_directories : includes,
-                   link_with : [libshared],
-                   dependencies : [threads,
-                                   libcryptsetup,
-                                   libblkid,
-                                   libcrypt,
-                                   libopenssl,
-                                   libfdisk,
-                                   libp11kit],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
-
-        executable('systemd-homed',
-                   systemd_homed_sources,
-                   include_directories : includes,
-                   link_with : [libshared],
-                   dependencies : [threads,
-                                   libcrypt,
-                                   libopenssl,
-                                   libpwquality],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
-
-        executable('homectl',
-                   homectl_sources,
-                   include_directories : includes,
-                   link_with : [libshared],
-                   dependencies : [threads,
-                                   libcrypt,
-                                   libopenssl,
-                                   libp11kit,
-                                   libpwquality],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootbindir)
+        executable(
+                'systemd-homework',
+                systemd_homework_sources,
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [threads,
+                                libcryptsetup,
+                                libblkid,
+                                libcrypt,
+                                libopenssl,
+                                libfdisk,
+                                libp11kit],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
+
+        executable(
+                'systemd-homed',
+                systemd_homed_sources,
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [threads,
+                                libcrypt,
+                                libopenssl,
+                                libpwquality],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
+
+        public_programs += executable(
+                'homectl',
+                homectl_sources,
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [threads,
+                                libcrypt,
+                                libopenssl,
+                                libp11kit,
+                                libpwquality],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootbindir)
 
         if conf.get('HAVE_PAM') == 1
                 version_script_arg = join_paths(project_source_root, pam_systemd_home_sym)
@@ -2142,115 +2195,127 @@ foreach alias : ['halt', 'poweroff', 'reboot', 'runlevel', 'shutdown', 'telinit'
 endforeach
 
 if conf.get('ENABLE_BACKLIGHT') == 1
-        executable('systemd-backlight',
-                   'src/backlight/backlight.c',
-                   include_directories : includes,
-                   link_with : [libshared],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
+        executable(
+                'systemd-backlight',
+                'src/backlight/backlight.c',
+                include_directories : includes,
+                link_with : [libshared],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
 endif
 
 if conf.get('ENABLE_RFKILL') == 1
-        executable('systemd-rfkill',
-                   'src/rfkill/rfkill.c',
-                   include_directories : includes,
-                   link_with : [libshared],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
-endif
-
-executable('systemd-system-update-generator',
-           'src/system-update-generator/system-update-generator.c',
-           include_directories : includes,
-           link_with : [libshared],
-           install_rpath : rootlibexecdir,
-           install : true,
-           install_dir : systemgeneratordir)
+        executable(
+                'systemd-rfkill',
+                'src/rfkill/rfkill.c',
+                include_directories : includes,
+                link_with : [libshared],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
+endif
+
+executable(
+        'systemd-system-update-generator',
+        'src/system-update-generator/system-update-generator.c',
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : systemgeneratordir)
 
 if conf.get('HAVE_LIBCRYPTSETUP') == 1
         systemd_cryptsetup_sources = files('''
-                src/cryptsetup/cryptsetup.c
                 src/cryptsetup/cryptsetup-pkcs11.h
+                src/cryptsetup/cryptsetup-util.c
+                src/cryptsetup/cryptsetup-util.h
+                src/cryptsetup/cryptsetup.c
 '''.split())
 
         if conf.get('HAVE_P11KIT') == 1
                 systemd_cryptsetup_sources += files('src/cryptsetup/cryptsetup-pkcs11.c')
         endif
 
-        executable('systemd-cryptsetup',
-                   systemd_cryptsetup_sources,
-                   include_directories : includes,
-                   link_with : [libshared],
-                   dependencies : [libcryptsetup,
-                                   libp11kit],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
-
-        executable('systemd-cryptsetup-generator',
-                   'src/cryptsetup/cryptsetup-generator.c',
-                   include_directories : includes,
-                   link_with : [libshared],
-                   dependencies : [libcryptsetup],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : systemgeneratordir)
-
-        executable('systemd-veritysetup',
-                   'src/veritysetup/veritysetup.c',
-                   include_directories : includes,
-                   link_with : [libshared],
-                   dependencies : [libcryptsetup],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
-
-        executable('systemd-veritysetup-generator',
-                   'src/veritysetup/veritysetup-generator.c',
-                   include_directories : includes,
-                   link_with : [libshared],
-                   dependencies : [libcryptsetup],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : systemgeneratordir)
+        executable(
+                'systemd-cryptsetup',
+                systemd_cryptsetup_sources,
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [libcryptsetup,
+                                libp11kit],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
+
+        executable(
+                'systemd-cryptsetup-generator',
+                'src/cryptsetup/cryptsetup-generator.c',
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [libcryptsetup],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : systemgeneratordir)
+
+        executable(
+                'systemd-veritysetup',
+                'src/veritysetup/veritysetup.c',
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [libcryptsetup],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
+
+        executable(
+                'systemd-veritysetup-generator',
+                'src/veritysetup/veritysetup-generator.c',
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [libcryptsetup],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : systemgeneratordir)
 endif
 
 if conf.get('HAVE_SYSV_COMPAT') == 1
-        executable('systemd-sysv-generator',
-                   'src/sysv-generator/sysv-generator.c',
-                   include_directories : includes,
-                   link_with : [libshared],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : systemgeneratordir)
-
-        executable('systemd-rc-local-generator',
-                   'src/rc-local-generator/rc-local-generator.c',
-                   include_directories : includes,
-                   link_with : [libshared],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : systemgeneratordir)
+        executable(
+                'systemd-sysv-generator',
+                'src/sysv-generator/sysv-generator.c',
+                include_directories : includes,
+                link_with : [libshared],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : systemgeneratordir)
+
+        executable(
+                'systemd-rc-local-generator',
+                'src/rc-local-generator/rc-local-generator.c',
+                include_directories : includes,
+                link_with : [libshared],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : systemgeneratordir)
 endif
 
 if conf.get('ENABLE_HOSTNAMED') == 1
-        executable('systemd-hostnamed',
-                   'src/hostname/hostnamed.c',
-                   include_directories : includes,
-                   link_with : [libshared],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
-
-        exe = executable('hostnamectl',
-                         'src/hostname/hostnamectl.c',
-                         include_directories : includes,
-                         link_with : [libshared],
-                         install_rpath : rootlibexecdir,
-                         install : true)
-        public_programs += exe
+        executable(
+                'systemd-hostnamed',
+                'src/hostname/hostnamed.c',
+                include_directories : includes,
+                link_with : [libshared],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
+
+        public_programs += executable(
+                'hostnamectl',
+                'src/hostname/hostnamectl.c',
+                include_directories : includes,
+                link_with : [libshared],
+                install_rpath : rootlibexecdir,
+                install : true)
 endif
 
 if conf.get('ENABLE_LOCALED') == 1
@@ -2261,43 +2326,45 @@ if conf.get('ENABLE_LOCALED') == 1
                 deps = []
         endif
 
-        executable('systemd-localed',
-                   systemd_localed_sources,
-                   include_directories : includes,
-                   link_with : [libshared],
-                   dependencies : deps,
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
-
-        exe = executable('localectl',
-                         localectl_sources,
-                         include_directories : includes,
-                         link_with : [libshared],
-                         install_rpath : rootlibexecdir,
-                         install : true)
-        public_programs += exe
+        executable(
+                'systemd-localed',
+                systemd_localed_sources,
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : deps,
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
+
+        public_programs += executable(
+                'localectl',
+                localectl_sources,
+                include_directories : includes,
+                link_with : [libshared],
+                install_rpath : rootlibexecdir,
+                install : true)
 endif
 
 if conf.get('ENABLE_TIMEDATED') == 1
-        executable('systemd-timedated',
-                   'src/timedate/timedated.c',
-                   include_directories : includes,
-                   link_with : [libshared],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
+        executable(
+                'systemd-timedated',
+                'src/timedate/timedated.c',
+                include_directories : includes,
+                link_with : [libshared],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
 endif
 
 if conf.get('ENABLE_TIMEDATECTL') == 1
-        exe = executable('timedatectl',
-                         'src/timedate/timedatectl.c',
-                         include_directories : includes,
-                         install_rpath : rootlibexecdir,
-                         link_with : [libshared],
-                         dependencies : [libm],
-                         install : true)
-        public_programs += exe
+        public_programs += executable(
+                'timedatectl',
+                'src/timedate/timedatectl.c',
+                include_directories : includes,
+                install_rpath : rootlibexecdir,
+                link_with : [libshared],
+                dependencies : [libm],
+                install : true)
 endif
 
 if conf.get('ENABLE_TIMESYNCD') == 1
@@ -2310,204 +2377,222 @@ if conf.get('ENABLE_TIMESYNCD') == 1
                                        libbasic_gcrypt]
         endif
 
-        executable('systemd-timesyncd',
-                   systemd_timesyncd_sources,
-                   include_directories : includes,
-                   link_with : [timesyncd_link_with],
-                   dependencies : [threads,
-                                   libm],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
-
-        executable('systemd-time-wait-sync',
-                   'src/time-wait-sync/time-wait-sync.c',
-                   include_directories : includes,
-                   link_with : [timesyncd_link_with],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
+        executable(
+                'systemd-timesyncd',
+                systemd_timesyncd_sources,
+                include_directories : includes,
+                link_with : [timesyncd_link_with],
+                dependencies : [threads,
+                                libm],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
+
+        executable(
+                'systemd-time-wait-sync',
+                'src/time-wait-sync/time-wait-sync.c',
+                include_directories : includes,
+                link_with : [timesyncd_link_with],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
 endif
 
 if conf.get('ENABLE_MACHINED') == 1
-        executable('systemd-machined',
-                   systemd_machined_sources,
-                   include_directories : includes,
-                   link_with : [libmachine_core,
-                                libshared],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
-
-        exe = executable('machinectl',
-                         'src/machine/machinectl.c',
-                         include_directories : includes,
-                         link_with : [libshared],
-                         dependencies : [threads,
-                                         libxz,
-                                         liblz4],
-                         install_rpath : rootlibexecdir,
-                         install : true,
-                         install_dir : rootbindir)
-        public_programs += exe
+        executable(
+                'systemd-machined',
+                systemd_machined_sources,
+                include_directories : includes,
+                link_with : [libmachine_core,
+                             libshared],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
+
+        public_programs += executable(
+                'machinectl',
+                'src/machine/machinectl.c',
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [threads,
+                                libxz,
+                                liblz4,
+                                libzstd],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootbindir)
 endif
 
 if conf.get('ENABLE_IMPORTD') == 1
-        executable('systemd-importd',
-                   systemd_importd_sources,
-                   include_directories : includes,
-                   link_with : [libshared],
-                   dependencies : [threads],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
-
-        systemd_pull = executable('systemd-pull',
-                                  systemd_pull_sources,
-                                  include_directories : includes,
-                                  link_with : [libshared],
-                                  dependencies : [versiondep,
-                                                  libcurl,
-                                                  libz,
-                                                  libbzip2,
-                                                  libxz,
-                                                  libgcrypt],
-                                  install_rpath : rootlibexecdir,
-                                  install : true,
-                                  install_dir : rootlibexecdir)
-
-        systemd_import = executable('systemd-import',
-                                    systemd_import_sources,
-                                    include_directories : includes,
-                                    link_with : [libshared],
-                                    dependencies : [libcurl,
-                                                    libz,
-                                                    libbzip2,
-                                                    libxz],
-                                    install_rpath : rootlibexecdir,
-                                    install : true,
-                                    install_dir : rootlibexecdir)
-
-        systemd_import_fs = executable('systemd-import-fs',
-                                    systemd_import_fs_sources,
-                                    include_directories : includes,
-                                    link_with : [libshared],
-                                    install_rpath : rootlibexecdir,
-                                    install : true,
-                                    install_dir : rootlibexecdir)
-
-        systemd_export = executable('systemd-export',
-                                    systemd_export_sources,
-                                    include_directories : includes,
-                                    link_with : [libshared],
-                                    dependencies : [libcurl,
-                                                    libz,
-                                                    libbzip2,
-                                                    libxz],
-                                    install_rpath : rootlibexecdir,
-                                    install : true,
-                                    install_dir : rootlibexecdir)
+        executable(
+                'systemd-importd',
+                systemd_importd_sources,
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [threads],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
+
+        systemd_pull = executable(
+                'systemd-pull',
+                systemd_pull_sources,
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [versiondep,
+                                libcurl,
+                                libz,
+                                libbzip2,
+                                libxz,
+                                libgcrypt],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
+
+        systemd_import = executable(
+                'systemd-import',
+                systemd_import_sources,
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [libcurl,
+                                libz,
+                                libbzip2,
+                                libxz],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
+
+        systemd_import_fs = executable(
+                'systemd-import-fs',
+                systemd_import_fs_sources,
+                include_directories : includes,
+                link_with : [libshared],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
+
+        systemd_export = executable(
+                'systemd-export',
+                systemd_export_sources,
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [libcurl,
+                                libz,
+                                libbzip2,
+                                libxz],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
 
         public_programs += [systemd_pull, systemd_import, systemd_import_fs, systemd_export]
 endif
 
 if conf.get('ENABLE_REMOTE') == 1 and conf.get('HAVE_LIBCURL') == 1
-        exe = executable('systemd-journal-upload',
-                         systemd_journal_upload_sources,
-                         include_directories : includes,
-                         link_with : [libshared],
-                         dependencies : [versiondep,
-                                         threads,
-                                         libcurl,
-                                         libgnutls,
-                                         libxz,
-                                         liblz4],
-                         install_rpath : rootlibexecdir,
-                         install : true,
-                         install_dir : rootlibexecdir)
-        public_programs += exe
+        public_programs += executable(
+                'systemd-journal-upload',
+                systemd_journal_upload_sources,
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [versiondep,
+                                threads,
+                                libcurl,
+                                libgnutls,
+                                libxz,
+                                liblz4,
+                                libzstd],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
 endif
 
 if conf.get('ENABLE_REMOTE') == 1 and conf.get('HAVE_MICROHTTPD') == 1
-        s_j_remote = executable('systemd-journal-remote',
-                                systemd_journal_remote_sources,
-                                include_directories : includes,
-                                link_with : [libshared,
-                                             libsystemd_journal_remote],
-                                dependencies : [threads,
-                                                libmicrohttpd,
-                                                libgnutls,
-                                                libxz,
-                                                liblz4],
-                                install_rpath : rootlibexecdir,
-                                install : true,
-                                install_dir : rootlibexecdir)
-
-        s_j_gatewayd = executable('systemd-journal-gatewayd',
-                                  systemd_journal_gatewayd_sources,
-                                  include_directories : includes,
-                                  link_with : [libshared],
-                                  dependencies : [threads,
-                                                  libmicrohttpd,
-                                                  libgnutls,
-                                                  libxz,
-                                                  liblz4],
-                                  install_rpath : rootlibexecdir,
-                                  install : true,
-                                  install_dir : rootlibexecdir)
-        public_programs += [s_j_remote, s_j_gatewayd]
+        public_programs += executable(
+                'systemd-journal-remote',
+                systemd_journal_remote_sources,
+                include_directories : includes,
+                link_with : [libshared,
+                             libsystemd_journal_remote],
+                dependencies : [threads,
+                                libmicrohttpd,
+                                libgnutls,
+                                libxz,
+                                liblz4,
+                                libzstd],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
+
+        public_programs += executable(
+                'systemd-journal-gatewayd',
+                systemd_journal_gatewayd_sources,
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [threads,
+                                libmicrohttpd,
+                                libgnutls,
+                                libxz,
+                                liblz4,
+                                libzstd],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
 endif
 
 if conf.get('ENABLE_COREDUMP') == 1
-        executable('systemd-coredump',
-                   systemd_coredump_sources,
-                   include_directories : includes,
-                   link_with : [libshared],
-                   dependencies : [threads,
-                                   libacl,
-                                   libdw,
-                                   libxz,
-                                   liblz4],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
-
-        exe = executable('coredumpctl',
-                         coredumpctl_sources,
-                         include_directories : includes,
-                         link_with : [libshared],
-                         dependencies : [threads,
-                                         libxz,
-                                         liblz4],
-                         install_rpath : rootlibexecdir,
-                         install : true)
-        public_programs += exe
+        executable(
+                'systemd-coredump',
+                systemd_coredump_sources,
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [threads,
+                                libacl,
+                                libdw,
+                                libxz,
+                                liblz4,
+                                libzstd],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
+
+        public_programs += executable(
+                'coredumpctl',
+                coredumpctl_sources,
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [threads,
+                                libxz,
+                                liblz4,
+                                libzstd],
+                install_rpath : rootlibexecdir,
+                install : true)
 endif
 
 if conf.get('ENABLE_PSTORE') == 1
-        executable('systemd-pstore',
-                   systemd_pstore_sources,
-                   include_directories : includes,
-                   link_with : [libshared],
-                   dependencies : [threads,
-                                   libacl,
-                                   libdw,
-                                   libxz,
-                                   liblz4],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
+        executable(
+                'systemd-pstore',
+                systemd_pstore_sources,
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [threads,
+                                libacl,
+                                libdw,
+                                libxz,
+                                liblz4,
+                                libzstd],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
 endif
 
 if conf.get('ENABLE_BINFMT') == 1
-        exe = executable('systemd-binfmt',
-                         'src/binfmt/binfmt.c',
-                         include_directories : includes,
-                         link_with : [libshared],
-                         install_rpath : rootlibexecdir,
-                         install : true,
-                         install_dir : rootlibexecdir)
-        public_programs += exe
+        public_programs += executable(
+                'systemd-binfmt',
+                'src/binfmt/binfmt.c',
+                include_directories : includes,
+                link_with : [libshared],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
 
         meson.add_install_script('sh', '-c',
                                  mkdir_p.format(binfmtdir))
@@ -2516,18 +2601,19 @@ if conf.get('ENABLE_BINFMT') == 1
 endif
 
 if conf.get('ENABLE_REPART') == 1
-        exe = executable('systemd-repart',
-                   systemd_repart_sources,
-                   include_directories : includes,
-                   link_with : [libshared],
-                   dependencies : [threads,
-                                   libcryptsetup,
-                                   libblkid,
-                                   libfdisk,
-                                   libopenssl],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootbindir)
+        exe = executable(
+                'systemd-repart',
+                systemd_repart_sources,
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [threads,
+                                libcryptsetup,
+                                libblkid,
+                                libfdisk,
+                                libopenssl],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootbindir)
 
         if want_tests != 'false'
                 test('test-repart',
@@ -2537,61 +2623,67 @@ if conf.get('ENABLE_REPART') == 1
 endif
 
 if conf.get('ENABLE_VCONSOLE') == 1
-        executable('systemd-vconsole-setup',
-                   'src/vconsole/vconsole-setup.c',
-                   include_directories : includes,
-                   link_with : [libshared],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
+        executable(
+                'systemd-vconsole-setup',
+                'src/vconsole/vconsole-setup.c',
+                include_directories : includes,
+                link_with : [libshared],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
 endif
 
 if conf.get('ENABLE_RANDOMSEED') == 1
-        executable('systemd-random-seed',
-                   'src/random-seed/random-seed.c',
-                   include_directories : includes,
-                   link_with : [libshared],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
+        executable(
+                'systemd-random-seed',
+                'src/random-seed/random-seed.c',
+                include_directories : includes,
+                link_with : [libshared],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
 endif
 
 if conf.get('ENABLE_FIRSTBOOT') == 1
-        executable('systemd-firstboot',
-                   'src/firstboot/firstboot.c',
-                   include_directories : includes,
-                   link_with : [libshared],
-                   dependencies : [libcrypt],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootbindir)
-endif
-
-executable('systemd-remount-fs',
-           'src/remount-fs/remount-fs.c',
-           include_directories : includes,
-           link_with : [libcore_shared,
-                        libshared],
-           install_rpath : rootlibexecdir,
-           install : true,
-           install_dir : rootlibexecdir)
+        executable(
+                'systemd-firstboot',
+                'src/firstboot/firstboot.c',
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [libcrypt],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootbindir)
+endif
+
+executable(
+        'systemd-remount-fs',
+        'src/remount-fs/remount-fs.c',
+        include_directories : includes,
+        link_with : [libcore_shared,
+                     libshared],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : rootlibexecdir)
 
-executable('systemd-machine-id-setup',
-           'src/machine-id-setup/machine-id-setup-main.c',
-           include_directories : includes,
-           link_with : [libcore_shared,
-                        libshared],
-           install_rpath : rootlibexecdir,
-           install : true,
-           install_dir : rootbindir)
+executable(
+        'systemd-machine-id-setup',
+        'src/machine-id-setup/machine-id-setup-main.c',
+        include_directories : includes,
+        link_with : [libcore_shared,
+                     libshared],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : rootbindir)
 
-executable('systemd-fsck',
-           'src/fsck/fsck.c',
-           include_directories : includes,
-           link_with : [libshared],
-           install_rpath : rootlibexecdir,
-           install : true,
-           install_dir : rootlibexecdir)
+executable(
+        'systemd-fsck',
+        'src/fsck/fsck.c',
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : rootlibexecdir)
 
 executable('systemd-growfs',
            'src/partition/growfs.c',
@@ -2602,217 +2694,227 @@ executable('systemd-growfs',
            install : true,
            install_dir : rootlibexecdir)
 
-executable('systemd-makefs',
-           'src/partition/makefs.c',
-           include_directories : includes,
-           link_with : [libshared],
-           install_rpath : rootlibexecdir,
-           install : true,
-           install_dir : rootlibexecdir)
+executable(
+        'systemd-makefs',
+        'src/partition/makefs.c',
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : rootlibexecdir)
 
-executable('systemd-sleep',
-           'src/sleep/sleep.c',
-           include_directories : includes,
-           link_with : [libshared],
-           install_rpath : rootlibexecdir,
-           install : true,
-           install_dir : rootlibexecdir)
+executable(
+        'systemd-sleep',
+        'src/sleep/sleep.c',
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : rootlibexecdir)
 
 install_data('src/sleep/sleep.conf',
              install_dir : pkgsysconfdir)
 
-exe = executable('systemd-sysctl',
-                 'src/sysctl/sysctl.c',
-                 include_directories : includes,
-                 link_with : [libshared],
-                 install_rpath : rootlibexecdir,
-                 install : true,
-                 install_dir : rootlibexecdir)
-public_programs += exe
-
-executable('systemd-ac-power',
-           'src/ac-power/ac-power.c',
-           include_directories : includes,
-           link_with : [libshared],
-           install_rpath : rootlibexecdir,
-           install : true,
-           install_dir : rootlibexecdir)
+public_programs += executable(
+        'systemd-sysctl',
+        'src/sysctl/sysctl.c',
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : rootlibexecdir)
 
-exe = executable('systemd-detect-virt',
-                 'src/detect-virt/detect-virt.c',
-                 include_directories : includes,
-                 link_with : [libshared],
-                 install_rpath : rootlibexecdir,
-                 install : true)
-public_programs += exe
-
-exe = executable('systemd-delta',
-                 'src/delta/delta.c',
-                 include_directories : includes,
-                 link_with : [libshared],
-                 install_rpath : rootlibexecdir,
-                 install : true)
-public_programs += exe
-
-exe = executable('systemd-escape',
-                 'src/escape/escape.c',
-                 include_directories : includes,
-                 link_with : [libshared],
-                 install_rpath : rootlibexecdir,
-                 install : true,
-                 install_dir : rootbindir)
-public_programs += exe
-
-exe = executable('systemd-notify',
-                 'src/notify/notify.c',
-                 include_directories : includes,
-                 link_with : [libshared],
-                 install_rpath : rootlibexecdir,
-                 install : true,
-                 install_dir : rootbindir)
-public_programs += exe
-
-executable('systemd-volatile-root',
-           'src/volatile-root/volatile-root.c',
-           include_directories : includes,
-           link_with : [libshared],
-           install_rpath : rootlibexecdir,
-           install : true,
-           install_dir : rootlibexecdir)
+executable(
+        'systemd-ac-power',
+        'src/ac-power/ac-power.c',
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : rootlibexecdir)
 
-executable('systemd-cgroups-agent',
-           'src/cgroups-agent/cgroups-agent.c',
-           include_directories : includes,
-           link_with : [libshared],
-           install_rpath : rootlibexecdir,
-           install : true,
-           install_dir : rootlibexecdir)
+public_programs += executable(
+        'systemd-detect-virt',
+        'src/detect-virt/detect-virt.c',
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : true)
 
-exe = executable('systemd-id128',
-                 'src/id128/id128.c',
-                 include_directories : includes,
-                 link_with : [libshared],
-                 install_rpath : rootlibexecdir,
-                 install : true)
-public_programs += exe
-
-exe = executable('systemd-path',
-                 'src/path/path.c',
-                 include_directories : includes,
-                 link_with : [libshared],
-                 install_rpath : rootlibexecdir,
-                 install : true)
-public_programs += exe
-
-exe = executable('systemd-ask-password',
-                 'src/ask-password/ask-password.c',
-                 include_directories : includes,
-                 link_with : [libshared],
-                 install_rpath : rootlibexecdir,
-                 install : true,
-                 install_dir : rootbindir)
-public_programs += exe
-
-executable('systemd-reply-password',
-           'src/reply-password/reply-password.c',
-           include_directories : includes,
-           link_with : [libshared],
-           install_rpath : rootlibexecdir,
-           install : true,
-           install_dir : rootlibexecdir)
+public_programs += executable(
+        'systemd-delta',
+        'src/delta/delta.c',
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : true)
 
-exe = executable('systemd-tty-ask-password-agent',
-                 'src/tty-ask-password-agent/tty-ask-password-agent.c',
-                 include_directories : includes,
-                 link_with : [libshared],
-                 install_rpath : rootlibexecdir,
-                 install : true,
-                 install_dir : rootbindir)
-public_programs += exe
-
-exe = executable('systemd-cgls',
-                 'src/cgls/cgls.c',
-                 include_directories : includes,
-                 link_with : [libshared],
-                 install_rpath : rootlibexecdir,
-                 install : true)
-public_programs += exe
-
-exe = executable('systemd-cgtop',
-                 'src/cgtop/cgtop.c',
-                 include_directories : includes,
-                 link_with : [libshared],
-                 install_rpath : rootlibexecdir,
-                 install : true)
-public_programs += exe
-
-executable('systemd-initctl',
-           'src/initctl/initctl.c',
-           include_directories : includes,
-           link_with : [libshared],
-           install_rpath : rootlibexecdir,
-           install : true,
-           install_dir : rootlibexecdir)
+public_programs += executable(
+        'systemd-escape',
+        'src/escape/escape.c',
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : rootbindir)
+
+public_programs += executable(
+        'systemd-notify',
+        'src/notify/notify.c',
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : rootbindir)
+
+executable(
+        'systemd-volatile-root',
+        'src/volatile-root/volatile-root.c',
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : conf.get('ENABLE_INITRD') == 1,
+        install_dir : rootlibexecdir)
+
+executable(
+        'systemd-cgroups-agent',
+        'src/cgroups-agent/cgroups-agent.c',
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : rootlibexecdir)
+
+public_programs += executable(
+        'systemd-id128',
+        'src/id128/id128.c',
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : true)
+
+public_programs += executable(
+        'systemd-path',
+        'src/path/path.c',
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : true)
+
+public_programs += executable(
+        'systemd-ask-password',
+        'src/ask-password/ask-password.c',
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : rootbindir)
+
+executable(
+        'systemd-reply-password',
+        'src/reply-password/reply-password.c',
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : rootlibexecdir)
+
+public_programs += executable(
+        'systemd-tty-ask-password-agent',
+        'src/tty-ask-password-agent/tty-ask-password-agent.c',
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : rootbindir)
+
+public_programs += executable(
+        'systemd-cgls',
+        'src/cgls/cgls.c',
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : true)
+
+public_programs += executable(
+        'systemd-cgtop',
+        'src/cgtop/cgtop.c',
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : true)
 
-exe = executable('systemd-mount',
-                 'src/mount/mount-tool.c',
-                 include_directories : includes,
-                 link_with : [libshared],
-                 dependencies: [libmount],
-                 install_rpath : rootlibexecdir,
-                 install : true)
-public_programs += exe
+executable(
+        'systemd-initctl',
+        'src/initctl/initctl.c',
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : rootlibexecdir)
+
+public_programs += executable(
+        'systemd-mount',
+        'src/mount/mount-tool.c',
+        include_directories : includes,
+        link_with : [libshared],
+        dependencies: [libmount],
+        install_rpath : rootlibexecdir,
+        install : true)
 
 meson.add_install_script(meson_make_symlink,
                          'systemd-mount', join_paths(bindir, 'systemd-umount'))
 
-exe = executable('systemd-run',
-                 'src/run/run.c',
-                 include_directories : includes,
-                 link_with : [libshared],
-                 install_rpath : rootlibexecdir,
-                 install : true)
-public_programs += exe
-
-exe = executable('systemd-stdio-bridge',
-                 'src/stdio-bridge/stdio-bridge.c',
-                 include_directories : includes,
-                 link_with : [libshared],
-                 dependencies : [versiondep],
-                 install_rpath : rootlibexecdir,
-                 install : true)
-public_programs += exe
-
-exe = executable('busctl',
-                 'src/busctl/busctl.c',
-                 'src/busctl/busctl-introspect.c',
-                 'src/busctl/busctl-introspect.h',
-                 include_directories : includes,
-                 link_with : [libshared],
-                 install_rpath : rootlibexecdir,
-                 install : true)
-public_programs += exe
+public_programs += executable(
+        'systemd-run',
+        'src/run/run.c',
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : true)
+
+public_programs += executable(
+        'systemd-stdio-bridge',
+        'src/stdio-bridge/stdio-bridge.c',
+        include_directories : includes,
+        link_with : [libshared],
+        dependencies : [versiondep],
+        install_rpath : rootlibexecdir,
+        install : true)
+
+public_programs += executable(
+        'busctl',
+        'src/busctl/busctl.c',
+        'src/busctl/busctl-introspect.c',
+        'src/busctl/busctl-introspect.h',
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : true)
 
 if conf.get('ENABLE_SYSUSERS') == 1
-        exe = executable('systemd-sysusers',
-                         'src/sysusers/sysusers.c',
-                         include_directories : includes,
-                         link_with : [libshared],
-                         install_rpath : rootlibexecdir,
-                         install : true,
-                         install_dir : rootbindir)
-        public_programs += exe
+        public_programs += executable(
+                'systemd-sysusers',
+                'src/sysusers/sysusers.c',
+                include_directories : includes,
+                link_with : [libshared],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootbindir)
 endif
 
 if conf.get('ENABLE_TMPFILES') == 1
-        exe = executable('systemd-tmpfiles',
-                         'src/tmpfiles/tmpfiles.c',
-                         include_directories : includes,
-                         link_with : [libshared],
-                         dependencies : [libacl],
-                         install_rpath : rootlibexecdir,
-                         install : true,
-                         install_dir : rootbindir)
+        exe = executable(
+                'systemd-tmpfiles',
+                'src/tmpfiles/tmpfiles.c',
+                'src/tmpfiles/offline-passwd.c',
+                'src/tmpfiles/offline-passwd.h',
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [libacl],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootbindir)
         public_programs += exe
 
         if want_tests != 'false'
@@ -2824,109 +2926,114 @@ if conf.get('ENABLE_TMPFILES') == 1
 endif
 
 if conf.get('ENABLE_HWDB') == 1
-        exe = executable('systemd-hwdb',
-                         'src/hwdb/hwdb.c',
-                         'src/libsystemd/sd-hwdb/hwdb-internal.h',
-                         include_directories : includes,
-                         link_with : [libudev_static],
-                         install_rpath : udev_rpath,
-                         install : true,
-                         install_dir : rootbindir)
-        public_programs += exe
+        public_programs += executable(
+                'systemd-hwdb',
+                'src/hwdb/hwdb.c',
+                'src/libsystemd/sd-hwdb/hwdb-internal.h',
+                include_directories : includes,
+                link_with : [libudev_static],
+                install_rpath : udev_rpath,
+                install : true,
+                install_dir : rootbindir)
 endif
 
 if conf.get('ENABLE_QUOTACHECK') == 1
-        executable('systemd-quotacheck',
-                   'src/quotacheck/quotacheck.c',
-                   include_directories : includes,
-                   link_with : [libshared],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
-endif
-
-exe = executable('systemd-socket-proxyd',
-                 'src/socket-proxy/socket-proxyd.c',
-                 include_directories : includes,
-                 link_with : [libshared],
-                 dependencies : [threads],
-                 install_rpath : rootlibexecdir,
-                 install : true,
-                 install_dir : rootlibexecdir)
-public_programs += exe
-
-exe = executable('systemd-udevd',
-                 systemd_udevd_sources,
-                 include_directories : includes,
-                 c_args : '-DLOG_REALM=LOG_REALM_UDEV',
-                 link_with : [libudev_core,
-                              libsystemd_network,
-                              libudev_static],
-                 dependencies : [versiondep,
-                                 threads,
-                                 libkmod,
-                                 libidn,
-                                 libacl,
-                                 libblkid],
-                 install_rpath : udev_rpath,
-                 install : true,
-                 install_dir : rootlibexecdir)
-public_programs += exe
-
-exe = executable('udevadm',
-                 udevadm_sources,
-                 c_args : '-DLOG_REALM=LOG_REALM_UDEV',
-                 include_directories : includes,
-                 link_with : [libudev_core,
-                              libsystemd_network,
-                              libudev_static],
-                 dependencies : [versiondep,
-                                 threads,
-                                 libkmod,
-                                 libidn,
-                                 libacl,
-                                 libblkid],
-                 install_rpath : udev_rpath,
-                 install : true,
-                 install_dir : rootbindir)
-public_programs += exe
-
-executable('systemd-shutdown',
-           systemd_shutdown_sources,
-           include_directories : includes,
-           link_with : [libcore_shared,
-                        libshared],
-           dependencies : [libmount],
-           install_rpath : rootlibexecdir,
-           install : true,
-           install_dir : rootlibexecdir)
+        executable(
+                'systemd-quotacheck',
+                'src/quotacheck/quotacheck.c',
+                include_directories : includes,
+                link_with : [libshared],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
+endif
+
+public_programs += executable(
+        'systemd-socket-proxyd',
+        'src/socket-proxy/socket-proxyd.c',
+        include_directories : includes,
+        link_with : [libshared],
+        dependencies : [threads],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : rootlibexecdir)
 
-executable('systemd-update-done',
-           'src/update-done/update-done.c',
-           include_directories : includes,
-           link_with : [libshared],
-           install_rpath : rootlibexecdir,
-           install : true,
-           install_dir : rootlibexecdir)
+public_programs += executable(
+        'systemd-udevd',
+        systemd_udevd_sources,
+        include_directories : includes,
+        c_args : '-DLOG_REALM=LOG_REALM_UDEV',
+        link_with : [libudev_core,
+                     libsystemd_network,
+                     libudev_static],
+        dependencies : [versiondep,
+                        threads,
+                        libkmod,
+                        libidn,
+                        libacl,
+                        libblkid],
+        install_rpath : udev_rpath,
+        install : true,
+        install_dir : rootlibexecdir)
 
-executable('systemd-update-utmp',
-           'src/update-utmp/update-utmp.c',
-           include_directories : includes,
-           link_with : [libshared],
-           dependencies : [libaudit],
-           install_rpath : rootlibexecdir,
-           install : true,
-           install_dir : rootlibexecdir)
+public_programs += executable(
+        'udevadm',
+        udevadm_sources,
+        c_args : '-DLOG_REALM=LOG_REALM_UDEV',
+        include_directories : includes,
+        link_with : [libudev_core,
+                     libsystemd_network,
+                     libudev_static],
+        dependencies : [versiondep,
+                        threads,
+                        libkmod,
+                        libidn,
+                        libacl,
+                        libblkid],
+        install_rpath : udev_rpath,
+        install : true,
+        install_dir : rootbindir)
+
+executable(
+        'systemd-shutdown',
+        systemd_shutdown_sources,
+        include_directories : includes,
+        link_with : [libcore_shared,
+                     libshared],
+        dependencies : [libmount],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : rootlibexecdir)
+
+executable(
+        'systemd-update-done',
+        'src/update-done/update-done.c',
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : rootlibexecdir)
+
+executable(
+        'systemd-update-utmp',
+        'src/update-utmp/update-utmp.c',
+        include_directories : includes,
+        link_with : [libshared],
+        dependencies : [libaudit],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : rootlibexecdir)
 
 if conf.get('HAVE_KMOD') == 1
-        executable('systemd-modules-load',
-                   'src/modules-load/modules-load.c',
-                   include_directories : includes,
-                   link_with : [libshared],
-                   dependencies : [libkmod],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
+        executable(
+                'systemd-modules-load',
+                'src/modules-load/modules-load.c',
+                include_directories : includes,
+                link_with : [libshared],
+                dependencies : [libkmod],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
 
         meson.add_install_script('sh', '-c',
                                  mkdir_p.format(modulesloaddir))
@@ -2934,57 +3041,60 @@ if conf.get('HAVE_KMOD') == 1
                                  mkdir_p.format(join_paths(sysconfdir, 'modules-load.d')))
 endif
 
-exe = executable('systemd-nspawn',
-                 systemd_nspawn_sources,
-                 include_directories : includes,
-                 link_with : [libcore_shared,
-                              libnspawn_core,
-                              libshared],
-                 dependencies : [libblkid,
-                                 libseccomp],
-                 install_rpath : rootlibexecdir,
-                 install : true)
-public_programs += exe
+public_programs += executable(
+        'systemd-nspawn',
+        systemd_nspawn_sources,
+        include_directories : includes,
+        link_with : [libcore_shared,
+                     libnspawn_core,
+                     libshared],
+        dependencies : [libblkid,
+                        libseccomp],
+        install_rpath : rootlibexecdir,
+        install : true)
 
 if conf.get('ENABLE_NETWORKD') == 1
-        executable('systemd-networkd',
-                   systemd_networkd_sources,
-                   include_directories : network_include_dir,
-                   link_with : [libnetworkd_core,
-                                libsystemd_network,
-                                libudev_static,
-                                networkd_link_with],
-                   dependencies : [threads],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
-
-        executable('systemd-networkd-wait-online',
-                   systemd_networkd_wait_online_sources,
-                   include_directories : includes,
-                   link_with : [libnetworkd_core,
-                                networkd_link_with],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
-
-        exe = executable('networkctl',
-                   networkctl_sources,
-                   include_directories : includes,
-                   link_with : [libsystemd_network,
-                              networkd_link_with],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootbindir)
-        public_programs += exe
-
-        exe = executable('systemd-network-generator',
-                   network_generator_sources,
-                   include_directories : includes,
-                   link_with : [networkd_link_with],
-                   install_rpath : rootlibexecdir,
-                   install : true,
-                   install_dir : rootlibexecdir)
+        executable(
+                'systemd-networkd',
+                systemd_networkd_sources,
+                include_directories : network_include_dir,
+                link_with : [libnetworkd_core,
+                             libsystemd_network,
+                             libudev_static,
+                             networkd_link_with],
+                dependencies : [threads],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
+
+        executable(
+                'systemd-networkd-wait-online',
+                systemd_networkd_wait_online_sources,
+                include_directories : includes,
+                link_with : [libnetworkd_core,
+                             networkd_link_with],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
+
+        public_programs += executable(
+                'networkctl',
+                networkctl_sources,
+                include_directories : includes,
+                link_with : [libsystemd_network,
+                             networkd_link_with],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootbindir)
+
+        exe = executable(
+                'systemd-network-generator',
+                network_generator_sources,
+                include_directories : includes,
+                link_with : [networkd_link_with],
+                install_rpath : rootlibexecdir,
+                install : true,
+                install_dir : rootlibexecdir)
 
         if want_tests != 'false'
                 test('test-network-generator-conversion',
@@ -2994,13 +3104,14 @@ if conf.get('ENABLE_NETWORKD') == 1
         endif
 endif
 
-executable('systemd-sulogin-shell',
-           ['src/sulogin-shell/sulogin-shell.c'],
-           include_directories : includes,
-           link_with : [libshared],
-           install_rpath : rootlibexecdir,
-           install : true,
-           install_dir : rootlibexecdir)
+executable(
+        'systemd-sulogin-shell',
+        ['src/sulogin-shell/sulogin-shell.c'],
+        include_directories : includes,
+        link_with : [libshared],
+        install_rpath : rootlibexecdir,
+        install : true,
+        install_dir : rootlibexecdir)
 
 ############################################################
 
@@ -3009,7 +3120,7 @@ custom_target(
         output : 'systemd-runtest.env',
         command : ['sh', '-c', '{ ' +
                    'echo SYSTEMD_TEST_DATA=@0@; '.format(join_paths(project_source_root, 'test')) +
-                   'echo SYSTEMD_CATALOG_DIR=@0@; '.format(join_paths(meson.current_build_dir(), 'catalog')) +
+                   'echo SYSTEMD_CATALOG_DIR=@0@; '.format(join_paths(project_build_root, 'catalog')) +
                    '} >@OUTPUT@'],
         build_by_default : true)
 
@@ -3114,41 +3225,42 @@ endif
 fuzzer_exes = []
 
 if get_option('tests') != 'false'
-foreach tuple : fuzzers
-        sources = tuple[0]
-        link_with = tuple[1].length() > 0 ? tuple[1] : [libshared]
-        dependencies = tuple[2]
-        defs = tuple.length() >= 4 ? tuple[3] : []
-        incs = tuple.length() >= 5 ? tuple[4] : includes
-        link_args = []
-
-        if want_ossfuzz
-                dependencies += fuzzing_engine
-        elif want_libfuzzer
-                if fuzzing_engine.found()
+        foreach tuple : fuzzers
+                sources = tuple[0]
+                link_with = tuple[1].length() > 0 ? tuple[1] : [libshared]
+                dependencies = tuple[2]
+                defs = tuple.length() >= 4 ? tuple[3] : []
+                incs = tuple.length() >= 5 ? tuple[4] : includes
+                link_args = []
+
+                if want_ossfuzz
                         dependencies += fuzzing_engine
+                elif want_libfuzzer
+                        if fuzzing_engine.found()
+                                dependencies += fuzzing_engine
+                        else
+                                link_args += ['-fsanitize=fuzzer']
+                        endif
                 else
-                        link_args += ['-fsanitize=fuzzer']
+                        sources += 'src/fuzz/fuzz-main.c'
                 endif
-        else
-                sources += 'src/fuzz/fuzz-main.c'
-        endif
 
-        name = sources[0].split('/')[-1].split('.')[0]
+                name = sources[0].split('/')[-1].split('.')[0]
 
-        fuzzer_exes += executable(
-                name,
-                sources,
-                include_directories : [incs, include_directories('src/fuzz')],
-                link_with : link_with,
-                dependencies : dependencies,
-                c_args : defs,
-                link_args: link_args,
-                install : false)
-endforeach
+                fuzzer_exes += executable(
+                        name,
+                        sources,
+                        include_directories : [incs, include_directories('src/fuzz')],
+                        link_with : link_with,
+                        dependencies : dependencies,
+                        c_args : defs,
+                        link_args: link_args,
+                        install : false)
+        endforeach
 endif
 
-run_target('fuzzers',
+run_target(
+        'fuzzers',
         depends : fuzzer_exes,
         command : ['true'])
 
@@ -3157,8 +3269,8 @@ run_target('fuzzers',
 make_directive_index_py = find_program('tools/make-directive-index.py')
 make_man_index_py = find_program('tools/make-man-index.py')
 xml_helper_py = find_program('tools/xml_helper.py')
-hwdb_update_sh = find_program('tools/meson-hwdb-update.sh')
-autosuspend_update_sh = find_program('tools/meson-autosuspend-update.sh')
+hwdb_update_sh = find_program('tools/hwdb-update.sh')
+autosuspend_update_sh = find_program('tools/autosuspend-update.sh')
 
 subdir('sysctl.d')
 subdir('sysusers.d')
@@ -3199,13 +3311,13 @@ meson.add_install_script('sh', '-c', 'touch $DESTDIR@0@'.format(prefixdir))
 
 ############################################################
 
-meson_check_help = find_program('tools/meson-check-help.sh')
+check_help = find_program('tools/check-help.sh')
 
 foreach exec : public_programs
         name = exec.full_path().split('/')[-1]
         if want_tests != 'false'
                 test('check-help-' + name,
-                     meson_check_help,
+                     check_help,
                      args : exec.full_path())
         endif
 endforeach
@@ -3256,6 +3368,8 @@ foreach tuple : sanitizers
                         if want_tests != 'false' and slow_tests
                                 test('@0@:@1@:@2@'.format(b, c, sanitizer),
                                      env,
+                                     env : ['UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1'],
+                                     timeout : 60,
                                      args : [exe.full_path(),
                                              join_paths(project_source_root, p)])
                         endif
@@ -3284,10 +3398,10 @@ if git.found()
 endif
 
 if git.found()
-        meson_git_contrib_sh = find_program('tools/meson-git-contrib.sh')
+        git_contrib_sh = find_program('tools/git-contrib.sh')
         run_target(
                 'git-contrib',
-                command : [meson_git_contrib_sh])
+                command : [git_contrib_sh])
 endif
 
 if git.found()
@@ -3311,11 +3425,11 @@ endif
 
 ############################################################
 
-meson_check_api_docs_sh = find_program('tools/meson-check-api-docs.sh')
+check_api_docs_sh = find_program('tools/check-api-docs.sh')
 run_target(
         'check-api-docs',
         depends : [man, libsystemd, libudev],
-        command : [meson_check_api_docs_sh, libsystemd.full_path(), libudev.full_path()])
+        command : [check_api_docs_sh, libsystemd.full_path(), libudev.full_path()])
 
 ############################################################
 watchdog_opt = service_watchdog == '' ? 'disabled' : service_watchdog
@@ -3423,6 +3537,7 @@ foreach tuple : [
         ['SMACK'],
         ['zlib'],
         ['xz'],
+        ['zstd'],
         ['lz4'],
         ['bzip2'],
         ['ACL'],
@@ -3433,6 +3548,7 @@ foreach tuple : [
         ['openssl'],
         ['libcurl'],
         ['idn'],
+        ['initrd'],
         ['libidn2'],
         ['libidn'],
         ['libiptc'],
index 3526645a5902a40bd87df3b86ba1f051ae8cc4fc..e9fff1660c8884b16ac87ac9e89be0419e43f251 100644 (file)
@@ -35,6 +35,8 @@ option('telinit-path', type : 'string', value : '/lib/sysvinit/telinit',
        description : 'path to telinit')
 option('rc-local', type : 'string',
        value : '/etc/rc.local')
+option('initrd', type: 'boolean',
+       description : 'install services for use when running systemd in initrd')
 
 option('quotaon-path', type : 'string', description : 'path to quotaon')
 option('quotacheck-path', type : 'string', description : 'path to quotacheck')
@@ -289,7 +291,7 @@ option('libcryptsetup', type : 'combo', choices : ['auto', 'true', 'false'],
 option('libcurl', type : 'combo', choices : ['auto', 'true', 'false'],
        description : 'libcurl support')
 option('idn', type : 'boolean',
-       description : 'use IDN when printing host names')
+       description : 'use IDN when printing hostnames')
 option('libidn2', type : 'combo', choices : ['auto', 'true', 'false'],
        description : 'libidn2 support')
 option('libidn', type : 'combo', choices : ['auto', 'true', 'false'],
@@ -316,6 +318,8 @@ option('xz', type : 'combo', choices : ['auto', 'true', 'false'],
        description : 'xz compression support')
 option('lz4', type : 'combo', choices : ['auto', 'true', 'false'],
        description : 'lz4 compression support')
+option('zstd', type : 'combo', choices : ['auto', 'true', 'false'],
+       description : 'zstd compression support')
 option('xkbcommon', type : 'combo', choices : ['auto', 'true', 'false'],
        description : 'xkbcommon keymap support')
 option('pcre2', type : 'combo', choices : ['auto', 'true', 'false'],
index 55d3c82287039a50f41bd56eba223237cfc121ec..65e5064fe06c16ba0751bb8b22085560f88259f3 100644 (file)
--- a/po/be.po
+++ b/po/be.po
@@ -70,21 +70,21 @@ msgid "Authentication is required to reload the systemd state."
 msgstr "Неабходна аўтэнтыфікацыя для перачытання стану systemd."
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "Усталяваць імя вузла"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "Неабходна аўтэнтыфікацыя для ўсталявання імя вузла."
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "Усталяваць статычнае імя вузла"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr ""
 "Неабходна аўтэнтыфікацыя для ўсталявання як статычнага так і прыгожага імя "
 "вузла."
index bbd9223b748763bf772671c22f462e4eca486844..1ce3efa8f532c3bdafcc1b952e11251dad85df27 100644 (file)
@@ -70,21 +70,21 @@ msgid "Authentication is required to reload the systemd state."
 msgstr "Nieabchodna aŭtentyfikacyja dlia pieračytannia stanu systemd."
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "Ustaliavać imia vuzla"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "Nieabchodna aŭtentyfikacyja dlia ŭstaliavannia imia vuzla."
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "Ustaliavać statyčnaje imia vuzla"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr ""
 "Nieabchodna aŭtentyfikacyja dlia ŭstaliavannia jak statyčnaha tak i "
 "pryhožaha imia vuzla."
index 38b952782489768318819a718b5f4cabc990910a..0e1f50736d610dc9ca5ac3c88ae8c42c6cb2c37c 100644 (file)
--- a/po/bg.po
+++ b/po/bg.po
@@ -69,21 +69,21 @@ msgid "Authentication is required to reload the systemd state."
 msgstr "За презареждане на състоянието на systemd е необходима идентификация."
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "Задаване на име на машината"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "За задаване на име на локалната машина е необходима идентификация."
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "Задаване на статично име на машината"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr ""
 "За задаване на статично име на локалната машина е необходима идентификация."
 
index dd8cc56e343b9dd85908e515307ad4f549ffc665..68123ca5da6d292c5be9799f9c6dfde7a926d999 100644 (file)
--- a/po/ca.po
+++ b/po/ca.po
@@ -73,21 +73,21 @@ msgid "Authentication is required to reload the systemd state."
 msgstr "Es requereix autenticació per tornar a carregar l'estat de systemd."
 
 #: src/hostname/org.freedesktop.hostname1.policy:22
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "Estableix el nom d'amfitrió"
 
 #: src/hostname/org.freedesktop.hostname1.policy:23
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "Es requereix autenticació per establir el nom d'amfitrió local."
 
 #: src/hostname/org.freedesktop.hostname1.policy:32
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "Estableix el nom d'amfitrió estàtic"
 
 #: src/hostname/org.freedesktop.hostname1.policy:33
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr ""
 "Es requereix autenticació per establir el nom d'amfitrió local configurat "
 "estàticament, així com el nom bonic d'amfitrió."
index 819800132a4d30af65d9df283fa748dabee66316..78180f638956961d420a4fb2cfc1cabbefbe072e 100644 (file)
--- a/po/cs.po
+++ b/po/cs.po
@@ -120,21 +120,21 @@ msgid ""
 msgstr "Pro změnu hesla domovského adresáře uživatele je vyžadováno ověření."
 
 #: src/hostname/org.freedesktop.hostname1.policy:20
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "Nastavit název stroje"
 
 #: src/hostname/org.freedesktop.hostname1.policy:21
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "Pro nastavení lokálního názvu stroje je vyžadováno ověření."
 
 #: src/hostname/org.freedesktop.hostname1.policy:30
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "Nastavit statický název stroje"
 
 #: src/hostname/org.freedesktop.hostname1.policy:31
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr ""
 "Pro nastavení staticky konfigurovaného názvu lokálního stroje, stejně tak "
 "pro změnu uživatelsky přívětivého jména je vyžadováno ověření."
index 7dee612867656dad3a9cbe49187c8e550a0a3d9e..276c9e10ce6973ca1a326db3c9caac24275dd294 100644 (file)
--- a/po/da.po
+++ b/po/da.po
@@ -66,21 +66,21 @@ msgid "Authentication is required to reload the systemd state."
 msgstr "Autentificering er nødvendig for at genindlæse systemd tilstanden."
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "Sæt værtsnavn"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "Autentificering er nødvendig for at sætte værtsnavn."
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "Sæt statisk værstnavn"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr ""
 "Autentificering er nødvendig for at sætte det statisk konfigurerede lokale "
 "værtsnavn, lige så vel som det pæne værtsnavn."
index cca79207d417bf5a4c903d7b776599eb0c5217b9..c5c753bb09362497030f8cbfe7e06a59d9669309 100644 (file)
--- a/po/de.po
+++ b/po/de.po
@@ -71,21 +71,21 @@ msgid "Authentication is required to reload the systemd state."
 msgstr "Legitimierung ist zum erneuten Laden des systemd-Zustands notwendig."
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "Rechnername festlegen"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "Legitimierung ist zum Festlegen des lokalen Rechnernamens notwendig"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "Statischen Rechnernamen festlegen"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr ""
 "Authentifizierung ist erforderlich, um den statisch geänderten, lokalen "
 "Rechnernamen, sowie den beschönigten Rechnernamen festzulegen."
index d96bf16264fa1d48df724c3171a12e0fc06cba75..c4225334dfccfb9576fa5a208af40f1c7d3a6f41 100644 (file)
--- a/po/el.po
+++ b/po/el.po
@@ -76,21 +76,21 @@ msgid "Authentication is required to reload the systemd state."
 msgstr "Απαιτείται πιστοποίηση για να ορίσετε την ώρα του συστήματος."
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "Ορισμός ονόματος οικοδεσπότη"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη."
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "Ορισμός στατικού ονόματος οικοδεσπότη"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr ""
 "Απαιτείται πιστοποίηση για να ορίσετε το στατικά ρυθμισμένο όνομα τοπικού "
 "οικοδεσπότη, καθώς και το pretty όνομα οικοδεσπότη."
index aa586a729d9998b2a5fa5106a4066b7a5bb61387..adfe827bc4f7b1e84d4be1ba5e0a72ecadaffebe 100644 (file)
--- a/po/es.po
+++ b/po/es.po
@@ -71,21 +71,21 @@ msgid "Authentication is required to reload the systemd state."
 msgstr "Se requiere autenticación para recargar el estado de systemd."
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "Establecer el nombre del equipo"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "Se requiere autenticación para establecer el nombre del equipo local."
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "Establecer nombre estático del equipo"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr ""
 "Se requiere autenticación para establecer el nombre estático de equipo "
 "local, así como el nombre visible del equipo."
index 0c5e0530184a0e7e8fa2e58f8eecd93494e326db..0999cf9dce766cbc87f14c6813816cedd26962e9 100644 (file)
--- a/po/fr.po
+++ b/po/fr.po
@@ -125,21 +125,21 @@ msgstr ""
 "d'un utilisateur."
 
 #: src/hostname/org.freedesktop.hostname1.policy:20
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "Définir le nom d'hôte"
 
 #: src/hostname/org.freedesktop.hostname1.policy:21
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "Authentification requise pour définir le nom d'hôte local."
 
 #: src/hostname/org.freedesktop.hostname1.policy:30
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "Définir le nom d'hôte statique"
 
 #: src/hostname/org.freedesktop.hostname1.policy:31
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr ""
 "Authentification requise pour définir le nom d'hôte local de manière "
 "statique, tout comme le nom d'hôte familier."
index 7796154aa7a495ffa50eed58213a21a25474b138..147d34da845543f1fad933f7a4f7e83652304c9a 100644 (file)
--- a/po/gl.po
+++ b/po/gl.po
@@ -70,21 +70,21 @@ msgid "Authentication is required to reload the systemd state."
 msgstr "Requírese autenticación para recargar o estado de systemd."
 
 #: src/hostname/org.freedesktop.hostname1.policy:20
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "Estabelecer o nome do equipo"
 
 #: src/hostname/org.freedesktop.hostname1.policy:21
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "Requírese autenticación para estabelecer o nome local do equiupo."
 
 #: src/hostname/org.freedesktop.hostname1.policy:30
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "Estabelecer o nome do equipo estático"
 
 #: src/hostname/org.freedesktop.hostname1.policy:31
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr ""
 "Requírese autenticación para estabelecer de forma o nome do equipo local "
 "estabelecido de forma estática, así como o nome do equipo lexíbel por "
index d77fee7df939a63c7b14ba1d0c5c1c90416bffc0..8385d5ae94b6aaa8e28839f4df52346fadf33c2a 100644 (file)
--- a/po/hr.po
+++ b/po/hr.po
@@ -118,21 +118,21 @@ msgid ""
 msgstr "Potrebna je ovjera za promjenu lozinke osobnog prostora korisnika."
 
 #: src/hostname/org.freedesktop.hostname1.policy:20
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "Postavi naziv računala"
 
 #: src/hostname/org.freedesktop.hostname1.policy:21
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "Potrebna je ovjera za postavljanje naziva lokalnog računala."
 
 #: src/hostname/org.freedesktop.hostname1.policy:30
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "Postavi nepromjenjivi naziv račumala"
 
 #: src/hostname/org.freedesktop.hostname1.policy:31
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr ""
 "Potrebna je ovjera za postavljenje nepromjenjivog naziva lokalnog računala, "
 "kao i prijatnog naziva računala."
index c9c8bc786faf6f3fa6eaeb34c36df14d3fa807c4..e4e5d540b72f8b8ee66f54d6384196c236593fcc 100644 (file)
--- a/po/hu.po
+++ b/po/hu.po
@@ -71,21 +71,21 @@ msgid "Authentication is required to reload the systemd state."
 msgstr "Hitelesítés szükséges a systemd állapotának újratöltéséhez."
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "Gépnév beállítása"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "Hitelesítés szükséges a helyi gépnév beállításához."
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "Statikus gépnév beállítása"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr ""
 "Hitelesítés szükséges a statikusan megadott helyi gépnév, valamint a szép "
 "gépnév beállításához."
index 66dd11ec77699d32cbfd7939a11f20d112e2e1e3..efc2ad700edd3b024ea583a3fcbf2cc9a90002c7 100644 (file)
--- a/po/id.po
+++ b/po/id.po
@@ -66,21 +66,21 @@ msgid "Authentication is required to reload the systemd state."
 msgstr "Otentikasi diperlukan untuk memuat ulang keadaan systemd."
 
 #: src/hostname/org.freedesktop.hostname1.policy:22
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "Setel nama host"
 
 #: src/hostname/org.freedesktop.hostname1.policy:23
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "Otentikasi diperlukan untuk menata nama host lokal."
 
 #: src/hostname/org.freedesktop.hostname1.policy:32
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "Setel nama host statik"
 
 #: src/hostname/org.freedesktop.hostname1.policy:33
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr ""
 "Otentikasi diperlukan untuk menata nama host lokal yang dikonfigurasi "
 "statik, maupun nama host cantik."
index 1410586999b2c95c567563db3873337d9ceea924..a2f45bd1d981ddf813c0da1b0db88639d16cabe6 100644 (file)
--- a/po/it.po
+++ b/po/it.po
@@ -124,21 +124,21 @@ msgstr ""
 "dell'utente."
 
 #: src/hostname/org.freedesktop.hostname1.policy:20
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "Configura il nome host"
 
 #: src/hostname/org.freedesktop.hostname1.policy:21
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "Autenticazione richiesta per configurare il nome host locale."
 
 #: src/hostname/org.freedesktop.hostname1.policy:30
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "Configura il nome host statico"
 
 #: src/hostname/org.freedesktop.hostname1.policy:31
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr ""
 "Autenticazione richiesta per configurare staticamente il nome host locale e "
 "il nome host descrittivo."
index 0847af1f71080f9a6e2dd8fbb8029e4d5ca05685..7662bec2e994e2be3df25ccc186a773bbcfb9afb 100644 (file)
--- a/po/ja.po
+++ b/po/ja.po
@@ -110,21 +110,21 @@ msgid "Authentication is required to change the password of a user's home area."
 msgstr "ユーザのホーム領域のパスワードを変更するには認証が必要です。"
 
 #: src/hostname/org.freedesktop.hostname1.policy:20
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "ホスト名の設定"
 
 #: src/hostname/org.freedesktop.hostname1.policy:21
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "ホスト名を設定するには認証が必要です。"
 
 #: src/hostname/org.freedesktop.hostname1.policy:30
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "静的なホスト名の設定"
 
 #: src/hostname/org.freedesktop.hostname1.policy:31
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr "静的なホスト名を設定するには認証が必要です。"
 
 #: src/hostname/org.freedesktop.hostname1.policy:41
index 53899fd9efc9ed921405c31c3feb0a5935f2c035..301a322406f548312e120e1324aad7bb22f7e92e 100644 (file)
--- a/po/ko.po
+++ b/po/ko.po
@@ -66,21 +66,21 @@ msgid "Authentication is required to reload the systemd state."
 msgstr "systemd 상태를 다시 불러오려면 인증이 필요합니다."
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "호스트 이름 설정"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "로컬 호스트 이름을 설정하려면 인증이 필요합니다."
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "정적 호스트 이름 설정"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr ""
 "로컬 호스트 이름을 모양새를 갖춘 호스트 이름 처럼  정적으로 설정하려면 인증"
 "이 필요합니다."
index 3350b56ee169026f9f149758ab0bca49d2d49344..2f03fd65eca205d103f628abfe920b2e7e53c5e8 100644 (file)
--- a/po/lt.po
+++ b/po/lt.po
@@ -68,22 +68,22 @@ msgid "Authentication is required to reload the systemd state."
 msgstr "Norint iš naujo įkelti systemd būseną, reikia patvirtinti tapatybę."
 
 #: src/hostname/org.freedesktop.hostname1.policy:20
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "Nustatyti serverio pavadinimą"
 
 #: src/hostname/org.freedesktop.hostname1.policy:21
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr ""
 "Norint nustatyti vietinio serverio pavadinimą, reikia nustatyti tapatybę."
 
 #: src/hostname/org.freedesktop.hostname1.policy:30
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "Nustatyti statinį serverio pavadinimą"
 
 #: src/hostname/org.freedesktop.hostname1.policy:31
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr ""
 "Norint nustatyti statiškai sukonfigūruotą serverio pavadinimą, o taip pat "
 "lengvai įsimenamą serverio pavadinimą, reikia nustatyti tapatybę."
index 3f7044ada765b4fc8199d9912dacdd138352c466..e942255985d70414621dae8decf133090414171e 100644 (file)
--- a/po/pl.po
+++ b/po/pl.po
@@ -6,8 +6,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: systemd\n"
 "Report-Msgid-Bugs-To: https://github.com/systemd/systemd/issues\n"
-"POT-Creation-Date: 2020-03-07 03:28+0000\n"
-"PO-Revision-Date: 2020-03-15 13:13+0100\n"
+"POT-Creation-Date: 2020-05-01 15:36+0000\n"
+"PO-Revision-Date: 2020-05-03 13:50+0200\n"
 "Last-Translator: Piotr Drąg <piotrdrag@gmail.com>\n"
 "Language-Team: Polish <trans-pl@lists.fedoraproject.org>\n"
 "Language: pl\n"
@@ -130,21 +130,21 @@ msgstr ""
 "użytkownika."
 
 #: src/hostname/org.freedesktop.hostname1.policy:20
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "Ustawienie nazwy komputera"
 
 #: src/hostname/org.freedesktop.hostname1.policy:21
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "Wymagane jest uwierzytelnienie, aby ustawić nazwę lokalnego komputera."
 
 #: src/hostname/org.freedesktop.hostname1.policy:30
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "Ustawienie statycznej nazwy komputera"
 
 #: src/hostname/org.freedesktop.hostname1.policy:31
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby ustawić statycznie skonfigurowaną nazwę "
 "lokalnego komputera, a także jego nazwę czytelną dla człowieka."
@@ -905,25 +905,25 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby kontrolować, czy włączyć synchronizację "
 "czasu przez sieć."
 
-#: src/core/dbus-unit.c:356
+#: src/core/dbus-unit.c:358
 msgid "Authentication is required to start '$(unit)'."
 msgstr "Wymagane jest uwierzytelnienie, aby uruchomić jednostkę „$(unit)”."
 
-#: src/core/dbus-unit.c:357
+#: src/core/dbus-unit.c:359
 msgid "Authentication is required to stop '$(unit)'."
 msgstr "Wymagane jest uwierzytelnienie, aby zatrzymać jednostkę „$(unit)”."
 
-#: src/core/dbus-unit.c:358
+#: src/core/dbus-unit.c:360
 msgid "Authentication is required to reload '$(unit)'."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby ponownie wczytać jednostkę „$(unit)”."
 
-#: src/core/dbus-unit.c:359 src/core/dbus-unit.c:360
+#: src/core/dbus-unit.c:361 src/core/dbus-unit.c:362
 msgid "Authentication is required to restart '$(unit)'."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby ponownie uruchomić jednostkę „$(unit)”."
 
-#: src/core/dbus-unit.c:532
+#: src/core/dbus-unit.c:534
 msgid ""
 "Authentication is required to send a UNIX signal to the processes of "
 "'$(unit)'."
@@ -931,18 +931,18 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby wysłać sygnał uniksowy do procesów "
 "jednostki „$(unit)”."
 
-#: src/core/dbus-unit.c:563
+#: src/core/dbus-unit.c:565
 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby przywrócić stan „failed” (niepowodzenia) "
 "jednostki „$(unit)”."
 
-#: src/core/dbus-unit.c:596
+#: src/core/dbus-unit.c:598
 msgid "Authentication is required to set properties on '$(unit)'."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby ustawić właściwości jednostki „$(unit)”."
 
-#: src/core/dbus-unit.c:705
+#: src/core/dbus-unit.c:707
 msgid ""
 "Authentication is required to delete files and directories associated with "
 "'$(unit)'."
@@ -950,6 +950,13 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby usunąć pliki i katalogi powiązane "
 "z jednostką „$(unit)”."
 
+#: src/core/dbus-unit.c:756
+msgid ""
+"Authentication is required to freeze or thaw the processes of '$(unit)' unit."
+msgstr ""
+"Wymagane jest uwierzytelnienie, aby zamrozić lub odmrozić procesy jednostki "
+"„$(unit)”."
+
 #~ msgid "Press Ctrl+C to cancel all filesystem checks in progress"
 #~ msgstr ""
 #~ "Naciśnięcie klawiszy Ctrl+C anuluje wszystkie trwające procesy "
index 06706fe8fca447cfa07d5c12afbd9a8f81b858f9..09964a12969822cdda772f3848a748e97a43da57 100644 (file)
@@ -74,21 +74,21 @@ msgid "Authentication is required to reload the systemd state."
 msgstr "É necessária autenticação para recarregar o estado do sistema."
 
 #: src/hostname/org.freedesktop.hostname1.policy:20
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "Definir nome de máquina"
 
 #: src/hostname/org.freedesktop.hostname1.policy:21
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "É necessária autenticação para definir nome de máquina local."
 
 #: src/hostname/org.freedesktop.hostname1.policy:30
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "Definir nome estático de máquina"
 
 #: src/hostname/org.freedesktop.hostname1.policy:31
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr ""
 "É necessária autenticação para definir o nome de máquina local configurado "
 "estaticamente, assim como o nome apresentável de máquina."
index e22f1a110a68c222af0f7f92234baa3503af005d..869cf6b625ff0afe4064dd84612a68dc81e9d6b9 100644 (file)
--- a/po/ro.po
+++ b/po/ro.po
@@ -73,21 +73,21 @@ msgid "Authentication is required to reload the systemd state."
 msgstr "Autentificarea este necesară pentru a reîncărca starea systemd."
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "Stabilește numele de server"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "Autentificarea este necesară pentru a stabili numele de server local."
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "Stabilește numele de server static"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr ""
 "Autentificarea este necesara pentru a stabili numele de server static "
 "configurat local, precum și numele lung de server."
index 35da66eefb90fe4c6ecdcdda5fc249a42f1052f3..f13c51f302d4d0d9650b387eeae5496efd14d20e 100644 (file)
--- a/po/ru.po
+++ b/po/ru.po
@@ -134,21 +134,21 @@ msgstr ""
 " пройти аутентификацию."
 
 #: src/hostname/org.freedesktop.hostname1.policy:20
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "Настроить имя компьютера"
 
 #: src/hostname/org.freedesktop.hostname1.policy:21
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "Чтобы настроить имя компьютера, необходимо пройти аутентификацию."
 
 #: src/hostname/org.freedesktop.hostname1.policy:30
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "Настроить статическое имя компьютера"
 
 #: src/hostname/org.freedesktop.hostname1.policy:31
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr ""
 "Чтобы настроить статическое имя компьютера, а также его «красивое» имя, "
 "необходимо пройти аутентификацию."
index ced96e8045ab326e8359ebce7012bc49a1f25208..971df90b28c089922b27fd0fa88d14b91c3375c1 100644 (file)
--- a/po/sk.po
+++ b/po/sk.po
@@ -72,21 +72,21 @@ msgstr ""
 "Vyžaduje sa overenie totožnosti na znovu načítanie stavu systému systemd."
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "Nastavenie názvu hostiteľa"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "Vyžaduje sa overenie totožnosti na nastavenie názvu hostiteľa."
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "Nastavenie nemenného názvu hostiteľa"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr ""
 "Vyžaduje sa overenie totožnosti na nastavenie pevne určeného názvu miestneho "
 "hostiteľa, známeho ako zrozumiteľný názov hostiteľa."
index 3d0bebd503619a3fff9d43156b0d9441f71510ef..a62f5cffe60f7b20e1d3a63831ed78eaf821f57b 100644 (file)
--- a/po/sr.po
+++ b/po/sr.po
@@ -72,21 +72,21 @@ msgstr ""
 "Потребно је да се идентификујете да бисте поново учитали стање систем-деа."
 
 #: src/hostname/org.freedesktop.hostname1.policy.in:22
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "Постави назив машине"
 
 #: src/hostname/org.freedesktop.hostname1.policy.in:23
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "Потребно је да се идентификујете да бисте поставили назив машине."
 
 #: src/hostname/org.freedesktop.hostname1.policy.in:32
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "Постави статички назив машине"
 
 #: src/hostname/org.freedesktop.hostname1.policy.in:33
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr ""
 "Потребно је да се идентификујете да бисте поставили статички назив машине и "
 "да бисте поставили леп назив машине."
index 5f40d455ab3c20deb798018820b0942754025d26..c8bd2ae2742980d3a82a70284f569c40ebde3a49 100644 (file)
--- a/po/sv.po
+++ b/po/sv.po
@@ -68,21 +68,21 @@ msgid "Authentication is required to reload the systemd state."
 msgstr "Autentisering krävs för att läsa om tillståndet för systemd."
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "Ange värdnamn"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "Autentisering krävs för att ställa in lokalt värdnamn."
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "Ange statiskt värdnamn"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr ""
 "Autentisering krävs för att ställa in det statiskt konfigurerade lokala "
 "värdnamnet såväl som det stiliga värdnamnet."
index 86c13448e23290009568f82d59a8ffdd2b867f40..b2af9e900450418f12563f87a29e782dd6e2d68a 100644 (file)
--- a/po/tr.po
+++ b/po/tr.po
@@ -70,21 +70,21 @@ msgid "Authentication is required to reload the systemd state."
 msgstr "systemd durumunu yeniden yüklemek kimlik doğrulaması gerektiriyor."
 
 #: src/hostname/org.freedesktop.hostname1.policy:20
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "Makine adını ayarla"
 
 #: src/hostname/org.freedesktop.hostname1.policy:21
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "Yerel makine adını ayarlamak kimlik doğrulaması gerektiriyor."
 
 #: src/hostname/org.freedesktop.hostname1.policy:30
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "Statik makine adı ayarla"
 
 #: src/hostname/org.freedesktop.hostname1.policy:31
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr ""
 "Statik olarak yapılandırılmış konak makine adını ve yerel makine adını "
 "ayarlamak kimlik doğrulaması gerektiriyor."
index aca1cf735c280ebc0b121a227571c4d7cf167ddb..f0a702802f9c4b4d8b6718932235a19d7cb76d44 100644 (file)
--- a/po/uk.po
+++ b/po/uk.po
@@ -126,21 +126,21 @@ msgstr ""
 "розпізнавання."
 
 #: src/hostname/org.freedesktop.hostname1.policy:20
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "Встановити назву вузла"
 
 #: src/hostname/org.freedesktop.hostname1.policy:21
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "Потрібна автентифікація, щоб встановити назву локального вузла."
 
 #: src/hostname/org.freedesktop.hostname1.policy:30
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "Встановити статичну назву вузла"
 
 #: src/hostname/org.freedesktop.hostname1.policy:31
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr ""
 "Потрібна автентифікація, щоб вказати статично налаштовану назву локального "
 "вузла, так само й форматовану."
index 7196cc50bff2f95e52656bdb99c88c1c30d86569..2655f62c694d07f13f8322fbcb0c16ce8619d76d 100644 (file)
@@ -64,15 +64,15 @@ msgid "Authentication is required to reload the systemd state."
 msgstr "重新载入 systemd 状态需要认证。"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "设置主机名"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "设置本地主机名需要认证。"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "设置静态主机名"
 
 # For pretty hostname, the zh_CN/zh_TW translation should be discussed again.
@@ -81,8 +81,8 @@ msgstr "设置静态主机名"
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
 #, fuzzy
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr "设置静态本地主机名或美观主机名需要认证。"
 
 #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:5
index d14a338e5c4989609decea125f30676d2946905c..ac6cd99efa42337d16d59a83dc319c754fedd628 100644 (file)
@@ -62,21 +62,21 @@ msgid "Authentication is required to reload the systemd state."
 msgstr "重新載入 systemd 狀態需要驗證。"
 
 #: src/hostname/org.freedesktop.hostname1.policy:20
-msgid "Set host name"
+msgid "Set hostname"
 msgstr "設定主機名稱"
 
 #: src/hostname/org.freedesktop.hostname1.policy:21
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
 msgstr "設定主機名稱需要驗證。"
 
 #: src/hostname/org.freedesktop.hostname1.policy:30
-msgid "Set static host name"
+msgid "Set static hostname"
 msgstr "設定靜態主機名稱"
 
 #: src/hostname/org.freedesktop.hostname1.policy:31
 msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
 msgstr "設定靜態預先設定或 pretty 本地主機名稱需要身份驗證。"
 
 #: src/hostname/org.freedesktop.hostname1.policy:41
index 04f6ee2605597978cfb1beb28851076e0f496486..288b2efd0402df006b0169cf62935523acb8668d 100755 (executable)
@@ -36,7 +36,7 @@ apt-get -q --allow-releaseinfo-change update
 apt-get -y dist-upgrade
 apt-get install -y eatmydata
 # The following four are needed as long as these deps are not covered by Debian's own packaging
-apt-get install -y libfdisk-dev libp11-kit-dev libssl-dev libpwquality-dev
+apt-get install -y fdisk libfdisk-dev libp11-kit-dev libssl-dev libpwquality-dev
 apt-get purge --auto-remove -y unattended-upgrades
 systemctl unmask systemd-networkd
 systemctl enable systemd-networkd
@@ -66,9 +66,9 @@ for phase in "${PHASES[@]}"; do
             git checkout FETCH_HEAD debian
 
             # craft changelog
-            UPSTREAM_VER=$(git describe | sed 's/^v//')
+            UPSTREAM_VER=$(git describe | sed 's/^v//;s/-/./g')
             cat << EOF > debian/changelog.new
-systemd (${UPSTREAM_VER}-0) UNRELEASED; urgency=low
+systemd (${UPSTREAM_VER}.0) UNRELEASED; urgency=low
 
   * Automatic build for upstream test
 
index c067bf8f2792ba50c5bd9b4b8ef3f62fa5c9eb9e..582d469c350e660a3eb68cd5f9cb19a2bb0678d6 100644 (file)
@@ -221,7 +221,11 @@ __systemctl()
     _systemctl_failed_units()  {_sys_failed_units=( ${${(f)"$(__systemctl list-units --state=failed "$PREFIX*" )"}%% *} ) }
 
 (( $+functions[_systemctl_unit_state] )) ||
-    _systemctl_unit_state() { typeset -gA _sys_unit_state; _sys_unit_state=( $(__systemctl list-unit-files "$PREFIX*" ) ) }
+    _systemctl_unit_state() {
+        setopt localoptions extendedglob
+        typeset -gA _sys_unit_state
+        _sys_unit_state=( ${=${${(f)"$(__systemctl list-unit-files "$PREFIX*" )"}%%[[:space:]]#}% *} )
+    }
 
 local fun
 # Completion functions for ALL_UNITS
index 89ba46c959d3bef8b60ac54cb2ccc1e980238173..75e72439fd85ec8eafa1951ade51c4e38635855e 100644 (file)
         _describe -t state 'state' _states || compadd "$@"
     }
 
+(( $+functions[_systemd-analyze_cat-config] )) ||
+       _systemd-analyze_cat-config() {
+        _files -W '(/run/systemd/ /etc/systemd/ /usr/lib/systemd/)' -P 'systemd/'
+    }
+
+(( $+functions[_systemd-analyze_security] )) ||
+    _systemd-analyze_security() {
+        _sd_unit_files
+    }
+
 (( $+functions[_systemd-analyze_commands] )) ||
     _systemd-analyze_commands(){
         local -a _systemd_analyze_cmds
             'plot:Output SVG graphic showing service initialization'
             'dot:Dump dependency graph (in dot(1) format)'
             'dump:Dump server status'
+            'cat-config:Cat systemd config files'
+            'unit-files:List files and symlinks for units'
             'unit-paths:List unit load paths'
-            'log-level:Get/set systemd log threshold'
-            'log-target:Get/set systemd log target'
-            'service-watchdogs:Get/set service watchdog status'
+            'exit-status:List known exit statuses'
             'syscall-filter:List syscalls in seccomp filter'
+            'condition:Evaluate Condition*= and Assert*= assignments'
             'verify:Check unit files for correctness'
             'calendar:Validate repetitive calendar time events'
+            'timestamp:Parse a systemd syntax timestamp'
+            'timespan:Parse a systemd syntax timespan'
+            'security:Analyze security settings of a service'
+            # 'log-level:Get/set systemd log threshold'
+            # 'log-target:Get/set systemd log target'
+            # 'service-watchdogs:Get/set service watchdog status'
         )
 
         if (( CURRENT == 1 )); then
index d0cefa099202d08587eea631f05986e537ee5489..d18ee9d043adaf4d3a4327cca0440c6ee6fdfbc8 100644 (file)
@@ -21,6 +21,7 @@ static const condition_definition condition_definitions[] = {
         { "ConditionPathIsSymbolicLink",     config_parse_unit_condition_path,   CONDITION_PATH_IS_SYMBOLIC_LINK    },
         { "ConditionPathIsMountPoint",       config_parse_unit_condition_path,   CONDITION_PATH_IS_MOUNT_POINT      },
         { "ConditionPathIsReadWrite",        config_parse_unit_condition_path,   CONDITION_PATH_IS_READ_WRITE       },
+        { "ConditionPathIsEncrypted",        config_parse_unit_condition_path,   CONDITION_PATH_IS_ENCRYPTED        },
         { "ConditionDirectoryNotEmpty",      config_parse_unit_condition_path,   CONDITION_DIRECTORY_NOT_EMPTY      },
         { "ConditionFileNotEmpty",           config_parse_unit_condition_path,   CONDITION_FILE_NOT_EMPTY           },
         { "ConditionFileIsExecutable",       config_parse_unit_condition_path,   CONDITION_FILE_IS_EXECUTABLE       },
@@ -44,6 +45,7 @@ static const condition_definition condition_definitions[] = {
         { "AssertPathIsSymbolicLink",        config_parse_unit_condition_path,   CONDITION_PATH_IS_SYMBOLIC_LINK    },
         { "AssertPathIsMountPoint",          config_parse_unit_condition_path,   CONDITION_PATH_IS_MOUNT_POINT      },
         { "AssertPathIsReadWrite",           config_parse_unit_condition_path,   CONDITION_PATH_IS_READ_WRITE       },
+        { "AssertPathIsEncrypted",           config_parse_unit_condition_path,   CONDITION_PATH_IS_ENCRYPTED        },
         { "AssertDirectoryNotEmpty",         config_parse_unit_condition_path,   CONDITION_DIRECTORY_NOT_EMPTY      },
         { "AssertFileNotEmpty",              config_parse_unit_condition_path,   CONDITION_FILE_NOT_EMPTY           },
         { "AssertFileIsExecutable",          config_parse_unit_condition_path,   CONDITION_FILE_IS_EXECUTABLE       },
@@ -143,11 +145,11 @@ int verify_conditions(char **lines, UnitFileScope scope) {
                         return r;
         }
 
-        r = condition_test_list(u->asserts, assert_type_to_string, log_helper, u);
+        r = condition_test_list(u->asserts, environ, assert_type_to_string, log_helper, u);
         if (u->asserts)
                 log_notice("Asserts %s.", r > 0 ? "succeeded" : "failed");
 
-        q = condition_test_list(u->conditions, condition_type_to_string, log_helper, u);
+        q = condition_test_list(u->conditions, environ, condition_type_to_string, log_helper, u);
         if (u->conditions)
                 log_notice("Conditions %s.", q > 0 ? "succeeded" : "failed");
 
index d681251c0460ed669a1e9fab14cbc5a76bd31e71..013788397668b9a0b09193ab6910ccd7afc3b502 100644 (file)
@@ -141,7 +141,7 @@ static void security_info_free(struct security_info *i) {
         strv_free(i->supplementary_groups);
         strv_free(i->system_call_architectures);
 
-        set_free_free(i->system_call_filter);
+        set_free(i->system_call_filter);
 }
 
 static bool security_info_runs_privileged(const struct security_info *i)  {
@@ -1728,11 +1728,7 @@ static int property_read_system_call_filter(
                 if (r == 0)
                         break;
 
-                r = set_ensure_allocated(&info->system_call_filter, &string_hash_ops);
-                if (r < 0)
-                        return r;
-
-                r = set_put_strdup(info->system_call_filter, name);
+                r = set_put_strdup(&info->system_call_filter, name);
                 if (r < 0)
                         return r;
         }
index 3ea9041c188c3403e928a1e105443d0c57b77153..faf50d2ac315663e9a7ab211a319765220f140c3 100644 (file)
@@ -349,14 +349,7 @@ static int acquire_time_data(sd_bus *bus, struct unit_times **out) {
         if (r < 0)
                 return r;
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "ListUnits",
-                        &error, &reply,
-                        NULL);
+        r = bus_call_method(bus, bus_systemd_mgr, "ListUnits", &error, &reply, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r));
 
@@ -1284,15 +1277,7 @@ static int dot(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return r;
 
-        r = sd_bus_call_method(
-                        bus,
-                       "org.freedesktop.systemd1",
-                       "/org/freedesktop/systemd1",
-                       "org.freedesktop.systemd1.Manager",
-                       "ListUnits",
-                       &error,
-                       &reply,
-                       "");
+        r = bus_call_method(bus, bus_systemd_mgr, "ListUnits", &error, &reply, "");
         if (r < 0)
                 log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r));
 
@@ -1334,15 +1319,7 @@ static int dump_fallback(sd_bus *bus) {
 
         assert(bus);
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "Dump",
-                        &error,
-                        &reply,
-                        NULL);
+        r = bus_call_method(bus, bus_systemd_mgr, "Dump", &error, &reply, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to issue method call Dump: %s", bus_error_message(&error, r));
 
@@ -1370,15 +1347,7 @@ static int dump(int argc, char *argv[], void *userdata) {
         if (!sd_bus_can_send(bus, SD_BUS_TYPE_UNIX_FD))
                 return dump_fallback(bus);
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "DumpByFileDescriptor",
-                        &error,
-                        &reply,
-                        NULL);
+        r = bus_call_method(bus, bus_systemd_mgr, "DumpByFileDescriptor", &error, &reply, NULL);
         if (r < 0) {
                 /* fall back to Dump if DumpByFileDescriptor is not supported */
                 if (!IN_SET(r, -EACCES, -EBADR))
@@ -1444,15 +1413,7 @@ static int set_log_level(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return log_error_errno(r, "Failed to create bus connection: %m");
 
-        r = sd_bus_set_property(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "LogLevel",
-                        &error,
-                        "s",
-                        argv[1]);
+        r = bus_set_property(bus, bus_systemd_mgr, "LogLevel", &error, "s", argv[1]);
         if (r < 0)
                 return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r));
 
@@ -1469,14 +1430,7 @@ static int get_log_level(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return log_error_errno(r, "Failed to create bus connection: %m");
 
-        r = sd_bus_get_property_string(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "LogLevel",
-                        &error,
-                        &level);
+        r = bus_get_property_string(bus, bus_systemd_mgr, "LogLevel", &error, &level);
         if (r < 0)
                 return log_error_errno(r, "Failed to get log level: %s", bus_error_message(&error, r));
 
@@ -1500,15 +1454,7 @@ static int set_log_target(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return log_error_errno(r, "Failed to create bus connection: %m");
 
-        r = sd_bus_set_property(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "LogTarget",
-                        &error,
-                        "s",
-                        argv[1]);
+        r = bus_set_property(bus, bus_systemd_mgr, "LogTarget", &error, "s", argv[1]);
         if (r < 0)
                 return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r));
 
@@ -1525,14 +1471,7 @@ static int get_log_target(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return log_error_errno(r, "Failed to create bus connection: %m");
 
-        r = sd_bus_get_property_string(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "LogTarget",
-                        &error,
-                        &target);
+        r = bus_get_property_string(bus, bus_systemd_mgr, "LogTarget", &error, &target);
         if (r < 0)
                 return log_error_errno(r, "Failed to get log target: %s", bus_error_message(&error, r));
 
@@ -1655,7 +1594,7 @@ static int dump_exit_status(int argc, char *argv[], void *userdata) {
 #if HAVE_SECCOMP
 
 static int load_kernel_syscalls(Set **ret) {
-        _cleanup_(set_free_freep) Set *syscalls = NULL;
+        _cleanup_set_free_ Set *syscalls = NULL;
         _cleanup_fclose_ FILE *f = NULL;
         int r;
 
@@ -1691,11 +1630,7 @@ static int load_kernel_syscalls(Set **ret) {
                 if (STR_IN_SET(e, "newuname", "newfstat", "newstat", "newlstat", "sysctl"))
                         continue;
 
-                r = set_ensure_allocated(&syscalls, &string_hash_ops);
-                if (r < 0)
-                        return log_oom();
-
-                r = set_put_strdup(syscalls, e);
+                r = set_put_strdup(&syscalls, e);
                 if (r < 0)
                         return log_error_errno(r, "Failed to add system call to list: %m");
         }
@@ -1735,7 +1670,7 @@ static int dump_syscall_filters(int argc, char *argv[], void *userdata) {
         (void) pager_open(arg_pager_flags);
 
         if (strv_isempty(strv_skip(argv, 1))) {
-                _cleanup_(set_free_freep) Set *kernel = NULL;
+                _cleanup_set_free_ Set *kernel = NULL;
                 int i, k;
 
                 k = load_kernel_syscalls(&kernel);
@@ -2121,15 +2056,7 @@ static int service_watchdogs(int argc, char *argv[], void *userdata) {
 
         if (argc == 1) {
                 /* get ServiceWatchdogs */
-                r = sd_bus_get_property_trivial(
-                                bus,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
-                                "ServiceWatchdogs",
-                                &error,
-                                'b',
-                                &b);
+                r = bus_get_property_trivial(bus, bus_systemd_mgr, "ServiceWatchdogs", &error, 'b', &b);
                 if (r < 0)
                         return log_error_errno(r, "Failed to get service-watchdog state: %s", bus_error_message(&error, r));
 
@@ -2141,15 +2068,7 @@ static int service_watchdogs(int argc, char *argv[], void *userdata) {
                 if (b < 0)
                         return log_error_errno(b, "Failed to parse service-watchdogs argument: %m");
 
-                r = sd_bus_set_property(
-                                bus,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
-                                "ServiceWatchdogs",
-                                &error,
-                                "b",
-                                b);
+                r = bus_set_property(bus, bus_systemd_mgr, "ServiceWatchdogs", &error, "b", b);
                 if (r < 0)
                         return log_error_errno(r, "Failed to set service-watchdog state: %s", bus_error_message(&error, r));
         }
index 7d94c55a6dcafb69dd3b4e0b864a131958d90e7f..5f8212685b7781522fec1e7bf82ee2246d0c068c 100644 (file)
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <sys/file.h>
 #include <unistd.h>
 
 #include "alloc-util.h"
@@ -29,6 +30,8 @@ int block_get_whole_disk(dev_t d, dev_t *ret) {
                 *ret = d;
                 return 0;
         }
+        if (errno != ENOENT)
+                return -errno;
 
         /* If it is a partition find the originating device */
         xsprintf_sys_block_path(p, "/partition", d);
@@ -185,3 +188,29 @@ int get_block_device_harder(const char *path, dev_t *ret) {
 
         return 1;
 }
+
+int lock_whole_block_device(dev_t devt, int operation) {
+        _cleanup_free_ char *whole_node = NULL;
+        _cleanup_close_ int lock_fd = -1;
+        dev_t whole_devt;
+        int r;
+
+        /* Let's get a BSD file lock on the whole block device, as per: https://systemd.io/BLOCK_DEVICE_LOCKING */
+
+        r = block_get_whole_disk(devt, &whole_devt);
+        if (r < 0)
+                return r;
+
+        r = device_path_make_major_minor(S_IFBLK, whole_devt, &whole_node);
+        if (r < 0)
+                return r;
+
+        lock_fd = open(whole_node, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
+        if (lock_fd < 0)
+                return -errno;
+
+        if (flock(lock_fd, operation) < 0)
+                return -errno;
+
+        return TAKE_FD(lock_fd);
+}
index 6d8a796568edf5dd843e38fbd003fd9a5d54f4ea..1e7588f71cab9f1d840fc7ba7e392da15c0ef333 100644 (file)
@@ -18,3 +18,5 @@ int block_get_originating(dev_t d, dev_t *ret);
 int get_block_device(const char *path, dev_t *dev);
 
 int get_block_device_harder(const char *path, dev_t *dev);
+
+int lock_whole_block_device(dev_t devt, int operation);
index 62f4fca947db9fecb20bdff65a06d65e19cd3bd7..17ee474f7332bdaf0d054623680519dc255fe646 100644 (file)
@@ -319,7 +319,7 @@ int btrfs_get_block_device_fd(int fd, dev_t *dev) {
                         return -errno;
 
                 if (!S_ISBLK(st.st_mode))
-                        return -ENODEV;
+                        return -ENOTBLK;
 
                 if (major(st.st_rdev) == 0)
                         return -ENODEV;
@@ -1149,7 +1149,6 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol
                 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
                         _cleanup_free_ char *p = NULL;
                         const struct btrfs_root_ref *ref;
-                        struct btrfs_ioctl_ino_lookup_args ino_args;
 
                         btrfs_ioctl_search_args_set(&args, sh);
 
@@ -1164,9 +1163,10 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol
                         if (!p)
                                 return -ENOMEM;
 
-                        zero(ino_args);
-                        ino_args.treeid = subvol_id;
-                        ino_args.objectid = htole64(ref->dirid);
+                        struct btrfs_ioctl_ino_lookup_args ino_args = {
+                                .treeid = subvol_id,
+                                .objectid = htole64(ref->dirid),
+                        };
 
                         if (ioctl(fd, BTRFS_IOC_INO_LOOKUP, &ino_args) < 0)
                                 return -errno;
@@ -1504,7 +1504,6 @@ static int subvol_snapshot_children(
 
                 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
                         _cleanup_free_ char *p = NULL, *c = NULL, *np = NULL;
-                        struct btrfs_ioctl_ino_lookup_args ino_args;
                         const struct btrfs_root_ref *ref;
                         _cleanup_close_ int old_child_fd = -1, new_child_fd = -1;
 
@@ -1528,9 +1527,10 @@ static int subvol_snapshot_children(
                         if (!p)
                                 return -ENOMEM;
 
-                        zero(ino_args);
-                        ino_args.treeid = old_subvol_id;
-                        ino_args.objectid = htole64(ref->dirid);
+                        struct btrfs_ioctl_ino_lookup_args ino_args = {
+                                .treeid = old_subvol_id,
+                                .objectid = htole64(ref->dirid),
+                        };
 
                         if (ioctl(old_fd, BTRFS_IOC_INO_LOOKUP, &ino_args) < 0)
                                 return -errno;
index c47e912eb0ac4617de7bc2b03c148cfcda143224..d160af5bc7e6d7e6101c73d54853eb3c37270877 100644 (file)
 #define _LZ4_FEATURE_ "-LZ4"
 #endif
 
+#if HAVE_ZSTD
+#define _ZSTD_FEATURE_ "+ZSTD"
+#else
+#define _ZSTD_FEATURE_ "-ZSTD"
+#endif
+
 #if HAVE_SECCOMP
 #define _SECCOMP_FEATURE_ "+SECCOMP"
 #else
         _ACL_FEATURE_ " "                                               \
         _XZ_FEATURE_ " "                                                \
         _LZ4_FEATURE_ " "                                               \
+        _ZSTD_FEATURE_ " "                                              \
         _SECCOMP_FEATURE_ " "                                           \
         _BLKID_FEATURE_ " "                                             \
         _ELFUTILS_FEATURE_ " "                                          \
index be73cfa3f0d475d7a3c423380214b11c6384a3cf..e94fcfad022c6fa9a56afe0709dc1137e900bb59 100644 (file)
@@ -149,6 +149,17 @@ bool cg_ns_supported(void) {
         return enabled;
 }
 
+bool cg_freezer_supported(void) {
+        static thread_local int supported = -1;
+
+        if (supported >= 0)
+                return supported;
+
+        supported = cg_all_unified() > 0 && access("/sys/fs/cgroup/init.scope/cgroup.freeze", F_OK) == 0;
+
+        return supported;
+}
+
 int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) {
         _cleanup_free_ char *fs = NULL;
         int r;
@@ -1684,12 +1695,13 @@ int cg_get_attribute_as_uint64(const char *controller, const char *path, const c
         return 0;
 }
 
-int cg_get_keyed_attribute(
+int cg_get_keyed_attribute_full(
                 const char *controller,
                 const char *path,
                 const char *attribute,
                 char **keys,
-                char **ret_values) {
+                char **ret_values,
+                CGroupKeyMode mode) {
 
         _cleanup_free_ char *filename = NULL, *contents = NULL;
         const char *p;
@@ -1701,7 +1713,8 @@ int cg_get_keyed_attribute(
          * all keys to retrieve. The 'ret_values' parameter should be passed as string size with the same number of
          * entries as 'keys'. On success each entry will be set to the value of the matching key.
          *
-         * If the attribute file doesn't exist at all returns ENOENT, if any key is not found returns ENXIO. */
+         * If the attribute file doesn't exist at all returns ENOENT, if any key is not found returns ENXIO. If mode
+         * is set to GG_KEY_MODE_GRACEFUL we ignore missing keys and return those that were parsed successfully. */
 
         r = cg_get_path(controller, path, attribute, &filename);
         if (r < 0)
@@ -1749,6 +1762,9 @@ int cg_get_keyed_attribute(
                 p += strspn(p, NEWLINE);
         }
 
+        if (mode & CG_KEY_MODE_GRACEFUL)
+                goto done;
+
         r = -ENXIO;
 
 fail:
@@ -1759,6 +1775,9 @@ fail:
 
 done:
         memcpy(ret_values, v, sizeof(char*) * n);
+        if (mode & CG_KEY_MODE_GRACEFUL)
+                return n_done;
+
         return 0;
 }
 
@@ -2010,6 +2029,9 @@ int cg_unified_cached(bool flush) {
                                 unified_cache = CGROUP_UNIFIED_NONE;
                         }
                 }
+        } else if (F_TYPE_EQUAL(fs.f_type, SYSFS_MAGIC)) {
+                return log_debug_errno(SYNTHETIC_ERRNO(ENOMEDIUM),
+                                       "No filesystem is currently mounted on /sys/fs/cgroup.");
         } else
                 return log_debug_errno(SYNTHETIC_ERRNO(ENOMEDIUM),
                                        "Unknown filesystem type %llx mounted on /sys/fs/cgroup.",
index 237139fad0060e105a06e1f6c153e27e7888d214..2b88571bc1c7767d57cc9de9d0a417fe2e0cbb82 100644 (file)
@@ -180,9 +180,31 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **path);
 
 int cg_rmdir(const char *controller, const char *path);
 
+typedef enum  {
+        CG_KEY_MODE_GRACEFUL = 1 << 0,
+} CGroupKeyMode;
+
 int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value);
 int cg_get_attribute(const char *controller, const char *path, const char *attribute, char **ret);
-int cg_get_keyed_attribute(const char *controller, const char *path, const char *attribute, char **keys, char **values);
+int cg_get_keyed_attribute_full(const char *controller, const char *path, const char *attribute, char **keys, char **values, CGroupKeyMode mode);
+
+static inline int cg_get_keyed_attribute(
+                const char *controller,
+                const char *path,
+                const char *attribute,
+                char **keys,
+                char **ret_values) {
+        return cg_get_keyed_attribute_full(controller, path, attribute, keys, ret_values, 0);
+}
+
+static inline int cg_get_keyed_attribute_graceful(
+                const char *controller,
+                const char *path,
+                const char *attribute,
+                char **keys,
+                char **ret_values) {
+        return cg_get_keyed_attribute_full(controller, path, attribute, keys, ret_values, CG_KEY_MODE_GRACEFUL);
+}
 
 int cg_get_attribute_as_uint64(const char *controller, const char *path, const char *attribute, uint64_t *ret);
 
@@ -238,6 +260,7 @@ int cg_mask_to_string(CGroupMask mask, char **ret);
 int cg_kernel_controllers(Set **controllers);
 
 bool cg_ns_supported(void);
+bool cg_freezer_supported(void);
 
 int cg_all_unified(void);
 int cg_hybrid_unified(void);
index 58eb62fb7a55d3592c788f59ffa128755ec567f0..eb19516c2acc2446243c8356ea9a6f2638f3b25a 100644 (file)
@@ -77,8 +77,10 @@ static int files_add(
                 /* Is this a masking entry? */
                 if ((flags & CONF_FILES_FILTER_MASKED))
                         if (null_or_empty(&st)) {
+                                assert(masked);
+
                                 /* Mark this one as masked */
-                                r = set_put_strdup(masked, de->d_name);
+                                r = set_put_strdup(&masked, de->d_name);
                                 if (r < 0)
                                         return r;
 
index 502c3a0c4448aa54565674e7372bd660ec8c43f7..b34df46926cded800f722a74414d67ade510ab0b 100644 (file)
 
 #if ENABLE_EFI
 
+/* Reads from efivarfs sometimes fail with EINTR. Retry that many times. */
+#define EFI_N_RETRIES 5
+#define EFI_RETRY_DELAY (50 * USEC_PER_MSEC)
+
 char* efi_variable_path(sd_id128_t vendor, const char *name) {
         char *p;
 
@@ -56,8 +60,8 @@ int efi_get_variable(
                 return -ENOMEM;
 
         if (!ret_value && !ret_size && !ret_attribute) {
-                /* If caller is not interested in anything, just check if the variable exists and is readable
-                 * to us. */
+                /* If caller is not interested in anything, just check if the variable exists and is
+                 * readable. */
                 if (access(p, R_OK) < 0)
                         return -errno;
 
@@ -66,7 +70,7 @@ int efi_get_variable(
 
         fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
         if (fd < 0)
-                return -errno;
+                return log_debug_errno(errno, "open(\"%s\") failed: %m", p);
 
         if (fstat(fd, &st) < 0)
                 return -errno;
@@ -76,9 +80,26 @@ int efi_get_variable(
                 return -E2BIG;
 
         if (ret_value || ret_attribute) {
-                n = read(fd, &a, sizeof(a));
-                if (n < 0)
-                        return -errno;
+                /* The kernel ratelimits reads from the efivarfs because EFI is inefficient, and we'll
+                 * occasionally fail with EINTR here. A slowdown is better than a failure for us, so
+                 * retry a few times and eventually fail with -EBUSY.
+                 *
+                 * See https://github.com/torvalds/linux/blob/master/fs/efivarfs/file.c#L75
+                 * and
+                 * https://github.com/torvalds/linux/commit/bef3efbeb897b56867e271cdbc5f8adaacaeb9cd.
+                 */
+                for (unsigned try = 0;; try++) {
+                        n = read(fd, &a, sizeof(a));
+                        if (n >= 0)
+                                break;
+                        log_debug_errno(errno, "read from \"%s\" failed: %m", p);
+                        if (errno != EINTR)
+                                return -errno;
+                        if (try >= EFI_N_RETRIES)
+                                return -EBUSY;
+                        usleep(EFI_RETRY_DELAY);
+                }
+
                 if (n != sizeof(a))
                         return -EIO;
         }
@@ -223,10 +244,16 @@ int efi_set_variable_string(sd_id128_t vendor, const char *name, const char *v)
 }
 
 bool is_efi_boot(void) {
-        if (detect_container() > 0)
-                return false;
+        static int cache = -1;
 
-        return access("/sys/firmware/efi/", F_OK) >= 0;
+        if (cache < 0) {
+                if (detect_container() > 0)
+                        cache = false;
+                else
+                        cache = access("/sys/firmware/efi/", F_OK) >= 0;
+        }
+
+        return cache;
 }
 
 static int read_flag(const char *varname) {
@@ -250,11 +277,21 @@ static int read_flag(const char *varname) {
 }
 
 bool is_efi_secure_boot(void) {
-        return read_flag("SecureBoot") > 0;
+        static int cache = -1;
+
+        if (cache < 0)
+                cache = read_flag("SecureBoot");
+
+        return cache > 0;
 }
 
 bool is_efi_secure_boot_setup_mode(void) {
-        return read_flag("SetupMode") > 0;
+        static int cache = -1;
+
+        if (cache < 0)
+                cache = read_flag("SetupMode");
+
+        return cache > 0;
 }
 
 int systemd_efi_options_variable(char **line) {
@@ -276,6 +313,29 @@ int systemd_efi_options_variable(char **line) {
                 return 0;
         }
 
+        /* In SecureBoot mode this is probably not what you want. As your cmdline is cryptographically signed
+         * like when using Type #2 EFI Unified Kernel Images (https://systemd.io/BOOT_LOADER_SPECIFICATION/)
+         * The user's intention is then that the cmdline should not be modified. You want to make sure that
+         * the system starts up as exactly specified in the signed artifact.
+         *
+         * (NB: to make testing purposes we still check the $SYSTEMD_EFI_OPTIONS env var above, even when in
+         * SecureBoot mode.) */
+        if (is_efi_secure_boot()) {
+                _cleanup_free_ char *k;
+
+                k = efi_variable_path(EFI_VENDOR_SYSTEMD, "SystemdOptions");
+                if (!k)
+                        return -ENOMEM;
+
+                /* Let's be helpful with the returned error and check if the variable exists at all. If it
+                 * does, let's return a recognizable error (EPERM), and if not ENODATA. */
+
+                if (access(k, F_OK) < 0)
+                        return errno == ENOENT ? -ENODATA : -errno;
+
+                return -EPERM;
+        }
+
         r = efi_get_variable_string(EFI_VENDOR_SYSTEMD, "SystemdOptions", line);
         if (r == -ENOENT)
                 return -ENODATA;
index a3dced441a09a2c6322282dd05fdc8faff92a58c..e2bee511478beab2fb5de276e9dcb08561e68e56 100644 (file)
 #include "path-util.h"
 #include "process-util.h"
 #include "socket-util.h"
+#include "stat-util.h"
 #include "stdio-util.h"
-#include "util.h"
 #include "tmpfile-util.h"
+#include "util.h"
 
 /* The maximum number of iterations in the loop to close descriptors in the fallback case
  * when /proc/self/fd/ is inaccessible. */
@@ -939,8 +940,15 @@ int fd_reopen(int fd, int flags) {
 
         xsprintf(procfs_path, "/proc/self/fd/%i", fd);
         new_fd = open(procfs_path, flags);
-        if (new_fd < 0)
-                return -errno;
+        if (new_fd < 0) {
+                if (errno != ENOENT)
+                        return -errno;
+
+                if (proc_mounted() == 0)
+                        return -ENOSYS; /* if we have no /proc/, the concept is not implementable */
+
+                return -ENOENT;
+        }
 
         return new_fd;
 }
index 34ee939526f9b43b8ca8d29c1d277d56d903601a..6b84d1462438033900801bc97c16c01900fb2049 100644 (file)
@@ -419,7 +419,7 @@ int read_full_virtual_file(const char *filename, char **ret_contents, size_t *re
                                 break;
                         }
 
-                        if (errno != -EINTR)
+                        if (errno != EINTR)
                                 return -errno;
                 }
 
index ef3b5a51842f31d307b315585ce1cbd27ce50d6f..2c5bfb3263f8e35d929a9170aafacf166aae17c6 100644 (file)
@@ -8,8 +8,10 @@
 #include <unistd.h>
 
 #include "alloc-util.h"
+#include "blockdev-util.h"
 #include "dirent-util.h"
 #include "fd-util.h"
+#include "fileio.h"
 #include "fs-util.h"
 #include "locale-util.h"
 #include "log.h"
@@ -21,6 +23,7 @@
 #include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
+#include "random-util.h"
 #include "stat-util.h"
 #include "stdio-util.h"
 #include "string-util.h"
@@ -337,8 +340,15 @@ int fchmod_opath(int fd, mode_t m) {
          * fchownat() does. */
 
         xsprintf(procfs_path, "/proc/self/fd/%i", fd);
-        if (chmod(procfs_path, m) < 0)
-                return -errno;
+        if (chmod(procfs_path, m) < 0) {
+                if (errno != ENOENT)
+                        return -errno;
+
+                if (proc_mounted() == 0)
+                        return -ENOSYS; /* if we have no /proc/, the concept is not implementable */
+
+                return -ENOENT;
+        }
 
         return 0;
 }
@@ -1294,11 +1304,13 @@ void unlink_tempfilep(char (*p)[]) {
                 (void) unlink_noerrno(*p);
 }
 
-int unlinkat_deallocate(int fd, const char *name, int flags) {
+int unlinkat_deallocate(int fd, const char *name, UnlinkDeallocateFlags flags) {
         _cleanup_close_ int truncate_fd = -1;
         struct stat st;
         off_t l, bs;
 
+        assert((flags & ~(UNLINK_REMOVEDIR|UNLINK_ERASE)) == 0);
+
         /* Operates like unlinkat() but also deallocates the file contents if it is a regular file and there's no other
          * link to it. This is useful to ensure that other processes that might have the file open for reading won't be
          * able to keep the data pinned on disk forever. This call is particular useful whenever we execute clean-up
@@ -1315,7 +1327,7 @@ int unlinkat_deallocate(int fd, const char *name, int flags) {
          * Note that we attempt deallocation, but failure to succeed with that is not considered fatal, as long as the
          * primary job – to delete the file – is accomplished. */
 
-        if ((flags & AT_REMOVEDIR) == 0) {
+        if (!FLAGS_SET(flags, UNLINK_REMOVEDIR)) {
                 truncate_fd = openat(fd, name, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW|O_NONBLOCK);
                 if (truncate_fd < 0) {
 
@@ -1331,7 +1343,7 @@ int unlinkat_deallocate(int fd, const char *name, int flags) {
                 }
         }
 
-        if (unlinkat(fd, name, flags) < 0)
+        if (unlinkat(fd, name, FLAGS_SET(flags, UNLINK_REMOVEDIR) ? AT_REMOVEDIR : 0) < 0)
                 return -errno;
 
         if (truncate_fd < 0) /* Don't have a file handle, can't do more ☹️ */
@@ -1342,7 +1354,45 @@ int unlinkat_deallocate(int fd, const char *name, int flags) {
                 return 0;
         }
 
-        if (!S_ISREG(st.st_mode) || st.st_blocks == 0 || st.st_nlink > 0)
+        if (!S_ISREG(st.st_mode))
+                return 0;
+
+        if (FLAGS_SET(flags, UNLINK_ERASE) && st.st_size > 0 && st.st_nlink == 0) {
+                uint64_t left = st.st_size;
+                char buffer[64 * 1024];
+
+                /* If erasing is requested, let's overwrite the file with random data once before deleting
+                 * it. This isn't going to give you shred(1) semantics, but hopefully should be good enough
+                 * for stuff backed by tmpfs at least.
+                 *
+                 * Note that we only erase like this if the link count of the file is zero. If it is higer it
+                 * is still linked by someone else and we'll leave it to them to remove it securely
+                 * eventually! */
+
+                random_bytes(buffer, sizeof(buffer));
+
+                while (left > 0) {
+                        ssize_t n;
+
+                        n = write(truncate_fd, buffer, MIN(sizeof(buffer), left));
+                        if (n < 0) {
+                                log_debug_errno(errno, "Failed to erase data in file '%s', ignoring.", name);
+                                break;
+                        }
+
+                        assert(left >= (size_t) n);
+                        left -= n;
+                }
+
+                /* Let's refresh metadata */
+                if (fstat(truncate_fd, &st) < 0) {
+                        log_debug_errno(errno, "Failed to stat file '%s' for deallocation, ignoring: %m", name);
+                        return 0;
+                }
+        }
+
+        /* Don't dallocate if there's nothing to deallocate or if the file is linked elsewhere */
+        if (st.st_blocks == 0 || st.st_nlink > 0)
                 return 0;
 
         /* If this is a regular file, it actually took up space on disk and there are no other links it's time to
@@ -1481,3 +1531,88 @@ int open_parent(const char *path, int flags, mode_t mode) {
 
         return fd;
 }
+
+static int blockdev_is_encrypted(const char *sysfs_path, unsigned depth_left) {
+        _cleanup_free_ char *p = NULL, *uuids = NULL;
+        _cleanup_closedir_ DIR *d = NULL;
+        int r, found_encrypted = false;
+
+        assert(sysfs_path);
+
+        if (depth_left == 0)
+                return -EINVAL;
+
+        p = path_join(sysfs_path, "dm/uuid");
+        if (!p)
+                return -ENOMEM;
+
+        r = read_one_line_file(p, &uuids);
+        if (r != -ENOENT) {
+                if (r < 0)
+                        return r;
+
+                /* The DM device's uuid attribute is prefixed with "CRYPT-" if this is a dm-crypt device. */
+                if (startswith(uuids, "CRYPT-"))
+                        return true;
+        }
+
+        /* Not a dm-crypt device itself. But maybe it is on top of one? Follow the links in the "slaves/"
+         * subdir. */
+
+        p = mfree(p);
+        p = path_join(sysfs_path, "slaves");
+        if (!p)
+                return -ENOMEM;
+
+        d = opendir(p);
+        if (!d) {
+                if (errno == ENOENT) /* Doesn't have slaves */
+                        return false;
+
+                return -errno;
+        }
+
+        for (;;) {
+                _cleanup_free_ char *q = NULL;
+                struct dirent *de;
+
+                errno = 0;
+                de = readdir_no_dot(d);
+                if (!de) {
+                        if (errno != 0)
+                                return -errno;
+
+                        break; /* No more slaves */
+                }
+
+                q = path_join(p, de->d_name);
+                if (!q)
+                        return -ENOMEM;
+
+                r = blockdev_is_encrypted(q, depth_left - 1);
+                if (r < 0)
+                        return r;
+                if (r == 0) /* we found one that is not encrypted? then propagate that immediately */
+                        return false;
+
+                found_encrypted = true;
+        }
+
+        return found_encrypted;
+}
+
+int path_is_encrypted(const char *path) {
+        char p[SYS_BLOCK_PATH_MAX(NULL)];
+        dev_t devt;
+        int r;
+
+        r = get_block_device(path, &devt);
+        if (r < 0)
+                return r;
+        if (r == 0) /* doesn't have a block device */
+                return false;
+
+        xsprintf_sys_block_path(p, NULL, devt);
+
+        return blockdev_is_encrypted(p, 10 /* safety net: maximum recursion depth */);
+}
index c2c39c4315d47f31d547c4ebb209ea338e434aa2..dd101c61cc6bc1b015babbd00fd56cd17552104a 100644 (file)
@@ -113,7 +113,13 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(char*, unlink_and_free);
 int access_fd(int fd, int mode);
 
 void unlink_tempfilep(char (*p)[]);
-int unlinkat_deallocate(int fd, const char *name, int flags);
+
+typedef enum UnlinkDeallocateFlags {
+        UNLINK_REMOVEDIR = 1 << 0,
+        UNLINK_ERASE     = 1 << 1,
+} UnlinkDeallocateFlags;
+
+int unlinkat_deallocate(int fd, const char *name, UnlinkDeallocateFlags flags);
 
 int fsync_directory_of_file(int fd);
 int fsync_full(int fd);
@@ -122,3 +128,5 @@ int fsync_path_at(int at_fd, const char *path);
 int syncfs_path(int atfd, const char *path);
 
 int open_parent(const char *path, int flags, mode_t mode);
+
+int path_is_encrypted(const char *path);
index e3aa6c2e152b4f9d7ecbb583770b02145188a838..1e7e301e09875d0e72579d45a03d895e3c29135d 100644 (file)
@@ -61,11 +61,11 @@ int glob_exists(const char *path) {
         return true;
 }
 
-int glob_extend(char ***strv, const char *path) {
+int glob_extend(char ***strv, const char *path, int flags) {
         _cleanup_globfree_ glob_t g = {};
         int k;
 
-        k = safe_glob(path, GLOB_NOSORT|GLOB_BRACE, &g);
+        k = safe_glob(path, GLOB_NOSORT|GLOB_BRACE|flags, &g);
         if (k < 0)
                 return k;
 
index 8b1bb02be138471ef399b6a2442f9ff177b671aa..3d5f5435085aca376f0362fdad86c8fe8f673d3f 100644 (file)
@@ -11,7 +11,7 @@
 int safe_glob(const char *path, int flags, glob_t *pglob);
 
 int glob_exists(const char *path);
-int glob_extend(char ***strv, const char *path);
+int glob_extend(char ***strv, const char *path, int flags);
 
 #define _cleanup_globfree_ _cleanup_(globfree)
 
index fce339512c6abe547d1133aaeb0658a7c25e14ae..fee0ba98eba938f2e59e5235bda8417c6719a37c 100644 (file)
@@ -10,6 +10,8 @@ void string_hash_func(const char *p, struct siphash *state) {
 }
 
 DEFINE_HASH_OPS(string_hash_ops, char, string_hash_func, string_compare_func);
+DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(string_hash_ops_free,
+                                    char, string_hash_func, string_compare_func, free);
 DEFINE_HASH_OPS_FULL(string_hash_ops_free_free,
                      char, string_hash_func, string_compare_func, free,
                      char, free);
index 7bb5d1cd0217ff6c82730c1d9269d710f239be70..264316c3dc1ba93cb500aeaee58501e579220422 100644 (file)
@@ -76,6 +76,7 @@ struct hash_ops {
 void string_hash_func(const char *p, struct siphash *state);
 #define string_compare_func strcmp
 extern const struct hash_ops string_hash_ops;
+extern const struct hash_ops string_hash_ops_free;
 extern const struct hash_ops string_hash_ops_free_free;
 
 void path_hash_func(const char *p, struct siphash *state);
index 4853514c96a6e66a608d03b3ad76271c456d1ac9..efbe95bb9e33f90e087fdad9e45b95da5e87a315 100644 (file)
@@ -1775,41 +1775,54 @@ int hashmap_put_strdup(Hashmap **h, const char *k, const char *v) {
                 return r;
 
         _cleanup_free_ char *kdup = NULL, *vdup = NULL;
+
         kdup = strdup(k);
-        vdup = strdup(v);
-        if (!kdup || !vdup)
+        if (!kdup)
                 return -ENOMEM;
 
+        if (v) {
+                vdup = strdup(v);
+                if (!vdup)
+                        return -ENOMEM;
+        }
+
         r = hashmap_put(*h, kdup, vdup);
         if (r < 0) {
-                if (r == -EEXIST && streq(v, hashmap_get(*h, kdup)))
+                if (r == -EEXIST && streq_ptr(v, hashmap_get(*h, kdup)))
                         return 0;
                 return r;
         }
 
-        assert(r > 0); /* 0 would mean vdup is already in the hashmap, which cannot be */
-        kdup = vdup = NULL;
+        /* 0 with non-null vdup would mean vdup is already in the hashmap, which cannot be */
+        assert(vdup == NULL || r > 0);
+        if (r > 0)
+                kdup = vdup = NULL;
 
-        return 0;
+        return r;
 }
 
-int set_put_strdup(Set *s, const char *p) {
+int set_put_strdup(Set **s, const char *p) {
         char *c;
+        int r;
 
         assert(s);
         assert(p);
 
-        if (set_contains(s, (char*) p))
+        r = set_ensure_allocated(s, &string_hash_ops_free);
+        if (r < 0)
+                return r;
+
+        if (set_contains(*s, (char*) p))
                 return 0;
 
         c = strdup(p);
         if (!c)
                 return -ENOMEM;
 
-        return set_consume(s, c);
+        return set_consume(*s, c);
 }
 
-int set_put_strdupv(Set *s, char **l) {
+int set_put_strdupv(Set **s, char **l) {
         int n = 0, r;
         char **i;
 
index 7bc2e3f370fb650f5f2f0093f58afb8e1f46f54a..90a3dfc86471d01d93c53d96678151593c796305 100644 (file)
@@ -12,6 +12,7 @@
 #include "hostname-util.h"
 #include "macro.h"
 #include "string-util.h"
+#include "strv.h"
 
 bool hostname_is_set(void) {
         struct utsname u;
@@ -21,7 +22,7 @@ bool hostname_is_set(void) {
         if (isempty(u.nodename))
                 return false;
 
-        /* This is the built-in kernel default host name */
+        /* This is the built-in kernel default hostname */
         if (streq(u.nodename, "(none)"))
                 return false;
 
@@ -30,6 +31,7 @@ bool hostname_is_set(void) {
 
 char* gethostname_malloc(void) {
         struct utsname u;
+        const char *s;
 
         /* This call tries to return something useful, either the actual hostname
          * or it makes something up. The only reason it might fail is OOM.
@@ -37,10 +39,28 @@ char* gethostname_malloc(void) {
 
         assert_se(uname(&u) >= 0);
 
-        if (isempty(u.nodename) || streq(u.nodename, "(none)"))
-                return strdup(FALLBACK_HOSTNAME);
+        s = u.nodename;
+        if (isempty(s) || streq(s, "(none)"))
+                s = FALLBACK_HOSTNAME;
 
-        return strdup(u.nodename);
+        return strdup(s);
+}
+
+char* gethostname_short_malloc(void) {
+        struct utsname u;
+        const char *s;
+
+        /* Like above, but kills the FQDN part if present. */
+
+        assert_se(uname(&u) >= 0);
+
+        s = u.nodename;
+        if (isempty(s) || streq(s, "(none)") || s[0] == '.') {
+                s = FALLBACK_HOSTNAME;
+                assert(s[0] != '.');
+        }
+
+        return strndup(s, strcspn(s, "."));
 }
 
 int gethostname_strict(char **ret) {
@@ -77,7 +97,7 @@ bool valid_ldh_char(char c) {
 }
 
 /**
- * Check if s looks like a valid host name or FQDN. This does not do
+ * Check if s looks like a valid hostname or FQDN. This does not do
  * full DNS validation, but only checks if the name is composed of
  * allowed characters and the length is not above the maximum allowed
  * by Linux (c.f. dns_name_is_valid()). Trailing dot is allowed if
@@ -180,14 +200,16 @@ bool is_localhost(const char *hostname) {
         /* This tries to identify local host and domain names
          * described in RFC6761 plus the redhatism of localdomain */
 
-        return strcaseeq(hostname, "localhost") ||
-               strcaseeq(hostname, "localhost.") ||
-               strcaseeq(hostname, "localhost.localdomain") ||
-               strcaseeq(hostname, "localhost.localdomain.") ||
-               endswith_no_case(hostname, ".localhost") ||
-               endswith_no_case(hostname, ".localhost.") ||
-               endswith_no_case(hostname, ".localhost.localdomain") ||
-               endswith_no_case(hostname, ".localhost.localdomain.");
+        return STRCASE_IN_SET(
+                        hostname,
+                        "localhost",
+                        "localhost.",
+                        "localhost.localdomain",
+                        "localhost.localdomain.") ||
+                endswith_no_case(hostname, ".localhost") ||
+                endswith_no_case(hostname, ".localhost.") ||
+                endswith_no_case(hostname, ".localhost.localdomain") ||
+                endswith_no_case(hostname, ".localhost.localdomain.");
 }
 
 bool is_gateway_hostname(const char *hostname) {
index 7ba386a0fd99c5162cd32b22e63b8ce24e344532..cafd6f020bff96eb6b9a1f2bf735774fb67351b5 100644 (file)
@@ -9,6 +9,7 @@
 bool hostname_is_set(void);
 
 char* gethostname_malloc(void);
+char* gethostname_short_malloc(void);
 int gethostname_strict(char **ret);
 
 bool valid_ldh_char(char c) _const_;
index 43f6b6f68a96d640120ec65f235b94725f4230a1..9da767a5706f11135cb042d8be6fe3f70cf07278 100644 (file)
@@ -41,6 +41,11 @@ uint64_t physical_memory(void) {
         }
         if (r > 0) {
                 r = cg_get_attribute("memory", root, "memory.max", &value);
+                if (r == -ENOENT) /* Field does not exist on the system's top-level cgroup, hence don't
+                                   * complain. (Note that it might exist on our own root though, if we live
+                                   * in a cgroup namespace, hence check anyway instead of not even
+                                   * trying.) */
+                        return mem;
                 if (r < 0) {
                         log_debug_errno(r, "Failed to read memory.max cgroup attribute, ignoring cgroup memory limit: %m");
                         return mem;
index e4ce289c519ed23f79c5b39b8859b625ad717cd3..ab5f86f54a308ecc68c0a2cd939fe44f78282080 100644 (file)
@@ -254,6 +254,21 @@ bool locale_is_valid(const char *name) {
         return true;
 }
 
+int locale_is_installed(const char *name) {
+        if (!locale_is_valid(name))
+                return false;
+
+        if (STR_IN_SET(name, "C", "POSIX")) /* These ones are always OK */
+                return true;
+
+        _cleanup_(freelocalep) locale_t loc =
+                newlocale(LC_ALL_MASK, name, 0);
+        if (loc == (locale_t) 0)
+                return errno == ENOMEM ? -ENOMEM : false;
+
+        return true;
+}
+
 void init_gettext(void) {
         setlocale(LC_ALL, "");
         textdomain(GETTEXT_PACKAGE);
index 7d77fa2bdae05de4bc650d90805fdca6d99cc621..6bd377205963aa82b32b3bd8a492d55e8e08f172 100644 (file)
@@ -31,6 +31,7 @@ typedef enum LocaleVariable {
 
 int get_locales(char ***l);
 bool locale_is_valid(const char *name);
+int locale_is_installed(const char *name);
 
 #define _(String) gettext(String)
 #define N_(String) String
index 2e76031b325c5e3904413a953349ed75e9a61f22..17af87a3aefe9b77f88866552d1f0cb2fadcdf74 100644 (file)
@@ -14,3 +14,7 @@
 #ifndef GRND_RANDOM
 #define GRND_RANDOM 0x0002
 #endif
+
+#ifndef GRND_INSECURE
+#define GRND_INSECURE 0x0004
+#endif
index 8de5cd5c568361e517c539b2022a77635ca19141..59f8a31cec9bae4f94d013d450f8c0853cf25e3a 100644 (file)
 #include "process-util.h"
 #include "stat-util.h"
 #include "string-util.h"
+#include "strv.h"
 
 int parse_boolean(const char *v) {
         if (!v)
                 return -EINVAL;
 
-        if (streq(v, "1") || strcaseeq(v, "yes") || strcaseeq(v, "y") || strcaseeq(v, "true") || strcaseeq(v, "t") || strcaseeq(v, "on"))
+        if (STRCASE_IN_SET(v,
+                           "1",
+                           "yes",
+                           "y",
+                           "true",
+                           "t",
+                           "on"))
                 return 1;
-        else if (streq(v, "0") || strcaseeq(v, "no") || strcaseeq(v, "n") || strcaseeq(v, "false") || strcaseeq(v, "f") || strcaseeq(v, "off"))
+
+        if (STRCASE_IN_SET(v,
+                           "0",
+                           "no",
+                           "n",
+                           "false",
+                           "f",
+                           "off"))
                 return 0;
 
         return -EINVAL;
index ba13de01ff0b194f6cc9925fe0fcd6e7078458d4..986dfe94a4b719b16e13c50b94bf6d041887c42d 100644 (file)
@@ -1051,7 +1051,7 @@ int systemd_installation_has_version(const char *root, unsigned minimal_version)
                 if (!path)
                         return -ENOMEM;
 
-                r = glob_extend(&names, path);
+                r = glob_extend(&names, path, 0);
                 if (r == -ENOENT)
                         continue;
                 if (r < 0)
index 1af58717c6868f514cc07df7d744a4b1a39954fb..d8d30b0f1df44a93c3572a2fc80ee385fe8a7f80 100644 (file)
@@ -39,18 +39,6 @@ int proc_cmdline(char **ret) {
                 return read_one_line_file("/proc/cmdline", ret);
 }
 
-/* In SecureBoot mode this is probably not what you want. As your cmdline is
- * cryptographically signed like when using Type #2 EFI Unified Kernel Images
- * (https://systemd.io/BOOT_LOADER_SPECIFICATION/) The user's intention is then
- * that the cmdline should not be modified.  You want to make sure that the
- * system starts up as exactly specified in the signed artifact. */
-static int systemd_options_variable(char **line) {
-        if (is_efi_secure_boot())
-                return -ENODATA;
-
-        return systemd_efi_options_variable(line);
-}
-
 static int proc_cmdline_extract_first(const char **p, char **ret_word, ProcCmdlineFlags flags) {
         const char *q = *p;
         int r;
@@ -131,7 +119,7 @@ int proc_cmdline_parse(proc_cmdline_parse_t parse_item, void *data, ProcCmdlineF
 
         /* We parse the EFI variable first, because later settings have higher priority. */
 
-        r = systemd_options_variable(&line);
+        r = systemd_efi_options_variable(&line);
         if (r < 0 && r != -ENODATA)
                 log_debug_errno(r, "Failed to get SystemdOptions EFI variable, ignoring: %m");
 
@@ -262,7 +250,7 @@ int proc_cmdline_get_key(const char *key, ProcCmdlineFlags flags, char **ret_val
                 return r;
 
         line = mfree(line);
-        r = systemd_options_variable(&line);
+        r = systemd_efi_options_variable(&line);
         if (r == -ENODATA)
                 return false; /* Not found */
         if (r < 0)
@@ -280,17 +268,17 @@ int proc_cmdline_get_bool(const char *key, bool *ret) {
         r = proc_cmdline_get_key(key, PROC_CMDLINE_VALUE_OPTIONAL, &v);
         if (r < 0)
                 return r;
-        if (r == 0) {
+        if (r == 0) { /* key not specified at all */
                 *ret = false;
                 return 0;
         }
 
-        if (v) { /* parameter passed */
+        if (v) { /* key with parameter passed */
                 r = parse_boolean(v);
                 if (r < 0)
                         return r;
                 *ret = r;
-        } else /* no parameter passed */
+        } else /* key without parameter passed */
                 *ret = true;
 
         return 1;
index 4115fdbc99fd7d00dbfc33b19681d16d54efcac6..275f46c89ec22987ec77eff2beb182de60683c0b 100644 (file)
@@ -6,9 +6,9 @@
 #include "log.h"
 
 typedef enum ProcCmdlineFlags {
-        PROC_CMDLINE_STRIP_RD_PREFIX = 1 << 0,
-        PROC_CMDLINE_VALUE_OPTIONAL  = 1 << 1,
-        PROC_CMDLINE_RD_STRICT       = 1 << 2,
+        PROC_CMDLINE_STRIP_RD_PREFIX = 1 << 0, /* automatically strip "rd." prefix if it is set (and we are in the initrd, since otherwise we'd not consider it anyway) */
+        PROC_CMDLINE_VALUE_OPTIONAL  = 1 << 1, /* the value is optional (for boolean switches that can omit the value) */
+        PROC_CMDLINE_RD_STRICT       = 1 << 2, /* ignore this in the initrd */
 } ProcCmdlineFlags;
 
 typedef int (*proc_cmdline_parse_t)(const char *key, const char *value, void *data);
index eae488ae5d921bb449d01b461cd7840815d1abef..73cc7272db41cfd8c2331da5030043f6e31b8b1c 100644 (file)
@@ -19,6 +19,7 @@
 #endif
 
 #include "alloc-util.h"
+#include "errno-util.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "io-util.h"
@@ -207,7 +208,9 @@ int genuine_random_bytes(void *p, size_t n, RandomFlags flags) {
         if (have_syscall != 0 && !HAS_FEATURE_MEMORY_SANITIZER) {
 
                 for (;;) {
-                        r = getrandom(p, n, FLAGS_SET(flags, RANDOM_BLOCK) ? 0 : GRND_NONBLOCK);
+                        r = getrandom(p, n,
+                                      (FLAGS_SET(flags, RANDOM_BLOCK) ? 0 : GRND_NONBLOCK) |
+                                      (FLAGS_SET(flags, RANDOM_ALLOW_INSECURE) ? GRND_INSECURE : 0));
                         if (r > 0) {
                                 have_syscall = true;
 
@@ -237,7 +240,7 @@ int genuine_random_bytes(void *p, size_t n, RandomFlags flags) {
                                 have_syscall = true;
                                 return -EIO;
 
-                        } else if (errno == ENOSYS) {
+                        } else if (ERRNO_IS_NOT_SUPPORTED(errno)) {
                                 /* We lack the syscall, continue with reading from /dev/urandom. */
                                 have_syscall = false;
                                 break;
@@ -263,6 +266,18 @@ int genuine_random_bytes(void *p, size_t n, RandomFlags flags) {
 
                                 /* Use /dev/urandom instead */
                                 break;
+
+                        } else if (errno == EINVAL) {
+
+                                /* Most likely: unknown flag. We know that GRND_INSECURE might cause this,
+                                 * hence try without. */
+
+                                if (FLAGS_SET(flags, RANDOM_ALLOW_INSECURE)) {
+                                        flags = flags &~ RANDOM_ALLOW_INSECURE;
+                                        continue;
+                                }
+
+                                return -errno;
                         } else
                                 return -errno;
                 }
@@ -325,9 +340,11 @@ void initialize_srand(void) {
 
 /* INT_MAX gives us only 31 bits, so use 24 out of that. */
 #if RAND_MAX >= INT_MAX
+assert_cc(RAND_MAX >= 16777215);
 #  define RAND_STEP 3
 #else
-/* SHORT_INT_MAX or lower gives at most 15 bits, we just just 8 out of that. */
+/* SHORT_INT_MAX or lower gives at most 15 bits, we just use 8 out of that. */
+assert_cc(RAND_MAX >= 255);
 #  define RAND_STEP 1
 #endif
 
@@ -392,7 +409,7 @@ void random_bytes(void *p, size_t n) {
          * This function is hence not useful for generating UUIDs or cryptographic key material.
          */
 
-        if (genuine_random_bytes(p, n, RANDOM_EXTEND_WITH_PSEUDO|RANDOM_MAY_FAIL|RANDOM_ALLOW_RDRAND) >= 0)
+        if (genuine_random_bytes(p, n, RANDOM_EXTEND_WITH_PSEUDO|RANDOM_MAY_FAIL|RANDOM_ALLOW_RDRAND|RANDOM_ALLOW_INSECURE) >= 0)
                 return;
 
         /* If for some reason some user made /dev/urandom unavailable to us, or the kernel has no entropy, use a PRNG instead. */
index facc11b976fbdba8376920af2966cb3f6cb4de21..d8e067d96e877af94aaa00fea1e1454eb6d1ee59 100644 (file)
@@ -10,6 +10,7 @@ typedef enum RandomFlags {
         RANDOM_BLOCK              = 1 << 1, /* Rather block than return crap randomness (only if the kernel supports that) */
         RANDOM_MAY_FAIL           = 1 << 2, /* If we can't get any randomness at all, return early with -ENODATA */
         RANDOM_ALLOW_RDRAND       = 1 << 3, /* Allow usage of the CPU RNG */
+        RANDOM_ALLOW_INSECURE     = 1 << 4, /* Allow usage of GRND_INSECURE flag to kernel's getrandom() API */
 } RandomFlags;
 
 int genuine_random_bytes(void *p, size_t n, RandomFlags flags); /* returns "genuine" randomness, optionally filled up with pseudo random, if not enough is available */
index 5f1956177e016669877fe90140aca8e9abd63b4a..f3501d17ae705dc2c0afa443ae71dca5898a906c 100644 (file)
@@ -113,8 +113,8 @@ static inline char **set_get_strv(Set *s) {
 }
 
 int set_consume(Set *s, void *value);
-int set_put_strdup(Set *s, const char *p);
-int set_put_strdupv(Set *s, char **l);
+int set_put_strdup(Set **s, const char *p);
+int set_put_strdupv(Set **s, char **l);
 int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags);
 
 #define SET_FOREACH(e, s, i) \
index ad467ab85119a8cf6cdeef12362e52672f483560..0be098df2ea1e411310c3dec500ded5bd0051003 100644 (file)
@@ -818,10 +818,7 @@ ssize_t send_one_fd_iov_sa(
                 const struct sockaddr *sa, socklen_t len,
                 int flags) {
 
-        union {
-                struct cmsghdr cmsghdr;
-                uint8_t buf[CMSG_SPACE(sizeof(int))];
-        } control = {};
+        CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int))) control = {};
         struct msghdr mh = {
                 .msg_name = (struct sockaddr*) sa,
                 .msg_namelen = len,
@@ -850,8 +847,6 @@ ssize_t send_one_fd_iov_sa(
                 cmsg->cmsg_type = SCM_RIGHTS;
                 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
                 memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
-
-                mh.msg_controllen = CMSG_SPACE(sizeof(int));
         }
         k = sendmsg(transport_fd, &mh, MSG_NOSIGNAL | flags);
         if (k < 0)
@@ -877,17 +872,14 @@ ssize_t receive_one_fd_iov(
                 int flags,
                 int *ret_fd) {
 
-        union {
-                struct cmsghdr cmsghdr;
-                uint8_t buf[CMSG_SPACE(sizeof(int))];
-        } control = {};
+        CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int))) control;
         struct msghdr mh = {
                 .msg_control = &control,
                 .msg_controllen = sizeof(control),
                 .msg_iov = iov,
                 .msg_iovlen = iovlen,
         };
-        struct cmsghdr *cmsg, *found = NULL;
+        struct cmsghdr *found;
         ssize_t k;
 
         assert(transport_fd >= 0);
@@ -901,26 +893,18 @@ ssize_t receive_one_fd_iov(
          * combination with send_one_fd().
          */
 
-        k = recvmsg(transport_fd, &mh, MSG_CMSG_CLOEXEC | flags);
+        k = recvmsg_safe(transport_fd, &mh, MSG_CMSG_CLOEXEC | flags);
         if (k < 0)
-                return (ssize_t) -errno;
+                return k;
 
-        CMSG_FOREACH(cmsg, &mh) {
-                if (cmsg->cmsg_level == SOL_SOCKET &&
-                    cmsg->cmsg_type == SCM_RIGHTS &&
-                    cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
-                        assert(!found);
-                        found = cmsg;
-                        break;
-                }
-        }
-
-        if (!found)
+        found = cmsg_find(&mh, SOL_SOCKET, SCM_RIGHTS, CMSG_LEN(sizeof(int)));
+        if (!found) {
                 cmsg_close_all(&mh);
 
-        /* If didn't receive an FD or any data, return an error. */
-        if (k == 0 && !found)
-                return -EIO;
+                /* If didn't receive an FD or any data, return an error. */
+                if (k == 0)
+                        return -EIO;
+        }
 
         if (found)
                 *ret_fd = *(int*) CMSG_DATA(found);
@@ -1171,3 +1155,24 @@ int socket_bind_to_ifindex(int fd, int ifindex) {
 
         return socket_bind_to_ifname(fd, ifname);
 }
+
+ssize_t recvmsg_safe(int sockfd, struct msghdr *msg, int flags) {
+        ssize_t n;
+
+        /* A wrapper around recvmsg() that checks for MSG_CTRUNC, and turns it into an error, in a reasonably
+         * safe way, closing any SCM_RIGHTS fds in the error path.
+         *
+         * Note that unlike our usual coding style this might modify *msg on failure. */
+
+        n = recvmsg(sockfd, msg, flags);
+        if (n < 0)
+                return -errno;
+
+        if (FLAGS_SET(msg->msg_flags, MSG_CTRUNC)) {
+                cmsg_close_all(msg);
+                return -EXFULL; /* a recognizable error code */
+        }
+
+        return n;
+
+}
index 24e12139516e121d6fd5aeb2a2d0d67de3ed5afb..6f366c042998184d190f0bd8222a321c388b71e0 100644 (file)
@@ -158,6 +158,25 @@ int flush_accept(int fd);
 
 struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t length);
 
+/* Type-safe, dereferencing version of cmsg_find() */
+#define CMSG_FIND_DATA(mh, level, type, ctype) \
+        ({                                                            \
+                struct cmsghdr *_found;                               \
+                _found = cmsg_find(mh, level, type, CMSG_LEN(sizeof(ctype))); \
+                (ctype*) (_found ? CMSG_DATA(_found) : NULL);         \
+        })
+
+/* Resolves to a type that can carry cmsghdr structures. Make sure things are properly aligned, i.e. the type
+ * itself is placed properly in memory and the size is also aligned to what's appropriate for "cmsghdr"
+ * structures. */
+#define CMSG_BUFFER_TYPE(size)                                          \
+        union {                                                         \
+                struct cmsghdr cmsghdr;                                 \
+                uint8_t buf[size];                                      \
+                uint8_t align_check[(size) >= CMSG_SPACE(0) &&          \
+                                    (size) == CMSG_ALIGN(size) ? 1 : -1]; \
+        }
+
 /*
  * Certain hardware address types (e.g Infiniband) do not fit into sll_addr
  * (8 bytes) and run over the structure. This macro returns the correct size that
@@ -199,3 +218,5 @@ static inline int setsockopt_int(int fd, int level, int optname, int value) {
 
 int socket_bind_to_ifname(int fd, const char *ifname);
 int socket_bind_to_ifindex(int fd, int ifindex);
+
+ssize_t recvmsg_safe(int sockfd, struct msghdr *msg, int flags);
index 5412ccbf7df978cc2de5f563e01aef3ef64518be..e4e4d8f0762108bedb3e8f863acb1d8887d33e7f 100644 (file)
@@ -178,13 +178,12 @@ int fd_is_fs_type(int fd, statfs_f_type_t magic_value) {
 }
 
 int path_is_fs_type(const char *path, statfs_f_type_t magic_value) {
-        _cleanup_close_ int fd = -1;
+        struct statfs s;
 
-        fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
-        if (fd < 0)
+        if (statfs(path, &s) < 0)
                 return -errno;
 
-        return fd_is_fs_type(fd, magic_value);
+        return is_fs_type(&s, magic_value);
 }
 
 bool is_temporary_fs(const struct statfs *s) {
@@ -377,3 +376,36 @@ int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret
 
         return 0;
 }
+
+int proc_mounted(void) {
+        int r;
+
+        /* A quick check of procfs is properly mounted */
+
+        r = path_is_fs_type("/proc/", PROC_SUPER_MAGIC);
+        if (r == -ENOENT) /* not mounted at all */
+                return false;
+
+        return r;
+}
+
+bool stat_inode_unmodified(const struct stat *a, const struct stat *b) {
+
+        /* Returns if the specified stat structures reference the same, unmodified inode. This check tries to
+         * be reasonably careful when detecting changes: we check both inode and mtime, to cater for file
+         * systems where mtimes are fixed to 0 (think: ostree/nixos type installations). We also check file
+         * size, backing device, inode type and if this refers to a device not the major/minor.
+         *
+         * Note that we don't care if file attributes such as ownership or access mode change, this here is
+         * about contents of the file. The purpose here is to detect file contents changes, and nothing
+         * else. */
+
+        return a && b &&
+                (a->st_mode & S_IFMT) != 0 && /* We use the check for .st_mode if the structure was ever initialized */
+                ((a->st_mode ^ b->st_mode) & S_IFMT) == 0 &&  /* same inode type */
+                a->st_mtime == b->st_mtime &&
+                (!S_ISREG(a->st_mode) || a->st_size == b->st_size) && /* if regular file, compare file size */
+                a->st_dev == b->st_dev &&
+                a->st_ino == b->st_ino &&
+                (!(S_ISCHR(a->st_mode) || S_ISBLK(a->st_mode)) || a->st_rdev == b->st_rdev); /* if device node, also compare major/minor, because we can */
+}
index 7824af35006e5ed03b7a8296f6dd524f223532ce..59aedcb7c4d727bfa1ecce990e6148c3c6cb21be 100644 (file)
@@ -87,3 +87,7 @@ int fd_verify_directory(int fd);
 int device_path_make_major_minor(mode_t mode, dev_t devno, char **ret);
 int device_path_make_canonical(mode_t mode, dev_t devno, char **ret);
 int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devno);
+
+int proc_mounted(void);
+
+bool stat_inode_unmodified(const struct stat *a, const struct stat *b);
index 096cb4e5d4d2fa545d99dba10d468d36471e4d9f..f1d2bb5190b037bc57412b93284194c98aa2cc43 100644 (file)
@@ -28,6 +28,18 @@ char *strv_find(char * const *l, const char *name) {
         return NULL;
 }
 
+char *strv_find_case(char * const *l, const char *name) {
+        char * const *i;
+
+        assert(name);
+
+        STRV_FOREACH(i, l)
+                if (strcaseeq(*i, name))
+                        return *i;
+
+        return NULL;
+}
+
 char *strv_find_prefix(char * const *l, const char *name) {
         char * const *i;
 
index dd3323c2235ab2fc64240a213effc5360cc628f6..0f81e345800dbb2c2a05f0060a2a8444402330de 100644 (file)
 #include "string-util.h"
 
 char *strv_find(char * const *l, const char *name) _pure_;
+char *strv_find_case(char * const *l, const char *name) _pure_;
 char *strv_find_prefix(char * const *l, const char *name) _pure_;
 char *strv_find_startswith(char * const *l, const char *name) _pure_;
 
+#define strv_contains(l, s) (!!strv_find((l), (s)))
+#define strv_contains_case(l, s) (!!strv_find_case((l), (s)))
+
 char **strv_free(char **l);
 DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free);
 #define _cleanup_strv_free_ _cleanup_(strv_freep)
@@ -54,8 +58,6 @@ static inline bool strv_equal(char * const *a, char * const *b) {
         return strv_compare(a, b) == 0;
 }
 
-#define strv_contains(l, s) (!!strv_find((l), (s)))
-
 char **strv_new_internal(const char *x, ...) _sentinel_;
 char **strv_new_ap(const char *x, va_list ap);
 #define strv_new(...) strv_new_internal(__VA_ARGS__, NULL)
@@ -104,14 +106,14 @@ bool strv_overlap(char * const *a, char * const *b) _pure_;
 
 #define STRV_FOREACH_BACKWARDS(s, l)                                \
         for (s = ({                                                 \
-                        char **_l = l;                              \
+                        typeof(l) _l = l;                           \
                         _l ? _l + strv_length(_l) - 1U : NULL;      \
                         });                                         \
              (l) && ((s) >= (l));                                   \
              (s)--)
 
 #define STRV_FOREACH_PAIR(x, y, l)               \
-        for ((x) = (l), (y) = (x+1); (x) && *(x) && *(y); (x) += 2, (y) = (x + 1))
+        for ((x) = (l), (y) = (x) ? (x+1) : NULL; (x) && *(x) && *(y); (x) += 2, (y) = (x + 1))
 
 char **strv_sort(char **l);
 void strv_print(char * const *l);
@@ -156,6 +158,13 @@ void strv_print(char * const *l);
                 _x && strv_contains(STRV_MAKE(__VA_ARGS__), _x); \
         })
 
+#define STRCASE_IN_SET(x, ...) strv_contains_case(STRV_MAKE(__VA_ARGS__), x)
+#define STRCASEPTR_IN_SET(x, ...)                                    \
+        ({                                                       \
+                const char* _x = (x);                            \
+                _x && strv_contains_case(STRV_MAKE(__VA_ARGS__), _x); \
+        })
+
 #define STARTSWITH_SET(p, ...)                                  \
         ({                                                      \
                 const char *_p = (p);                           \
index c7570c7a617ff2c9d7604dd0f0da33f12b5193c5..67634b4d4698a377b1050c8502f10d3ffada14b4 100644 (file)
@@ -28,6 +28,7 @@
 #define ANSI_HIGHLIGHT_YELLOW4           "\x1B[0;1;38;5;100m"
 
 /* Underlined */
+#define ANSI_GREY_UNDERLINE              "\x1B[0;4;38;5;245m"
 #define ANSI_HIGHLIGHT_RED_UNDERLINE     "\x1B[0;1;4;31m"
 #define ANSI_HIGHLIGHT_GREEN_UNDERLINE   "\x1B[0;1;4;32m"
 #define ANSI_HIGHLIGHT_YELLOW_UNDERLINE  "\x1B[0;1;4;38;5;185m"
@@ -138,6 +139,7 @@ DEFINE_ANSI_FUNC(highlight_grey,    HIGHLIGHT_GREY);
 
 DEFINE_ANSI_FUNC_UNDERLINE(underline,                   UNDERLINE, NORMAL);
 DEFINE_ANSI_FUNC_UNDERLINE(highlight_underline,         HIGHLIGHT_UNDERLINE, HIGHLIGHT);
+DEFINE_ANSI_FUNC_UNDERLINE(grey_underline,              GREY_UNDERLINE, GREY);
 DEFINE_ANSI_FUNC_UNDERLINE(highlight_red_underline,     HIGHLIGHT_RED_UNDERLINE, HIGHLIGHT_RED);
 DEFINE_ANSI_FUNC_UNDERLINE(highlight_green_underline,   HIGHLIGHT_GREEN_UNDERLINE, HIGHLIGHT_GREEN);
 DEFINE_ANSI_FUNC_UNDERLINE(highlight_yellow_underline,  HIGHLIGHT_YELLOW_UNDERLINE, HIGHLIGHT_YELLOW);
index dba218b38869f755bc3f49a67f663cc834f7d200..64b2b2dd7e115ab98a6d5632a42eb06a3d08a23a 100644 (file)
@@ -108,6 +108,15 @@ static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = {
 
 DEFINE_STRING_TABLE_LOOKUP(unit_active_state, UnitActiveState);
 
+static const char* const freezer_state_table[_FREEZER_STATE_MAX] = {
+        [FREEZER_RUNNING] = "running",
+        [FREEZER_FREEZING] = "freezing",
+        [FREEZER_FROZEN] = "frozen",
+        [FREEZER_THAWING] = "thawing",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(freezer_state, FreezerState);
+
 static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = {
         [AUTOMOUNT_DEAD] = "dead",
         [AUTOMOUNT_WAITING] = "waiting",
index edb3ff8fe8aed01db5e3da73e23159c380f625a3..a7d67819884f3785ad883b935ab5634fde88326d 100644 (file)
@@ -48,6 +48,15 @@ typedef enum UnitActiveState {
         _UNIT_ACTIVE_STATE_INVALID = -1
 } UnitActiveState;
 
+typedef enum FreezerState {
+        FREEZER_RUNNING,
+        FREEZER_FREEZING,
+        FREEZER_FROZEN,
+        FREEZER_THAWING,
+        _FREEZER_STATE_MAX,
+        _FREEZER_STATE_INVALID = -1
+} FreezerState;
+
 typedef enum AutomountState {
         AUTOMOUNT_DEAD,
         AUTOMOUNT_WAITING,
@@ -253,6 +262,9 @@ UnitLoadState unit_load_state_from_string(const char *s) _pure_;
 const char *unit_active_state_to_string(UnitActiveState i) _const_;
 UnitActiveState unit_active_state_from_string(const char *s) _pure_;
 
+const char *freezer_state_to_string(FreezerState i) _const_;
+FreezerState freezer_state_from_string(const char *s) _pure_;
+
 const char* automount_state_to_string(AutomountState i) _const_;
 AutomountState automount_state_from_string(const char *s) _pure_;
 
index f21a36c6fea1b1368ccc299c2277e88e94a65998..c6bff6b16e814a3d50968e3f7d4622eccdfee7f3 100644 (file)
@@ -464,12 +464,10 @@ int detect_container(void) {
                 goto finish;
         }
 
-        /* "Official" way of detecting WSL https://github.com/Microsoft/WSL/issues/423#issuecomment-221627364,
-         * ... and a working one, since the official one doesn't actually work ;(
-         */
+        /* "Official" way of detecting WSL https://github.com/Microsoft/WSL/issues/423#issuecomment-221627364 */
         r = read_one_line_file("/proc/sys/kernel/osrelease", &o);
         if (r >= 0 &&
-            (strstr(o, "Microsoft") || strstr(o, "microsoft") || strstr(o, "WSL"))) {
+            (strstr(o, "Microsoft") || strstr(o, "WSL"))) {
                 r = VIRTUALIZATION_WSL;
                 goto finish;
         }
index 7ff844c78c3a87253935b5ff93dcbff944658da3..06aee22dc0f7ac2dc09cec48fed0a0feb54ca10c 100644 (file)
@@ -10,6 +10,7 @@
 #include <sys/types.h>
 
 #include "alloc-util.h"
+#include "binfmt-util.h"
 #include "conf-files.h"
 #include "def.h"
 #include "fd-util.h"
@@ -24,6 +25,7 @@
 
 static bool arg_cat_config = false;
 static PagerFlags arg_pager_flags = 0;
+static bool arg_unregister = false;
 
 static int delete_rule(const char *rule) {
         _cleanup_free_ char *x = NULL, *fn = NULL;
@@ -32,18 +34,17 @@ static int delete_rule(const char *rule) {
         assert(rule);
         assert(rule[0]);
 
-        x = strdup(rule);
+        e = strchrnul(rule + 1, rule[0]);
+        x = strndup(rule + 1, e - rule - 1);
         if (!x)
                 return log_oom();
 
-        e = strchrnul(x+1, x[0]);
-        *e = 0;
-
-        if (!filename_is_valid(x + 1))
+        if (!filename_is_valid(x) ||
+            STR_IN_SET(x, "register", "status"))
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "Rule file name '%s' is not valid, refusing.", x + 1);
+                                       "Rule file name '%s' is not valid, refusing.", x);
 
-        fn = path_join("/proc/sys/fs/binfmt_misc", x+1);
+        fn = path_join("/proc/sys/fs/binfmt_misc", x);
         if (!fn)
                 return log_oom();
 
@@ -116,6 +117,7 @@ static int help(void) {
                "     --version          Show package version\n"
                "     --cat-config       Show configuration files\n"
                "     --no-pager         Do not pipe output into a pager\n"
+               "     --unregister       Unregister all existing entries\n"
                "\nSee the %s for details.\n"
                , program_invocation_short_name
                , link
@@ -129,6 +131,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_VERSION = 0x100,
                 ARG_CAT_CONFIG,
                 ARG_NO_PAGER,
+                ARG_UNREGISTER,
         };
 
         static const struct option options[] = {
@@ -136,6 +139,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "version",    no_argument, NULL, ARG_VERSION    },
                 { "cat-config", no_argument, NULL, ARG_CAT_CONFIG },
                 { "no-pager",   no_argument, NULL, ARG_NO_PAGER   },
+                { "unregister", no_argument, NULL, ARG_UNREGISTER },
                 {}
         };
 
@@ -162,6 +166,10 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_pager_flags |= PAGER_DISABLE;
                         break;
 
+                case ARG_UNREGISTER:
+                        arg_unregister = true;
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -169,9 +177,9 @@ static int parse_argv(int argc, char *argv[]) {
                         assert_not_reached("Unhandled option");
                 }
 
-        if (arg_cat_config && argc > optind)
+        if ((arg_unregister || arg_cat_config) && argc > optind)
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "Positional arguments are not allowed with --cat-config");
+                                       "Positional arguments are not allowed with --cat-config or --unregister");
 
         return 1;
 }
@@ -189,6 +197,9 @@ static int run(int argc, char *argv[]) {
 
         r = 0;
 
+        if (arg_unregister)
+                return disable_binfmt();
+
         if (argc > optind) {
                 int i;
 
index 222b382d5729f16a8d67cf44ad9cfa4f37870054..a197668ce96e287998d31a6b2131ec4a9ae43612 100644 (file)
@@ -517,7 +517,7 @@ static int copy_file_with_version_check(const char *from, const char *to, bool f
         if (!force) {
                 fd_to = open(to, O_RDONLY|O_CLOEXEC|O_NOCTTY);
                 if (fd_to < 0) {
-                        if (errno != -ENOENT)
+                        if (errno != ENOENT)
                                 return log_error_errno(errno, "Failed to open \"%s\" for reading: %m", to);
                 } else {
                         r = version_check(fd_from, from, fd_to, to);
index 4fb5a8cedcd601f64aabdb9e730aa44a8a1ba5ee..7aceb1796f1621c56e2fde5c50792cd9e1a592e3 100644 (file)
@@ -458,7 +458,7 @@ static int on_path(const char *path, void *userdata) {
 
         assert(paths);
 
-        r = set_put_strdup(paths, path);
+        r = set_put_strdup(&paths, path);
         if (r < 0)
                 return log_oom();
 
@@ -856,20 +856,24 @@ static int on_interface(const char *interface, uint64_t flags, void *userdata) {
         assert(interface);
         assert(members);
 
-        m = new0(Member, 1);
+        m = new(Member, 1);
         if (!m)
                 return log_oom();
 
-        m->type = "interface";
-        m->flags = flags;
+        *m = (Member) {
+                .type = "interface",
+                .flags = flags,
+        };
 
         r = free_and_strdup(&m->interface, interface);
         if (r < 0)
                 return log_oom();
 
         r = set_put(members, m);
-        if (r <= 0)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Duplicate interface");
+        if (r == -EEXIST)
+                return log_error_errno(r,  "Invalid introspection data: duplicate interface '%s'.", interface);
+        if (r < 0)
+                return log_oom();
 
         m = NULL;
         return 0;
@@ -883,12 +887,14 @@ static int on_method(const char *interface, const char *name, const char *signat
         assert(interface);
         assert(name);
 
-        m = new0(Member, 1);
+        m = new(Member, 1);
         if (!m)
                 return log_oom();
 
-        m->type = "method";
-        m->flags = flags;
+        *m = (Member) {
+                .type = "method",
+                .flags = flags,
+        };
 
         r = free_and_strdup(&m->interface, interface);
         if (r < 0)
@@ -907,8 +913,10 @@ static int on_method(const char *interface, const char *name, const char *signat
                 return log_oom();
 
         r = set_put(members, m);
-        if (r <= 0)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Duplicate method");
+        if (r == -EEXIST)
+                return log_error_errno(r, "Invalid introspection data: duplicate method '%s' on interface '%s'.", name, interface);
+        if (r < 0)
+                return log_oom();
 
         m = NULL;
         return 0;
@@ -922,12 +930,14 @@ static int on_signal(const char *interface, const char *name, const char *signat
         assert(interface);
         assert(name);
 
-        m = new0(Member, 1);
+        m = new(Member, 1);
         if (!m)
                 return log_oom();
 
-        m->type = "signal";
-        m->flags = flags;
+        *m = (Member) {
+                .type = "signal",
+                .flags = flags,
+        };
 
         r = free_and_strdup(&m->interface, interface);
         if (r < 0)
@@ -942,8 +952,10 @@ static int on_signal(const char *interface, const char *name, const char *signat
                 return log_oom();
 
         r = set_put(members, m);
-        if (r <= 0)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Duplicate signal");
+        if (r == -EEXIST)
+                return log_error_errno(r, "Invalid introspection data: duplicate signal '%s' on interface '%s'.", name, interface);
+        if (r < 0)
+                return log_oom();
 
         m = NULL;
         return 0;
@@ -957,13 +969,15 @@ static int on_property(const char *interface, const char *name, const char *sign
         assert(interface);
         assert(name);
 
-        m = new0(Member, 1);
+        m = new(Member, 1);
         if (!m)
                 return log_oom();
 
-        m->type = "property";
-        m->flags = flags;
-        m->writable = writable;
+        *m = (Member) {
+                .type = "property",
+                .flags = flags,
+                .writable = writable,
+        };
 
         r = free_and_strdup(&m->interface, interface);
         if (r < 0)
@@ -978,8 +992,10 @@ static int on_property(const char *interface, const char *name, const char *sign
                 return log_oom();
 
         r = set_put(members, m);
-        if (r <= 0)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Duplicate property");
+        if (r == -EEXIST)
+                return log_error_errno(r, "Invalid introspection data: duplicate property '%s' on interface '%s'.", name, interface);
+        if (r < 0)
+                return log_oom();
 
         m = NULL;
         return 0;
index 0b3f498bfcb3bb222f5b1139b7255d3f51bf1da8..566b56eb349ee667ea537b45fb9cc6af1db392ea 100644 (file)
@@ -152,6 +152,10 @@ static int automount_add_default_dependencies(Automount *a) {
         if (!MANAGER_IS_SYSTEM(UNIT(a)->manager))
                 return 0;
 
+        r = unit_add_dependency_by_name(UNIT(a), UNIT_BEFORE, SPECIAL_LOCAL_FS_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
+        if (r < 0)
+                return r;
+
         r = unit_add_dependency_by_name(UNIT(a), UNIT_AFTER, SPECIAL_LOCAL_FS_PRE_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
         if (r < 0)
                 return r;
@@ -1133,7 +1137,6 @@ const UnitVTable automount_vtable = {
 
         .reset_failed = automount_reset_failed,
 
-        .bus_vtable = bus_automount_vtable,
         .bus_set_property = bus_automount_set_property,
 
         .shutdown = automount_shutdown,
index 5e4fe600a2974e788f8409bb1774ca0aaf920ccc..7d45438e85a116aede08dc98e103e6c1e4daa48e 100644 (file)
@@ -16,7 +16,9 @@
 #include "fd-util.h"
 #include "fileio.h"
 #include "fs-util.h"
+#include "io-util.h"
 #include "limits-util.h"
+#include "nulstr-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
@@ -2661,6 +2663,16 @@ void unit_add_to_cgroup_empty_queue(Unit *u) {
                 log_debug_errno(r, "Failed to enable cgroup empty event source: %m");
 }
 
+static void unit_remove_from_cgroup_empty_queue(Unit *u) {
+        assert(u);
+
+        if (!u->in_cgroup_empty_queue)
+                return;
+
+        LIST_REMOVE(cgroup_empty_queue, u->manager->cgroup_empty_queue, u);
+        u->in_cgroup_empty_queue = false;
+}
+
 int unit_check_oom(Unit *u) {
         _cleanup_free_ char *oom_kill = NULL;
         bool increased;
@@ -2761,6 +2773,41 @@ static void unit_add_to_cgroup_oom_queue(Unit *u) {
                 log_error_errno(r, "Failed to enable cgroup oom event source: %m");
 }
 
+static int unit_check_cgroup_events(Unit *u) {
+        char *values[2] = {};
+        int r;
+
+        assert(u);
+
+        r = cg_get_keyed_attribute_graceful(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, "cgroup.events",
+                                            STRV_MAKE("populated", "frozen"), values);
+        if (r < 0)
+                return r;
+
+        /* The cgroup.events notifications can be merged together so act as we saw the given state for the
+         * first time. The functions we call to handle given state are idempotent, which makes them
+         * effectively remember the previous state. */
+        if (values[0]) {
+                if (streq(values[0], "1"))
+                        unit_remove_from_cgroup_empty_queue(u);
+                else
+                        unit_add_to_cgroup_empty_queue(u);
+        }
+
+        /* Disregard freezer state changes due to operations not initiated by us */
+        if (values[1] && IN_SET(u->freezer_state, FREEZER_FREEZING, FREEZER_THAWING)) {
+                if (streq(values[1], "0"))
+                        unit_thawed(u);
+                else
+                        unit_frozen(u);
+        }
+
+        free(values[0]);
+        free(values[1]);
+
+        return 0;
+}
+
 static int on_cgroup_inotify_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
         Manager *m = userdata;
 
@@ -2797,7 +2844,7 @@ static int on_cgroup_inotify_event(sd_event_source *s, int fd, uint32_t revents,
 
                         u = hashmap_get(m->cgroup_control_inotify_wd_unit, INT_TO_PTR(e->wd));
                         if (u)
-                                unit_add_to_cgroup_empty_queue(u);
+                                unit_check_cgroup_events(u);
 
                         u = hashmap_get(m->cgroup_memory_inotify_wd_unit, INT_TO_PTR(e->wd));
                         if (u)
@@ -3550,6 +3597,46 @@ int compare_job_priority(const void *a, const void *b) {
         return strcmp(x->unit->id, y->unit->id);
 }
 
+int unit_cgroup_freezer_action(Unit *u, FreezerAction action) {
+        _cleanup_free_ char *path = NULL;
+        FreezerState target, kernel = _FREEZER_STATE_INVALID;
+        int r;
+
+        assert(u);
+        assert(IN_SET(action, FREEZER_FREEZE, FREEZER_THAW));
+
+        if (!u->cgroup_realized)
+                return -EBUSY;
+
+        target = action == FREEZER_FREEZE ? FREEZER_FROZEN : FREEZER_RUNNING;
+
+        r = unit_freezer_state_kernel(u, &kernel);
+        if (r < 0)
+                log_unit_debug_errno(u, r, "Failed to obtain cgroup freezer state: %m");
+
+        if (target == kernel) {
+                u->freezer_state = target;
+                return 0;
+        }
+
+        r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, "cgroup.freeze", &path);
+        if (r < 0)
+                return r;
+
+        log_unit_debug(u, "%s unit.", action == FREEZER_FREEZE ? "Freezing" : "Thawing");
+
+        if (action == FREEZER_FREEZE)
+                u->freezer_state = FREEZER_FREEZING;
+        else
+                u->freezer_state = FREEZER_THAWING;
+
+        r = write_string_file(path, one_zero(action == FREEZER_FREEZE), WRITE_STRING_FILE_DISABLE_BUFFER);
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
 static const char* const cgroup_device_policy_table[_CGROUP_DEVICE_POLICY_MAX] = {
         [CGROUP_DEVICE_POLICY_AUTO]   = "auto",
         [CGROUP_DEVICE_POLICY_CLOSED] = "closed",
@@ -3585,3 +3672,10 @@ int unit_get_cpuset(Unit *u, CPUSet *cpus, const char *name) {
 }
 
 DEFINE_STRING_TABLE_LOOKUP(cgroup_device_policy, CGroupDevicePolicy);
+
+static const char* const freezer_action_table[_FREEZER_ACTION_MAX] = {
+        [FREEZER_FREEZE] = "freeze",
+        [FREEZER_THAW] = "thaw",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(freezer_action, FreezerAction);
index b6bd4e0de5312d067204d8305d5ded5c0f75da93..52d028e740ff38e7c29a07be98f32c1e8c15adca 100644 (file)
@@ -47,6 +47,14 @@ typedef enum CGroupDevicePolicy {
         _CGROUP_DEVICE_POLICY_INVALID = -1
 } CGroupDevicePolicy;
 
+typedef enum FreezerAction {
+        FREEZER_FREEZE,
+        FREEZER_THAW,
+
+        _FREEZER_ACTION_MAX,
+        _FREEZER_ACTION_INVALID = -1,
+} FreezerAction;
+
 struct CGroupDeviceAllow {
         LIST_FIELDS(CGroupDeviceAllow, device_allow);
         char *path;
@@ -274,3 +282,7 @@ bool unit_cgroup_delegate(Unit *u);
 int compare_job_priority(const void *a, const void *b);
 
 int unit_get_cpuset(Unit *u, CPUSet *cpus, const char *name);
+int unit_cgroup_freezer_action(Unit *u, FreezerAction action);
+
+const char* freezer_action_to_string(FreezerAction a) _const_;
+FreezerAction freezer_action_from_string(const char *s) _pure_;
index 8a2984a2d4c936c645898cad96bca285825294c5..eca27f4d7d116c59cc8f9a87218c0fec9044b69a 100644 (file)
@@ -289,11 +289,13 @@ int manager_varlink_init(Manager *m) {
         if (r < 0)
                 return log_error_errno(r, "Failed to register varlink methods: %m");
 
-        (void) mkdir_p("/run/systemd/userdb", 0755);
+        if (!MANAGER_IS_TEST_RUN(m)) {
+                (void) mkdir_p("/run/systemd/userdb", 0755);
 
-        r = varlink_server_listen_address(s, "/run/systemd/userdb/io.systemd.DynamicUser", 0666);
-        if (r < 0)
-                return log_error_errno(r, "Failed to bind to varlink socket: %m");
+                r = varlink_server_listen_address(s, "/run/systemd/userdb/io.systemd.DynamicUser", 0666);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to bind to varlink socket: %m");
+        }
 
         r = varlink_server_attach_event(s, m->event, SD_EVENT_PRIORITY_NORMAL);
         if (r < 0)
index 0e952c875759929016d4b353f773f31734151172..404984f664881d06574dfb4460005b7d9d8cb542 100644 (file)
@@ -140,6 +140,58 @@ const sd_bus_vtable bus_job_vtable[] = {
         SD_BUS_VTABLE_END
 };
 
+static int bus_job_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
+        Manager *m = userdata;
+        Job *j;
+        int r;
+
+        assert(bus);
+        assert(path);
+        assert(interface);
+        assert(found);
+        assert(m);
+
+        r = manager_get_job_from_dbus_path(m, path, &j);
+        if (r < 0)
+                return 0;
+
+        *found = j;
+        return 1;
+}
+
+static int bus_job_enumerate(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
+        _cleanup_strv_free_ char **l = NULL;
+        Manager *m = userdata;
+        unsigned k = 0;
+        Iterator i;
+        Job *j;
+
+        l = new0(char*, hashmap_size(m->jobs)+1);
+        if (!l)
+                return -ENOMEM;
+
+        HASHMAP_FOREACH(j, m->jobs, i) {
+                l[k] = job_dbus_path(j);
+                if (!l[k])
+                        return -ENOMEM;
+
+                k++;
+        }
+
+        assert(hashmap_size(m->jobs) == k);
+
+        *nodes = TAKE_PTR(l);
+
+        return k;
+}
+
+const BusObjectImplementation job_object = {
+        "/org/freedesktop/systemd1/job",
+        "org.freedesktop.systemd1.Job",
+        .fallback_vtables = BUS_FALLBACK_VTABLES({bus_job_vtable, bus_job_find}),
+        .node_enumerator = bus_job_enumerate,
+};
+
 static int send_new_signal(sd_bus *bus, void *userdata) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
         _cleanup_free_ char *p = NULL;
index 380e117fca9141418c1ee14cd4f1f352a5a38ede..a840c6dfe82c5c2428b955bb886039dc7ca5b4bf 100644 (file)
@@ -2,11 +2,12 @@
 #pragma once
 
 #include "sd-bus.h"
-#include "sd-bus-vtable.h"
 
 #include "unit.h"
+#include "bus-util.h"
 
 extern const sd_bus_vtable bus_job_vtable[];
+extern const BusObjectImplementation job_object;
 
 int bus_job_method_cancel(sd_bus_message *message, void *job, sd_bus_error *error);
 int bus_job_method_get_waiting_jobs(sd_bus_message *message, void *userdata, sd_bus_error *error);
index 5f862e47fda38fb2901c7eae535353e96d314eef..51254b92da536404a6812d22243048ded2955002 100644 (file)
@@ -244,28 +244,116 @@ static int property_get_show_status(
         return sd_bus_message_append_basic(reply, 'b', &b);
 }
 
-static int property_set_runtime_watchdog(
+static int property_get_runtime_watchdog(
                 sd_bus *bus,
                 const char *path,
                 const char *interface,
                 const char *property,
-                sd_bus_message *value,
+                sd_bus_message *reply,
                 void *userdata,
                 sd_bus_error *error) {
 
-        usec_t *t = userdata;
-        int r;
+        Manager *m = userdata;
+
+        assert(m);
+        assert(bus);
+        assert(reply);
+
+        return sd_bus_message_append(reply, "t", manager_get_watchdog(m, WATCHDOG_RUNTIME));
+}
+
+static int property_get_reboot_watchdog(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        Manager *m = userdata;
 
+        assert(m);
         assert(bus);
+        assert(reply);
+
+        return sd_bus_message_append(reply, "t", manager_get_watchdog(m, WATCHDOG_REBOOT));
+}
+
+static int property_get_kexec_watchdog(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        Manager *m = userdata;
+
+        assert(m);
+        assert(bus);
+        assert(reply);
+
+        return sd_bus_message_append(reply, "t", manager_get_watchdog(m, WATCHDOG_KEXEC));
+}
+
+static int property_set_watchdog(Manager *m, WatchdogType type, sd_bus_message *value) {
+        usec_t timeout;
+        int r;
+
+        assert(m);
         assert(value);
 
         assert_cc(sizeof(usec_t) == sizeof(uint64_t));
 
-        r = sd_bus_message_read(value, "t", t);
+        r = sd_bus_message_read(value, "t", &timeout);
         if (r < 0)
                 return r;
 
-        return watchdog_set_timeout(t);
+        return manager_set_watchdog_overridden(m, type, timeout);
+}
+
+static int property_set_runtime_watchdog(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *value,
+                void *userdata,
+                sd_bus_error *error) {
+
+        return property_set_watchdog(userdata, WATCHDOG_RUNTIME, value);
+}
+
+static int property_set_reboot_watchdog(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *value,
+                void *userdata,
+                sd_bus_error *error) {
+
+        return property_set_watchdog(userdata, WATCHDOG_REBOOT, value);
+}
+
+static int property_set_kexec_watchdog(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *value,
+                void *userdata,
+                sd_bus_error *error) {
+
+        Manager *m = userdata;
+
+        assert(m);
+        assert(bus);
+        assert(value);
+
+        return property_set_watchdog(userdata, WATCHDOG_KEXEC, value);
 }
 
 static int bus_get_unit_by_name(Manager *m, sd_bus_message *message, const char *name, Unit **ret_unit, sd_bus_error *error) {
@@ -620,6 +708,14 @@ static int method_clean_unit(sd_bus_message *message, void *userdata, sd_bus_err
         return method_generic_unit_operation(message, userdata, error, bus_unit_method_clean, GENERIC_UNIT_LOAD|GENERIC_UNIT_VALIDATE_LOADED);
 }
 
+static int method_freeze_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return method_generic_unit_operation(message, userdata, error, bus_unit_method_freeze, 0);
+}
+
+static int method_thaw_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return method_generic_unit_operation(message, userdata, error, bus_unit_method_thaw, 0);
+}
+
 static int method_reset_failed_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         /* Don't load the unit (because unloaded units can't be in failed state), and don't insist on the
          * unit to be loaded properly (since a failed unit might have its unit file disappeared) */
@@ -2396,11 +2492,11 @@ const sd_bus_vtable bus_manager_vtable[] = {
         SD_BUS_PROPERTY("UnitPath", "as", NULL, offsetof(Manager, lookup_paths.search_path), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("DefaultStandardOutput", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("DefaultStandardError", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_WRITABLE_PROPERTY("RuntimeWatchdogUSec", "t", bus_property_get_usec, property_set_runtime_watchdog, offsetof(Manager, runtime_watchdog), 0),
-        SD_BUS_WRITABLE_PROPERTY("RebootWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, reboot_watchdog), 0),
+        SD_BUS_WRITABLE_PROPERTY("RuntimeWatchdogUSec", "t", property_get_runtime_watchdog, property_set_runtime_watchdog, 0, 0),
+        SD_BUS_WRITABLE_PROPERTY("RebootWatchdogUSec", "t", property_get_reboot_watchdog, property_set_reboot_watchdog, 0, 0),
         /* The following item is an obsolete alias */
-        SD_BUS_WRITABLE_PROPERTY("ShutdownWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, reboot_watchdog), SD_BUS_VTABLE_HIDDEN),
-        SD_BUS_WRITABLE_PROPERTY("KExecWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, kexec_watchdog), 0),
+        SD_BUS_WRITABLE_PROPERTY("ShutdownWatchdogUSec", "t", property_get_reboot_watchdog, property_set_reboot_watchdog, 0, SD_BUS_VTABLE_HIDDEN),
+        SD_BUS_WRITABLE_PROPERTY("KExecWatchdogUSec", "t", property_get_kexec_watchdog, property_set_kexec_watchdog, 0, 0),
         SD_BUS_WRITABLE_PROPERTY("ServiceWatchdogs", "b", bus_property_get_bool, bus_property_set_bool, offsetof(Manager, service_watchdogs), 0),
         SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Manager, cgroup_root), 0),
         SD_BUS_PROPERTY("SystemState", "s", property_get_system_state, 0, 0),
@@ -2584,6 +2680,18 @@ const sd_bus_vtable bus_manager_vtable[] = {
                                  NULL,,
                                  method_clean_unit,
                                  SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_NAMES("FreezeUnit",
+                                 "s",
+                                 SD_BUS_PARAM(name),
+                                 NULL,,
+                                 method_freeze_unit,
+                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_NAMES("ThawUnit",
+                                 "s",
+                                 SD_BUS_PARAM(name),
+                                 NULL,,
+                                 method_thaw_unit,
+                                 SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD_WITH_NAMES("ResetFailedUnit",
                                  "s",
                                  SD_BUS_PARAM(name),
index b6d61627ebb13b446c269856d42db10aa5acc5c3..3ab5ecc425c1e023cebbea51e82d326c88e44259 100644 (file)
@@ -51,6 +51,7 @@ const sd_bus_vtable bus_mount_vtable[] = {
         SD_BUS_PROPERTY("SloppyOptions", "b", bus_property_get_bool, offsetof(Mount, sloppy_options), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("LazyUnmount", "b", bus_property_get_bool, offsetof(Mount, lazy_unmount), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("ForceUnmount", "b", bus_property_get_bool, offsetof(Mount, force_unmount), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("ReadWriteOnly", "b", bus_property_get_bool, offsetof(Mount, read_write_only), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Mount, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("UID", "u", bus_property_get_uid, offsetof(Unit, ref_uid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("GID", "u", bus_property_get_gid, offsetof(Unit, ref_gid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
@@ -102,6 +103,9 @@ static int bus_mount_set_transient_property(
         if (streq(name, "ForceUnmount"))
                 return bus_set_transient_bool(u, name, &m->force_unmount, message, flags, error);
 
+        if (streq(name, "ReadWriteOnly"))
+                return bus_set_transient_bool(u, name, &m->read_write_only, message, flags, error);
+
         return 0;
 }
 
index 7a1f5041f3f94e0fe2dc439d73e24f930886b4ad..dedc39566644aa4d4c9ee715df3cf982856d7f6e 100644 (file)
@@ -46,12 +46,14 @@ static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode);
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_emergency_action, emergency_action, EmergencyAction);
 static BUS_DEFINE_PROPERTY_GET(property_get_description, "s", Unit, unit_description);
 static BUS_DEFINE_PROPERTY_GET2(property_get_active_state, "s", Unit, unit_active_state, unit_active_state_to_string);
+static BUS_DEFINE_PROPERTY_GET2(property_get_freezer_state, "s", Unit, unit_freezer_state, freezer_state_to_string);
 static BUS_DEFINE_PROPERTY_GET(property_get_sub_state, "s", Unit, unit_sub_state_to_string);
 static BUS_DEFINE_PROPERTY_GET2(property_get_unit_file_state, "s", Unit, unit_get_unit_file_state, unit_file_state_to_string);
 static BUS_DEFINE_PROPERTY_GET(property_get_can_reload, "b", Unit, unit_can_reload);
 static BUS_DEFINE_PROPERTY_GET(property_get_can_start, "b", Unit, unit_can_start_refuse_manual);
 static BUS_DEFINE_PROPERTY_GET(property_get_can_stop, "b", Unit, unit_can_stop_refuse_manual);
 static BUS_DEFINE_PROPERTY_GET(property_get_can_isolate, "b", Unit, unit_can_isolate_refuse_manual);
+static BUS_DEFINE_PROPERTY_GET(property_get_can_freeze, "b", Unit, unit_can_freeze);
 static BUS_DEFINE_PROPERTY_GET(property_get_need_daemon_reload, "b", Unit, unit_need_daemon_reload);
 static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_empty_strv, "as", 0);
 
@@ -724,6 +726,79 @@ int bus_unit_method_clean(sd_bus_message *message, void *userdata, sd_bus_error
         return sd_bus_reply_method_return(message, NULL);
 }
 
+static int bus_unit_method_freezer_generic(sd_bus_message *message, void *userdata, sd_bus_error *error, FreezerAction action) {
+        const char* perm;
+        int (*method)(Unit*);
+        Unit *u = userdata;
+        bool reply_no_delay = false;
+        int r;
+
+        assert(message);
+        assert(u);
+        assert(IN_SET(action, FREEZER_FREEZE, FREEZER_THAW));
+
+        if (action == FREEZER_FREEZE) {
+                perm = "stop";
+                method = unit_freeze;
+        } else {
+                perm = "start";
+                method = unit_thaw;
+        }
+
+        r = mac_selinux_unit_access_check(u, message, perm, error);
+        if (r < 0)
+                return r;
+
+        r = bus_verify_manage_units_async_full(
+                        u,
+                        perm,
+                        CAP_SYS_ADMIN,
+                        N_("Authentication is required to freeze or thaw the processes of '$(unit)' unit."),
+                        true,
+                        message,
+                        error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
+        r = method(u);
+        if (r == -EOPNOTSUPP)
+                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Unit '%s' does not support freezing.", u->id);
+        if (r == -EBUSY)
+                return sd_bus_error_setf(error, BUS_ERROR_UNIT_BUSY, "Unit has a pending job.");
+        if (r == -EHOSTDOWN)
+                return sd_bus_error_setf(error, BUS_ERROR_UNIT_INACTIVE, "Unit is inactive.");
+        if (r == -EALREADY)
+                return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Previously requested freezer operation for unit '%s' is still in progress.", u->id);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                reply_no_delay = true;
+
+        assert(!u->pending_freezer_message);
+
+        r = sd_bus_message_new_method_return(message, &u->pending_freezer_message);
+        if (r < 0)
+                return r;
+
+        if (reply_no_delay) {
+                r = bus_unit_send_pending_freezer_message(u);
+                if (r < 0)
+                        return r;
+        }
+
+        return 1;
+}
+
+int bus_unit_method_thaw(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return bus_unit_method_freezer_generic(message, userdata, error, FREEZER_THAW);
+}
+
+int bus_unit_method_freeze(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return bus_unit_method_freezer_generic(message, userdata, error, FREEZER_FREEZE);
+}
+
 static int property_get_refs(
                 sd_bus *bus,
                 const char *path,
@@ -793,6 +868,7 @@ const sd_bus_vtable bus_unit_vtable[] = {
         SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("LoadState", "s", property_get_load_state, offsetof(Unit, load_state), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("FreezerState", "s", property_get_freezer_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("SubState", "s", property_get_sub_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("FragmentPath", "s", NULL, offsetof(Unit, fragment_path), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -809,6 +885,7 @@ const sd_bus_vtable bus_unit_vtable[] = {
         SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("CanClean", "as", property_get_can_clean, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("CanFreeze", "b", property_get_can_freeze, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("Job", "(uo)", property_get_job, offsetof(Unit, job), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool, offsetof(Unit, stop_when_unneeded), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_start), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -940,6 +1017,16 @@ const sd_bus_vtable bus_unit_vtable[] = {
                                  NULL,,
                                  bus_unit_method_clean,
                                  SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("Freeze",
+                      NULL,
+                      NULL,
+                      bus_unit_method_freeze,
+                      SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("Thaw",
+                      NULL,
+                      NULL,
+                      bus_unit_method_thaw,
+                      SD_BUS_VTABLE_UNPRIVILEGED),
 
         /* For dependency types we don't support anymore always return an empty array */
         SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_empty_strv, 0, SD_BUS_VTABLE_HIDDEN),
@@ -1566,6 +1653,23 @@ void bus_unit_send_pending_change_signal(Unit *u, bool including_new) {
         bus_unit_send_change_signal(u);
 }
 
+int bus_unit_send_pending_freezer_message(Unit *u) {
+        int r;
+
+        assert(u);
+
+        if (!u->pending_freezer_message)
+                return 0;
+
+        r = sd_bus_send(NULL, u->pending_freezer_message, NULL);
+        if (r < 0)
+                log_warning_errno(r, "Failed to send queued message, ignoring: %m");
+
+        u->pending_freezer_message = sd_bus_message_unref(u->pending_freezer_message);
+
+        return 0;
+}
+
 static int send_removed_signal(sd_bus *bus, void *userdata) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
         _cleanup_free_ char *p = NULL;
@@ -1620,7 +1724,7 @@ int bus_unit_queue_job(
 
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         _cleanup_free_ char *job_path = NULL, *unit_path = NULL;
-        _cleanup_(set_freep) Set *affected = NULL;
+        _cleanup_set_free_ Set *affected = NULL;
         Iterator i;
         Job *j, *a;
         int r;
index 91711311a7836b9f7aae865dd7a798a41b3c0569..f21f23602563aa96e0506786a8d33c9ab7e48d0b 100644 (file)
@@ -2,7 +2,6 @@
 #pragma once
 
 #include "sd-bus.h"
-#include "sd-bus-vtable.h"
 
 #include "unit.h"
 
@@ -11,6 +10,7 @@ extern const sd_bus_vtable bus_unit_cgroup_vtable[];
 
 void bus_unit_send_change_signal(Unit *u);
 void bus_unit_send_pending_change_signal(Unit *u, bool including_new);
+int bus_unit_send_pending_freezer_message(Unit *u);
 void bus_unit_send_removed_signal(Unit *u);
 
 int bus_unit_method_start_generic(sd_bus_message *message, Unit *u, JobType job_type, bool reload_if_possible, sd_bus_error *error);
@@ -25,6 +25,8 @@ int bus_unit_method_attach_processes(sd_bus_message *message, void *userdata, sd
 int bus_unit_method_ref(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_unit_method_unref(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_unit_method_clean(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_unit_method_freeze(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_unit_method_thaw(sd_bus_message *message, void *userdata, sd_bus_error *error);
 
 typedef enum BusUnitQueueFlags {
         BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE = 1 << 0,
index 8a586e11710765a11b64611406589d4d3b2d16af..76bb91d0ea1646c23258dc493c6679e06f720e57 100644 (file)
@@ -274,25 +274,6 @@ static int mac_selinux_filter(sd_bus_message *message, void *userdata, sd_bus_er
 }
 #endif
 
-static int bus_job_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
-        Manager *m = userdata;
-        Job *j;
-        int r;
-
-        assert(bus);
-        assert(path);
-        assert(interface);
-        assert(found);
-        assert(m);
-
-        r = manager_get_job_from_dbus_path(m, path, &j);
-        if (r < 0)
-                return 0;
-
-        *found = j;
-        return 1;
-}
-
 static int find_unit(Manager *m, sd_bus *bus, const char *path, Unit **unit, sd_bus_error *error) {
         Unit *u = NULL;  /* just to appease gcc, initialization is not really necessary */
         int r;
@@ -472,32 +453,6 @@ static int bus_kill_context_find(sd_bus *bus, const char *path, const char *inte
         return 1;
 }
 
-static int bus_job_enumerate(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
-        _cleanup_strv_free_ char **l = NULL;
-        Manager *m = userdata;
-        unsigned k = 0;
-        Iterator i;
-        Job *j;
-
-        l = new0(char*, hashmap_size(m->jobs)+1);
-        if (!l)
-                return -ENOMEM;
-
-        HASHMAP_FOREACH(j, m->jobs, i) {
-                l[k] = job_dbus_path(j);
-                if (!l[k])
-                        return -ENOMEM;
-
-                k++;
-        }
-
-        assert(hashmap_size(m->jobs) == k);
-
-        *nodes = TAKE_PTR(l);
-
-        return k;
-}
-
 static int bus_unit_enumerate(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
         _cleanup_strv_free_ char **l = NULL;
         Manager *m = userdata;
@@ -522,8 +477,147 @@ static int bus_unit_enumerate(sd_bus *bus, const char *path, void *userdata, cha
         return k;
 }
 
+static const BusObjectImplementation unit_object = {
+        "/org/freedesktop/systemd1/unit",
+        "org.freedesktop.systemd1.Unit",
+        .fallback_vtables = BUS_FALLBACK_VTABLES(
+                { bus_unit_vtable,        bus_unit_find }),
+        .node_enumerator = bus_unit_enumerate,
+};
+
+static const BusObjectImplementation bus_automount_object = {
+        "/org/freedesktop/systemd1/unit",
+        "org.freedesktop.systemd1.Automount",
+        .fallback_vtables = BUS_FALLBACK_VTABLES(
+                { bus_automount_vtable,   bus_unit_interface_find }),
+};
+
+static const BusObjectImplementation bus_device_object = {
+        "/org/freedesktop/systemd1/unit",
+        "org.freedesktop.systemd1.Device",
+        .fallback_vtables = BUS_FALLBACK_VTABLES(
+                { bus_device_vtable,      bus_unit_interface_find }),
+};
+
+static const BusObjectImplementation bus_mount_object = {
+        "/org/freedesktop/systemd1/unit",
+        "org.freedesktop.systemd1.Mount",
+        .fallback_vtables = BUS_FALLBACK_VTABLES(
+                { bus_mount_vtable,       bus_unit_interface_find },
+                { bus_unit_cgroup_vtable, bus_unit_cgroup_find },
+                { bus_cgroup_vtable,      bus_cgroup_context_find },
+                { bus_exec_vtable,        bus_exec_context_find },
+                { bus_kill_vtable,        bus_kill_context_find }),
+};
+
+static const BusObjectImplementation bus_path_object = {
+        "/org/freedesktop/systemd1/unit",
+        "org.freedesktop.systemd1.Path",
+        .fallback_vtables = BUS_FALLBACK_VTABLES(
+                { bus_path_vtable,        bus_unit_interface_find }),
+};
+
+static const BusObjectImplementation bus_scope_object = {
+        "/org/freedesktop/systemd1/unit",
+        "org.freedesktop.systemd1.Scope",
+        .fallback_vtables = BUS_FALLBACK_VTABLES(
+                { bus_scope_vtable,       bus_unit_interface_find },
+                { bus_unit_cgroup_vtable, bus_unit_cgroup_find },
+                { bus_cgroup_vtable,      bus_cgroup_context_find },
+                { bus_kill_vtable,        bus_kill_context_find }),
+};
+
+static const BusObjectImplementation bus_service_object = {
+        "/org/freedesktop/systemd1/unit",
+        "org.freedesktop.systemd1.Service",
+        .fallback_vtables = BUS_FALLBACK_VTABLES(
+                { bus_service_vtable,     bus_unit_interface_find },
+                { bus_unit_cgroup_vtable, bus_unit_cgroup_find },
+                { bus_cgroup_vtable,      bus_cgroup_context_find },
+                { bus_exec_vtable,        bus_exec_context_find },
+                { bus_kill_vtable,        bus_kill_context_find }),
+};
+
+static const BusObjectImplementation bus_slice_object = {
+        "/org/freedesktop/systemd1/unit",
+        "org.freedesktop.systemd1.Slice",
+        .fallback_vtables = BUS_FALLBACK_VTABLES(
+                { bus_slice_vtable,       bus_unit_interface_find },
+                { bus_unit_cgroup_vtable, bus_unit_cgroup_find },
+                { bus_cgroup_vtable,      bus_cgroup_context_find }),
+};
+
+static const BusObjectImplementation bus_socket_object = {
+        "/org/freedesktop/systemd1/unit",
+        "org.freedesktop.systemd1.Socket",
+        .fallback_vtables = BUS_FALLBACK_VTABLES(
+                { bus_socket_vtable,      bus_unit_interface_find },
+                { bus_unit_cgroup_vtable, bus_unit_cgroup_find },
+                { bus_cgroup_vtable,      bus_cgroup_context_find },
+                { bus_exec_vtable,        bus_exec_context_find },
+                { bus_kill_vtable,        bus_kill_context_find }),
+};
+
+static const BusObjectImplementation bus_swap_object = {
+        "/org/freedesktop/systemd1/unit",
+        "org.freedesktop.systemd1.Swap",
+        .fallback_vtables = BUS_FALLBACK_VTABLES(
+                { bus_swap_vtable,        bus_unit_interface_find },
+                { bus_unit_cgroup_vtable, bus_unit_cgroup_find },
+                { bus_cgroup_vtable,      bus_cgroup_context_find },
+                { bus_exec_vtable,        bus_exec_context_find },
+                { bus_kill_vtable,        bus_kill_context_find }),
+};
+
+static const BusObjectImplementation bus_target_object = {
+        "/org/freedesktop/systemd1/unit",
+        "org.freedesktop.systemd1.Target",
+        .fallback_vtables = BUS_FALLBACK_VTABLES(
+                { bus_target_vtable,      bus_unit_interface_find }),
+};
+
+static const BusObjectImplementation bus_timer_object = {
+        "/org/freedesktop/systemd1/unit",
+        "org.freedesktop.systemd1.Timer",
+        .fallback_vtables = BUS_FALLBACK_VTABLES(
+                { bus_timer_vtable,       bus_unit_interface_find }),
+};
+
+static const BusObjectImplementation bus_manager_object = {
+        "/org/freedesktop/systemd1",
+        "org.freedesktop.systemd1.Manager",
+        .vtables = BUS_VTABLES(bus_manager_vtable),
+        .children = BUS_IMPLEMENTATIONS(
+                        &job_object,
+                        &unit_object,
+                        &bus_automount_object,
+                        &bus_device_object,
+                        &bus_mount_object,
+                        &bus_path_object,
+                        &bus_scope_object,
+                        &bus_service_object,
+                        &bus_slice_object,
+                        &bus_socket_object,
+                        &bus_swap_object,
+                        &bus_target_object,
+                        &bus_timer_object),
+};
+
+static const BusObjectImplementation manager_log_control_object = {
+        "/org/freedesktop/LogControl1",
+        "org.freedesktop.LogControl1",
+        .vtables = BUS_VTABLES(bus_manager_log_control_vtable),
+};
+
+int bus_manager_introspect_implementations(FILE *out, const char *pattern) {
+        return bus_introspect_implementations(
+                        out,
+                        pattern,
+                        BUS_IMPLEMENTATIONS(&bus_manager_object,
+                                            &manager_log_control_object));
+}
+
 static int bus_setup_api_vtables(Manager *m, sd_bus *bus) {
-        UnitType t;
         int r;
 
         assert(m);
@@ -535,63 +629,11 @@ static int bus_setup_api_vtables(Manager *m, sd_bus *bus) {
                 return log_error_errno(r, "Failed to add SELinux access filter: %m");
 #endif
 
-        r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", bus_manager_vtable, m);
-        if (r < 0)
-                return log_error_errno(r, "Failed to register Manager vtable: %m");
-
-        r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/LogControl1", "org.freedesktop.LogControl1", bus_manager_log_control_vtable, m);
+        r = bus_add_implementation(bus, &bus_manager_object, m);
         if (r < 0)
-                return log_error_errno(r, "Failed to register service API vtable: %m");
-
-        r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/job", "org.freedesktop.systemd1.Job", bus_job_vtable, bus_job_find, m);
-        if (r < 0)
-                return log_error_errno(r, "Failed to register Job vtable: %m");
-
-        r = sd_bus_add_node_enumerator(bus, NULL, "/org/freedesktop/systemd1/job", bus_job_enumerate, m);
-        if (r < 0)
-                return log_error_errno(r, "Failed to add job enumerator: %m");
-
-        r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", "org.freedesktop.systemd1.Unit", bus_unit_vtable, bus_unit_find, m);
-        if (r < 0)
-                return log_error_errno(r, "Failed to register Unit vtable: %m");
-
-        r = sd_bus_add_node_enumerator(bus, NULL, "/org/freedesktop/systemd1/unit", bus_unit_enumerate, m);
-        if (r < 0)
-                return log_error_errno(r, "Failed to add job enumerator: %m");
-
-        for (t = 0; t < _UNIT_TYPE_MAX; t++) {
-                const char *interface;
-
-                assert_se(interface = unit_dbus_interface_from_type(t));
-
-                r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, unit_vtable[t]->bus_vtable, bus_unit_interface_find, m);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to register type specific vtable for %s: %m", interface);
-
-                if (unit_vtable[t]->cgroup_context_offset > 0) {
-                        r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, bus_unit_cgroup_vtable, bus_unit_cgroup_find, m);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to register control group unit vtable for %s: %m", interface);
-
-                        r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, bus_cgroup_vtable, bus_cgroup_context_find, m);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to register control group vtable for %s: %m", interface);
-                }
-
-                if (unit_vtable[t]->exec_context_offset > 0) {
-                        r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, bus_exec_vtable, bus_exec_context_find, m);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to register execute vtable for %s: %m", interface);
-                }
-
-                if (unit_vtable[t]->kill_context_offset > 0) {
-                        r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, bus_kill_vtable, bus_kill_context_find, m);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to register kill vtable for %s: %m", interface);
-                }
-        }
+                return r;
 
-        return 0;
+        return bus_add_implementation(bus, &manager_log_control_object, m);
 }
 
 static int bus_setup_disconnected_match(Manager *m, sd_bus *bus) {
@@ -960,10 +1002,15 @@ static void destroy_bus(Manager *m, sd_bus **bus) {
                 if (j->bus_track && sd_bus_track_get_bus(j->bus_track) == *bus)
                         j->bus_track = sd_bus_track_unref(j->bus_track);
 
-        HASHMAP_FOREACH(u, m->units, i)
+        HASHMAP_FOREACH(u, m->units, i) {
                 if (u->bus_track && sd_bus_track_get_bus(u->bus_track) == *bus)
                         u->bus_track = sd_bus_track_unref(u->bus_track);
 
+                /* Get rid of pending freezer messages on this bus */
+                if (u->pending_freezer_message && sd_bus_message_get_bus(u->pending_freezer_message) == *bus)
+                        u->pending_freezer_message = sd_bus_message_unref(u->pending_freezer_message);
+        }
+
         /* Get rid of queued message on this bus */
         if (m->pending_reload_message && sd_bus_message_get_bus(m->pending_reload_message) == *bus)
                 m->pending_reload_message = sd_bus_message_unref(m->pending_reload_message);
index d5ba6537eaf5509947f1f4b684e1e08e8ea0a152..812f56ea2a58ccdfb3e12f766a9532071147f9f3 100644 (file)
@@ -33,3 +33,4 @@ int bus_forward_agent_released(Manager *m, const char *path);
 uint64_t manager_bus_n_queued_write(Manager *m);
 
 void dump_bus_properties(FILE *f);
+int bus_manager_introspect_implementations(FILE *out, const char *pattern);
index 8e00fd3df6e546c135a5e6aa045a7384e59eb225..50d55289fa88db5c7c9e1aa102d2a732bb000f9d 100644 (file)
@@ -1063,7 +1063,6 @@ const UnitVTable device_vtable = {
                 "Device\0"
                 "Install\0",
 
-        .refuse_after = true,
         .gc_jobs = true,
 
         .init = device_init,
@@ -1081,8 +1080,6 @@ const UnitVTable device_vtable = {
         .active_state = device_active_state,
         .sub_state_to_string = device_sub_state_to_string,
 
-        .bus_vtable = bus_device_vtable,
-
         .following = device_following,
         .following_set = device_following_set,
 
index b5f77a15e41d412896cea82bbe82950b6acf587e..aa253a5ddff0aaebf059c75bf3b5c13c6c9c954f 100644 (file)
@@ -219,17 +219,10 @@ static bool is_terminal_input(ExecInput i) {
 static bool is_terminal_output(ExecOutput o) {
         return IN_SET(o,
                       EXEC_OUTPUT_TTY,
-                      EXEC_OUTPUT_SYSLOG_AND_CONSOLE,
                       EXEC_OUTPUT_KMSG_AND_CONSOLE,
                       EXEC_OUTPUT_JOURNAL_AND_CONSOLE);
 }
 
-static bool is_syslog_output(ExecOutput o) {
-        return IN_SET(o,
-                      EXEC_OUTPUT_SYSLOG,
-                      EXEC_OUTPUT_SYSLOG_AND_CONSOLE);
-}
-
 static bool is_kmsg_output(ExecOutput o) {
         return IN_SET(o,
                       EXEC_OUTPUT_KMSG,
@@ -361,7 +354,7 @@ static int connect_logger_as(
                 params->flags & EXEC_PASS_LOG_UNIT ? unit->id : "",
                 context->syslog_priority,
                 !!context->syslog_level_prefix,
-                is_syslog_output(output),
+                false,
                 is_kmsg_output(output),
                 is_terminal_output(output)) < 0)
                 return -errno;
@@ -664,8 +657,6 @@ static int setup_output(
                 /* We don't reset the terminal if this is just about output */
                 return open_terminal_as(exec_context_tty_path(context), O_WRONLY, fileno);
 
-        case EXEC_OUTPUT_SYSLOG:
-        case EXEC_OUTPUT_SYSLOG_AND_CONSOLE:
         case EXEC_OUTPUT_KMSG:
         case EXEC_OUTPUT_KMSG_AND_CONSOLE:
         case EXEC_OUTPUT_JOURNAL:
@@ -1647,8 +1638,6 @@ static int apply_lock_personality(const Unit* u, const ExecContext *c) {
 #endif
 
 static int apply_protect_hostname(const Unit *u, const ExecContext *c, int *ret_exit_status) {
-        int r;
-
         assert(u);
         assert(c);
 
@@ -1668,6 +1657,8 @@ static int apply_protect_hostname(const Unit *u, const ExecContext *c, int *ret_
                 log_unit_warning(u, "ProtectHostname=yes is configured, but the kernel does not support UTS namespaces, ignoring namespace setup.");
 
 #if HAVE_SECCOMP
+        int r;
+
         if (skip_seccomp_unavailable(u, "ProtectHostname="))
                 return 0;
 
@@ -4736,17 +4727,13 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
                         prefix, yes_no(c->tty_vt_disallocate));
 
         if (IN_SET(c->std_output,
-                   EXEC_OUTPUT_SYSLOG,
                    EXEC_OUTPUT_KMSG,
                    EXEC_OUTPUT_JOURNAL,
-                   EXEC_OUTPUT_SYSLOG_AND_CONSOLE,
                    EXEC_OUTPUT_KMSG_AND_CONSOLE,
                    EXEC_OUTPUT_JOURNAL_AND_CONSOLE) ||
             IN_SET(c->std_error,
-                   EXEC_OUTPUT_SYSLOG,
                    EXEC_OUTPUT_KMSG,
                    EXEC_OUTPUT_JOURNAL,
-                   EXEC_OUTPUT_SYSLOG_AND_CONSOLE,
                    EXEC_OUTPUT_KMSG_AND_CONSOLE,
                    EXEC_OUTPUT_JOURNAL_AND_CONSOLE)) {
 
@@ -5764,8 +5751,6 @@ static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = {
         [EXEC_OUTPUT_INHERIT] = "inherit",
         [EXEC_OUTPUT_NULL] = "null",
         [EXEC_OUTPUT_TTY] = "tty",
-        [EXEC_OUTPUT_SYSLOG] = "syslog",
-        [EXEC_OUTPUT_SYSLOG_AND_CONSOLE] = "syslog+console",
         [EXEC_OUTPUT_KMSG] = "kmsg",
         [EXEC_OUTPUT_KMSG_AND_CONSOLE] = "kmsg+console",
         [EXEC_OUTPUT_JOURNAL] = "journal",
index f96a2915eb75701f084a78ca40e93ab1870497c2..7e1015631f1ffe35748b82f987fab66edae602b7 100644 (file)
@@ -52,8 +52,6 @@ typedef enum ExecOutput {
         EXEC_OUTPUT_INHERIT,
         EXEC_OUTPUT_NULL,
         EXEC_OUTPUT_TTY,
-        EXEC_OUTPUT_SYSLOG,
-        EXEC_OUTPUT_SYSLOG_AND_CONSOLE,
         EXEC_OUTPUT_KMSG,
         EXEC_OUTPUT_KMSG_AND_CONSOLE,
         EXEC_OUTPUT_JOURNAL,
index 83cce88131eb656396c2ef86216060ce600b68db..6d047db8388c8e94b3947f75e8c1a4fac35e6ba1 100644 (file)
 #include "hostname-util.h"
 #include "log.h"
 #include "macro.h"
+#include "proc-cmdline.h"
 #include "string-util.h"
 #include "util.h"
 
 int hostname_setup(void) {
         _cleanup_free_ char *b = NULL;
+        const char *hn = NULL;
         bool enoent = false;
-        const char *hn;
         int r;
 
-        r = read_etc_hostname(NULL, &b);
-        if (r < 0) {
-                if (r == -ENOENT)
-                        enoent = true;
-                else
-                        log_warning_errno(r, "Failed to read configured hostname: %m");
+        r = proc_cmdline_get_key("systemd.hostname", 0, &b);
+        if (r < 0)
+                log_warning_errno(r, "Failed to retrieve system hostname from kernel command line, ignoring: %m");
+        else if (r > 0) {
+                if (hostname_is_valid(b, true))
+                        hn = b;
+                else  {
+                        log_warning("Hostname specified on kernel command line is invalid, ignoring: %s", b);
+                        b = mfree(b);
+                }
+        }
 
-                hn = NULL;
-        } else
-                hn = b;
+        if (!hn) {
+                r = read_etc_hostname(NULL, &b);
+                if (r < 0) {
+                        if (r == -ENOENT)
+                                enoent = true;
+                        else
+                                log_warning_errno(r, "Failed to read configured hostname: %m");
+                } else
+                        hn = b;
+        }
 
         if (isempty(hn)) {
-                /* Don't override the hostname if it is already set
-                 * and not explicitly configured */
+                /* Don't override the hostname if it is already set and not explicitly configured */
                 if (hostname_is_set())
                         return 0;
 
index 165b9ca9c12c260b67ae98c9d7a2c1ce93f16513..5fd58b379baa5152eede3f2d4267a8549009da1b 100644 (file)
@@ -429,6 +429,7 @@ Mount.DirectoryMode,             config_parse_mode,                  0,
 Mount.SloppyOptions,             config_parse_bool,                  0,                             offsetof(Mount, sloppy_options)
 Mount.LazyUnmount,               config_parse_bool,                  0,                             offsetof(Mount, lazy_unmount)
 Mount.ForceUnmount,              config_parse_bool,                  0,                             offsetof(Mount, force_unmount)
+Mount.ReadWriteOnly,             config_parse_bool,                  0,                             offsetof(Mount, read_write_only)
 EXEC_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
 CGROUP_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
 KILL_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
index b16c62a5c7c62d2adb10623c0759cc6ef6159893..e420239e157eb4af9d5feba7aba56d56f3e74716 100644 (file)
@@ -1099,6 +1099,7 @@ int config_parse_exec_output(
         const char *n;
         ExecContext *c = data;
         const Unit *u = userdata;
+        bool obsolete = false;
         ExecOutput eo;
         int r;
 
@@ -1123,6 +1124,14 @@ int config_parse_exec_output(
 
                 eo = EXEC_OUTPUT_NAMED_FD;
 
+        } else if (streq(rvalue, "syslog")) {
+                eo = EXEC_OUTPUT_JOURNAL;
+                obsolete = true;
+
+        } else if (streq(rvalue, "syslog+console")) {
+                eo = EXEC_OUTPUT_JOURNAL_AND_CONSOLE;
+                obsolete = true;
+
         } else if ((n = startswith(rvalue, "file:"))) {
 
                 r = unit_full_printf(u, n, &resolved);
@@ -1154,6 +1163,11 @@ int config_parse_exec_output(
                 }
         }
 
+        if (obsolete)
+                log_syntax(unit, LOG_NOTICE, filename, line, 0,
+                           "Standard output type %s is obsolete, automatically updating to %s. Please update your unit file, and consider removing the setting altogether.",
+                           rvalue, exec_output_to_string(eo));
+
         if (streq(lvalue, "StandardOutput")) {
                 if (eo == EXEC_OUTPUT_NAMED_FD)
                         free_and_replace(c->stdio_fdname[STDOUT_FILENO], resolved);
@@ -2889,7 +2903,7 @@ int config_parse_syscall_filter(
                 void *userdata) {
 
         ExecContext *c = data;
-        const Unit *u = userdata;
+        _unused_ const Unit *u = userdata;
         bool invert = false;
         const char *p;
         int r;
@@ -5051,23 +5065,37 @@ int config_parse_output_restricted(
                 void *userdata) {
 
         ExecOutput t, *eo = data;
+        bool obsolete = false;
 
         assert(filename);
         assert(lvalue);
         assert(rvalue);
         assert(data);
 
-        t = exec_output_from_string(rvalue);
-        if (t < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse output type, ignoring: %s", rvalue);
-                return 0;
-        }
+        if (streq(rvalue, "syslog")) {
+                t = EXEC_OUTPUT_JOURNAL;
+                obsolete = true;
+        } else if (streq(rvalue, "syslog+console")) {
+                t = EXEC_OUTPUT_JOURNAL_AND_CONSOLE;
+                obsolete = true;
+        } else {
+                t = exec_output_from_string(rvalue);
+                if (t < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse output type, ignoring: %s", rvalue);
+                        return 0;
+                }
 
-        if (IN_SET(t, EXEC_OUTPUT_SOCKET, EXEC_OUTPUT_NAMED_FD, EXEC_OUTPUT_FILE, EXEC_OUTPUT_FILE_APPEND)) {
-                log_syntax(unit, LOG_ERR, filename, line, 0, "Standard output types socket, fd:, file:, append: are not supported as defaults, ignoring: %s", rvalue);
-                return 0;
+                if (IN_SET(t, EXEC_OUTPUT_SOCKET, EXEC_OUTPUT_NAMED_FD, EXEC_OUTPUT_FILE, EXEC_OUTPUT_FILE_APPEND)) {
+                        log_syntax(unit, LOG_ERR, filename, line, 0, "Standard output types socket, fd:, file:, append: are not supported as defaults, ignoring: %s", rvalue);
+                        return 0;
+                }
         }
 
+        if (obsolete)
+                log_syntax(unit, LOG_NOTICE, filename, line, 0,
+                           "Standard output type %s is obsolete, automatically updating to %s. Please update your configuration.",
+                           rvalue, exec_output_to_string(t));
+
         *eo = t;
         return 0;
 }
@@ -5129,7 +5157,7 @@ int config_parse_swap_priority(
 
         r = safe_atoi(rvalue, &priority);
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r, "Invalid swap pririty '%s', ignoring.", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, r, "Invalid swap priority '%s', ignoring.", rvalue);
                 return 0;
         }
 
index ae78ba549d724baa2a4d845bd19dc72f6503b1f6..30e1b3d19d5586e4beb1ba3cbd75351ae992ada9 100644 (file)
@@ -93,8 +93,11 @@ static enum {
         ACTION_TEST,
         ACTION_DUMP_CONFIGURATION_ITEMS,
         ACTION_DUMP_BUS_PROPERTIES,
+        ACTION_BUS_INTROSPECT,
 } arg_action = ACTION_RUN;
 
+static const char *arg_bus_introspect = NULL;
+
 /* Those variables are initialized to 0 automatically, so we avoid uninitialized memory access.
  * Real defaults are assigned in reset_arguments() below. */
 static char *arg_default_unit;
@@ -143,6 +146,7 @@ static EmergencyAction arg_cad_burst_action;
 static OOMPolicy arg_default_oom_policy;
 static CPUSet arg_cpu_affinity;
 static NUMAPolicy arg_numa_policy;
+static usec_t arg_clock_usec;
 
 /* A copy of the original environment block */
 static char **saved_env = NULL;
@@ -488,6 +492,15 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
 
                 (void) parse_path_argument_and_warn(value, false, &arg_watchdog_device);
 
+        } else if (proc_cmdline_key_streq(key, "systemd.clock_usec")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
+
+                r = safe_atou64(value, &arg_clock_usec);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to parse systemd.clock_usec= argument, ignoring: %s", value);
+
         } else if (streq(key, "quiet") && !value) {
 
                 if (arg_show_status == _SHOW_STATUS_INVALID)
@@ -700,16 +713,18 @@ static void set_manager_settings(Manager *m) {
 
         assert(m);
 
-        /* Propagates the various manager settings into the manager object, i.e. properties that effect the manager
-         * itself (as opposed to just being inherited into newly allocated units, see set_manager_defaults() above). */
+        /* Propagates the various manager settings into the manager object, i.e. properties that
+         * effect the manager itself (as opposed to just being inherited into newly allocated
+         * units, see set_manager_defaults() above). */
 
         m->confirm_spawn = arg_confirm_spawn;
         m->service_watchdogs = arg_service_watchdogs;
-        m->runtime_watchdog = arg_runtime_watchdog;
-        m->reboot_watchdog = arg_reboot_watchdog;
-        m->kexec_watchdog = arg_kexec_watchdog;
         m->cad_burst_action = arg_cad_burst_action;
 
+        manager_set_watchdog(m, WATCHDOG_RUNTIME, arg_runtime_watchdog);
+        manager_set_watchdog(m, WATCHDOG_REBOOT, arg_reboot_watchdog);
+        manager_set_watchdog(m, WATCHDOG_KEXEC, arg_kexec_watchdog);
+
         manager_set_show_status(m, arg_show_status, "commandline");
         m->status_unit_format = arg_status_unit_format;
 }
@@ -729,6 +744,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_VERSION,
                 ARG_DUMP_CONFIGURATION_ITEMS,
                 ARG_DUMP_BUS_PROPERTIES,
+                ARG_BUS_INTROSPECT,
                 ARG_DUMP_CORE,
                 ARG_CRASH_CHVT,
                 ARG_CRASH_SHELL,
@@ -758,6 +774,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "version",                  no_argument,       NULL, ARG_VERSION                  },
                 { "dump-configuration-items", no_argument,       NULL, ARG_DUMP_CONFIGURATION_ITEMS },
                 { "dump-bus-properties",      no_argument,       NULL, ARG_DUMP_BUS_PROPERTIES      },
+                { "bus-introspect",           required_argument, NULL, ARG_BUS_INTROSPECT           },
                 { "dump-core",                optional_argument, NULL, ARG_DUMP_CORE                },
                 { "crash-chvt",               required_argument, NULL, ARG_CRASH_CHVT               },
                 { "crash-shell",              optional_argument, NULL, ARG_CRASH_SHELL              },
@@ -885,6 +902,11 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_action = ACTION_DUMP_BUS_PROPERTIES;
                         break;
 
+                case ARG_BUS_INTROSPECT:
+                        arg_bus_introspect = optarg;
+                        arg_action = ACTION_BUS_INTROSPECT;
+                        break;
+
                 case ARG_DUMP_CORE:
                         if (!optarg)
                                 arg_dump_core = true;
@@ -1033,7 +1055,9 @@ static int help(void) {
                 return log_oom();
 
         printf("%s [OPTIONS...]\n\n"
-               "Starts up and maintains the system or user services.\n\n"
+               "%sStarts and monitors system and user services.%s\n\n"
+               "This program takes no positional arguments.\n\n"
+               "%sOptions%s:\n"
                "  -h --help                      Show this help\n"
                "     --version                   Show version\n"
                "     --test                      Determine initial transaction, dump it and exit\n"
@@ -1042,6 +1066,7 @@ static int help(void) {
                "     --no-pager                  Do not pipe output into a pager\n"
                "     --dump-configuration-items  Dump understood unit configuration items\n"
                "     --dump-bus-properties       Dump exposed bus properties\n"
+               "     --bus-introspect=PATH       Write XML introspection data\n"
                "     --unit=UNIT                 Set default unit\n"
                "     --dump-core[=BOOL]          Dump core on crash\n"
                "     --crash-vt=NR               Change to specified VT on crash\n"
@@ -1058,6 +1083,8 @@ static int help(void) {
                "     --default-standard-error=   Set default standard error output for services\n"
                "\nSee the %s for details.\n"
                , program_invocation_short_name
+               , ansi_highlight(), ansi_normal()
+               , ansi_underline(), ansi_normal()
                , link
         );
 
@@ -1208,6 +1235,7 @@ static int bump_rlimit_nofile(struct rlimit *saved_rlimit) {
 
 static int bump_rlimit_memlock(struct rlimit *saved_rlimit) {
         struct rlimit new_rlimit;
+        uint64_t mm;
         int r;
 
         /* BPF_MAP_TYPE_LPM_TRIE bpf maps are charged against RLIMIT_MEMLOCK, even if we have CAP_IPC_LOCK which should
@@ -1218,9 +1246,12 @@ static int bump_rlimit_memlock(struct rlimit *saved_rlimit) {
          * must be unsigned, hence this is a given, but let's make this clear here. */
         assert_cc(RLIM_INFINITY > 0);
 
+        mm = physical_memory() / 8; /* Let's scale how much we allow to be locked by the amount of physical
+                                     * RAM. We allow an eighth to be locked by us, just to pick a value. */
+
         new_rlimit = (struct rlimit) {
-                .rlim_cur = MAX(HIGH_RLIMIT_MEMLOCK, saved_rlimit->rlim_cur),
-                .rlim_max = MAX(HIGH_RLIMIT_MEMLOCK, saved_rlimit->rlim_max),
+                .rlim_cur = MAX3(HIGH_RLIMIT_MEMLOCK, saved_rlimit->rlim_cur, mm),
+                .rlim_max = MAX3(HIGH_RLIMIT_MEMLOCK, saved_rlimit->rlim_max, mm),
         };
 
         if (saved_rlimit->rlim_max >= new_rlimit.rlim_cur &&
@@ -1485,6 +1516,9 @@ static int become_shutdown(
 static void initialize_clock(void) {
         int r;
 
+        /* This is called very early on, before we parse the kernel command line or otherwise figure out why
+         * we are running, but only once. */
+
         if (clock_is_localtime(NULL) > 0) {
                 int min;
 
@@ -1523,6 +1557,25 @@ static void initialize_clock(void) {
                 log_info("System time before build time, advancing clock.");
 }
 
+static void apply_clock_update(void) {
+        struct timespec ts;
+
+        /* This is called later than initialize_clock(), i.e. after we parsed configuration files/kernel
+         * command line and such. */
+
+        if (arg_clock_usec == 0)
+                return;
+
+        if (clock_settime(CLOCK_REALTIME, timespec_store(&ts, arg_clock_usec)) < 0)
+                log_error_errno(errno, "Failed to set system clock to time specified on kernel command line: %m");
+        else {
+                char buf[FORMAT_TIMESTAMP_MAX];
+
+                log_info("Set system clock to %s, as specified on the kernel command line.",
+                         format_timestamp(buf, sizeof(buf), arg_clock_usec));
+        }
+}
+
 static void initialize_coredump(bool skip_setup) {
 #if ENABLE_COREDUMP
         if (getpid_cached() != 1)
@@ -1765,6 +1818,7 @@ static int invoke_main_loop(
                         (void) parse_configuration(saved_rlimit_nofile, saved_rlimit_memlock);
 
                         set_manager_defaults(m);
+                        set_manager_settings(m);
 
                         update_cpu_affinity(false);
                         update_numa_policy(false);
@@ -1955,9 +2009,6 @@ static int initialize_runtime(
                         if (r < 0)
                                 log_warning_errno(r, "Failed to set watchdog device to %s, ignoring: %m", arg_watchdog_device);
                 }
-
-                if (timestamp_is_set(arg_runtime_watchdog))
-                        watchdog_set_timeout(&arg_runtime_watchdog);
         }
 
         if (arg_timer_slack_nsec != NSEC_INFINITY)
@@ -2231,29 +2282,6 @@ static int parse_configuration(const struct rlimit *saved_rlimit_nofile,
         /* Note that this also parses bits from the kernel command line, including "debug". */
         log_parse_environment();
 
-        return 0;
-}
-
-static int load_configuration(
-                int argc,
-                char **argv,
-                const struct rlimit *saved_rlimit_nofile,
-                const struct rlimit *saved_rlimit_memlock,
-                const char **ret_error_message) {
-        int r;
-
-        assert(saved_rlimit_nofile);
-        assert(saved_rlimit_memlock);
-        assert(ret_error_message);
-
-        (void) parse_configuration(saved_rlimit_nofile, saved_rlimit_memlock);
-
-        r = parse_argv(argc, argv);
-        if (r < 0) {
-                *ret_error_message = "Failed to parse commandline arguments";
-                return r;
-        }
-
         /* Initialize the show status setting if it hasn't been set explicitly yet */
         if (arg_show_status == _SHOW_STATUS_INVALID)
                 arg_show_status = SHOW_STATUS_YES;
@@ -2599,15 +2627,19 @@ int main(int argc, char *argv[]) {
         (void) reset_all_signal_handlers();
         (void) ignore_signals(SIGNALS_IGNORE, -1);
 
-        r = load_configuration(argc, argv, &saved_rlimit_nofile, &saved_rlimit_memlock, &error_message);
-        if (r < 0)
+        (void) parse_configuration(&saved_rlimit_nofile, &saved_rlimit_memlock);
+
+        r = parse_argv(argc, argv);
+        if (r < 0) {
+                error_message = "Failed to parse commandline arguments";
                 goto finish;
+        }
 
         r = safety_checks();
         if (r < 0)
                 goto finish;
 
-        if (IN_SET(arg_action, ACTION_TEST, ACTION_HELP, ACTION_DUMP_CONFIGURATION_ITEMS, ACTION_DUMP_BUS_PROPERTIES))
+        if (IN_SET(arg_action, ACTION_TEST, ACTION_HELP, ACTION_DUMP_CONFIGURATION_ITEMS, ACTION_DUMP_BUS_PROPERTIES, ACTION_BUS_INTROSPECT))
                 (void) pager_open(arg_pager_flags);
 
         if (arg_action != ACTION_RUN)
@@ -2627,6 +2659,10 @@ int main(int argc, char *argv[]) {
                 dump_bus_properties(stdout);
                 retval = EXIT_SUCCESS;
                 goto finish;
+        } else if (arg_action == ACTION_BUS_INTROSPECT) {
+                r = bus_manager_introspect_implementations(stdout, arg_bus_introspect);
+                retval = r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+                goto finish;
         }
 
         assert_se(IN_SET(arg_action, ACTION_RUN, ACTION_TEST));
@@ -2635,6 +2671,8 @@ int main(int argc, char *argv[]) {
         assert_se(chdir("/") == 0);
 
         if (arg_action == ACTION_RUN) {
+                /* Apply the systemd.clock_usec= kernel command line switch */
+                apply_clock_update();
 
                 /* A core pattern might have been specified via the cmdline.  */
                 initialize_core_pattern(skip_setup);
@@ -2730,8 +2768,8 @@ finish:
         pager_close();
 
         if (m) {
-                arg_reboot_watchdog = m->reboot_watchdog;
-                arg_kexec_watchdog = m->kexec_watchdog;
+                arg_reboot_watchdog = manager_get_watchdog(m, WATCHDOG_REBOOT);
+                arg_kexec_watchdog = manager_get_watchdog(m, WATCHDOG_KEXEC);
                 m = manager_free(m);
         }
 
index 7536a9ca84de5f186bd18195aa1ce720bf6c2983..ac5a3b68051612ab8fcb8781be1b4e945a2c19e2 100644 (file)
@@ -110,6 +110,7 @@ static int manager_dispatch_sigchld(sd_event_source *source, void *userdata);
 static int manager_dispatch_timezone_change(sd_event_source *source, const struct inotify_event *event, void *userdata);
 static int manager_run_environment_generators(Manager *m);
 static int manager_run_generators(Manager *m);
+static void manager_vacuum(Manager *m);
 
 static usec_t manager_watch_jobs_next_time(Manager *m) {
         return usec_add(now(CLOCK_MONOTONIC),
@@ -181,7 +182,7 @@ static void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned po
         }
 }
 
-void manager_flip_auto_status(Manager *m, bool enable, const char *reason) {
+static void manager_flip_auto_status(Manager *m, bool enable, const char *reason) {
         assert(m);
 
         if (enable) {
@@ -779,6 +780,10 @@ int manager_new(UnitFileScope scope, ManagerTestRunFlags test_run_flags, Manager
                 .original_log_level = -1,
                 .original_log_target = _LOG_TARGET_INVALID,
 
+                .watchdog_overridden[WATCHDOG_RUNTIME] = USEC_INFINITY,
+                .watchdog_overridden[WATCHDOG_REBOOT] = USEC_INFINITY,
+                .watchdog_overridden[WATCHDOG_KEXEC] = USEC_INFINITY,
+
                 .notify_fd = -1,
                 .cgroups_agent_fd = -1,
                 .signal_fd = -1,
@@ -1596,20 +1601,6 @@ static void manager_preset_all(Manager *m) {
                 log_info("Populated /etc with preset unit settings.");
 }
 
-static void manager_vacuum(Manager *m) {
-        assert(m);
-
-        /* Release any dynamic users no longer referenced */
-        dynamic_user_vacuum(m, true);
-
-        /* Release any references to UIDs/GIDs no longer referenced, and destroy any IPC owned by them */
-        manager_vacuum_uid_refs(m);
-        manager_vacuum_gid_refs(m);
-
-        /* Release any runtimes no longer referenced */
-        exec_runtime_vacuum(m);
-}
-
 static void manager_ready(Manager *m) {
         assert(m);
 
@@ -1968,7 +1959,6 @@ int manager_load_unit_prepare(
         int r;
 
         assert(m);
-        assert(name || path);
         assert(_ret);
 
         /* This will prepare the unit for loading, but not actually
@@ -1977,8 +1967,13 @@ int manager_load_unit_prepare(
         if (path && !is_path(path))
                 return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not absolute.", path);
 
-        if (!name)
+        if (!name) {
+                /* 'name' and 'path' must not both be null. Check here 'path' using assert_se() to
+                 * workaround a bug in gcc that generates a -Wnonnull warning when calling basename(),
+                 * but this cannot be possible in any code path (See #6119). */
+                assert_se(path);
                 name = basename(path);
+        }
 
         t = unit_name_to_type(name);
 
@@ -2284,37 +2279,48 @@ static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, ui
         return 0;
 }
 
+static bool manager_process_barrier_fd(char * const *tags, FDSet *fds) {
+
+        /* nothing else must be sent when using BARRIER=1 */
+        if (strv_contains(tags, "BARRIER=1")) {
+                if (strv_length(tags) == 1) {
+                        if (fdset_size(fds) != 1)
+                                log_warning("Got incorrect number of fds with BARRIER=1, closing them.");
+                } else
+                        log_warning("Extra notification messages sent with BARRIER=1, ignoring everything.");
+
+                /* Drop the message if BARRIER=1 was found */
+                return true;
+        }
+
+        return false;
+}
+
 static void manager_invoke_notify_message(
                 Manager *m,
                 Unit *u,
                 const struct ucred *ucred,
-                const char *buf,
+                char * const *tags,
                 FDSet *fds) {
 
         assert(m);
         assert(u);
         assert(ucred);
-        assert(buf);
+        assert(tags);
 
         if (u->notifygen == m->notifygen) /* Already invoked on this same unit in this same iteration? */
                 return;
         u->notifygen = m->notifygen;
 
-        if (UNIT_VTABLE(u)->notify_message) {
-                _cleanup_strv_free_ char **tags = NULL;
-
-                tags = strv_split(buf, NEWLINE);
-                if (!tags) {
-                        log_oom();
-                        return;
-                }
-
+        if (UNIT_VTABLE(u)->notify_message)
                 UNIT_VTABLE(u)->notify_message(u, ucred, tags, fds);
 
-        else if (DEBUG_LOGGING) {
-                _cleanup_free_ char *x = NULL, *y = NULL;
+        else if (DEBUG_LOGGING) {
+                _cleanup_free_ char *buf = NULL, *x = NULL, *y = NULL;
 
-                x = ellipsize(buf, 20, 90);
+                buf = strv_join(tags, ", ");
+                if (buf)
+                        x = ellipsize(buf, 20, 90);
                 if (x)
                         y = cescape(x);
 
@@ -2331,11 +2337,8 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t
                 .iov_base = buf,
                 .iov_len = sizeof(buf)-1,
         };
-        union {
-                struct cmsghdr cmsghdr;
-                uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
-                            CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)];
-        } control = {};
+        CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred)) +
+                         CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)) control;
         struct msghdr msghdr = {
                 .msg_iov = &iovec,
                 .msg_iovlen = 1,
@@ -2346,6 +2349,7 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t
         struct cmsghdr *cmsg;
         struct ucred *ucred = NULL;
         _cleanup_free_ Unit **array_copy = NULL;
+        _cleanup_strv_free_ char **tags = NULL;
         Unit *u1, *u2, **array;
         int r, *fd_array = NULL;
         size_t n_fds = 0;
@@ -2360,20 +2364,20 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t
                 return 0;
         }
 
-        n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC|MSG_TRUNC);
-        if (n < 0) {
-                if (IN_SET(errno, EAGAIN, EINTR))
-                        return 0; /* Spurious wakeup, try again */
-
-                /* If this is any other, real error, then let's stop processing this socket. This of course means we
-                 * won't take notification messages anymore, but that's still better than busy looping around this:
-                 * being woken up over and over again but being unable to actually read the message off the socket. */
-                return log_error_errno(errno, "Failed to receive notification message: %m");
-        }
+        n = recvmsg_safe(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC|MSG_TRUNC);
+        if (IN_SET(n, -EAGAIN, -EINTR))
+                return 0; /* Spurious wakeup, try again */
+        if (n < 0)
+                /* If this is any other, real error, then let's stop processing this socket. This of course
+                 * means we won't take notification messages anymore, but that's still better than busy
+                 * looping around this: being woken up over and over again but being unable to actually read
+                 * the message off the socket. */
+                return log_error_errno(n, "Failed to receive notification message: %m");
 
         CMSG_FOREACH(cmsg, &msghdr) {
                 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
 
+                        assert(!fd_array);
                         fd_array = (int*) CMSG_DATA(cmsg);
                         n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
 
@@ -2381,6 +2385,7 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t
                            cmsg->cmsg_type == SCM_CREDENTIALS &&
                            cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
 
+                        assert(!ucred);
                         ucred = (struct ucred*) CMSG_DATA(cmsg);
                 }
         }
@@ -2413,8 +2418,17 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t
                 return 0;
         }
 
-        /* Make sure it's NUL-terminated. */
+        /* Make sure it's NUL-terminated, then parse it to obtain the tags list */
         buf[n] = 0;
+        tags = strv_split_newlines(buf);
+        if (!tags) {
+                log_oom();
+                return 0;
+        }
+
+        /* possibly a barrier fd, let's see */
+        if (manager_process_barrier_fd(tags, fds))
+                return 0;
 
         /* Increase the generation counter used for filtering out duplicate unit invocations. */
         m->notifygen++;
@@ -2436,16 +2450,16 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t
         /* And now invoke the per-unit callbacks. Note that manager_invoke_notify_message() will handle duplicate units
          * make sure we only invoke each unit's handler once. */
         if (u1) {
-                manager_invoke_notify_message(m, u1, ucred, buf, fds);
+                manager_invoke_notify_message(m, u1, ucred, tags, fds);
                 found = true;
         }
         if (u2) {
-                manager_invoke_notify_message(m, u2, ucred, buf, fds);
+                manager_invoke_notify_message(m, u2, ucred, tags, fds);
                 found = true;
         }
         if (array_copy)
                 for (size_t i = 0; array_copy[i]; i++) {
-                        manager_invoke_notify_message(m, array_copy[i], ucred, buf, fds);
+                        manager_invoke_notify_message(m, array_copy[i], ucred, tags, fds);
                         found = true;
                 }
 
@@ -2899,9 +2913,10 @@ int manager_loop(Manager *m) {
                 return log_error_errno(r, "Failed to enable SIGCHLD event source: %m");
 
         while (m->objective == MANAGER_OK) {
-                usec_t wait_usec;
+                usec_t wait_usec, watchdog_usec;
 
-                if (timestamp_is_set(m->runtime_watchdog) && MANAGER_IS_SYSTEM(m))
+                watchdog_usec = manager_get_watchdog(m, WATCHDOG_RUNTIME);
+                if (timestamp_is_set(watchdog_usec))
                         watchdog_ping();
 
                 if (!ratelimit_below(&rl)) {
@@ -2932,7 +2947,7 @@ int manager_loop(Manager *m) {
                         continue;
 
                 /* Sleep for watchdog runtime wait time */
-                if (MANAGER_IS_SYSTEM(m))
+                if (timestamp_is_set(watchdog_usec))
                         wait_usec = watchdog_runtime_wait();
                 else
                         wait_usec = USEC_INFINITY;
@@ -3135,6 +3150,47 @@ static bool manager_timestamp_shall_serialize(ManagerTimestamp t) {
                        MANAGER_TIMESTAMP_UNITS_LOAD_START, MANAGER_TIMESTAMP_UNITS_LOAD_FINISH);
 }
 
+#define DESTROY_IPC_FLAG (UINT32_C(1) << 31)
+
+static void manager_serialize_uid_refs_internal(
+                Manager *m,
+                FILE *f,
+                Hashmap **uid_refs,
+                const char *field_name) {
+
+        Iterator i;
+        void *p, *k;
+
+        assert(m);
+        assert(f);
+        assert(uid_refs);
+        assert(field_name);
+
+        /* Serialize the UID reference table. Or actually, just the IPC destruction flag of it, as
+         * the actual counter of it is better rebuild after a reload/reexec. */
+
+        HASHMAP_FOREACH_KEY(p, k, *uid_refs, i) {
+                uint32_t c;
+                uid_t uid;
+
+                uid = PTR_TO_UID(k);
+                c = PTR_TO_UINT32(p);
+
+                if (!(c & DESTROY_IPC_FLAG))
+                        continue;
+
+                (void) serialize_item_format(f, field_name, UID_FMT, uid);
+        }
+}
+
+static void manager_serialize_uid_refs(Manager *m, FILE *f) {
+        manager_serialize_uid_refs_internal(m, f, &m->uid_refs, "destroy-ipc-uid");
+}
+
+static void manager_serialize_gid_refs(Manager *m, FILE *f) {
+        manager_serialize_uid_refs_internal(m, f, &m->gid_refs, "destroy-ipc-gid");
+}
+
 int manager_serialize(
                 Manager *m,
                 FILE *f,
@@ -3173,6 +3229,10 @@ int manager_serialize(
         if (m->log_target_overridden)
                 (void) serialize_item(f, "log-target-override", log_target_to_string(log_get_target()));
 
+        (void) serialize_usec(f, "runtime-watchdog-overridden", m->watchdog_overridden[WATCHDOG_RUNTIME]);
+        (void) serialize_usec(f, "reboot-watchdog-overridden", m->watchdog_overridden[WATCHDOG_REBOOT]);
+        (void) serialize_usec(f, "kexec-watchdog-overridden", m->watchdog_overridden[WATCHDOG_KEXEC]);
+
         for (q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) {
                 _cleanup_free_ char *joined = NULL;
 
@@ -3305,6 +3365,114 @@ static int manager_deserialize_units(Manager *m, FILE *f, FDSet *fds) {
         return 0;
 }
 
+usec_t manager_get_watchdog(Manager *m, WatchdogType t) {
+        assert(m);
+
+        if (MANAGER_IS_USER(m))
+                return USEC_INFINITY;
+
+        if (timestamp_is_set(m->watchdog_overridden[t]))
+                return m->watchdog_overridden[t];
+
+        return m->watchdog[t];
+}
+
+void manager_set_watchdog(Manager *m, WatchdogType t, usec_t timeout) {
+        int r = 0;
+
+        assert(m);
+
+        if (MANAGER_IS_USER(m))
+                return;
+
+        if (m->watchdog[t] == timeout)
+                return;
+
+        if (t == WATCHDOG_RUNTIME)
+                if (!timestamp_is_set(m->watchdog_overridden[WATCHDOG_RUNTIME])) {
+                        if (timestamp_is_set(timeout))
+                                r = watchdog_set_timeout(&timeout);
+                        else
+                                watchdog_close(true);
+                }
+
+        if (r >= 0)
+                m->watchdog[t] = timeout;
+}
+
+int manager_set_watchdog_overridden(Manager *m, WatchdogType t, usec_t timeout) {
+        int r = 0;
+
+        assert(m);
+
+        if (MANAGER_IS_USER(m))
+                return 0;
+
+        if (m->watchdog_overridden[t] == timeout)
+                return 0;
+
+        if (t == WATCHDOG_RUNTIME) {
+                usec_t *p;
+
+                p = timestamp_is_set(timeout) ? &timeout : &m->watchdog[t];
+                if (timestamp_is_set(*p))
+                        r = watchdog_set_timeout(p);
+                else
+                        watchdog_close(true);
+        }
+
+        if (r >= 0)
+                m->watchdog_overridden[t] = timeout;
+
+        return 0;
+}
+
+static void manager_deserialize_uid_refs_one_internal(
+                Manager *m,
+                Hashmap** uid_refs,
+                const char *value) {
+
+        uid_t uid;
+        uint32_t c;
+        int r;
+
+        assert(m);
+        assert(uid_refs);
+        assert(value);
+
+        r = parse_uid(value, &uid);
+        if (r < 0 || uid == 0) {
+                log_debug("Unable to parse UID reference serialization: " UID_FMT, uid);
+                return;
+        }
+
+        r = hashmap_ensure_allocated(uid_refs, &trivial_hash_ops);
+        if (r < 0) {
+                log_oom();
+                return;
+        }
+
+        c = PTR_TO_UINT32(hashmap_get(*uid_refs, UID_TO_PTR(uid)));
+        if (c & DESTROY_IPC_FLAG)
+                return;
+
+        c |= DESTROY_IPC_FLAG;
+
+        r = hashmap_replace(*uid_refs, UID_TO_PTR(uid), UINT32_TO_PTR(c));
+        if (r < 0) {
+                log_debug_errno(r, "Failed to add UID reference entry: %m");
+                return;
+        }
+}
+
+static void manager_deserialize_uid_refs_one(Manager *m, const char *value) {
+        manager_deserialize_uid_refs_one_internal(m, &m->uid_refs, value);
+}
+
+static void manager_deserialize_gid_refs_one(Manager *m, const char *value) {
+        manager_deserialize_uid_refs_one_internal(m, &m->gid_refs, value);
+}
+
 int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
         int r = 0;
 
@@ -3428,6 +3596,30 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
                         else
                                 manager_override_log_target(m, target);
 
+                } else if ((val = startswith(l, "runtime-watchdog-overridden="))) {
+                        usec_t t;
+
+                        if (deserialize_usec(val, &t) < 0)
+                                log_notice("Failed to parse runtime-watchdog-overridden value '%s', ignoring.", val);
+                        else
+                                manager_set_watchdog_overridden(m, WATCHDOG_RUNTIME, t);
+
+                } else if ((val = startswith(l, "reboot-watchdog-overridden="))) {
+                        usec_t t;
+
+                        if (deserialize_usec(val, &t) < 0)
+                                log_notice("Failed to parse reboot-watchdog-overridden value '%s', ignoring.", val);
+                        else
+                                manager_set_watchdog_overridden(m, WATCHDOG_REBOOT, t);
+
+                } else if ((val = startswith(l, "kexec-watchdog-overridden="))) {
+                        usec_t t;
+
+                        if (deserialize_usec(val, &t) < 0)
+                                log_notice("Failed to parse kexec-watchdog-overridden value '%s', ignoring.", val);
+                        else
+                                manager_set_watchdog_overridden(m, WATCHDOG_KEXEC, t);
+
                 } else if (startswith(l, "env=")) {
                         r = deserialize_environment(l + 4, &m->client_environment);
                         if (r < 0)
@@ -4278,8 +4470,6 @@ ManagerState manager_state(Manager *m) {
         return MANAGER_RUNNING;
 }
 
-#define DESTROY_IPC_FLAG (UINT32_C(1) << 31)
-
 static void manager_unref_uid_internal(
                 Manager *m,
                 Hashmap **uid_refs,
@@ -4418,97 +4608,26 @@ static void manager_vacuum_uid_refs_internal(
         }
 }
 
-void manager_vacuum_uid_refs(Manager *m) {
+static void manager_vacuum_uid_refs(Manager *m) {
         manager_vacuum_uid_refs_internal(m, &m->uid_refs, clean_ipc_by_uid);
 }
 
-void manager_vacuum_gid_refs(Manager *m) {
+static void manager_vacuum_gid_refs(Manager *m) {
         manager_vacuum_uid_refs_internal(m, &m->gid_refs, clean_ipc_by_gid);
 }
 
-static void manager_serialize_uid_refs_internal(
-                Manager *m,
-                FILE *f,
-                Hashmap **uid_refs,
-                const char *field_name) {
-
-        Iterator i;
-        void *p, *k;
-
-        assert(m);
-        assert(f);
-        assert(uid_refs);
-        assert(field_name);
-
-        /* Serialize the UID reference table. Or actually, just the IPC destruction flag of it, as the actual counter
-         * of it is better rebuild after a reload/reexec. */
-
-        HASHMAP_FOREACH_KEY(p, k, *uid_refs, i) {
-                uint32_t c;
-                uid_t uid;
-
-                uid = PTR_TO_UID(k);
-                c = PTR_TO_UINT32(p);
-
-                if (!(c & DESTROY_IPC_FLAG))
-                        continue;
-
-                (void) serialize_item_format(f, field_name, UID_FMT, uid);
-        }
-}
-
-void manager_serialize_uid_refs(Manager *m, FILE *f) {
-        manager_serialize_uid_refs_internal(m, f, &m->uid_refs, "destroy-ipc-uid");
-}
-
-void manager_serialize_gid_refs(Manager *m, FILE *f) {
-        manager_serialize_uid_refs_internal(m, f, &m->gid_refs, "destroy-ipc-gid");
-}
-
-static void manager_deserialize_uid_refs_one_internal(
-                Manager *m,
-                Hashmap** uid_refs,
-                const char *value) {
-
-        uid_t uid;
-        uint32_t c;
-        int r;
-
+static void manager_vacuum(Manager *m) {
         assert(m);
-        assert(uid_refs);
-        assert(value);
-
-        r = parse_uid(value, &uid);
-        if (r < 0 || uid == 0) {
-                log_debug("Unable to parse UID reference serialization: " UID_FMT, uid);
-                return;
-        }
-
-        r = hashmap_ensure_allocated(uid_refs, &trivial_hash_ops);
-        if (r < 0) {
-                log_oom();
-                return;
-        }
-
-        c = PTR_TO_UINT32(hashmap_get(*uid_refs, UID_TO_PTR(uid)));
-        if (c & DESTROY_IPC_FLAG)
-                return;
-
-        c |= DESTROY_IPC_FLAG;
 
-        r = hashmap_replace(*uid_refs, UID_TO_PTR(uid), UINT32_TO_PTR(c));
-        if (r < 0) {
-                log_debug_errno(r, "Failed to add UID reference entry: %m");
-                return;
-        }
-}
+        /* Release any dynamic users no longer referenced */
+        dynamic_user_vacuum(m, true);
 
-void manager_deserialize_uid_refs_one(Manager *m, const char *value) {
-        manager_deserialize_uid_refs_one_internal(m, &m->uid_refs, value);
-}
+        /* Release any references to UIDs/GIDs no longer referenced, and destroy any IPC owned by them */
+        manager_vacuum_uid_refs(m);
+        manager_vacuum_gid_refs(m);
 
-void manager_deserialize_gid_refs_one(Manager *m, const char *value) {
-        manager_deserialize_uid_refs_one_internal(m, &m->gid_refs, value);
+        /* Release any runtimes no longer referenced */
+        exec_runtime_vacuum(m);
 }
 
 int manager_dispatch_user_lookup_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
index 10c34f95433cfcb0eec1f16c4971dc65b77d6281..a29d976eae531cab80715d9cebb77bf906f514ac 100644 (file)
@@ -114,6 +114,13 @@ typedef enum ManagerTimestamp {
         _MANAGER_TIMESTAMP_INVALID = -1,
 } ManagerTimestamp;
 
+typedef enum WatchdogType {
+        WATCHDOG_RUNTIME,
+        WATCHDOG_REBOOT,
+        WATCHDOG_KEXEC,
+        _WATCHDOG_TYPE_MAX,
+} WatchdogType;
+
 #include "execute.h"
 #include "job.h"
 #include "path-lookup.h"
@@ -231,9 +238,8 @@ struct Manager {
         char **transient_environment;  /* The environment, as determined from config files, kernel cmdline and environment generators */
         char **client_environment;     /* Environment variables created by clients through the bus API */
 
-        usec_t runtime_watchdog;
-        usec_t reboot_watchdog;
-        usec_t kexec_watchdog;
+        usec_t watchdog[_WATCHDOG_TYPE_MAX];
+        usec_t watchdog_overridden[_WATCHDOG_TYPE_MAX];
 
         dual_timestamp timestamps[_MANAGER_TIMESTAMP_MAX];
 
@@ -510,7 +516,6 @@ void manager_set_show_status(Manager *m, ShowStatus mode, const char *reason);
 void manager_set_first_boot(Manager *m, bool b);
 
 void manager_status_printf(Manager *m, StatusType type, const char *status, const char *format, ...) _printf_(4,5);
-void manager_flip_auto_status(Manager *m, bool enable, const char *reason);
 
 Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path);
 
@@ -524,15 +529,6 @@ int manager_ref_uid(Manager *m, uid_t uid, bool clean_ipc);
 void manager_unref_gid(Manager *m, gid_t gid, bool destroy_now);
 int manager_ref_gid(Manager *m, gid_t gid, bool destroy_now);
 
-void manager_vacuum_uid_refs(Manager *m);
-void manager_vacuum_gid_refs(Manager *m);
-
-void manager_serialize_uid_refs(Manager *m, FILE *f);
-void manager_deserialize_uid_refs_one(Manager *m, const char *value);
-
-void manager_serialize_gid_refs(Manager *m, FILE *f);
-void manager_deserialize_gid_refs_one(Manager *m, const char *value);
-
 char *manager_taint_string(Manager *m);
 
 void manager_ref_console(Manager *m);
@@ -555,5 +551,9 @@ const char *manager_timestamp_to_string(ManagerTimestamp m) _const_;
 ManagerTimestamp manager_timestamp_from_string(const char *s) _pure_;
 ManagerTimestamp manager_timestamp_initrd_mangle(ManagerTimestamp s);
 
+usec_t manager_get_watchdog(Manager *m, WatchdogType t);
+void manager_set_watchdog(Manager *m, WatchdogType t, usec_t timeout);
+int manager_set_watchdog_overridden(Manager *m, WatchdogType t, usec_t timeout);
+
 const char* oom_policy_to_string(OOMPolicy i) _const_;
 OOMPolicy oom_policy_from_string(const char *s) _pure_;
index ffe3d4cc64127419d14ca53b36b6843a825d9e1e..dd44d5eb9203d2e4d727c592b3d27d7f66c86c77 100644 (file)
@@ -23,6 +23,7 @@
 #include "macro.h"
 #include "mkdir.h"
 #include "mount-setup.h"
+#include "mount-util.h"
 #include "mountpoint-util.h"
 #include "nulstr-util.h"
 #include "path-util.h"
@@ -60,51 +61,51 @@ typedef struct MountPoint {
 #endif
 
 static const MountPoint mount_table[] = {
-        { "sysfs",       "/sys",                      "sysfs",      NULL,                      MS_NOSUID|MS_NOEXEC|MS_NODEV,
+        { "sysfs",       "/sys",                      "sysfs",      NULL,                                           MS_NOSUID|MS_NOEXEC|MS_NODEV,
           NULL,          MNT_FATAL|MNT_IN_CONTAINER },
-        { "proc",        "/proc",                     "proc",       NULL,                      MS_NOSUID|MS_NOEXEC|MS_NODEV,
+        { "proc",        "/proc",                     "proc",       NULL,                                           MS_NOSUID|MS_NOEXEC|MS_NODEV,
           NULL,          MNT_FATAL|MNT_IN_CONTAINER },
-        { "devtmpfs",    "/dev",                      "devtmpfs",   "mode=755",                MS_NOSUID|MS_NOEXEC|MS_STRICTATIME,
+        { "devtmpfs",    "/dev",                      "devtmpfs",   "mode=755" TMPFS_LIMITS_DEV,                    MS_NOSUID|MS_NOEXEC|MS_STRICTATIME,
           NULL,          MNT_FATAL|MNT_IN_CONTAINER },
-        { "securityfs",  "/sys/kernel/security",      "securityfs", NULL,                      MS_NOSUID|MS_NOEXEC|MS_NODEV,
+        { "securityfs",  "/sys/kernel/security",      "securityfs", NULL,                                           MS_NOSUID|MS_NOEXEC|MS_NODEV,
           NULL,          MNT_NONE                   },
 #if ENABLE_SMACK
-        { "smackfs",     "/sys/fs/smackfs",           "smackfs",    "smackfsdef=*",            MS_NOSUID|MS_NOEXEC|MS_NODEV,
+        { "smackfs",     "/sys/fs/smackfs",           "smackfs",    "smackfsdef=*",                                 MS_NOSUID|MS_NOEXEC|MS_NODEV,
           mac_smack_use, MNT_FATAL                  },
-        { "tmpfs",       "/dev/shm",                  "tmpfs",      "mode=1777,smackfsroot=*", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+        { "tmpfs",       "/dev/shm",                  "tmpfs",      "mode=1777,smackfsroot=*" TMPFS_LIMITS_DEV_SHM, MS_NOSUID|MS_NODEV|MS_STRICTATIME,
           mac_smack_use, MNT_FATAL                  },
 #endif
-        { "tmpfs",       "/dev/shm",                  "tmpfs",      "mode=1777",               MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+        { "tmpfs",       "/dev/shm",                  "tmpfs",      "mode=1777" TMPFS_LIMITS_DEV_SHM,               MS_NOSUID|MS_NODEV|MS_STRICTATIME,
           NULL,          MNT_FATAL|MNT_IN_CONTAINER },
-        { "devpts",      "/dev/pts",                  "devpts",     "mode=620,gid=" STRINGIFY(TTY_GID), MS_NOSUID|MS_NOEXEC,
+        { "devpts",      "/dev/pts",                  "devpts",     "mode=620,gid=" STRINGIFY(TTY_GID),             MS_NOSUID|MS_NOEXEC,
           NULL,          MNT_IN_CONTAINER           },
 #if ENABLE_SMACK
-        { "tmpfs",       "/run",                      "tmpfs",      "mode=755,smackfsroot=*",  MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+        { "tmpfs",       "/run",                      "tmpfs",      "mode=755,smackfsroot=*" TMPFS_LIMITS_RUN,      MS_NOSUID|MS_NODEV|MS_STRICTATIME,
           mac_smack_use, MNT_FATAL                  },
 #endif
-        { "tmpfs",       "/run",                      "tmpfs",      "mode=755",                MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+        { "tmpfs",       "/run",                      "tmpfs",      "mode=755" TMPFS_LIMITS_RUN,                    MS_NOSUID|MS_NODEV|MS_STRICTATIME,
           NULL,          MNT_FATAL|MNT_IN_CONTAINER },
-        { "cgroup2",     "/sys/fs/cgroup",            "cgroup2",    "nsdelegate",              MS_NOSUID|MS_NOEXEC|MS_NODEV,
+        { "cgroup2",     "/sys/fs/cgroup",            "cgroup2",    "nsdelegate",                                   MS_NOSUID|MS_NOEXEC|MS_NODEV,
           cg_is_unified_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
-        { "cgroup2",     "/sys/fs/cgroup",            "cgroup2",    NULL,                      MS_NOSUID|MS_NOEXEC|MS_NODEV,
+        { "cgroup2",     "/sys/fs/cgroup",            "cgroup2",    NULL,                                           MS_NOSUID|MS_NOEXEC|MS_NODEV,
           cg_is_unified_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
-        { "tmpfs",       "/sys/fs/cgroup",            "tmpfs",      "mode=755",                MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
+        { "tmpfs",       "/sys/fs/cgroup",            "tmpfs",      "mode=755" TMPFS_LIMITS_SYS_FS_CGROUP,          MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
           cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER },
-        { "cgroup2",     "/sys/fs/cgroup/unified",    "cgroup2",    "nsdelegate",              MS_NOSUID|MS_NOEXEC|MS_NODEV,
+        { "cgroup2",     "/sys/fs/cgroup/unified",    "cgroup2",    "nsdelegate",                                   MS_NOSUID|MS_NOEXEC|MS_NODEV,
           cg_is_hybrid_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
-        { "cgroup2",     "/sys/fs/cgroup/unified",    "cgroup2",    NULL,                      MS_NOSUID|MS_NOEXEC|MS_NODEV,
+        { "cgroup2",     "/sys/fs/cgroup/unified",    "cgroup2",    NULL,                                           MS_NOSUID|MS_NOEXEC|MS_NODEV,
           cg_is_hybrid_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
-        { "cgroup",      "/sys/fs/cgroup/systemd",    "cgroup",     "none,name=systemd,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV,
+        { "cgroup",      "/sys/fs/cgroup/systemd",    "cgroup",     "none,name=systemd,xattr",                      MS_NOSUID|MS_NOEXEC|MS_NODEV,
           cg_is_legacy_wanted, MNT_IN_CONTAINER     },
-        { "cgroup",      "/sys/fs/cgroup/systemd",    "cgroup",     "none,name=systemd",       MS_NOSUID|MS_NOEXEC|MS_NODEV,
+        { "cgroup",      "/sys/fs/cgroup/systemd",    "cgroup",     "none,name=systemd",                            MS_NOSUID|MS_NOEXEC|MS_NODEV,
           cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER },
-        { "pstore",      "/sys/fs/pstore",            "pstore",     NULL,                      MS_NOSUID|MS_NOEXEC|MS_NODEV,
+        { "pstore",      "/sys/fs/pstore",            "pstore",     NULL,                                           MS_NOSUID|MS_NOEXEC|MS_NODEV,
           NULL,          MNT_NONE                   },
 #if ENABLE_EFI
-        { "efivarfs",    "/sys/firmware/efi/efivars", "efivarfs",   NULL,                      MS_NOSUID|MS_NOEXEC|MS_NODEV,
+        { "efivarfs",    "/sys/firmware/efi/efivars", "efivarfs",   NULL,                                           MS_NOSUID|MS_NOEXEC|MS_NODEV,
           is_efi_boot,   MNT_NONE                   },
 #endif
-        { "bpf",         "/sys/fs/bpf",               "bpf",        "mode=700",                MS_NOSUID|MS_NOEXEC|MS_NODEV,
+        { "bpf",         "/sys/fs/bpf",               "bpf",        "mode=700",                                     MS_NOSUID|MS_NOEXEC|MS_NODEV,
           NULL,          MNT_NONE,                  },
 };
 
@@ -352,7 +353,7 @@ int mount_cgroup_controllers(void) {
         }
 
         /* Now that we mounted everything, let's make the tmpfs the cgroup file systems are mounted into read-only. */
-        (void) mount("tmpfs", "/sys/fs/cgroup", "tmpfs", MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY, "mode=755");
+        (void) mount("tmpfs", "/sys/fs/cgroup", "tmpfs", MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY, "mode=755" TMPFS_LIMITS_SYS_FS_CGROUP);
 
         return 0;
 }
index 1c4aefd734f3e01664f419b0f0d7c5e3b41ccec8..48500b49327580434fddbb94c9651fd2a3333a36 100644 (file)
@@ -66,6 +66,14 @@ static bool MOUNT_STATE_WITH_PROCESS(MountState state) {
                       MOUNT_CLEANING);
 }
 
+static bool mount_is_automount(const MountParameters *p) {
+        assert(p);
+
+        return fstab_test_option(p->options,
+                                 "comment=systemd.automount\0"
+                                 "x-systemd.automount\0");
+}
+
 static bool mount_is_network(const MountParameters *p) {
         assert(p);
 
@@ -78,6 +86,15 @@ static bool mount_is_network(const MountParameters *p) {
         return false;
 }
 
+static bool mount_is_nofail(const Mount *m) {
+        assert(m);
+
+        if (!m->from_fragment)
+                return false;
+
+        return fstab_test_yes_no_option(m->parameters_fragment.options, "nofail\0" "fail\0");
+}
+
 static bool mount_is_loop(const MountParameters *p) {
         assert(p);
 
@@ -400,42 +417,72 @@ static bool mount_is_extrinsic(Mount *m) {
         MountParameters *p;
         assert(m);
 
-        /* Returns true for all units that are "magic" and should be excluded from the usual start-up and shutdown
-         * dependencies. We call them "extrinsic" here, as they are generally mounted outside of the systemd dependency
-         * logic. We shouldn't attempt to manage them ourselves but it's fine if the user operates on them with us. */
+        /* Returns true for all units that are "magic" and should be excluded from the usual
+         * start-up and shutdown dependencies. We call them "extrinsic" here, as they are generally
+         * mounted outside of the systemd dependency logic. We shouldn't attempt to manage them
+         * ourselves but it's fine if the user operates on them with us. */
 
-        if (!MANAGER_IS_SYSTEM(UNIT(m)->manager)) /* We only automatically manage mounts if we are in system mode */
+        /* We only automatically manage mounts if we are in system mode */
+        if (!MANAGER_IS_SYSTEM(UNIT(m)->manager))
                 return true;
 
         if (UNIT(m)->perpetual) /* All perpetual units never change state */
                 return true;
 
-        if (PATH_IN_SET(m->where,  /* Don't bother with the OS data itself */
-                        "/",       /* (strictly speaking redundant: should already be covered by the perpetual flag check above) */
-                        "/usr",
-                        "/etc"))
-                return true;
-
-        if (PATH_STARTSWITH_SET(m->where,
-                                "/run/initramfs",    /* This should stay around from before we boot until after we shutdown */
-                                "/proc",             /* All of this is API VFS */
-                                "/sys",              /* … dito … */
-                                "/dev"))             /* … dito … */
-                return true;
-
-        /* If this is an initrd mount, and we are not in the initrd, then leave this around forever, too. */
         p = get_mount_parameters(m);
-        if (p && fstab_test_option(p->options, "x-initrd.mount\0") && !in_initrd())
+        if (p && fstab_is_extrinsic(m->where, p->options))
                 return true;
 
         return false;
 }
 
+static int mount_add_default_ordering_dependencies(
+                Mount *m,
+                MountParameters *p,
+                UnitDependencyMask mask) {
+
+        const char *after, *before, *e;
+        int r;
+
+        assert(m);
+
+        e = path_startswith(m->where, "/sysroot");
+        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. */
+
+                after = NULL;
+                before = isempty(e) ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_INITRD_FS_TARGET;
+
+        } else if (mount_is_network(p)) {
+                after = SPECIAL_REMOTE_FS_PRE_TARGET;
+                before = SPECIAL_REMOTE_FS_TARGET;
+
+        } else {
+                after = SPECIAL_LOCAL_FS_PRE_TARGET;
+                before = SPECIAL_LOCAL_FS_TARGET;
+        }
+
+        if (!mount_is_nofail(m) && !mount_is_automount(p)) {
+                r = unit_add_dependency_by_name(UNIT(m), UNIT_BEFORE, before, true, mask);
+                if (r < 0)
+                        return r;
+        }
+
+        if (after) {
+                r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, true, mask);
+                if (r < 0)
+                        return r;
+        }
+
+        return unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS,
+                                                 SPECIAL_UMOUNT_TARGET, true, mask);
+}
+
 static int mount_add_default_dependencies(Mount *m) {
-        const char *after, *before;
         UnitDependencyMask mask;
         MountParameters *p;
-        bool nofail;
         int r;
 
         assert(m);
@@ -443,9 +490,10 @@ static int mount_add_default_dependencies(Mount *m) {
         if (!UNIT(m)->default_dependencies)
                 return 0;
 
-        /* We do not add any default dependencies to /, /usr or /run/initramfs/, since they are guaranteed to stay
-         * mounted the whole time, since our system is on it.  Also, don't bother with anything mounted below virtual
-         * file systems, it's also going to be virtual, and hence not worth the effort. */
+        /* We do not add any default dependencies to /, /usr or /run/initramfs/, since they are
+         * guaranteed to stay mounted the whole time, since our system is on it.  Also, don't
+         * bother with anything mounted below virtual file systems, it's also going to be virtual,
+         * and hence not worth the effort. */
         if (mount_is_extrinsic(m))
                 return 0;
 
@@ -454,51 +502,31 @@ static int mount_add_default_dependencies(Mount *m) {
                 return 0;
 
         mask = m->from_fragment ? UNIT_DEPENDENCY_FILE : UNIT_DEPENDENCY_MOUNTINFO_DEFAULT;
-        nofail = m->from_fragment ? fstab_test_yes_no_option(m->parameters_fragment.options, "nofail\0" "fail\0") : false;
+
+        r = mount_add_default_ordering_dependencies(m, p, mask);
+        if (r < 0)
+                return r;
 
         if (mount_is_network(p)) {
-                /* We order ourselves after network.target. This is
-                 * primarily useful at shutdown: services that take
-                 * down the network should order themselves before
-                 * network.target, so that they are shut down only
-                 * after this mount unit is stopped. */
+                /* We order ourselves after network.target. This is primarily useful at shutdown:
+                 * services that take down the network should order themselves before
+                 * network.target, so that they are shut down only after this mount unit is
+                 * stopped. */
 
                 r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_NETWORK_TARGET, true, mask);
                 if (r < 0)
                         return r;
 
-                /* We pull in network-online.target, and order
-                 * ourselves after it. This is useful at start-up to
-                 * actively pull in tools that want to be started
-                 * before we start mounting network file systems, and
-                 * whose purpose it is to delay this until the network
-                 * is "up". */
+                /* We pull in network-online.target, and order ourselves after it. This is useful
+                 * at start-up to actively pull in tools that want to be started before we start
+                 * mounting network file systems, and whose purpose it is to delay this until the
+                 * network is "up". */
 
                 r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_WANTS, UNIT_AFTER, SPECIAL_NETWORK_ONLINE_TARGET, true, mask);
                 if (r < 0)
                         return r;
-
-                after = SPECIAL_REMOTE_FS_PRE_TARGET;
-                before = SPECIAL_REMOTE_FS_TARGET;
-        } else {
-                after = SPECIAL_LOCAL_FS_PRE_TARGET;
-                before = SPECIAL_LOCAL_FS_TARGET;
         }
 
-        if (!nofail) {
-                r = unit_add_dependency_by_name(UNIT(m), UNIT_BEFORE, before, true, mask);
-                if (r < 0)
-                        return r;
-        }
-
-        r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, true, mask);
-        if (r < 0)
-                return r;
-
-        r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, true, mask);
-        if (r < 0)
-                return r;
-
         /* If this is a tmpfs mount then we have to unmount it before we try to deactivate swaps */
         if (streq_ptr(p->fstype, "tmpfs")) {
                 r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_SWAP_TARGET, true, mask);
@@ -752,6 +780,7 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) {
                 "%sSloppyOptions: %s\n"
                 "%sLazyUnmount: %s\n"
                 "%sForceUnmount: %s\n"
+                "%sReadWriteOnly: %s\n"
                 "%sTimeoutSec: %s\n",
                 prefix, mount_state_to_string(m->state),
                 prefix, mount_result_to_string(m->result),
@@ -767,6 +796,7 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) {
                 prefix, yes_no(m->sloppy_options),
                 prefix, yes_no(m->lazy_unmount),
                 prefix, yes_no(m->force_unmount),
+                prefix, yes_no(m->read_write_only),
                 prefix, format_timespan(buf, sizeof(buf), m->timeout_usec, USEC_PER_SEC));
 
         if (m->control_pid > 0)
@@ -998,6 +1028,8 @@ static void mount_enter_mounting(Mount *m) {
                 r = exec_command_set(m->control_command, MOUNT_PATH, p->what, m->where, NULL);
                 if (r >= 0 && m->sloppy_options)
                         r = exec_command_append(m->control_command, "-s", NULL);
+                if (r >= 0 && m->read_write_only)
+                        r = exec_command_append(m->control_command, "-w", NULL);
                 if (r >= 0 && p->fstype)
                         r = exec_command_append(m->control_command, "-t", p->fstype, NULL);
                 if (r >= 0 && !isempty(opts))
@@ -1058,6 +1090,8 @@ static void mount_enter_remounting(Mount *m) {
                                      "-o", o, NULL);
                 if (r >= 0 && m->sloppy_options)
                         r = exec_command_append(m->control_command, "-s", NULL);
+                if (r >= 0 && m->read_write_only)
+                        r = exec_command_append(m->control_command, "-w", NULL);
                 if (r >= 0 && p->fstype)
                         r = exec_command_append(m->control_command, "-t", p->fstype, NULL);
         } else
@@ -1878,7 +1912,7 @@ static int mount_process_proc_self_mountinfo(Manager *m) {
 
                                 /* Remember that this device might just have disappeared */
                                 if (set_ensure_allocated(&gone, &path_hash_ops) < 0 ||
-                                    set_put_strdup(gone, mount->parameters_proc_self_mountinfo.what) < 0)
+                                    set_put_strdup(&gone, mount->parameters_proc_self_mountinfo.what) < 0)
                                         log_oom(); /* we don't care too much about OOM here... */
                         }
 
@@ -1933,7 +1967,7 @@ static int mount_process_proc_self_mountinfo(Manager *m) {
                         /* Track devices currently used */
 
                         if (set_ensure_allocated(&around, &path_hash_ops) < 0 ||
-                            set_put_strdup(around, mount->parameters_proc_self_mountinfo.what) < 0)
+                            set_put_strdup(&around, mount->parameters_proc_self_mountinfo.what) < 0)
                                 log_oom();
                 }
 
@@ -2110,7 +2144,6 @@ const UnitVTable mount_vtable = {
 
         .control_pid = mount_control_pid,
 
-        .bus_vtable = bus_mount_vtable,
         .bus_set_property = bus_mount_set_property,
         .bus_commit_properties = bus_mount_commit_properties,
 
index 07fa05f3ca69635a82d4c4d5c323c58dc643a1de..a1bc2d71a64db0ac07bb288d3ab1bdefdfedd992 100644 (file)
@@ -59,6 +59,8 @@ struct Mount {
         bool lazy_unmount;
         bool force_unmount;
 
+        bool read_write_only;
+
         MountResult result;
         MountResult reload_result;
         MountResult clean_result;
index d4d6970af37b3a779185183754f7a73f19b02f34..34eb469fb825990d84a2c704fd451cea13dc4e02 100644 (file)
@@ -130,9 +130,9 @@ static const MountEntry protect_home_read_only_table[] = {
 
 /* ProtectHome=tmpfs table */
 static const MountEntry protect_home_tmpfs_table[] = {
-        { "/home",               TMPFS,        true, .read_only = true, .options_const = "mode=0755", .flags = MS_NODEV|MS_STRICTATIME },
-        { "/run/user",           TMPFS,        true, .read_only = true, .options_const = "mode=0755", .flags = MS_NODEV|MS_STRICTATIME },
-        { "/root",               TMPFS,        true, .read_only = true, .options_const = "mode=0700", .flags = MS_NODEV|MS_STRICTATIME },
+        { "/home",               TMPFS,        true, .read_only = true, .options_const = "mode=0755" TMPFS_LIMITS_EMPTY_OR_ALMOST, .flags = MS_NODEV|MS_STRICTATIME },
+        { "/run/user",           TMPFS,        true, .read_only = true, .options_const = "mode=0755" TMPFS_LIMITS_EMPTY_OR_ALMOST, .flags = MS_NODEV|MS_STRICTATIME },
+        { "/root",               TMPFS,        true, .read_only = true, .options_const = "mode=0700" TMPFS_LIMITS_EMPTY_OR_ALMOST, .flags = MS_NODEV|MS_STRICTATIME },
 };
 
 /* ProtectHome=yes table */
@@ -295,7 +295,7 @@ static int append_empty_dir_mounts(MountEntry **p, char **strv) {
                         .mode = EMPTY_DIR,
                         .ignore = false,
                         .read_only = true,
-                        .options_const = "mode=755",
+                        .options_const = "mode=755" TMPFS_LIMITS_EMPTY_OR_ALMOST,
                         .flags = MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
                 };
         }
@@ -341,7 +341,7 @@ static int append_tmpfs_mounts(MountEntry **p, const TemporaryFileSystem *tmpfs,
                                                "Path is not absolute: %s",
                                                t->path);
 
-                str = strjoin("mode=0755,", t->options);
+                str = strjoin("mode=0755" TMPFS_LIMITS_TEMPORARY_FS ",", t->options);
                 if (!str)
                         return -ENOMEM;
 
@@ -686,7 +686,7 @@ static int mount_private_dev(MountEntry *m) {
 
         dev = strjoina(temporary_mount, "/dev");
         (void) mkdir(dev, 0755);
-        if (mount("tmpfs", dev, "tmpfs", DEV_MOUNT_OPTIONS, "mode=755") < 0) {
+        if (mount("tmpfs", dev, "tmpfs", DEV_MOUNT_OPTIONS, "mode=755" TMPFS_LIMITS_DEV) < 0) {
                 r = log_debug_errno(errno, "Failed to mount tmpfs on '%s': %m", dev);
                 goto fail;
         }
@@ -1624,8 +1624,9 @@ int setup_namespace(
         r = 0;
 
 finish:
-        for (m = mounts; m < mounts + n_mounts; m++)
-                mount_entry_done(m);
+        if (n_mounts > 0)
+                for (m = mounts; m < mounts + n_mounts; m++)
+                        mount_entry_done(m);
 
         free(mounts);
 
index cb75d778afa0f695b9b5667b121f1373589391b1..1bbf27c5c571c1fb2aba6a8cf5060c3609b67a63 100644 (file)
@@ -223,11 +223,10 @@ static void path_spec_mkdir(PathSpec *s, mode_t mode) {
 }
 
 static void path_spec_dump(PathSpec *s, FILE *f, const char *prefix) {
-        fprintf(f,
-                "%s%s: %s\n",
-                prefix,
-                path_type_to_string(s->type),
-                s->path);
+        const char *type;
+
+        assert_se(type = path_type_to_string(s->type));
+        fprintf(f, "%s%s: %s\n", prefix, type, s->path);
 }
 
 void path_spec_done(PathSpec *s) {
@@ -607,14 +606,16 @@ static int path_serialize(Unit *u, FILE *f, FDSet *fds) {
         (void) serialize_item(f, "result", path_result_to_string(p->result));
 
         LIST_FOREACH(spec, s, p->specs) {
+                const char *type;
                 _cleanup_free_ char *escaped = NULL;
 
                 escaped = cescape(s->path);
                 if (!escaped)
                         return log_oom();
 
+                assert_se(type = path_type_to_string(s->type));
                 (void) serialize_item_format(f, "path-spec", "%s %i %s",
-                                             path_type_to_string(s->type),
+                                             type,
                                              s->previous_exists,
                                              s->path);
         }
@@ -830,6 +831,5 @@ const UnitVTable path_vtable = {
 
         .reset_failed = path_reset_failed,
 
-        .bus_vtable = bus_path_vtable,
         .bus_set_property = bus_path_set_property,
 };
index 76358c416ad1422930faced879b95c2b8523231f..42c51b08651641664183950ea874c110dbc1139c 100644 (file)
@@ -635,6 +635,9 @@ const UnitVTable scope_vtable = {
 
         .kill = scope_kill,
 
+        .freeze = unit_freeze_vtable_common,
+        .thaw = unit_thaw_vtable_common,
+
         .get_timeout = scope_get_timeout,
 
         .serialize = scope_serialize,
@@ -649,7 +652,6 @@ const UnitVTable scope_vtable = {
 
         .notify_cgroup_empty = scope_notify_cgroup_empty_event,
 
-        .bus_vtable = bus_scope_vtable,
         .bus_set_property = bus_scope_set_property,
         .bus_commit_properties = bus_scope_commit_properties,
 
index 56448c18f12023f31b6deb42f516b0274101e787..c6043943f16c44ac77af45b45756b9c6f11f7d12 100644 (file)
@@ -227,7 +227,7 @@ int mac_selinux_generic_access_check(
                 if (getfilecon_raw(path, &fcon) < 0) {
                         r = -errno;
 
-                        log_warning_errno(r, "SELinux getfilecon_raw on '%s' failed%s (perm=%s): %m",
+                        log_warning_errno(r, "SELinux getfilecon_raw() on '%s' failed%s (perm=%s): %m",
                                           path,
                                           enforce ? "" : ", ignoring",
                                           permission);
@@ -243,7 +243,7 @@ int mac_selinux_generic_access_check(
                 if (getcon_raw(&fcon) < 0) {
                         r = -errno;
 
-                        log_warning_errno(r, "SELinux getcon_raw failed%s (perm=%s): %m",
+                        log_warning_errno(r, "SELinux getcon_raw() failed%s (perm=%s): %m",
                                           enforce ? "" : ", ignoring",
                                           permission);
                         if (!enforce)
index da2e6cbd740695c401df9e8e1270a0be3648da31..58f737de0971be154e489707bf7eec16a9728fb2 100644 (file)
@@ -7,17 +7,8 @@
 
 int mac_selinux_generic_access_check(sd_bus_message *message, const char *path, const char *permission, sd_bus_error *error);
 
-#if HAVE_SELINUX
-
 #define mac_selinux_access_check(message, permission, error) \
         mac_selinux_generic_access_check((message), NULL, (permission), (error))
 
 #define mac_selinux_unit_access_check(unit, message, permission, error) \
         mac_selinux_generic_access_check((message), unit_label_path(unit), (permission), (error))
-
-#else
-
-#define mac_selinux_access_check(message, permission, error) 0
-#define mac_selinux_unit_access_check(unit, message, permission, error) 0
-
-#endif
index 7d5928e455ce369ef1695b1903bcc539a8ccc6d7..6e2a82a2865055e8b1ea76237cf99a125a0748e8 100644 (file)
@@ -423,7 +423,7 @@ static int on_fd_store_io(sd_event_source *e, int fd, uint32_t revents, void *us
         return 0;
 }
 
-static int service_add_fd_store(Service *s, int fd, const char *name) {
+static int service_add_fd_store(Service *s, int fd, const char *name, bool do_poll) {
         ServiceFDStore *fs;
         int r;
 
@@ -453,19 +453,22 @@ static int service_add_fd_store(Service *s, int fd, const char *name) {
 
         fs->fd = fd;
         fs->service = s;
+        fs->do_poll = do_poll;
         fs->fdname = strdup(name ?: "stored");
         if (!fs->fdname) {
                 free(fs);
                 return -ENOMEM;
         }
 
-        r = sd_event_add_io(UNIT(s)->manager->event, &fs->event_source, fd, 0, on_fd_store_io, fs);
-        if (r < 0 && r != -EPERM) { /* EPERM indicates fds that aren't pollable, which is OK */
-                free(fs->fdname);
-                free(fs);
-                return r;
-        } else if (r >= 0)
-                (void) sd_event_source_set_description(fs->event_source, "service-fd-store");
+        if (do_poll) {
+                r = sd_event_add_io(UNIT(s)->manager->event, &fs->event_source, fd, 0, on_fd_store_io, fs);
+                if (r < 0 && r != -EPERM) { /* EPERM indicates fds that aren't pollable, which is OK */
+                        free(fs->fdname);
+                        free(fs);
+                        return r;
+                } else if (r >= 0)
+                        (void) sd_event_source_set_description(fs->event_source, "service-fd-store");
+        }
 
         LIST_PREPEND(fd_store, s->fd_store, fs);
         s->n_fd_store++;
@@ -473,7 +476,7 @@ static int service_add_fd_store(Service *s, int fd, const char *name) {
         return 1; /* fd newly stored */
 }
 
-static int service_add_fd_store_set(Service *s, FDSet *fds, const char *name) {
+static int service_add_fd_store_set(Service *s, FDSet *fds, const char *name, bool do_poll) {
         int r;
 
         assert(s);
@@ -485,7 +488,7 @@ static int service_add_fd_store_set(Service *s, FDSet *fds, const char *name) {
                 if (fd < 0)
                         break;
 
-                r = service_add_fd_store(s, fd, name);
+                r = service_add_fd_store(s, fd, name, do_poll);
                 if (r == -EXFULL)
                         return log_unit_warning_errno(UNIT(s), r,
                                                       "Cannot store more fds than FileDescriptorStoreMax=%u, closing remaining.",
@@ -2715,7 +2718,7 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
                 if (!c)
                         return log_oom();
 
-                (void) serialize_item_format(f, "fd-store-fd", "%i %s", copy, c);
+                (void) serialize_item_format(f, "fd-store-fd", "%i \"%s\" %i", copy, c, fs->do_poll);
         }
 
         if (s->main_exec_status.pid > 0) {
@@ -2944,30 +2947,36 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
                         s->socket_fd = fdset_remove(fds, fd);
                 }
         } else if (streq(key, "fd-store-fd")) {
-                const char *fdv;
-                size_t pf;
+                _cleanup_free_ char *fdv = NULL, *fdn = NULL, *fdp = NULL;
                 int fd;
+                int do_poll;
 
-                pf = strcspn(value, WHITESPACE);
-                fdv = strndupa(value, pf);
-
-                if (safe_atoi(fdv, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+                r = extract_first_word(&value, &fdv, NULL, 0);
+                if (r <= 0 || safe_atoi(fdv, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) {
                         log_unit_debug(u, "Failed to parse fd-store-fd value: %s", value);
-                else {
-                        _cleanup_free_ char *t = NULL;
-                        const char *fdn;
+                        return 0;
+                }
 
-                        fdn = value + pf;
-                        fdn += strspn(fdn, WHITESPACE);
-                        (void) cunescape(fdn, 0, &t);
+                r = extract_first_word(&value, &fdn, NULL, EXTRACT_CUNESCAPE | EXTRACT_UNQUOTE);
+                if (r <= 0) {
+                        log_unit_debug_errno(u, r, "Failed to parse fd-store-fd value \"%s\": %m", value);
+                        return 0;
+                }
 
-                        r = service_add_fd_store(s, fd, t);
-                        if (r < 0)
-                                log_unit_error_errno(u, r, "Failed to add fd to store: %m");
-                        else
-                                fdset_remove(fds, fd);
+                r = extract_first_word(&value, &fdp, NULL, 0);
+                if (r == 0) {
+                        /* If the value is not present, we assume the default */
+                        do_poll = 1;
+                } else if (r < 0 || safe_atoi(fdp, &do_poll) < 0) {
+                        log_unit_debug_errno(u, r, "Failed to parse fd-store-fd value \"%s\": %m", value);
+                        return 0;
                 }
 
+                r = service_add_fd_store(s, fd, fdn, do_poll);
+                if (r < 0)
+                        log_unit_error_errno(u, r, "Failed to add fd to store: %m");
+                else
+                        fdset_remove(fds, fd);
         } else if (streq(key, "main-exec-status-pid")) {
                 pid_t pid;
 
@@ -3838,7 +3847,7 @@ static int service_dispatch_watchdog(sd_event_source *source, usec_t usec, void
         return 0;
 }
 
-static bool service_notify_message_authorized(Service *s, pid_t pid, char **tags, FDSet *fds) {
+static bool service_notify_message_authorized(Service *s, pid_t pid, FDSet *fds) {
         assert(s);
 
         if (s->notify_access == NOTIFY_NONE) {
@@ -3885,19 +3894,19 @@ static void service_force_watchdog(Service *s) {
 static void service_notify_message(
                 Unit *u,
                 const struct ucred *ucred,
-                char **tags,
+                char * const *tags,
                 FDSet *fds) {
 
         Service *s = SERVICE(u);
         bool notify_dbus = false;
         const char *e;
-        char **i;
+        char * const *i;
         int r;
 
         assert(u);
         assert(ucred);
 
-        if (!service_notify_message_authorized(SERVICE(u), ucred->pid, tags, fds))
+        if (!service_notify_message_authorized(SERVICE(u), ucred->pid, fds))
                 return;
 
         if (DEBUG_LOGGING) {
@@ -4068,7 +4077,7 @@ static void service_notify_message(
                         name = NULL;
                 }
 
-                (void) service_add_fd_store_set(s, fds, name);
+                (void) service_add_fd_store_set(s, fds, name, !strv_contains(tags, "FDPOLL=0"));
         }
 
         /* Notify clients about changed status or main pid */
@@ -4449,6 +4458,9 @@ const UnitVTable service_vtable = {
         .clean = service_clean,
         .can_clean = service_can_clean,
 
+        .freeze = unit_freeze_vtable_common,
+        .thaw = unit_thaw_vtable_common,
+
         .serialize = service_serialize,
         .deserialize_item = service_deserialize_item,
 
@@ -4472,7 +4484,6 @@ const UnitVTable service_vtable = {
 
         .bus_name_owner_change = service_bus_name_owner_change,
 
-        .bus_vtable = bus_service_vtable,
         .bus_set_property = bus_service_set_property,
         .bus_commit_properties = bus_service_commit_properties,
 
index 11e861a3d4325bf92635662811a0cd648de4c10e..b9c8036f225b289ec6dba652252461ee9eac5b83 100644 (file)
@@ -80,6 +80,7 @@ struct ServiceFDStore {
         int fd;
         char *fdname;
         sd_event_source *event_source;
+        bool do_poll;
 
         LIST_FIELDS(ServiceFDStore, fd_store);
 };
index d97a262786be3d0ad873cd1615256b96bedd83d5..38a2805200b3eb42c74be172215f07fb5c13667d 100644 (file)
@@ -5,6 +5,7 @@
 #include "alloc-util.h"
 #include "dbus-slice.h"
 #include "dbus-unit.h"
+#include "fd-util.h"
 #include "log.h"
 #include "serialize.h"
 #include "slice.h"
@@ -347,6 +348,82 @@ static void slice_enumerate_perpetual(Manager *m) {
                 (void) slice_make_perpetual(m, SPECIAL_SYSTEM_SLICE, NULL);
 }
 
+static bool slice_freezer_action_supported_by_children(Unit *s) {
+        Unit *member;
+        void *v;
+        Iterator i;
+
+        assert(s);
+
+        HASHMAP_FOREACH_KEY(v, member, s->dependencies[UNIT_BEFORE], i) {
+                int r;
+
+                if (UNIT_DEREF(member->slice) != s)
+                        continue;
+
+                if (member->type == UNIT_SLICE) {
+                        r = slice_freezer_action_supported_by_children(member);
+                        if (!r)
+                                return r;
+                }
+
+                if (!UNIT_VTABLE(member)->freeze)
+                        return false;
+        }
+
+        return true;
+}
+
+static int slice_freezer_action(Unit *s, FreezerAction action) {
+        Unit *member;
+        void *v;
+        Iterator i;
+        int r;
+
+        assert(s);
+        assert(IN_SET(action, FREEZER_FREEZE, FREEZER_THAW));
+
+        if (!slice_freezer_action_supported_by_children(s))
+                return log_unit_warning(s, "Requested freezer operation is not supported by all children of the slice");
+
+        HASHMAP_FOREACH_KEY(v, member, s->dependencies[UNIT_BEFORE], i) {
+                if (UNIT_DEREF(member->slice) != s)
+                        continue;
+
+                if (action == FREEZER_FREEZE)
+                        r = UNIT_VTABLE(member)->freeze(member);
+                else
+                        r = UNIT_VTABLE(member)->thaw(member);
+
+                if (r < 0)
+                        return r;
+        }
+
+        r = unit_cgroup_freezer_action(s, action);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+static int slice_freeze(Unit *s) {
+        assert(s);
+
+        return slice_freezer_action(s, FREEZER_FREEZE);
+}
+
+static int slice_thaw(Unit *s) {
+        assert(s);
+
+        return slice_freezer_action(s, FREEZER_THAW);
+}
+
+static bool slice_can_freeze(Unit *s) {
+        assert(s);
+
+        return slice_freezer_action_supported_by_children(s);
+}
+
 const UnitVTable slice_vtable = {
         .object_size = sizeof(Slice),
         .cgroup_context_offset = offsetof(Slice, cgroup_context),
@@ -371,13 +448,16 @@ const UnitVTable slice_vtable = {
 
         .kill = slice_kill,
 
+        .freeze = slice_freeze,
+        .thaw = slice_thaw,
+        .can_freeze = slice_can_freeze,
+
         .serialize = slice_serialize,
         .deserialize_item = slice_deserialize_item,
 
         .active_state = slice_active_state,
         .sub_state_to_string = slice_sub_state_to_string,
 
-        .bus_vtable = bus_slice_vtable,
         .bus_set_property = bus_slice_set_property,
         .bus_commit_properties = bus_slice_commit_properties,
 
index 4a0e3a253e854d23c71b00d128ba66ad5ac8b44b..5e8f317bfc5add3eb8f618b4804bd54692034265 100644 (file)
@@ -3462,7 +3462,6 @@ const UnitVTable socket_vtable = {
 
         .control_pid = socket_control_pid,
 
-        .bus_vtable = bus_socket_vtable,
         .bus_set_property = bus_socket_set_property,
         .bus_commit_properties = bus_socket_commit_properties,
 
index c5945371df7c7b8f38b359c40bd8c2b820bd2c3f..0b42236aca33e9180e458b4432a89b1bf107d11b 100644 (file)
@@ -1655,7 +1655,6 @@ const UnitVTable swap_vtable = {
 
         .control_pid = swap_control_pid,
 
-        .bus_vtable = bus_swap_vtable,
         .bus_set_property = bus_swap_set_property,
         .bus_commit_properties = bus_swap_commit_properties,
 
index 357ca70e090c377885cfbcdae62e9a3e42f5df36..a1d1cfc38aff46b5be66410ab23d0fa2a2909b5f 100644 (file)
@@ -207,8 +207,6 @@ const UnitVTable target_vtable = {
         .active_state = target_active_state,
         .sub_state_to_string = target_sub_state_to_string,
 
-        .bus_vtable = bus_target_vtable,
-
         .status_message_formats = {
                 .finished_start_job = {
                         [JOB_DONE]       = "Reached target %s.",
index 57d979d52da1e58d3e7b79319cae29418ee9cf66..7f779fb936b5471a4e039dcbf740a0bac47eb790 100644 (file)
@@ -925,6 +925,5 @@ const UnitVTable timer_vtable = {
         .time_change = timer_time_change,
         .timezone_change = timer_timezone_change,
 
-        .bus_vtable = bus_timer_vtable,
         .bus_set_property = bus_timer_set_property,
 };
index 2daaaf997175c142c865d81a649bf28578e8889d..4fee5dc6dc3e83362397d5eaf1e474102dd70578 100644 (file)
@@ -186,8 +186,14 @@ int unit_name_printf(const Unit *u, const char* format, char **ret) {
          * %u: the username of the running user
          *
          * %m: the machine ID of the running system
-         * %H: the host name of the running system
          * %b: the boot ID of the running system
+         * %H: the hostname of the running system
+         * %v: the kernel version
+         * %a: the native userspace architecture
+         * %o: the OS ID according to /etc/os-release
+         * %w: the OS version ID, according to /etc/os-release
+         * %B: the OS build ID, according to /etc/os-release
+         * %W: the OS variant ID, according to /etc/os-release
          */
 
         const Specifier table[] = {
@@ -203,8 +209,14 @@ int unit_name_printf(const Unit *u, const char* format, char **ret) {
                 { 'u', specifier_user_name,           NULL },
 
                 { 'm', specifier_machine_id,          NULL },
-                { 'H', specifier_host_name,           NULL },
                 { 'b', specifier_boot_id,             NULL },
+                { 'H', specifier_host_name,           NULL },
+                { 'v', specifier_kernel_release,      NULL },
+                { 'a', specifier_architecture,        NULL },
+                { 'o', specifier_os_id,               NULL },
+                { 'w', specifier_os_version_id,       NULL },
+                { 'B', specifier_os_build_id,         NULL },
+                { 'W', specifier_os_variant_id,       NULL },
                 {}
         };
 
@@ -279,6 +291,7 @@ int unit_full_printf(const Unit *u, const char *format, char **ret) {
 
                 { 'm', specifier_machine_id,               NULL },
                 { 'H', specifier_host_name,                NULL },
+                { 'l', specifier_short_host_name,          NULL },
                 { 'b', specifier_boot_id,                  NULL },
                 { 'v', specifier_kernel_release,           NULL },
                 {}
index 6a33657b8875119275191af5c22fdfd6e8ac381c..c5eb72163b85f8b84b3453a375072dbd0b3c357d 100644 (file)
@@ -628,6 +628,7 @@ void unit_free(Unit *u) {
         sd_bus_slot_unref(u->match_bus_slot);
         sd_bus_track_unref(u->bus_track);
         u->deserialized_refs = strv_free(u->deserialized_refs);
+        u->pending_freezer_message = sd_bus_message_unref(u->pending_freezer_message);
 
         unit_free_requires_mounts_for(u);
 
@@ -737,6 +738,38 @@ void unit_free(Unit *u) {
         free(u);
 }
 
+FreezerState unit_freezer_state(Unit *u) {
+        assert(u);
+
+        return u->freezer_state;
+}
+
+int unit_freezer_state_kernel(Unit *u, FreezerState *ret) {
+        char *values[1] = {};
+        int r;
+
+        assert(u);
+
+        r = cg_get_keyed_attribute(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, "cgroup.events",
+                                   STRV_MAKE("frozen"), values);
+        if (r < 0)
+                return r;
+
+        r = _FREEZER_STATE_INVALID;
+
+        if (values[0])  {
+                if (streq(values[0], "0"))
+                        r = FREEZER_RUNNING;
+                else if (streq(values[0], "1"))
+                        r = FREEZER_FROZEN;
+        }
+
+        free(values[0]);
+        *ret = r;
+
+        return 0;
+}
+
 UnitActiveState unit_active_state(Unit *u) {
         assert(u);
 
@@ -1090,12 +1123,10 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) {
 
         if (!IN_SET(c->std_output,
                     EXEC_OUTPUT_JOURNAL, EXEC_OUTPUT_JOURNAL_AND_CONSOLE,
-                    EXEC_OUTPUT_KMSG, EXEC_OUTPUT_KMSG_AND_CONSOLE,
-                    EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_SYSLOG_AND_CONSOLE) &&
+                    EXEC_OUTPUT_KMSG, EXEC_OUTPUT_KMSG_AND_CONSOLE) &&
             !IN_SET(c->std_error,
                     EXEC_OUTPUT_JOURNAL, EXEC_OUTPUT_JOURNAL_AND_CONSOLE,
-                    EXEC_OUTPUT_KMSG, EXEC_OUTPUT_KMSG_AND_CONSOLE,
-                    EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_SYSLOG_AND_CONSOLE) &&
+                    EXEC_OUTPUT_KMSG, EXEC_OUTPUT_KMSG_AND_CONSOLE) &&
             !c->log_namespace)
                 return 0;
 
@@ -1674,24 +1705,50 @@ static int log_unit_internal(void *userdata, int level, int error, const char *f
 }
 
 static bool unit_test_condition(Unit *u) {
+        _cleanup_strv_free_ char **env = NULL;
+        int r;
+
         assert(u);
 
         dual_timestamp_get(&u->condition_timestamp);
-        u->condition_result = condition_test_list(u->conditions, condition_type_to_string, log_unit_internal, u);
 
-        unit_add_to_dbus_queue(u);
+        r = manager_get_effective_environment(u->manager, &env);
+        if (r < 0) {
+                log_unit_error_errno(u, r, "Failed to determine effective environment: %m");
+                u->condition_result = CONDITION_ERROR;
+        } else
+                u->condition_result = condition_test_list(
+                                u->conditions,
+                                env,
+                                condition_type_to_string,
+                                log_unit_internal,
+                                u);
 
+        unit_add_to_dbus_queue(u);
         return u->condition_result;
 }
 
 static bool unit_test_assert(Unit *u) {
+        _cleanup_strv_free_ char **env = NULL;
+        int r;
+
         assert(u);
 
         dual_timestamp_get(&u->assert_timestamp);
-        u->assert_result = condition_test_list(u->asserts, assert_type_to_string, log_unit_internal, u);
 
-        unit_add_to_dbus_queue(u);
+        r = manager_get_effective_environment(u->manager, &env);
+        if (r < 0) {
+                log_unit_error_errno(u, r, "Failed to determine effective environment: %m");
+                u->assert_result = CONDITION_ERROR;
+        } else
+                u->assert_result = condition_test_list(
+                                u->asserts,
+                                env,
+                                assert_type_to_string,
+                                log_unit_internal,
+                                u);
 
+        unit_add_to_dbus_queue(u);
         return u->assert_result;
 }
 
@@ -1846,6 +1903,7 @@ int unit_start(Unit *u) {
          * waits for a holdoff timer to elapse before it will start again. */
 
         unit_add_to_dbus_queue(u);
+        unit_cgroup_freezer_action(u, FREEZER_THAW);
 
         return UNIT_VTABLE(u)->start(u);
 }
@@ -1898,6 +1956,7 @@ int unit_stop(Unit *u) {
                 return -EBADR;
 
         unit_add_to_dbus_queue(u);
+        unit_cgroup_freezer_action(u, FREEZER_THAW);
 
         return UNIT_VTABLE(u)->stop(u);
 }
@@ -1954,6 +2013,8 @@ int unit_reload(Unit *u) {
                 return 0;
         }
 
+        unit_cgroup_freezer_action(u, FREEZER_THAW);
+
         return UNIT_VTABLE(u)->reload(u);
 }
 
@@ -2740,7 +2801,7 @@ void unit_unwatch_pid(Unit *u, pid_t pid) {
 
                 if (m == 0) {
                         /* The array is now empty, remove the entire entry */
-                        assert(hashmap_remove(u->manager->watch_pids, PID_TO_PTR(-pid)) == array);
+                        assert_se(hashmap_remove(u->manager->watch_pids, PID_TO_PTR(-pid)) == array);
                         free(array);
                 }
         }
@@ -2993,13 +3054,10 @@ int unit_add_dependency(
                 return 0;
         }
 
-        if (d == UNIT_AFTER && UNIT_VTABLE(u)->refuse_after) {
-                log_unit_warning(u, "Requested dependency After=%s ignored (%s units cannot be delayed).", other->id, unit_type_to_string(u->type));
-                return 0;
-        }
-
-        if (d == UNIT_BEFORE && UNIT_VTABLE(other)->refuse_after) {
-                log_unit_warning(u, "Requested dependency Before=%s ignored (%s units cannot be delayed).", other->id, unit_type_to_string(other->type));
+        /* Note that ordering a device unit after a unit is permitted since it
+         * allows to start its job running timeout at a specific time. */
+        if (d == UNIT_BEFORE && other->type == UNIT_DEVICE) {
+                log_unit_warning(u, "Dependency Before=%s ignored (.device units cannot be delayed)", other->id);
                 return 0;
         }
 
@@ -3497,6 +3555,8 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
         if (!sd_id128_is_null(u->invocation_id))
                 (void) serialize_item_format(f, "invocation-id", SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(u->invocation_id));
 
+        (void) serialize_item_format(f, "freezer-state", "%s", freezer_state_to_string(unit_freezer_state(u)));
+
         bus_track_serialize(u->bus_track, f, "ref");
 
         for (m = 0; m < _CGROUP_IP_ACCOUNTING_METRIC_MAX; m++) {
@@ -3805,6 +3865,16 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
                                         log_unit_warning_errno(u, r, "Failed to set invocation ID for unit: %m");
                         }
 
+                        continue;
+                } else if (streq(l, "freezer-state")) {
+                        FreezerState s;
+
+                        s = freezer_state_from_string(v);
+                        if (s < 0)
+                                log_unit_debug(u, "Failed to deserialize freezer-state '%s', ignoring.", v);
+                        else
+                                u->freezer_state = s;
+
                         continue;
                 }
 
@@ -4267,7 +4337,8 @@ int unit_get_unit_file_preset(Unit *u) {
                 u->unit_file_preset = unit_file_query_preset(
                                 u->manager->unit_file_scope,
                                 NULL,
-                                basename(u->fragment_path));
+                                basename(u->fragment_path),
+                                NULL);
 
         return u->unit_file_preset;
 }
@@ -4659,7 +4730,7 @@ int unit_write_setting(Unit *u, UnitWriteFlags flags, const char *name, const ch
         /* Make sure the drop-in dir is registered in our path cache. This way we don't need to stupidly
          * recreate the cache after every drop-in we write. */
         if (u->manager->unit_path_cache) {
-                r = set_put_strdup(u->manager->unit_path_cache, p);
+                r = set_put_strdup(&u->manager->unit_path_cache, p);
                 if (r < 0)
                         return r;
         }
@@ -6076,6 +6147,80 @@ int unit_can_clean(Unit *u, ExecCleanMask *ret) {
         return UNIT_VTABLE(u)->can_clean(u, ret);
 }
 
+bool unit_can_freeze(Unit *u) {
+        assert(u);
+
+        if (UNIT_VTABLE(u)->can_freeze)
+                return UNIT_VTABLE(u)->can_freeze(u);
+
+        return UNIT_VTABLE(u)->freeze;
+}
+
+void unit_frozen(Unit *u) {
+        assert(u);
+
+        u->freezer_state = FREEZER_FROZEN;
+
+        bus_unit_send_pending_freezer_message(u);
+}
+
+void unit_thawed(Unit *u) {
+        assert(u);
+
+        u->freezer_state = FREEZER_RUNNING;
+
+        bus_unit_send_pending_freezer_message(u);
+}
+
+static int unit_freezer_action(Unit *u, FreezerAction action) {
+        UnitActiveState s;
+        int (*method)(Unit*);
+        int r;
+
+        assert(u);
+        assert(IN_SET(action, FREEZER_FREEZE, FREEZER_THAW));
+
+        method = action == FREEZER_FREEZE ? UNIT_VTABLE(u)->freeze : UNIT_VTABLE(u)->thaw;
+        if (!method || !cg_freezer_supported())
+                return -EOPNOTSUPP;
+
+        if (u->job)
+                return -EBUSY;
+
+        if (u->load_state != UNIT_LOADED)
+                return -EHOSTDOWN;
+
+        s = unit_active_state(u);
+        if (s != UNIT_ACTIVE)
+                return -EHOSTDOWN;
+
+        if (IN_SET(u->freezer_state, FREEZER_FREEZING, FREEZER_THAWING))
+                return -EALREADY;
+
+        r = method(u);
+        if (r <= 0)
+                return r;
+
+        return 1;
+}
+
+int unit_freeze(Unit *u) {
+        return unit_freezer_action(u, FREEZER_FREEZE);
+}
+
+int unit_thaw(Unit *u) {
+        return unit_freezer_action(u, FREEZER_THAW);
+}
+
+/* Wrappers around low-level cgroup freezer operations common for service and scope units */
+int unit_freeze_vtable_common(Unit *u) {
+        return unit_cgroup_freezer_action(u, FREEZER_FREEZE);
+}
+
+int unit_thaw_vtable_common(Unit *u) {
+        return unit_cgroup_freezer_action(u, FREEZER_THAW);
+}
+
 static const char* const collect_mode_table[_COLLECT_MODE_MAX] = {
         [COLLECT_INACTIVE] = "inactive",
         [COLLECT_INACTIVE_OR_FAILED] = "inactive-or-failed",
index e38871a97c0d02599b3e2bd55304f15f43a992a9..bee68607fefa15c0dd716951615e520acc59acf5 100644 (file)
@@ -114,6 +114,9 @@ typedef struct Unit {
         UnitLoadState load_state;
         Unit *merged_into;
 
+        FreezerState freezer_state;
+        sd_bus_message *pending_freezer_message;
+
         char *id; /* One name is special because we use it for identification. Points to an entry in the names set */
         char *instance;
 
@@ -483,6 +486,11 @@ typedef struct UnitVTable {
         /* Clear out the various runtime/state/cache/logs/configuration data */
         int (*clean)(Unit *u, ExecCleanMask m);
 
+        /* Freeze the unit */
+        int (*freeze)(Unit *u);
+        int (*thaw)(Unit *u);
+        bool (*can_freeze)(Unit *u);
+
         /* Return which kind of data can be cleaned */
         int (*can_clean)(Unit *u, ExecCleanMask *ret);
 
@@ -531,7 +539,7 @@ typedef struct UnitVTable {
         void (*notify_cgroup_oom)(Unit *u);
 
         /* Called whenever a process of this unit sends us a message */
-        void (*notify_message)(Unit *u, const struct ucred *ucred, char **tags, FDSet *fds);
+        void (*notify_message)(Unit *u, const struct ucred *ucred, char * const *tags, FDSet *fds);
 
         /* Called whenever a name this Unit registered for comes or goes away. */
         void (*bus_name_owner_change)(Unit *u, const char *new_owner);
@@ -592,9 +600,6 @@ typedef struct UnitVTable {
          * of this type will immediately fail. */
         bool (*supported)(void);
 
-        /* The bus vtable */
-        const sd_bus_vtable *bus_vtable;
-
         /* The strings to print in status messages */
         UnitStatusMessageFormats status_message_formats;
 
@@ -610,9 +615,6 @@ typedef struct UnitVTable {
         /* True if the unit type knows a failure state, and thus can be source of an OnFailure= dependency */
         bool can_fail:1;
 
-        /* True if After= dependencies should be refused */
-        bool refuse_after:1;
-
         /* True if units of this type shall be startable only once and then never again */
         bool once_only:1;
 
@@ -695,6 +697,8 @@ const char *unit_status_string(Unit *u) _pure_;
 bool unit_has_name(const Unit *u, const char *name);
 
 UnitActiveState unit_active_state(Unit *u);
+FreezerState unit_freezer_state(Unit *u);
+int unit_freezer_state_kernel(Unit *u, FreezerState *ret);
 
 const char* unit_sub_state_to_string(Unit *u);
 
@@ -878,6 +882,16 @@ void unit_destroy_runtime_directory(Unit *u, const ExecContext *context);
 int unit_clean(Unit *u, ExecCleanMask mask);
 int unit_can_clean(Unit *u, ExecCleanMask *ret_mask);
 
+bool unit_can_freeze(Unit *u);
+int unit_freeze(Unit *u);
+void unit_frozen(Unit *u);
+
+int unit_thaw(Unit *u);
+void unit_thawed(Unit *u);
+
+int unit_freeze_vtable_common(Unit *u);
+int unit_thaw_vtable_common(Unit *u);
+
 /* Macros which append UNIT= or USER_UNIT= to the message */
 
 #define log_unit_full(unit, level, error, ...)                          \
index ee4268b96572a423b6f7a02f36132da70609388d..42231dbd6b679d05205849690ee71491051bc3cc 100644 (file)
@@ -420,7 +420,7 @@ static int save_external_coredump(
                 goto fail;
         }
 
-#if HAVE_XZ || HAVE_LZ4
+#if HAVE_XZ || HAVE_LZ4 || HAVE_ZSTD
         /* If we will remove the coredump anyway, do not compress. */
         if (arg_compress && !maybe_remove_external_coredump(NULL, st.st_size)) {
 
@@ -884,10 +884,7 @@ static int process_socket(int fd) {
         log_debug("Processing coredump received on stdin...");
 
         for (;;) {
-                union {
-                        struct cmsghdr cmsghdr;
-                        uint8_t buf[CMSG_SPACE(sizeof(int))];
-                } control = {};
+                CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int))) control;
                 struct msghdr mh = {
                         .msg_control = &control,
                         .msg_controllen = sizeof(control),
@@ -911,39 +908,33 @@ static int process_socket(int fd) {
 
                 mh.msg_iov = &iovec;
 
-                n = recvmsg(fd, &mh, MSG_CMSG_CLOEXEC);
+                n = recvmsg_safe(fd, &mh, MSG_CMSG_CLOEXEC);
                 if (n < 0)  {
                         free(iovec.iov_base);
-                        r = log_error_errno(errno, "Failed to receive datagram: %m");
+                        r = log_error_errno(n, "Failed to receive datagram: %m");
                         goto finish;
                 }
 
                 /* The final zero-length datagram carries the file descriptor and tells us
                  * that we're done. */
                 if (n == 0) {
-                        struct cmsghdr *cmsg, *found = NULL;
+                        struct cmsghdr *found;
 
                         free(iovec.iov_base);
 
-                        CMSG_FOREACH(cmsg, &mh) {
-                                if (cmsg->cmsg_level == SOL_SOCKET &&
-                                    cmsg->cmsg_type == SCM_RIGHTS &&
-                                    cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
-                                        assert(!found);
-                                        found = cmsg;
-                                }
-                        }
-
+                        found = cmsg_find(&mh, SOL_SOCKET, SCM_RIGHTS, CMSG_LEN(sizeof(int)));
                         if (!found) {
-                                log_error("Coredump file descriptor missing.");
-                                r = -EBADMSG;
+                                cmsg_close_all(&mh);
+                                r = log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
+                                                    "Coredump file descriptor missing.");
                                 goto finish;
                         }
 
                         assert(input_fd < 0);
                         input_fd = *(int*) CMSG_DATA(found);
                         break;
-                }
+                } else
+                        cmsg_close_all(&mh);
 
                 /* Add trailing NUL byte, in case these are strings */
                 ((char*) iovec.iov_base)[n] = 0;
@@ -952,8 +943,6 @@ static int process_socket(int fd) {
                 r = iovw_put(&iovw, iovec.iov_base, iovec.iov_len);
                 if (r < 0)
                         goto finish;
-
-                cmsg_close_all(&mh);
         }
 
         /* Make sure we got all data we really need */
index a848268177ae5558ce5ab7974c4c274a894de24f..ed4d06e9866dd1e4af044bc99d33e4d3b1b10139 100644 (file)
@@ -237,7 +237,7 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_FILE:
-                        r = glob_extend(&arg_file, optarg);
+                        r = glob_extend(&arg_file, optarg, GLOB_NOCHECK);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to add paths: %m");
                         break;
@@ -765,7 +765,7 @@ static int save_core(sd_journal *j, FILE *file, char **path, bool *unlink_temp)
                 if (access(filename, R_OK) < 0)
                         return log_error_errno(errno, "File \"%s\" is not readable: %m", filename);
 
-                if (path && !endswith(filename, ".xz") && !endswith(filename, ".lz4")) {
+                if (path && !ENDSWITH_SET(filename, ".xz", ".lz4", ".zst")) {
                         *path = TAKE_PTR(filename);
 
                         return 0;
@@ -824,7 +824,7 @@ static int save_core(sd_journal *j, FILE *file, char **path, bool *unlink_temp)
         }
 
         if (filename) {
-#if HAVE_XZ || HAVE_LZ4
+#if HAVE_XZ || HAVE_LZ4 || HAVE_ZSTD
                 _cleanup_close_ int fdf;
 
                 fdf = open(filename, O_RDONLY | O_CLOEXEC);
index 20c752d88db24705ece07b6fbeb4417faffd6c26..7974c19a4466b7c68236d29d82a34318d92e92a2 100644 (file)
@@ -188,7 +188,11 @@ static int print_dependencies(FILE *f, const char* device_path) {
                 /* None, nothing to do */
                 return 0;
 
-        if (PATH_IN_SET(device_path, "/dev/urandom", "/dev/random", "/dev/hw_random")) {
+        if (PATH_IN_SET(device_path,
+                        "/dev/urandom",
+                        "/dev/random",
+                        "/dev/hw_random",
+                        "/dev/hwrng")) {
                 /* RNG device, add random dep */
                 fputs("After=systemd-random-seed.service\n", f);
                 return 0;
@@ -209,7 +213,9 @@ static int print_dependencies(FILE *f, const char* device_path) {
                 if (r < 0)
                         return log_error_errno(r, "Failed to generate unit name: %m");
 
-                fprintf(f, "After=%1$s\nRequires=%1$s\n", unit);
+                fprintf(f,
+                        "After=%1$s\n"
+                        "Requires=%1$s\n", unit);
         } else {
                 /* Regular file, add mount dependency */
                 _cleanup_free_ char *escaped_path = specifier_escape(device_path);
@@ -367,12 +373,12 @@ static int create_disk(
 
         if (tmp)
                 fprintf(f,
-                        "ExecStartPost=/sbin/mke2fs '/dev/mapper/%s'\n",
+                        "ExecStartPost=" ROOTLIBEXECDIR "/systemd-makefs ext2 '/dev/mapper/%s'\n",
                         name_escaped);
 
         if (swap)
                 fprintf(f,
-                        "ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n",
+                        "ExecStartPost=" ROOTLIBEXECDIR "/systemd-makefs swap '/dev/mapper/%s'\n",
                         name_escaped);
 
         if (keydev)
index ec9186a6aaa527fd59b0dfc425f48553cf6b11af..642a1b7d11a8843732d9e781d4e9e91830cc1d44 100644 (file)
@@ -10,6 +10,7 @@
 #include "alloc-util.h"
 #include "ask-password-api.h"
 #include "cryptsetup-pkcs11.h"
+#include "cryptsetup-util.h"
 #include "escape.h"
 #include "fd-util.h"
 #include "format-util.h"
 #include "stat-util.h"
 #include "strv.h"
 
-#define KEY_FILE_SIZE_MAX (16U*1024U*1024U) /* 16 MiB */
-
-static int load_key_file(
-                const char *key_file,
-                size_t key_file_size,
-                uint64_t key_file_offset,
-                void **ret_encrypted_key,
-                size_t *ret_encrypted_key_size) {
-
-        _cleanup_(erase_and_freep) char *buffer = NULL;
-        _cleanup_close_ int fd = -1;
-        ssize_t n;
-        int r;
-
-        assert(key_file);
-        assert(ret_encrypted_key);
-        assert(ret_encrypted_key_size);
-
-        fd = open(key_file, O_RDONLY|O_CLOEXEC);
-        if (fd < 0)
-                return log_error_errno(errno, "Failed to load encrypted PKCS#11 key: %m");
-
-        if (key_file_size == 0) {
-                struct stat st;
-
-                if (fstat(fd, &st) < 0)
-                        return log_error_errno(errno, "Failed to stat key file: %m");
-
-                r = stat_verify_regular(&st);
-                if (r < 0)
-                        return log_error_errno(r, "Key file is not a regular file: %m");
-
-                if (st.st_size == 0)
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file is empty, refusing.");
-                if ((uint64_t) st.st_size > KEY_FILE_SIZE_MAX) {
-                        char buf1[FORMAT_BYTES_MAX], buf2[FORMAT_BYTES_MAX];
-                        return log_error_errno(SYNTHETIC_ERRNO(ERANGE),
-                                               "Key file larger (%s) than allowed maximum size (%s), refusing.",
-                                               format_bytes(buf1, sizeof(buf1), st.st_size),
-                                               format_bytes(buf2, sizeof(buf2), KEY_FILE_SIZE_MAX));
-                }
-
-                if (key_file_offset >= (uint64_t) st.st_size)
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file offset too large for file, refusing.");
-
-                key_file_size = st.st_size - key_file_offset;
-        }
-
-        buffer = malloc(key_file_size);
-        if (!buffer)
-                return log_oom();
-
-        if (key_file_offset > 0)
-                n = pread(fd, buffer, key_file_size, key_file_offset);
-        else
-                n = read(fd, buffer, key_file_size);
-        if (n < 0)
-                return log_error_errno(errno, "Failed to read PKCS#11 key file: %m");
-        if (n == 0)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Empty encrypted key found, refusing.");
-
-        *ret_encrypted_key = TAKE_PTR(buffer);
-        *ret_encrypted_key_size = (size_t) n;
-
-        return 0;
-}
-
 struct pkcs11_callback_data {
         const char *friendly_name;
         usec_t until;
@@ -93,11 +27,14 @@ struct pkcs11_callback_data {
         size_t encrypted_key_size;
         void *decrypted_key;
         size_t decrypted_key_size;
+        bool free_encrypted_key;
 };
 
 static void pkcs11_callback_data_release(struct pkcs11_callback_data *data) {
         free(data->decrypted_key);
-        free(data->encrypted_key);
+
+        if (data->free_encrypted_key)
+                free(data->encrypted_key);
 }
 
 static int pkcs11_callback(
@@ -160,9 +97,11 @@ static int pkcs11_callback(
 int decrypt_pkcs11_key(
                 const char *friendly_name,
                 const char *pkcs11_uri,
-                const char *key_file,
+                const char *key_file,         /* We either expect key_file and associated parameters to be set (for file keys) … */
                 size_t key_file_size,
                 uint64_t key_file_offset,
+                const void *key_data,         /* … or key_data and key_data_size (for literal keys) */
+                size_t key_data_size,
                 usec_t until,
                 void **ret_decrypted_key,
                 size_t *ret_decrypted_key_size) {
@@ -175,15 +114,24 @@ int decrypt_pkcs11_key(
 
         assert(friendly_name);
         assert(pkcs11_uri);
-        assert(key_file);
+        assert(key_file || key_data);
         assert(ret_decrypted_key);
         assert(ret_decrypted_key_size);
 
         /* The functions called here log about all errors, except for EAGAIN which means "token not found right now" */
 
-        r = load_key_file(key_file, key_file_size, key_file_offset, &data.encrypted_key, &data.encrypted_key_size);
-        if (r < 0)
-                return r;
+        if (key_data) {
+                data.encrypted_key = (void*) key_data;
+                data.encrypted_key_size = key_data_size;
+
+                data.free_encrypted_key = false;
+        } else {
+                r = load_key_file(key_file, NULL, key_file_size, key_file_offset, &data.encrypted_key, &data.encrypted_key_size);
+                if (r < 0)
+                        return r;
+
+                data.free_encrypted_key = true;
+        }
 
         r = pkcs11_find_token(pkcs11_uri, pkcs11_callback, &data);
         if (r < 0)
index 264ccb66b107d279a63ec9f04cbfe0fcacbafb5c..af2487e75bdfc5d8c38dc0297af42f015d70363d 100644 (file)
@@ -14,6 +14,8 @@ int decrypt_pkcs11_key(
                 const char *key_file,
                 size_t key_file_size,
                 uint64_t key_file_offset,
+                const void *key_data,
+                size_t key_data_size,
                 usec_t until,
                 void **ret_decrypted_key,
                 size_t *ret_decrypted_key_size);
@@ -26,6 +28,8 @@ static inline int decrypt_pkcs11_key(
                 const char *key_file,
                 size_t key_file_size,
                 uint64_t key_file_offset,
+                const void *key_data,
+                size_t key_data_size,
                 usec_t until,
                 void **ret_decrypted_key,
                 size_t *ret_decrypted_key_size) {
diff --git a/src/cryptsetup/cryptsetup-util.c b/src/cryptsetup/cryptsetup-util.c
new file mode 100644 (file)
index 0000000..8ae70a5
--- /dev/null
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <unistd.h>
+
+#include "cryptsetup-util.h"
+#include "fd-util.h"
+#include "format-util.h"
+#include "memory-util.h"
+#include "path-util.h"
+#include "stat-util.h"
+#include "strv.h"
+
+#define KEY_FILE_SIZE_MAX (16U*1024U*1024U) /* 16 MiB */
+
+int load_key_file(
+                const char *key_file,
+                char **search_path,
+                size_t key_file_size,
+                uint64_t key_file_offset,
+                void **ret_key,
+                size_t *ret_key_size) {
+
+        _cleanup_(erase_and_freep) char *buffer = NULL;
+        _cleanup_free_ char *discovered_path = NULL;
+        _cleanup_close_ int fd = -1;
+        ssize_t n;
+        int r;
+
+        assert(key_file);
+        assert(ret_key);
+        assert(ret_key_size);
+
+        if (strv_isempty(search_path) || path_is_absolute(key_file)) {
+                fd = open(key_file, O_RDONLY|O_CLOEXEC);
+                if (fd < 0)
+                        return log_error_errno(errno, "Failed to load key file '%s': %m", key_file);
+        } else {
+                char **i;
+
+                STRV_FOREACH(i, search_path) {
+                        _cleanup_free_ char *joined;
+
+                        joined = path_join(*i, key_file);
+                        if (!joined)
+                                return log_oom();
+
+                        fd = open(joined, O_RDONLY|O_CLOEXEC);
+                        if (fd >= 0) {
+                                discovered_path = TAKE_PTR(joined);
+                                break;
+                        }
+                        if (errno != ENOENT)
+                                return log_error_errno(errno, "Failed to load key file '%s': %m", joined);
+                }
+
+                if (!discovered_path) {
+                        /* Search path supplied, but file not found, report by returning NULL, but not failing */
+                        *ret_key = NULL;
+                        *ret_key_size = 0;
+                        return 0;
+                }
+
+                assert(fd >= 0);
+                key_file = discovered_path;
+        }
+
+        if (key_file_size == 0) {
+                struct stat st;
+
+                if (fstat(fd, &st) < 0)
+                        return log_error_errno(errno, "Failed to stat key file '%s': %m", key_file);
+
+                r = stat_verify_regular(&st);
+                if (r < 0)
+                        return log_error_errno(r, "Key file is not a regular file: %m");
+
+                if (st.st_size == 0)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file is empty, refusing.");
+                if ((uint64_t) st.st_size > KEY_FILE_SIZE_MAX) {
+                        char buf1[FORMAT_BYTES_MAX], buf2[FORMAT_BYTES_MAX];
+                        return log_error_errno(SYNTHETIC_ERRNO(ERANGE),
+                                               "Key file larger (%s) than allowed maximum size (%s), refusing.",
+                                               format_bytes(buf1, sizeof(buf1), st.st_size),
+                                               format_bytes(buf2, sizeof(buf2), KEY_FILE_SIZE_MAX));
+                }
+
+                if (key_file_offset >= (uint64_t) st.st_size)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file offset too large for file, refusing.");
+
+                key_file_size = st.st_size - key_file_offset;
+        }
+
+        buffer = malloc(key_file_size);
+        if (!buffer)
+                return log_oom();
+
+        if (key_file_offset > 0)
+                n = pread(fd, buffer, key_file_size, key_file_offset);
+        else
+                n = read(fd, buffer, key_file_size);
+        if (n < 0)
+                return log_error_errno(errno, "Failed to read key file '%s': %m", key_file);
+        if (n == 0)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Empty encrypted key found, refusing.");
+
+        *ret_key = TAKE_PTR(buffer);
+        *ret_key_size = (size_t) n;
+
+        return 1;
+}
diff --git a/src/cryptsetup/cryptsetup-util.h b/src/cryptsetup/cryptsetup-util.h
new file mode 100644 (file)
index 0000000..7bb7822
--- /dev/null
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <inttypes.h>
+#include <sys/types.h>
+
+int load_key_file(
+                const char *key_file,
+                char **search_path,
+                size_t key_file_size,
+                uint64_t key_file_offset,
+                void **ret_key,
+                size_t *ret_key_size);
index 860b29b3b6c049aac28f1293b5d094a236c4b922..8c3eafbd61c80481011e8d780453cd3686dacdfe 100644 (file)
 #include "ask-password-api.h"
 #include "crypt-util.h"
 #include "cryptsetup-pkcs11.h"
+#include "cryptsetup-util.h"
 #include "device-util.h"
 #include "escape.h"
 #include "fileio.h"
+#include "fs-util.h"
 #include "fstab-util.h"
 #include "hexdecoct.h"
 #include "log.h"
 #include "main-func.h"
+#include "memory-util.h"
 #include "mount-util.h"
 #include "nulstr-util.h"
 #include "parse-util.h"
@@ -42,6 +45,8 @@ static unsigned arg_sector_size = CRYPT_SECTOR_SIZE;
 static int arg_key_slot = CRYPT_ANY_SLOT;
 static unsigned arg_keyfile_size = 0;
 static uint64_t arg_keyfile_offset = 0;
+static bool arg_keyfile_erase = false;
+static bool arg_try_empty_password = false;
 static char *arg_hash = NULL;
 static char *arg_header = NULL;
 static unsigned arg_tries = 3;
@@ -67,12 +72,14 @@ STATIC_DESTRUCTOR_REGISTER(arg_pkcs11_uri, freep);
 
 /* Options Debian's crypttab knows we don't:
 
-    precheck=
     check=
     checkargs=
-    noearly=
-    loud=
+    noearly
+    loud
+    quiet
     keyscript=
+    tmp= (the version without argument is supported)
+    initramfs
 */
 
 static int parse_one_option(const char *option) {
@@ -126,7 +133,8 @@ static int parse_one_option(const char *option) {
                         return 0;
                 }
 
-        } else if ((val = startswith(option, "key-slot="))) {
+        } else if ((val = startswith(option, "key-slot=")) ||
+                   (val = startswith(option, "keyslot="))) {
 
                 arg_type = ANY_LUKS;
                 r = safe_atoi(val, &arg_key_slot);
@@ -160,7 +168,20 @@ static int parse_one_option(const char *option) {
                         return 0;
                 }
 
-        } else if ((val = startswith(option, "hash="))) {
+        } else if ((val = startswith(option, "keyfile-erase="))) {
+
+                r = parse_boolean(val);
+                if (r < 0) {
+                        log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
+                        return 0;
+                }
+
+                arg_keyfile_erase = r;
+
+        } else if (streq(option, "keyfile-erase"))
+                arg_keyfile_erase = true;
+
+        else if ((val = startswith(option, "hash="))) {
                 r = free_and_strdup(&arg_hash, val);
                 if (r < 0)
                         return log_oom();
@@ -202,13 +223,13 @@ static int parse_one_option(const char *option) {
                 arg_type = ANY_LUKS;
         else if (streq(option, "tcrypt"))
                 arg_type = CRYPT_TCRYPT;
-        else if (streq(option, "tcrypt-hidden")) {
+        else if (STR_IN_SET(option, "tcrypt-hidden", "tcrypthidden")) {
                 arg_type = CRYPT_TCRYPT;
                 arg_tcrypt_hidden = true;
         } else if (streq(option, "tcrypt-system")) {
                 arg_type = CRYPT_TCRYPT;
                 arg_tcrypt_system = true;
-        } else if (streq(option, "tcrypt-veracrypt")) {
+        } else if (STR_IN_SET(option, "tcrypt-veracrypt", "veracrypt")) {
                 arg_type = CRYPT_TCRYPT;
                 arg_tcrypt_veracrypt = true;
         } else if (STR_IN_SET(option, "plain", "swap", "tmp"))
@@ -242,7 +263,20 @@ static int parse_one_option(const char *option) {
                 if (r < 0)
                         return log_oom();
 
-        } else if (!streq(option, "x-initrd.attach"))
+        } else if ((val = startswith(option, "try-empty-password="))) {
+
+                r = parse_boolean(val);
+                if (r < 0) {
+                        log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
+                        return 0;
+                }
+
+                arg_try_empty_password = r;
+
+        } else if (streq(option, "try-empty-password"))
+                arg_try_empty_password = true;
+
+        else if (!streq(option, "x-initrd.attach"))
                 log_warning("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
 
         return 0;
@@ -440,6 +474,8 @@ static int attach_tcrypt(
                 struct crypt_device *cd,
                 const char *name,
                 const char *key_file,
+                const void *key_data,
+                size_t key_data_size,
                 char **passwords,
                 uint32_t flags) {
 
@@ -453,7 +489,7 @@ static int attach_tcrypt(
 
         assert(cd);
         assert(name);
-        assert(key_file || (passwords && passwords[0]));
+        assert(key_file || key_data || !strv_isempty(passwords));
 
         if (arg_pkcs11_uri)
                 /* Ask for a regular password */
@@ -469,22 +505,33 @@ static int attach_tcrypt(
         if (arg_tcrypt_veracrypt)
                 params.flags |= CRYPT_TCRYPT_VERA_MODES;
 
-        if (key_file) {
-                r = read_one_line_file(key_file, &passphrase);
-                if (r < 0) {
-                        log_error_errno(r, "Failed to read password file '%s': %m", key_file);
-                        return -EAGAIN; /* log with the actual error, but return EAGAIN */
-                }
+        if (key_data) {
+                params.passphrase = key_data;
+                params.passphrase_size = key_data_size;
+        } else {
+                if (key_file) {
+                        r = read_one_line_file(key_file, &passphrase);
+                        if (r < 0) {
+                                log_error_errno(r, "Failed to read password file '%s': %m", key_file);
+                                return -EAGAIN; /* log with the actual error, but return EAGAIN */
+                        }
 
-                params.passphrase = passphrase;
-        } else
-                params.passphrase = passwords[0];
-        params.passphrase_size = strlen(params.passphrase);
+                        params.passphrase = passphrase;
+                } else
+                        params.passphrase = passwords[0];
+
+                params.passphrase_size = strlen(params.passphrase);
+        }
 
         r = crypt_load(cd, CRYPT_TCRYPT, &params);
         if (r < 0) {
-                if (key_file && r == -EPERM) {
-                        log_error_errno(r, "Failed to activate using password file '%s'. (Key data not correct?)", key_file);
+                if (r == -EPERM) {
+                        if (key_data)
+                                log_error_errno(r, "Failed to activate using discovered key. (Key not correct?)");
+
+                        if (key_file)
+                                log_error_errno(r, "Failed to activate using password file '%s'. (Key data not correct?)", key_file);
+
                         return -EAGAIN; /* log the actual error, but return EAGAIN */
                 }
 
@@ -502,6 +549,8 @@ static int attach_luks_or_plain(
                 struct crypt_device *cd,
                 const char *name,
                 const char *key_file,
+                const void *key_data,
+                size_t key_data_size,
                 char **passwords,
                 uint32_t flags,
                 usec_t until) {
@@ -571,7 +620,7 @@ static int attach_luks_or_plain(
                 _cleanup_free_ char *friendly = NULL;
                 size_t decrypted_key_size = 0;
 
-                if (!key_file)
+                if (!key_file && !key_data)
                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "PKCS#11 mode selected but no key file specified, refusing.");
 
                 friendly = friendly_disk_name(crypt_get_device_name(cd), name);
@@ -584,8 +633,8 @@ static int attach_luks_or_plain(
                         r = decrypt_pkcs11_key(
                                         friendly,
                                         arg_pkcs11_uri,
-                                        key_file,
-                                        arg_keyfile_size, arg_keyfile_offset,
+                                        key_file, arg_keyfile_size, arg_keyfile_offset,
+                                        key_data, key_data_size,
                                         until,
                                         &decrypted_key, &decrypted_key_size);
                         if (r >= 0)
@@ -620,7 +669,7 @@ static int attach_luks_or_plain(
                                         return log_error_errno(r, "Failed to start device monitor: %m");
 
                                 log_notice("Security token %s not present for unlocking volume %s, please plug it in.",
-                                         arg_pkcs11_uri, friendly);
+                                           arg_pkcs11_uri, friendly);
 
                                 /* Let's immediately rescan in case the token appeared in the time we needed
                                  * to create and configure the monitor */
@@ -668,6 +717,18 @@ static int attach_luks_or_plain(
                 if (r < 0)
                         return log_error_errno(r, "Failed to activate with PKCS#11 acquired key: %m");
 
+        } else if (key_data) {
+                if (pass_volume_key)
+                        r = crypt_activate_by_volume_key(cd, name, key_data, key_data_size, flags);
+                else
+                        r = crypt_activate_by_passphrase(cd, name, arg_key_slot, key_data, key_data_size, flags);
+                if (r == -EPERM) {
+                        log_error_errno(r, "Failed to activate. (Key incorrect?)");
+                        return -EAGAIN; /* Log actual error, but return EAGAIN */
+                }
+                if (r < 0)
+                        return log_error_errno(r, "Failed to activate: %m");
+
         } else if (key_file) {
                 r = crypt_activate_by_keyfile_device_offset(cd, name, arg_key_slot, key_file, arg_keyfile_size, arg_keyfile_offset, flags);
                 if (r == -EPERM) {
@@ -748,6 +809,17 @@ static uint32_t determine_flags(void) {
         return flags;
 }
 
+static void remove_and_erasep(const char **p) {
+        int r;
+
+        if (!*p)
+                return;
+
+        r = unlinkat_deallocate(AT_FDCWD, *p, UNLINK_ERASE);
+        if (r < 0 && r != -ENOENT)
+                log_warning_errno(r, "Unable to erase key file '%s', ignoring: %m", *p);
+}
+
 static int run(int argc, char *argv[]) {
         _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
         int r;
@@ -774,13 +846,19 @@ static int run(int argc, char *argv[]) {
                 unsigned tries;
                 usec_t until;
                 crypt_status_info status;
+                _cleanup_(remove_and_erasep) const char *destroy_key_file = NULL;
                 const char *key_file = NULL;
+                _cleanup_(erase_and_freep) void *key_data = NULL;
+                size_t key_data_size = 0;
 
                 /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
 
                 if (argc < 4)
                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "attach requires at least two arguments.");
 
+                if (!filename_is_valid(argv[2]))
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", argv[2]);
+
                 if (argc >= 5 && !STR_IN_SET(argv[4], "", "-", "none")) {
                         if (path_is_absolute(argv[4]))
                                 key_file = argv[4];
@@ -797,6 +875,24 @@ static int run(int argc, char *argv[]) {
                 /* A delicious drop of snake oil */
                 (void) mlockall(MCL_FUTURE);
 
+                if (!key_file) {
+                        const char *fn;
+
+                        /* If a key file is not explicitly specified, search for a key in a well defined
+                         * search path, and load it. */
+
+                        fn = strjoina(argv[2], ".key");
+                        r = load_key_file(fn,
+                                          STRV_MAKE("/etc/cryptsetup-keys.d", "/run/cryptsetup-keys.d"),
+                                          0, 0,  /* Note we leave arg_keyfile_offset/arg_keyfile_size as something that only applies to arg_keyfile! */
+                                          &key_data, &key_data_size);
+                        if (r < 0)
+                                return r;
+                        if (r > 0)
+                                log_debug("Automatically discovered key for volume '%s'.", argv[2]);
+                } else if (arg_keyfile_erase)
+                        destroy_key_file = key_file; /* let's get this baby erased when we leave */
+
                 if (arg_header) {
                         log_debug("LUKS header: %s", arg_header);
                         r = crypt_init(&cd, arg_header);
@@ -843,7 +939,7 @@ static int run(int argc, char *argv[]) {
                         }
 
                         /* Tokens are available in LUKS2 only, but it is ok to call (and fail) with LUKS1. */
-                        if (!key_file) {
+                        if (!key_file && !key_data) {
                                 r = crypt_activate_by_token(cd, argv[2], CRYPT_ANY_TOKEN, NULL, flags);
                                 if (r >= 0) {
                                         log_debug("Volume %s activated with LUKS token id %i.", argv[2], r);
@@ -857,26 +953,53 @@ static int run(int argc, char *argv[]) {
                 for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
                         _cleanup_strv_free_erase_ char **passwords = NULL;
 
-                        if (!key_file && !arg_pkcs11_uri) {
-                                r = get_password(argv[2], argv[3], until, tries == 0 && !arg_verify, &passwords);
-                                if (r == -EAGAIN)
-                                        continue;
-                                if (r < 0)
-                                        return r;
+                        /* When we were able to acquire multiple keys, let's always process them in this order:
+                         *
+                         *    1. A key acquired via PKCS#11 token
+                         *    2. The discovered key: i.e. key_data + key_data_size
+                         *    3. The configured key: i.e. key_file + arg_keyfile_offset + arg_keyfile_size
+                         *    4. The empty password, in case arg_try_empty_password is set
+                         *    5. We enquire the user for a password
+                         */
+
+                        if (!key_file && !key_data && !arg_pkcs11_uri) {
+
+                                if (arg_try_empty_password) {
+                                        /* Hmm, let's try an empty password now, but only once */
+                                        arg_try_empty_password = false;
+
+                                        key_data = strdup("");
+                                        if (!key_data)
+                                                return log_oom();
+
+                                        key_data_size = 0;
+                                } else {
+                                        /* Ask the user for a passphrase only as last resort, if we have
+                                         * nothing else to check for */
+
+                                        r = get_password(argv[2], argv[3], until, tries == 0 && !arg_verify, &passwords);
+                                        if (r == -EAGAIN)
+                                                continue;
+                                        if (r < 0)
+                                                return r;
+                                }
                         }
 
                         if (streq_ptr(arg_type, CRYPT_TCRYPT))
-                                r = attach_tcrypt(cd, argv[2], key_file, passwords, flags);
+                                r = attach_tcrypt(cd, argv[2], key_file, key_data, key_data_size, passwords, flags);
                         else
-                                r = attach_luks_or_plain(cd, argv[2], key_file, passwords, flags, until);
+                                r = attach_luks_or_plain(cd, argv[2], key_file, key_data, key_data_size, passwords, flags, until);
                         if (r >= 0)
                                 break;
                         if (r != -EAGAIN)
                                 return r;
 
-                        /* Passphrase not correct? Let's try again! */
+                        /* Key not correct? Let's try again! */
+
                         key_file = NULL;
-                        arg_pkcs11_uri = NULL;
+                        key_data = erase_and_free(key_data);
+                        key_data_size = 0;
+                        arg_pkcs11_uri = mfree(arg_pkcs11_uri);
                 }
 
                 if (arg_tries != 0 && tries >= arg_tries)
@@ -884,6 +1007,9 @@ static int run(int argc, char *argv[]) {
 
         } else if (streq(argv[1], "detach")) {
 
+                if (!filename_is_valid(argv[2]))
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", argv[2]);
+
                 r = crypt_init_by_name(&cd, argv[2]);
                 if (r == -ENODEV) {
                         log_info("Volume %s already inactive.", argv[2]);
index 901fbf081591347bc2b480ed7097ee3b9f24dd2a..f9fdf7b1d7fc67c755856b81953018e37e1eb627 100644 (file)
@@ -205,6 +205,14 @@ static int prompt_loop(const char *text, char **l, unsigned percentage, bool (*i
         }
 }
 
+static bool locale_is_ok(const char *name) {
+
+        if (arg_root)
+                return locale_is_valid(name);
+
+        return locale_is_installed(name) > 0;
+}
+
 static int prompt_locale(void) {
         _cleanup_strv_free_ char **locales = NULL;
         int r;
@@ -238,7 +246,7 @@ static int prompt_locale(void) {
                 print_welcome();
 
                 r = prompt_loop("Please enter system locale name or number",
-                                locales, 60, locale_is_valid, &arg_locale);
+                                locales, 60, locale_is_ok, &arg_locale);
                 if (r < 0)
                         return r;
 
@@ -246,7 +254,7 @@ static int prompt_locale(void) {
                         return 0;
 
                 r = prompt_loop("Please enter system message locale name or number",
-                                locales, 60, locale_is_valid, &arg_locale_messages);
+                                locales, 60, locale_is_ok, &arg_locale_messages);
                 if (r < 0)
                         return r;
 
@@ -691,7 +699,7 @@ static int help(void) {
                "     --locale-messages=LOCALE  Set message locale (LC_MESSAGES=)\n"
                "     --keymap=KEYMAP           Set keymap\n"
                "     --timezone=TIMEZONE       Set timezone\n"
-               "     --hostname=NAME           Set host name\n"
+               "     --hostname=NAME           Set hostname\n"
                "     --machine-ID=ID           Set machine ID\n"
                "     --root-password=PASSWORD  Set root password\n"
                "     --root-password-file=FILE Set root password from file\n"
@@ -791,10 +799,6 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_LOCALE:
-                        if (!locale_is_valid(optarg))
-                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                                       "Locale %s is not valid.", optarg);
-
                         r = free_and_strdup(&arg_locale, optarg);
                         if (r < 0)
                                 return log_oom();
@@ -802,10 +806,6 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_LOCALE_MESSAGES:
-                        if (!locale_is_valid(optarg))
-                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                                       "Locale %s is not valid.", optarg);
-
                         r = free_and_strdup(&arg_locale_messages, optarg);
                         if (r < 0)
                                 return log_oom();
@@ -927,6 +927,14 @@ static int parse_argv(int argc, char *argv[]) {
                         assert_not_reached("Unhandled option");
                 }
 
+        /* We check if the specified locale strings are valid down here, so that we can take --root= into
+         * account when looking for the locale files. */
+
+        if (arg_locale && !locale_is_ok(arg_locale))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Locale %s is not installed.", arg_locale);
+        if (arg_locale_messages && !locale_is_ok(arg_locale_messages))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Locale %s is not installed.", arg_locale_messages);
+
         return 1;
 }
 
index 08c7b76dbaeb9378772f4b02289398aa8b22bc9e..36a8ff23d4c3a9a48e13f83b331b5f72e844dd12 100644 (file)
@@ -35,6 +35,7 @@ typedef enum MountpointFlags {
         AUTOMOUNT = 1 << 2,
         MAKEFS    = 1 << 3,
         GROWFS    = 1 << 4,
+        RWONLY    = 1 << 5,
 } MountpointFlags;
 
 static const char *arg_dest = NULL;
@@ -391,12 +392,6 @@ static int add_mount(
                 "SourcePath=%s\n",
                 source);
 
-        /* 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. */
-        if (in_initrd() && path_startswith(where, "/sysroot"))
-                fprintf(f, "DefaultDependencies=no\n");
-
         if (STRPTR_IN_SET(fstype, "nfs", "nfs4") && !(flags & AUTOMOUNT) &&
             fstab_test_yes_no_option(opts, "bg\0" "fg\0")) {
                 /* The default retry timeout that mount.nfs uses for 'bg' mounts
@@ -411,9 +406,6 @@ static int add_mount(
                 SET_FLAG(flags, NOFAIL, true);
         }
 
-        if (!(flags & NOFAIL) && !(flags & AUTOMOUNT))
-                fprintf(f, "Before=%s\n", post);
-
         if (!(flags & AUTOMOUNT) && opts) {
                  r = write_after(f, opts);
                  if (r < 0)
@@ -481,6 +473,9 @@ static int add_mount(
         if (r < 0)
                 return r;
 
+        if (flags & RWONLY)
+                fprintf(f, "ReadWriteOnly=yes\n");
+
         r = fflush_and_check(f);
         if (r < 0)
                 return log_error_errno(r, "Failed to write unit file %s: %m", name);
@@ -535,8 +530,6 @@ static int add_mount(
                         "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
                         source);
 
-                fprintf(f, "Before=%s\n", post);
-
                 if (opts) {
                         r = write_after(f, opts);
                         if (r < 0)
@@ -594,7 +587,7 @@ static int parse_fstab(bool initrd) {
 
         while ((me = getmntent(f))) {
                 _cleanup_free_ char *where = NULL, *what = NULL, *canonical_where = NULL;
-                bool makefs, growfs, noauto, nofail;
+                bool makefs, growfs, noauto, nofail, rwonly;
                 int k;
 
                 if (initrd && !mount_in_initrd(me))
@@ -634,6 +627,7 @@ static int parse_fstab(bool initrd) {
 
                 makefs = fstab_test_option(me->mnt_opts, "x-systemd.makefs\0");
                 growfs = fstab_test_option(me->mnt_opts, "x-systemd.growfs\0");
+                rwonly = fstab_test_option(me->mnt_opts, "x-systemd.rw-only\0");
                 noauto = fstab_test_yes_no_option(me->mnt_opts, "noauto\0" "auto\0");
                 nofail = fstab_test_yes_no_option(me->mnt_opts, "nofail\0" "fail\0");
 
@@ -666,7 +660,7 @@ static int parse_fstab(bool initrd) {
                                       me->mnt_type,
                                       me->mnt_opts,
                                       me->mnt_passno,
-                                      makefs*MAKEFS | growfs*GROWFS | noauto*NOAUTO | nofail*NOFAIL | automount*AUTOMOUNT,
+                                      makefs*MAKEFS | growfs*GROWFS | noauto*NOAUTO | nofail*NOFAIL | automount*AUTOMOUNT | rwonly*RWONLY,
                                       post,
                                       fstab);
                 }
@@ -809,7 +803,7 @@ static int add_volatile_var(void) {
                          "/var",
                          NULL,
                          "tmpfs",
-                         "mode=0755",
+                         "mode=0755" TMPFS_LIMITS_VAR,
                          0,
                          0,
                          SPECIAL_LOCAL_FS_TARGET,
index 69ab645484d8377ed0629015d73fc5249c6f9c32..3fd57639f84192d0a329ed8a8e5554cf57d44d0a 100644 (file)
@@ -64,6 +64,12 @@ int suitable_image_path(const char *path) {
                 path_is_absolute(path);
 }
 
+bool supported_fstype(const char *fstype) {
+        /* Limit the set of supported file systems a bit, as protection against little tested kernel file
+         * systems. Also, we only support the resize ioctls for these file systems. */
+        return STR_IN_SET(fstype, "ext4", "btrfs", "xfs");
+}
+
 int split_user_name_realm(const char *t, char **ret_user_name, char **ret_realm) {
         _cleanup_free_ char *user_name = NULL, *realm = NULL;
         const char *c;
@@ -124,6 +130,8 @@ int bus_message_append_secret(sd_bus_message *m, UserRecord *secret) {
         if (r < 0)
                 return r;
 
+        (void) sd_bus_message_sensitive(m);
+
         return sd_bus_message_append(m, "s", formatted);
 }
 
index df20c0af71e57d6a3494442df1917b220aadb88e..78d6e7b41768340b840d2f30ec3d978e2711b342 100644 (file)
@@ -12,6 +12,8 @@ bool suitable_user_name(const char *name);
 int suitable_realm(const char *realm);
 int suitable_image_path(const char *path);
 
+bool supported_fstype(const char *fstype);
+
 int split_user_name_realm(const char *t, char **ret_user_name, char **ret_realm);
 
 int bus_message_append_secret(sd_bus_message *m, UserRecord *secret);
index 6ba8e7fa2929b2de138f3722565905a9167be454..e9eb7c0ddbcee38dde01763a620f22ef5ebf17b4 100644 (file)
@@ -66,12 +66,6 @@ static enum {
         EXPORT_FORMAT_MINIMAL,       /* also strip signature */
 } arg_export_format = EXPORT_FORMAT_FULL;
 
-static const BusLocator home_mgr = {
-        .destination = "org.freedesktop.home1",
-        .path = "/org/freedesktop/home1",
-        .interface = "org.freedesktop.home1.Manager",
-};
-
 STATIC_DESTRUCTOR_REGISTER(arg_identity_extra, json_variant_unrefp);
 STATIC_DESTRUCTOR_REGISTER(arg_identity_extra_this_machine, json_variant_unrefp);
 STATIC_DESTRUCTOR_REGISTER(arg_identity_extra_privileged, json_variant_unrefp);
@@ -122,7 +116,7 @@ static int list_homes(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return r;
 
-        r = bus_call_method(bus, &home_mgr, "ListHomes", &error, &reply, NULL);
+        r = bus_call_method(bus, bus_home_mgr, "ListHomes", &error, &reply, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to list homes: %s", bus_error_message(&error, r));
 
@@ -190,9 +184,9 @@ static int list_homes(int argc, char *argv[], void *userdata) {
 
         if (arg_legend && !arg_json) {
                 if (table_get_rows(table) > 1)
-                        printf("\n%zu homes listed.\n", table_get_rows(table) - 1);
+                        printf("\n%zu home areas listed.\n", table_get_rows(table) - 1);
                 else
-                        printf("No homes.\n");
+                        printf("No home areas.\n");
         }
 
         return 0;
@@ -385,7 +379,7 @@ static int activate_home(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 *m = NULL;
 
-                        r = bus_message_new_method_call(bus, &m, &home_mgr, "ActivateHome");
+                        r = bus_message_new_method_call(bus, &m, bus_home_mgr, "ActivateHome");
                         if (r < 0)
                                 return bus_log_create_error(r);
 
@@ -427,7 +421,7 @@ static int deactivate_home(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 *m = NULL;
 
-                r = bus_message_new_method_call(bus, &m, &home_mgr, "DeactivateHome");
+                r = bus_message_new_method_call(bus, &m, bus_home_mgr, "DeactivateHome");
                 if (r < 0)
                         return bus_log_create_error(r);
 
@@ -534,9 +528,9 @@ static int inspect_home(int argc, char *argv[], void *userdata) {
                                 continue;
                         }
 
-                        r = bus_call_method(bus, &home_mgr, "GetUserRecordByName", &error, &reply, "s", *i);
+                        r = bus_call_method(bus, bus_home_mgr, "GetUserRecordByName", &error, &reply, "s", *i);
                 } else
-                        r = bus_call_method(bus, &home_mgr, "GetUserRecordByUID", &error, &reply, "u", (uint32_t) uid);
+                        r = bus_call_method(bus, bus_home_mgr, "GetUserRecordByUID", &error, &reply, "u", (uint32_t) uid);
 
                 if (r < 0) {
                         log_error_errno(r, "Failed to inspect home: %s", bus_error_message(&error, r));
@@ -610,7 +604,7 @@ static int authenticate_home(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 *m = NULL;
 
-                        r = bus_message_new_method_call(bus, &m, &home_mgr, "AuthenticateHome");
+                        r = bus_message_new_method_call(bus, &m, bus_home_mgr, "AuthenticateHome");
                         if (r < 0)
                                 return bus_log_create_error(r);
 
@@ -1431,10 +1425,12 @@ static int create_home(int argc, char *argv[], void *userdata) {
                 if (r < 0)
                         return r;
 
-                r = bus_message_new_method_call(bus, &m, &home_mgr, "CreateHome");
+                r = bus_message_new_method_call(bus, &m, bus_home_mgr, "CreateHome");
                 if (r < 0)
                         return bus_log_create_error(r);
 
+                (void) sd_bus_message_sensitive(m);
+
                 r = sd_bus_message_append(m, "s", formatted);
                 if (r < 0)
                         return bus_log_create_error(r);
@@ -1480,7 +1476,7 @@ static int remove_home(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 *m = NULL;
 
-                r = bus_message_new_method_call(bus, &m, &home_mgr, "RemoveHome");
+                r = bus_message_new_method_call(bus, &m, bus_home_mgr, "RemoveHome");
                 if (r < 0)
                         return bus_log_create_error(r);
 
@@ -1543,7 +1539,7 @@ static int acquire_updated_home_record(
                 if (!identity_properties_specified())
                         return log_error_errno(SYNTHETIC_ERRNO(EALREADY), "No field to change specified.");
 
-                r = bus_call_method(bus, &home_mgr, "GetUserRecordByName", &error, &reply, "s", username);
+                r = bus_call_method(bus, bus_home_mgr, "GetUserRecordByName", &error, &reply, "s", username);
                 if (r < 0)
                         return log_error_errno(r, "Failed to acquire user home record: %s", bus_error_message(&error, r));
 
@@ -1629,7 +1625,7 @@ static int update_home(int argc, char *argv[], void *userdata) {
                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
                 _cleanup_free_ char *formatted = NULL;
 
-                r = bus_message_new_method_call(bus, &m, &home_mgr, "UpdateHome");
+                r = bus_message_new_method_call(bus, &m, bus_home_mgr, "UpdateHome");
                 if (r < 0)
                         return bus_log_create_error(r);
 
@@ -1637,6 +1633,8 @@ static int update_home(int argc, char *argv[], void *userdata) {
                 if (r < 0)
                         return r;
 
+                (void) sd_bus_message_sensitive(m);
+
                 r = sd_bus_message_append(m, "s", formatted);
                 if (r < 0)
                         return bus_log_create_error(r);
@@ -1664,7 +1662,7 @@ static int update_home(int argc, char *argv[], void *userdata) {
 
                 log_debug("Resizing");
 
-                r = bus_message_new_method_call(bus, &m, &home_mgr, "ResizeHome");
+                r = bus_message_new_method_call(bus, &m, bus_home_mgr, "ResizeHome");
                 if (r < 0)
                         return bus_log_create_error(r);
 
@@ -1697,7 +1695,7 @@ static int update_home(int argc, char *argv[], void *userdata) {
 
                 log_debug("Propagating password");
 
-                r = bus_message_new_method_call(bus, &m, &home_mgr, "ChangePasswordHome");
+                r = bus_message_new_method_call(bus, &m, bus_home_mgr, "ChangePasswordHome");
                 if (r < 0)
                         return bus_log_create_error(r);
 
@@ -1769,7 +1767,7 @@ static int passwd_home(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 *m = NULL;
 
-                r = bus_message_new_method_call(bus, &m, &home_mgr, "ChangePasswordHome");
+                r = bus_message_new_method_call(bus, &m, bus_home_mgr, "ChangePasswordHome");
                 if (r < 0)
                         return bus_log_create_error(r);
 
@@ -1848,7 +1846,7 @@ static int resize_home(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 *m = NULL;
 
-                r = bus_message_new_method_call(bus, &m, &home_mgr, "ResizeHome");
+                r = bus_message_new_method_call(bus, &m, bus_home_mgr, "ResizeHome");
                 if (r < 0)
                         return bus_log_create_error(r);
 
@@ -1885,7 +1883,7 @@ static int lock_home(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 *m = NULL;
 
-                r = bus_message_new_method_call(bus, &m, &home_mgr, "LockHome");
+                r = bus_message_new_method_call(bus, &m, bus_home_mgr, "LockHome");
                 if (r < 0)
                         return bus_log_create_error(r);
 
@@ -1924,7 +1922,7 @@ static int unlock_home(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 *m = NULL;
 
-                        r = bus_message_new_method_call(bus, &m, &home_mgr, "UnlockHome");
+                        r = bus_message_new_method_call(bus, &m, bus_home_mgr, "UnlockHome");
                         if (r < 0)
                                 return bus_log_create_error(r);
 
@@ -1987,7 +1985,7 @@ static int with_home(int argc, char *argv[], void *userdata) {
                 return log_oom();
 
         for (;;) {
-                r = bus_message_new_method_call(bus, &m, &home_mgr, "AcquireHome");
+                r = bus_message_new_method_call(bus, &m, bus_home_mgr, "AcquireHome");
                 if (r < 0)
                         return bus_log_create_error(r);
 
@@ -2027,7 +2025,7 @@ static int with_home(int argc, char *argv[], void *userdata) {
                 }
         }
 
-        r = bus_call_method(bus, &home_mgr, "GetHomeByName", &error, &reply, "s", argv[1]);
+        r = bus_call_method(bus, bus_home_mgr, "GetHomeByName", &error, &reply, "s", argv[1]);
         if (r < 0)
                 return log_error_errno(r, "Failed to inspect home: %s", bus_error_message(&error, r));
 
@@ -2054,7 +2052,7 @@ static int with_home(int argc, char *argv[], void *userdata) {
         /* Close the fd that pings the home now. */
         acquired_fd = safe_close(acquired_fd);
 
-        r = bus_message_new_method_call(bus, &m, &home_mgr, "ReleaseHome");
+        r = bus_message_new_method_call(bus, &m, bus_home_mgr, "ReleaseHome");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -2083,7 +2081,7 @@ static int lock_all_homes(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return r;
 
-        r = bus_message_new_method_call(bus, &m, &home_mgr, "LockAllHomes");
+        r = bus_message_new_method_call(bus, &m, bus_home_mgr, "LockAllHomes");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -2134,20 +2132,20 @@ static int help(int argc, char *argv[], void *userdata) {
         printf("%1$s [OPTIONS...] COMMAND ...\n\n"
                "%2$sCreate, manipulate or inspect home directories.%3$s\n"
                "\n%4$sCommands:%5$s\n"
-               "  list                        List homes\n"
-               "  activate USER…              Activate home\n"
-               "  deactivate USER…            Deactivate home\n"
-               "  inspect USER…               Inspect home\n"
-               "  authenticate USER…          Authenticate home\n"
+               "  list                        List home areas\n"
+               "  activate USER…              Activate a home area\n"
+               "  deactivate USER…            Deactivate a home area\n"
+               "  inspect USER…               Inspect a home area\n"
+               "  authenticate USER…          Authenticate a home area\n"
                "  create USER                 Create a home area\n"
                "  remove USER…                Remove a home area\n"
                "  update USER                 Update a home area\n"
                "  passwd USER                 Change password of a home area\n"
                "  resize USER SIZE            Resize a home area\n"
-               "  lock USER…                  Temporarily lock an active home\n"
-               "  unlock USER…                Unlock a temporarily locked home\n"
-               "  lock-all                    Lock all suitable homes\n"
-               "  with USER [COMMAND…]        Run shell or command with access to home\n"
+               "  lock USER…                  Temporarily lock an active home area\n"
+               "  unlock USER…                Unlock a temporarily locked home area\n"
+               "  lock-all                    Lock all suitable home areas\n"
+               "  with USER [COMMAND…]        Run shell or command with access to a home area\n"
                "\n%4$sOptions:%5$s\n"
                "  -h --help                   Show this help\n"
                "     --version                Show package version\n"
@@ -2228,6 +2226,9 @@ static int help(int argc, char *argv[], void *userdata) {
                "     --fs-type=TYPE           File system type to use in case of luks\n"
                "                              storage (ext4, xfs, btrfs)\n"
                "     --luks-discard=BOOL      Whether to use 'discard' feature of file system\n"
+               "                              when activated (mounted)\n"
+               "     --luks-offline-discard=BOOL\n"
+               "                              Whether to trim file on logout\n"
                "     --luks-cipher=CIPHER     Cipher to use for LUKS encryption\n"
                "     --luks-cipher-mode=MODE  Cipher mode to use for LUKS encryption\n"
                "     --luks-volume-key-size=BITS\n"
@@ -2248,7 +2249,7 @@ static int help(int argc, char *argv[], void *userdata) {
                "\n%4$sCIFS User Record Properties:%5$s\n"
                "     --cifs-domain=DOMAIN     CIFS (Windows) domain\n"
                "     --cifs-user-name=USER    CIFS (Windows) user name\n"
-               "     --cifs-service=SERVICE   CIFS (Windows) service to mount as home\n"
+               "     --cifs-service=SERVICE   CIFS (Windows) service to mount as home area\n"
                "\n%4$sLogin Behaviour User Record Properties:%5$s\n"
                "     --stop-delay=SECS        How long to leave user services running after\n"
                "                              logout\n"
@@ -2281,6 +2282,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_IMAGE_PATH,
                 ARG_UMASK,
                 ARG_LUKS_DISCARD,
+                ARG_LUKS_OFFLINE_DISCARD,
                 ARG_JSON,
                 ARG_SETENV,
                 ARG_TIMEZONE,
@@ -2374,6 +2376,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "image-path",                  required_argument, NULL, ARG_IMAGE_PATH                  },
                 { "fs-type",                     required_argument, NULL, ARG_FS_TYPE                     },
                 { "luks-discard",                required_argument, NULL, ARG_LUKS_DISCARD                },
+                { "luks-offline-discard",        required_argument, NULL, ARG_LUKS_OFFLINE_DISCARD        },
                 { "luks-cipher",                 required_argument, NULL, ARG_LUKS_CIPHER                 },
                 { "luks-cipher-mode",            required_argument, NULL, ARG_LUKS_CIPHER_MODE            },
                 { "luks-volume-key-size",        required_argument, NULL, ARG_LUKS_VOLUME_KEY_SIZE        },
@@ -2803,6 +2806,9 @@ static int parse_argv(int argc, char *argv[]) {
                         if (!locale_is_valid(optarg))
                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Locale '%s' is not valid.", optarg);
 
+                        if (locale_is_installed(optarg) <= 0)
+                                log_warning("Locale '%s' is not installed, accepting anyway.", optarg);
+
                         r = json_variant_set_field_string(&arg_identity_extra, "preferredLanguage", optarg);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to set preferredLanguage field: %m");
@@ -2943,6 +2949,25 @@ static int parse_argv(int argc, char *argv[]) {
 
                         break;
 
+                case ARG_LUKS_OFFLINE_DISCARD:
+                        if (isempty(optarg)) {
+                                r = drop_from_identity("luksOfflineDiscard");
+                                if (r < 0)
+                                        return r;
+
+                                break;
+                        }
+
+                        r = parse_boolean(optarg);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to parse --luks-offline-discard= parameter: %s", optarg);
+
+                        r = json_variant_set_field_boolean(&arg_identity_extra, "luksOfflineDiscard", r);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to set offline discard field: %m");
+
+                        break;
+
                 case ARG_LUKS_VOLUME_KEY_SIZE:
                 case ARG_LUKS_PBKDF_PARALLEL_THREADS:
                 case ARG_RATE_LIMIT_BURST: {
diff --git a/src/home/homed-conf.c b/src/home/homed-conf.c
new file mode 100644 (file)
index 0000000..14ec8b3
--- /dev/null
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "conf-parser.h"
+#include "def.h"
+#include "home-util.h"
+#include "homed-conf.h"
+
+int manager_parse_config_file(Manager *m) {
+        int r;
+
+        assert(m);
+
+        r = config_parse_many_nulstr(PKGSYSCONFDIR "/homed.conf",
+                                     CONF_PATHS_NULSTR("systemd/homed.conf.d"),
+                                     "Home\0",
+                                     config_item_perf_lookup, homed_gperf_lookup,
+                                     CONFIG_PARSE_WARN, m);
+        if (r < 0)
+                return r;
+
+        return 0;
+
+}
+
+DEFINE_CONFIG_PARSE_ENUM(config_parse_default_storage, user_storage, UserStorage, "Failed to parse default storage setting");
+
+int config_parse_default_file_system_type(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        char **s = data;
+
+        assert(rvalue);
+        assert(s);
+
+        if (!isempty(rvalue) && !supported_fstype(rvalue)) {
+                log_syntax(unit, LOG_ERR, filename, line, 0, "Unsupported file system, ignoring: %s", rvalue);
+                return 0;
+        }
+
+        return free_and_strdup_warn(s, empty_to_null(rvalue));
+
+}
diff --git a/src/home/homed-conf.h b/src/home/homed-conf.h
new file mode 100644 (file)
index 0000000..00eb3fd
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include "conf-parser.h"
+#include "homed-manager.h"
+
+int manager_parse_config_file(Manager *m);
+
+const struct ConfigPerfItem* homed_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
+
+CONFIG_PARSER_PROTOTYPE(config_parse_default_storage);
+CONFIG_PARSER_PROTOTYPE(config_parse_default_file_system_type);
diff --git a/src/home/homed-gperf.gperf b/src/home/homed-gperf.gperf
new file mode 100644 (file)
index 0000000..970da5f
--- /dev/null
@@ -0,0 +1,21 @@
+%{
+#if __GNUC__ >= 7
+_Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
+#endif
+#include <stddef.h>
+#include "conf-parser.h"
+#include "homed-conf.h"
+%}
+struct ConfigPerfItem;
+%null_strings
+%language=ANSI-C
+%define slot-name section_and_lvalue
+%define hash-function-name homed_gperf_hash
+%define lookup-function-name homed_gperf_lookup
+%readonly-tables
+%omit-struct-type
+%struct-type
+%includes
+%%
+Home.DefaultStorage,        config_parse_default_storage,          0, offsetof(Manager, default_storage)
+Home.DefaultFileSystemType, config_parse_default_file_system_type, 0, offsetof(Manager, default_file_system_type)
index 6b4fa58a6f62b1862667b39fb6e582703455f122..6be361a5aace96b4847e288c4b78a78b428e7ae2 100644 (file)
@@ -712,38 +712,13 @@ int bus_home_method_release(
 /* We map a uid_t as uint32_t bus property, let's ensure this is safe. */
 assert_cc(sizeof(uid_t) == sizeof(uint32_t));
 
-const sd_bus_vtable home_vtable[] = {
-        SD_BUS_VTABLE_START(0),
-        SD_BUS_PROPERTY("UserName", "s", NULL, offsetof(Home, user_name), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("UID", "u", NULL, offsetof(Home, uid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
-        SD_BUS_PROPERTY("UnixRecord", "(suusss)", property_get_unix_record, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
-        SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
-        SD_BUS_PROPERTY("UserRecord", "(sb)", property_get_user_record, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION|SD_BUS_VTABLE_SENSITIVE),
-        SD_BUS_METHOD("Activate", "s", NULL, bus_home_method_activate, SD_BUS_VTABLE_SENSITIVE),
-        SD_BUS_METHOD("Deactivate", NULL, NULL, bus_home_method_deactivate, 0),
-        SD_BUS_METHOD("Unregister", NULL, NULL, bus_home_method_unregister, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("Realize", "s", NULL, bus_home_method_realize, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
-        SD_BUS_METHOD("Remove", NULL, NULL, bus_home_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("Fixate", "s", NULL, bus_home_method_fixate, SD_BUS_VTABLE_SENSITIVE),
-        SD_BUS_METHOD("Authenticate", "s", NULL, bus_home_method_authenticate, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
-        SD_BUS_METHOD("Update", "s", NULL, bus_home_method_update, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
-        SD_BUS_METHOD("Resize", "ts", NULL, bus_home_method_resize, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
-        SD_BUS_METHOD("ChangePassword", "ss", NULL, bus_home_method_change_password, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
-        SD_BUS_METHOD("Lock", NULL, NULL, bus_home_method_lock, 0),
-        SD_BUS_METHOD("Unlock", "s", NULL, bus_home_method_unlock, SD_BUS_VTABLE_SENSITIVE),
-        SD_BUS_METHOD("Acquire", "sb", "h", bus_home_method_acquire, SD_BUS_VTABLE_SENSITIVE),
-        SD_BUS_METHOD("Ref", "b", "h", bus_home_method_ref, 0),
-        SD_BUS_METHOD("Release", NULL, NULL, bus_home_method_release, 0),
-        SD_BUS_VTABLE_END
-};
-
 int bus_home_path(Home *h, char **ret) {
         assert(ret);
 
         return sd_bus_path_encode("/org/freedesktop/home1/home", h->user_name, ret);
 }
 
-int bus_home_object_find(
+static int bus_home_object_find(
                 sd_bus *bus,
                 const char *path,
                 const char *interface,
@@ -772,7 +747,7 @@ int bus_home_object_find(
         return 1;
 }
 
-int bus_home_node_enumerator(
+static int bus_home_node_enumerator(
                 sd_bus *bus,
                 const char *path,
                 void *userdata,
@@ -802,6 +777,107 @@ int bus_home_node_enumerator(
         return 1;
 }
 
+const sd_bus_vtable home_vtable[] = {
+        SD_BUS_VTABLE_START(0),
+
+        SD_BUS_PROPERTY("UserName", "s",
+                        NULL, offsetof(Home, user_name),
+                        SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("UID", "u",
+                        NULL, offsetof(Home, uid),
+                        SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("UnixRecord", "(suusss)",
+                        property_get_unix_record, 0,
+                        SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("State", "s",
+                        property_get_state, 0,
+                        0),
+        SD_BUS_PROPERTY("UserRecord", "(sb)",
+                        property_get_user_record, 0,
+                        SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION|SD_BUS_VTABLE_SENSITIVE),
+
+        SD_BUS_METHOD_WITH_NAMES("Activate",
+                                 "s",
+                                 SD_BUS_PARAM(secret),
+                                 NULL,,
+                                 bus_home_method_activate,
+                                 SD_BUS_VTABLE_SENSITIVE),
+        SD_BUS_METHOD("Deactivate", NULL, NULL, bus_home_method_deactivate, 0),
+        SD_BUS_METHOD("Unregister", NULL, NULL, bus_home_method_unregister, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_NAMES("Realize",
+                                 "s",
+                                 SD_BUS_PARAM(secret),
+                                 NULL,,
+                                 bus_home_method_realize,
+                                 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+
+        SD_BUS_METHOD("Remove", NULL, NULL, bus_home_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_NAMES("Fixate",
+                                 "s",
+                                 SD_BUS_PARAM(secret),
+                                 NULL,,
+                                 bus_home_method_fixate,
+                                 SD_BUS_VTABLE_SENSITIVE),
+        SD_BUS_METHOD_WITH_NAMES("Authenticate",
+                                 "s",
+                                 SD_BUS_PARAM(secret),
+                                 NULL,,
+                                 bus_home_method_authenticate,
+                                 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+        SD_BUS_METHOD_WITH_NAMES("Update",
+                                 "s",
+                                 SD_BUS_PARAM(user_record),
+                                 NULL,,
+                                 bus_home_method_update,
+                                 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+        SD_BUS_METHOD_WITH_NAMES("Resize",
+                                 "ts",
+                                 SD_BUS_PARAM(size)
+                                 SD_BUS_PARAM(secret),
+                                 NULL,,
+                                 bus_home_method_resize,
+                                 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+        SD_BUS_METHOD_WITH_NAMES("ChangePassword",
+                                 "ss",
+                                 SD_BUS_PARAM(new_secret)
+                                 SD_BUS_PARAM(old_secret),
+                                 NULL,,
+                                 bus_home_method_change_password,
+                                 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+        SD_BUS_METHOD("Lock", NULL, NULL, bus_home_method_lock, 0),
+        SD_BUS_METHOD_WITH_NAMES("Unlock",
+                                 "s",
+                                 SD_BUS_PARAM(secret),
+                                 NULL,,
+                                 bus_home_method_unlock,
+                                 SD_BUS_VTABLE_SENSITIVE),
+        SD_BUS_METHOD_WITH_NAMES("Acquire",
+                                 "sb",
+                                 SD_BUS_PARAM(secret)
+                                 SD_BUS_PARAM(please_suspend),
+                                 "h",
+                                 SD_BUS_PARAM(send_fd),
+                                 bus_home_method_acquire,
+                                 SD_BUS_VTABLE_SENSITIVE),
+        SD_BUS_METHOD_WITH_NAMES("Ref",
+                                 "b",
+                                 SD_BUS_PARAM(please_suspend),
+                                 "h",
+                                 SD_BUS_PARAM(send_fd),
+                                 bus_home_method_ref,
+                                 0),
+        SD_BUS_METHOD("Release", NULL, NULL, bus_home_method_release, 0),
+        SD_BUS_VTABLE_END
+};
+
+const BusObjectImplementation home_object = {
+        "/org/freedesktop/home1/home",
+        "org.freedesktop.home1.Home",
+        .fallback_vtables = BUS_FALLBACK_VTABLES({home_vtable, bus_home_object_find}),
+        .node_enumerator = bus_home_node_enumerator,
+        .manager = true,
+};
+
 static int on_deferred_change(sd_event_source *s, void *userdata) {
         _cleanup_free_ char *path = NULL;
         Home *h = userdata;
index 20516b120535015bd49af97e5901c10b0942de2f..59b2a970b849d57259d952588bb99ac1157aad3e 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "sd-bus.h"
 
+#include "bus-util.h"
 #include "homed-home.h"
 
 int bus_home_client_is_trusted(Home *h, sd_bus_message *message);
@@ -25,12 +26,9 @@ int bus_home_method_acquire(sd_bus_message *message, void *userdata, sd_bus_erro
 int bus_home_method_ref(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_home_method_release(sd_bus_message *message, void *userdata, sd_bus_error *error);
 
-extern const sd_bus_vtable home_vtable[];
+extern const BusObjectImplementation home_object;
 
 int bus_home_path(Home *h, char **ret);
 
-int bus_home_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error);
-int bus_home_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error);
-
 int bus_home_emit_change(Home *h);
 int bus_home_emit_remove(Home *h);
index c98e18c6863a1854dac2b290e7bfec97679163ad..65e363c23c1d1b3dc0ea52d677543f8a599e5986 100644 (file)
@@ -1002,6 +1002,8 @@ static int home_start_work(Home *h, const char *verb, UserRecord *hr, UserRecord
         if (r < 0)
                 return r;
         if (r == 0) {
+                const char *homework;
+
                 /* Child */
 
                 if (setenv("NOTIFY_SOCKET", "/run/systemd/home/notify", 1) < 0) {
@@ -1009,6 +1011,18 @@ static int home_start_work(Home *h, const char *verb, UserRecord *hr, UserRecord
                         _exit(EXIT_FAILURE);
                 }
 
+                if (h->manager->default_storage >= 0)
+                        if (setenv("SYSTEMD_HOME_DEFAULT_STORAGE", user_storage_to_string(h->manager->default_storage), 1) < 0) {
+                                log_error_errno(errno, "Failed to set $SYSTEMD_HOME_DEFAULT_STORAGE: %m");
+                                _exit(EXIT_FAILURE);
+                        }
+
+                if (h->manager->default_file_system_type)
+                        if (setenv("SYSTEMD_HOME_DEFAULT_FILE_SYSTEM_TYPE", h->manager->default_file_system_type, 1) < 0) {
+                                log_error_errno(errno, "Failed to set $SYSTEMD_HOME_DEFAULT_FILE_SYSTEM_TYPE: %m");
+                                _exit(EXIT_FAILURE);
+                        }
+
                 r = rearrange_stdio(stdin_fd, stdout_fd, STDERR_FILENO);
                 if (r < 0) {
                         log_error_errno(r, "Failed to rearrange stdin/stdout/stderr: %m");
@@ -1017,7 +1031,11 @@ static int home_start_work(Home *h, const char *verb, UserRecord *hr, UserRecord
 
                 stdin_fd = stdout_fd = -1; /* have been invalidated by rearrange_stdio() */
 
-                execl(SYSTEMD_HOMEWORK_PATH, SYSTEMD_HOMEWORK_PATH, verb, NULL);
+                /* Allow overriding the homework path via an environment variable, to make debugging
+                 * easier. */
+                homework = getenv("SYSTEMD_HOMEWORK_PATH") ?: SYSTEMD_HOMEWORK_PATH;
+
+                execl(homework, homework, verb, NULL);
                 log_error_errno(errno, "Failed to invoke " SYSTEMD_HOMEWORK_PATH ": %m");
                 _exit(EXIT_FAILURE);
         }
index b239a71887fb1456eb1c0935d814675ee6cfdba2..ce6919a1a7f01cd098d54dbf9e27cbec6eae9184 100644 (file)
@@ -600,44 +600,210 @@ static int method_lock_all_homes(sd_bus_message *message, void *userdata, sd_bus
         return sd_bus_reply_method_return(message, NULL);
 }
 
-const sd_bus_vtable manager_vtable[] = {
+static const sd_bus_vtable manager_vtable[] = {
         SD_BUS_VTABLE_START(0),
 
         SD_BUS_PROPERTY("AutoLogin", "a(sso)", property_get_auto_login, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
 
-        SD_BUS_METHOD("GetHomeByName", "s", "usussso", method_get_home_by_name, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("GetHomeByUID", "u", "ssussso", method_get_home_by_uid, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("GetUserRecordByName", "s", "sbo", method_get_user_record_by_name, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
-        SD_BUS_METHOD("GetUserRecordByUID", "u", "sbo", method_get_user_record_by_uid, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
-        SD_BUS_METHOD("ListHomes", NULL, "a(susussso)", method_list_homes, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_NAMES("GetHomeByName",
+                                 "s",
+                                 SD_BUS_PARAM(user_name),
+                                 "usussso",
+                                 SD_BUS_PARAM(uid)
+                                 SD_BUS_PARAM(home_state)
+                                 SD_BUS_PARAM(gid)
+                                 SD_BUS_PARAM(real_name)
+                                 SD_BUS_PARAM(home_directory)
+                                 SD_BUS_PARAM(shell)
+                                 SD_BUS_PARAM(bus_path),
+                                 method_get_home_by_name,
+                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_NAMES("GetHomeByUID",
+                                 "u",
+                                 SD_BUS_PARAM(uid),
+                                 "ssussso",
+                                 SD_BUS_PARAM(user_name)
+                                 SD_BUS_PARAM(home_state)
+                                 SD_BUS_PARAM(gid)
+                                 SD_BUS_PARAM(real_name)
+                                 SD_BUS_PARAM(home_directory)
+                                 SD_BUS_PARAM(shell)
+                                 SD_BUS_PARAM(bus_path),
+                                 method_get_home_by_uid,
+                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_NAMES("GetUserRecordByName",
+                                 "s",
+                                 SD_BUS_PARAM(user_name),
+                                 "sbo",
+                                 SD_BUS_PARAM(user_record)
+                                 SD_BUS_PARAM(incomplete)
+                                 SD_BUS_PARAM(bus_path),
+                                 method_get_user_record_by_name,
+                                 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+        SD_BUS_METHOD_WITH_NAMES("GetUserRecordByUID",
+                                 "u",
+                                 SD_BUS_PARAM(uid),
+                                 "sbo",
+                                 SD_BUS_PARAM(user_record)
+                                 SD_BUS_PARAM(incomplete)
+                                 SD_BUS_PARAM(bus_path),
+                                 method_get_user_record_by_uid,
+                                 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+        SD_BUS_METHOD_WITH_NAMES("ListHomes",
+                                 NULL,,
+                                 "a(susussso)",
+                                 SD_BUS_PARAM(home_areas),
+                                 method_list_homes,
+                                 SD_BUS_VTABLE_UNPRIVILEGED),
 
         /* The following methods directly execute an operation on a home area, without ref-counting, queueing
          * or anything, and are accessible through homectl. */
-        SD_BUS_METHOD("ActivateHome", "ss", NULL, method_activate_home, SD_BUS_VTABLE_SENSITIVE),
-        SD_BUS_METHOD("DeactivateHome", "s", NULL, method_deactivate_home, 0),
-        SD_BUS_METHOD("RegisterHome", "s", NULL, method_register_home, SD_BUS_VTABLE_UNPRIVILEGED),                                  /* Add JSON record to homed, but don't create actual $HOME */
-        SD_BUS_METHOD("UnregisterHome", "s", NULL, method_unregister_home, SD_BUS_VTABLE_UNPRIVILEGED),                              /* Remove JSON record from homed, but don't remove actual $HOME  */
-        SD_BUS_METHOD("CreateHome", "s", NULL, method_create_home, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),              /* Add JSON record, and create $HOME for it */
-        SD_BUS_METHOD("RealizeHome", "ss", NULL, method_realize_home, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),           /* Create $HOME for already registered JSON entry */
-        SD_BUS_METHOD("RemoveHome", "s", NULL, method_remove_home, SD_BUS_VTABLE_UNPRIVILEGED),                                      /* Remove JSON record and remove $HOME */
-        SD_BUS_METHOD("FixateHome", "ss", NULL, method_fixate_home, SD_BUS_VTABLE_SENSITIVE),                                        /* Investigate $HOME and propagate contained JSON record into our database */
-        SD_BUS_METHOD("AuthenticateHome", "ss", NULL, method_authenticate_home, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE), /* Just check credentials */
-        SD_BUS_METHOD("UpdateHome", "s", NULL, method_update_home, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),              /* Update JSON record of existing user */
-        SD_BUS_METHOD("ResizeHome", "sts", NULL, method_resize_home, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
-        SD_BUS_METHOD("ChangePasswordHome", "sss", NULL, method_change_password_home, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
-        SD_BUS_METHOD("LockHome", "s", NULL, method_lock_home, 0),                                                                   /* Prepare active home for system suspend: flush out passwords, suspend access */
-        SD_BUS_METHOD("UnlockHome", "ss", NULL, method_unlock_home, SD_BUS_VTABLE_SENSITIVE),                                        /* Make $HOME usable after system resume again */
-
-        /* The following methods implement ref-counted activation, and are what the PAM module calls (and
-         * what "homectl with" runs). In contrast to the methods above which fail if an operation is already
-         * being executed on a home directory, these ones will queue the request, and are thus more
-         * reliable. Moreover, they are a bit smarter: AcquireHome() will fixate, activate, unlock, or
-         * authenticate depending on the state of the home, so that the end result is always the same
-         * (i.e. the home directory is accessible), and we always validate the specified passwords. RefHome()
-         * will not authenticate, and thus only works if home is already active. */
-        SD_BUS_METHOD("AcquireHome", "ssb", "h", method_acquire_home, SD_BUS_VTABLE_SENSITIVE),
-        SD_BUS_METHOD("RefHome", "sb", "h", method_ref_home, 0),
-        SD_BUS_METHOD("ReleaseHome", "s", NULL, method_release_home, 0),
+        SD_BUS_METHOD_WITH_NAMES("ActivateHome",
+                                 "ss",
+                                 SD_BUS_PARAM(user_name)
+                                 SD_BUS_PARAM(secret),
+                                 NULL,,
+                                 method_activate_home,
+                                 SD_BUS_VTABLE_SENSITIVE),
+        SD_BUS_METHOD_WITH_NAMES("DeactivateHome",
+                                 "s",
+                                 SD_BUS_PARAM(user_name),
+                                 NULL,,
+                                 method_deactivate_home,
+                                 0),
+
+        /* Add the JSON record to homed, but don't create actual $HOME */
+        SD_BUS_METHOD_WITH_NAMES("RegisterHome",
+                                 "s",
+                                 SD_BUS_PARAM(user_record),
+                                 NULL,,
+                                 method_register_home,
+                                 SD_BUS_VTABLE_UNPRIVILEGED),
+
+        /* Remove the JSON record from homed, but don't remove actual $HOME  */
+        SD_BUS_METHOD_WITH_NAMES("UnregisterHome",
+                                 "s",
+                                 SD_BUS_PARAM(user_name),
+                                 NULL,,
+                                 method_unregister_home,
+                                 SD_BUS_VTABLE_UNPRIVILEGED),
+
+        /* Add JSON record, and create $HOME for it */
+        SD_BUS_METHOD_WITH_NAMES("CreateHome",
+                                 "s",
+                                 SD_BUS_PARAM(user_record),
+                                 NULL,,
+                                 method_create_home,
+                                 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+
+        /* Create $HOME for already registered JSON entry */
+        SD_BUS_METHOD_WITH_NAMES("RealizeHome",
+                                 "ss",
+                                 SD_BUS_PARAM(user_name)
+                                 SD_BUS_PARAM(secret),
+                                 NULL,,
+                                 method_realize_home,
+                                 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+
+        /* Remove the JSON record and remove $HOME */
+        SD_BUS_METHOD_WITH_NAMES("RemoveHome",
+                                 "s",
+                                 SD_BUS_PARAM(user_name),
+                                 NULL,,
+                                 method_remove_home,
+                                 SD_BUS_VTABLE_UNPRIVILEGED),
+
+        /* Investigate $HOME and propagate contained JSON record into our database */
+        SD_BUS_METHOD_WITH_NAMES("FixateHome",
+                                 "ss",
+                                 SD_BUS_PARAM(user_name)
+                                 SD_BUS_PARAM(secret),
+                                 NULL,,
+                                 method_fixate_home,
+                                 SD_BUS_VTABLE_SENSITIVE),
+
+        /* Just check credentials */
+        SD_BUS_METHOD_WITH_NAMES("AuthenticateHome",
+                                 "ss",
+                                 SD_BUS_PARAM(user_name)
+                                 SD_BUS_PARAM(secret),
+                                 NULL,,
+                                 method_authenticate_home,
+                                 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+
+        /* Update the JSON record of existing user */
+        SD_BUS_METHOD_WITH_NAMES("UpdateHome",
+                                 "s",
+                                 SD_BUS_PARAM(user_record),
+                                 NULL,,
+                                 method_update_home,
+                                 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+
+        SD_BUS_METHOD_WITH_NAMES("ResizeHome",
+                                 "sts",
+                                 SD_BUS_PARAM(user_name)
+                                 SD_BUS_PARAM(size)
+                                 SD_BUS_PARAM(secret),
+                                 NULL,,
+                                 method_resize_home,
+                                 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+
+        SD_BUS_METHOD_WITH_NAMES("ChangePasswordHome",
+                                 "sss",
+                                 SD_BUS_PARAM(user_name)
+                                 SD_BUS_PARAM(new_secret)
+                                 SD_BUS_PARAM(old_secret),
+                                 NULL,,
+                                 method_change_password_home,
+                                 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+
+        /* Prepare active home for system suspend: flush out passwords, suspend access */
+        SD_BUS_METHOD_WITH_NAMES("LockHome",
+                                 "s",
+                                 SD_BUS_PARAM(user_name),
+                                 NULL,,
+                                 method_lock_home,
+                                 0),
+
+        /* Make $HOME usable after system resume again */
+        SD_BUS_METHOD_WITH_NAMES("UnlockHome",
+                                 "ss",
+                                 SD_BUS_PARAM(user_name)
+                                 SD_BUS_PARAM(secret),
+                                 NULL,,
+                                 method_unlock_home,
+                                 SD_BUS_VTABLE_SENSITIVE),
+
+        /* The following methods implement ref-counted activation, and are what the PAM module and "homectl
+         * with" use. In contrast to the methods above which fail if an operation is already being executed
+         * on a home directory, these ones will queue the request, and are thus more reliable. Moreover,
+         * they are a bit smarter: AcquireHome() will fixate, activate, unlock, or authenticate depending on
+         * the state of the home area, so that the end result is always the same (i.e. the home directory is
+         * accessible), and we always validate the specified passwords. RefHome() will not authenticate, and
+         * thus only works if the home area is already active. */
+        SD_BUS_METHOD_WITH_NAMES("AcquireHome",
+                                 "ssb",
+                                 SD_BUS_PARAM(user_name)
+                                 SD_BUS_PARAM(secret)
+                                 SD_BUS_PARAM(please_suspend),
+                                 "h",
+                                 SD_BUS_PARAM(send_fd),
+                                 method_acquire_home,
+                                 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+        SD_BUS_METHOD_WITH_NAMES("RefHome",
+                                 "sb",
+                                 SD_BUS_PARAM(user_name)
+                                 SD_BUS_PARAM(please_suspend),
+                                 "h",
+                                 SD_BUS_PARAM(send_fd),
+                                 method_ref_home,
+                                 0),
+        SD_BUS_METHOD_WITH_NAMES("ReleaseHome",
+                                 "s",
+                                 SD_BUS_PARAM(user_name),
+                                 NULL,,
+                                 method_release_home,
+                                 0),
 
         /* An operation that acts on all homes that allow it */
         SD_BUS_METHOD("LockAllHomes", NULL, NULL, method_lock_all_homes, 0),
@@ -645,6 +811,13 @@ const sd_bus_vtable manager_vtable[] = {
         SD_BUS_VTABLE_END
 };
 
+const BusObjectImplementation manager_object = {
+        "/org/freedesktop/home1",
+        "org.freedesktop.home1.Manager",
+        .vtables = BUS_VTABLES(manager_vtable),
+        .children = BUS_IMPLEMENTATIONS(&home_object),
+};
+
 static int on_deferred_auto_login(sd_event_source *s, void *userdata) {
         Manager *m = userdata;
         int r;
index 40e1cc3d86d60b8165d494a1d44afcd3358cd465..93bef9df8eb905332cc7c6b29e62d5bf6dd7ffe4 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
-#include "sd-bus.h"
+#include "bus-util.h"
 
-extern const sd_bus_vtable manager_vtable[];
+extern const BusObjectImplementation manager_object;
index ed2a54615c66c5fdab99410f10bf6ab1899eb66b..df0ed2f4f36f550b6a7d6fc3e2f53f43fde8a155 100644 (file)
@@ -24,6 +24,7 @@
 #include "fs-util.h"
 #include "gpt.h"
 #include "home-util.h"
+#include "homed-conf.h"
 #include "homed-home-bus.h"
 #include "homed-home.h"
 #include "homed-manager-bus.h"
@@ -184,10 +185,18 @@ int manager_new(Manager **ret) {
 
         assert(ret);
 
-        m = new0(Manager, 1);
+        m = new(Manager, 1);
         if (!m)
                 return -ENOMEM;
 
+        *m = (Manager) {
+                .default_storage = _USER_STORAGE_INVALID,
+        };
+
+        r = manager_parse_config_file(m);
+        if (r < 0)
+                return r;
+
         r = sd_event_default(&m->event);
         if (r < 0)
                 return r;
@@ -251,6 +260,8 @@ Manager* manager_free(Manager *m) {
 
         varlink_server_unref(m->varlink_server);
 
+        free(m->default_file_system_type);
+
         return mfree(m);
 }
 
@@ -879,23 +890,7 @@ static int manager_connect_bus(Manager *m) {
         if (r < 0)
                 return log_error_errno(r, "Failed to connect to system bus: %m");
 
-        r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/home1", "org.freedesktop.home1.Manager", manager_vtable, m);
-        if (r < 0)
-                return log_error_errno(r, "Failed to add manager object vtable: %m");
-
-        r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/home1/home", "org.freedesktop.home1.Home", home_vtable, bus_home_object_find, m);
-        if (r < 0)
-                return log_error_errno(r, "Failed to add image object vtable: %m");
-
-        r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/home1/home", bus_home_node_enumerator, m);
-        if (r < 0)
-                return log_error_errno(r, "Failed to add image enumerator: %m");
-
-        r = sd_bus_add_object_manager(m->bus, NULL, "/org/freedesktop/home1/home");
-        if (r < 0)
-                return log_error_errno(r, "Failed to add object manager: %m");
-
-        r = bus_log_control_api_register(m->bus);
+        r = bus_add_implementation(m->bus, &manager_object, m);
         if (r < 0)
                 return r;
 
@@ -962,10 +957,7 @@ static ssize_t read_datagram(int fd, struct ucred *ret_sender, void **ret) {
                 return -ENOMEM;
 
         if (ret_sender) {
-                union {
-                        struct cmsghdr cmsghdr;
-                        uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
-                } control;
+                CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
                 bool found_ucred = false;
                 struct cmsghdr *cmsg;
                 struct msghdr mh;
@@ -981,9 +973,9 @@ static ssize_t read_datagram(int fd, struct ucred *ret_sender, void **ret) {
                         .msg_controllen = sizeof(control),
                 };
 
-                m = recvmsg(fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
+                m = recvmsg_safe(fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
                 if (m < 0)
-                        return -errno;
+                        return m;
 
                 cmsg_close_all(&mh);
 
index 6deffb0d26bd9532159f436c03331c8512548813..83a714462792a103cc0d0f010df40fe40ad52555 100644 (file)
@@ -28,6 +28,8 @@ struct Manager {
         Hashmap *homes_by_sysfs;
 
         bool scan_slash_home;
+        UserStorage default_storage;
+        char *default_file_system_type;
 
         sd_event_source *inotify_event_source;
 
index ca435582691e33d2bb22df4279e9ccdc02f88134..2fd3b65d8983d255c26c98b21fbcb9805f3d0a8b 100644 (file)
@@ -3,10 +3,13 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include "bus-log-control-api.h"
 #include "daemon-util.h"
 #include "homed-manager.h"
+#include "homed-manager-bus.h"
 #include "log.h"
 #include "main-func.h"
+#include "service-util.h"
 #include "signal-util.h"
 
 static int run(int argc, char *argv[]) {
@@ -16,10 +19,15 @@ static int run(int argc, char *argv[]) {
 
         log_setup_service();
 
-        umask(0022);
+        r = service_parse_argv("systemd-homed.service",
+                               "A service to create, remove, change or inspect home areas.",
+                               BUS_IMPLEMENTATIONS(&manager_object,
+                                                   &log_control_object),
+                               argc, argv);
+        if (r <= 0)
+                return r;
 
-        if (argc != 1)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments.");
+        umask(0022);
 
         if (setenv("SYSTEMD_BYPASS_USERDB", "io.systemd.Home", 1) < 0)
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to set $SYSTEMD_BYPASS_USERDB: %m");
diff --git a/src/home/homed.conf b/src/home/homed.conf
new file mode 100644 (file)
index 0000000..6de75fc
--- /dev/null
@@ -0,0 +1,16 @@
+#  This file is part of systemd.
+#
+#  systemd is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU Lesser General Public License as published by
+#  the Free Software Foundation; either version 2.1 of the License, or
+#  (at your option) any later version.
+#
+# Entries in this file show the compile time defaults.
+# You can change settings by editing this file.
+# Defaults can be restored by simply deleting this file.
+#
+# See homed.conf(5) for details
+
+[Home]
+#DefaultStorage=
+#DefaultFileSystemType=ext4
index 5eb67bc2b3bb36237d386073cc785a43ba77d41d..caa4168265a0a2ef50f74119f98a1fef74415f40 100644 (file)
@@ -16,6 +16,7 @@
 #include "fileio.h"
 #include "fs-util.h"
 #include "fsck-util.h"
+#include "home-util.h"
 #include "homework-luks.h"
 #include "homework-mount.h"
 #include "id128-util.h"
  * strictly round disk sizes down to the next 1K boundary.*/
 #define DISK_SIZE_ROUND_DOWN(x) ((x) & ~UINT64_C(1023))
 
-static bool supported_fstype(const char *fstype) {
-        /* Limit the set of supported file systems a bit, as protection against little tested kernel file
-         * systems. Also, we only support the resize ioctls for these file systems. */
-        return STR_IN_SET(fstype, "ext4", "btrfs", "xfs");
-}
-
 static int probe_file_system_by_fd(
                 int fd,
                 char **ret_fstype,
@@ -893,19 +888,19 @@ int home_store_header_identity_luks(
         return 1;
 }
 
-static int run_fitrim(int root_fd) {
+int run_fitrim(int root_fd) {
         char buf[FORMAT_BYTES_MAX];
         struct fstrim_range range = {
                 .len = UINT64_MAX,
         };
 
         /* If discarding is on, discard everything right after mounting, so that the discard setting takes
-         * effect on activation. */
+         * effect on activation. (Also, optionally, trim on logout) */
 
         assert(root_fd >= 0);
 
         if (ioctl(root_fd, FITRIM, &range) < 0) {
-                if (IN_SET(errno, ENOTTY, EOPNOTSUPP, EBADF)) {
+                if (ERRNO_IS_NOT_SUPPORTED(errno) || errno == EBADF) {
                         log_debug_errno(errno, "File system does not support FITRIM, not trimming.");
                         return 0;
                 }
@@ -918,15 +913,32 @@ static int run_fitrim(int root_fd) {
         return 1;
 }
 
-static int run_fallocate(int backing_fd, const struct stat *st) {
+int run_fitrim_by_path(const char *root_path) {
+        _cleanup_close_ int root_fd = -1;
+
+        root_fd = open(root_path, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
+        if (root_fd < 0)
+                return log_error_errno(errno, "Failed to open file system '%s' for trimming: %m", root_path);
+
+        return run_fitrim(root_fd);
+}
+
+int run_fallocate(int backing_fd, const struct stat *st) {
         char buf[FORMAT_BYTES_MAX];
+        struct stat stbuf;
 
         assert(backing_fd >= 0);
-        assert(st);
 
         /* If discarding is off, let's allocate the whole image before mounting, so that the setting takes
          * effect on activation */
 
+        if (!st) {
+                if (fstat(backing_fd, &stbuf) < 0)
+                        return log_error_errno(errno, "Failed to fstat(): %m");
+
+                st = &stbuf;
+        }
+
         if (!S_ISREG(st->st_mode))
                 return 0;
 
@@ -955,6 +967,16 @@ static int run_fallocate(int backing_fd, const struct stat *st) {
         return 1;
 }
 
+int run_fallocate_by_path(const char *backing_path) {
+        _cleanup_close_ int backing_fd = -1;
+
+        backing_fd = open(backing_path, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
+        if (backing_fd < 0)
+                return log_error_errno(errno, "Failed to open '%s' for fallocate(): %m", backing_path);
+
+        return run_fallocate(backing_fd, NULL);
+}
+
 int home_prepare_luks(
                 UserRecord *h,
                 bool already_activated,
@@ -1111,7 +1133,7 @@ int home_prepare_luks(
                                h->luks_volume_key_size,
                                h->password,
                                pkcs11_decrypted_passwords ? *pkcs11_decrypted_passwords : NULL,
-                               user_record_luks_discard(h),
+                               user_record_luks_discard(h) || user_record_luks_offline_discard(h),
                                &cd,
                                &found_luks_uuid,
                                &volume_key,
@@ -1147,6 +1169,9 @@ int home_prepare_luks(
 
                 if (user_record_luks_discard(h))
                         (void) run_fitrim(root_fd);
+
+                setup->image_fd = TAKE_FD(fd);
+                setup->do_offline_fallocate = !(setup->do_offline_fitrim = user_record_luks_offline_discard(h));
         }
 
         setup->loop = TAKE_PTR(loop);
@@ -1259,6 +1284,7 @@ int home_activate_luks(
                 return r;
 
         setup.undo_mount = false;
+        setup.do_offline_fitrim = false;
 
         loop_device_relinquish(setup.loop);
 
@@ -1267,6 +1293,7 @@ int home_activate_luks(
                 log_warning_errno(r, "Failed to relinquish DM device, ignoring: %m");
 
         setup.undo_dm = false;
+        setup.do_offline_fallocate = false;
 
         log_info("Everything completed.");
 
@@ -1279,6 +1306,7 @@ int home_activate_luks(
 int home_deactivate_luks(UserRecord *h) {
         _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
         _cleanup_free_ char *dm_name = NULL, *dm_node = NULL;
+        bool we_detached;
         int r;
 
         /* Note that the DM device and loopback device are set to auto-detach, hence strictly speaking we
@@ -1293,23 +1321,45 @@ int home_deactivate_luks(UserRecord *h) {
 
         r = crypt_init_by_name(&cd, dm_name);
         if (IN_SET(r, -ENODEV, -EINVAL, -ENOENT)) {
-                log_debug_errno(r, "LUKS device %s is already detached.", dm_name);
-                return false;
+                log_debug_errno(r, "LUKS device %s has already been detached.", dm_name);
+                we_detached = false;
         } else if (r < 0)
                 return log_error_errno(r, "Failed to initialize cryptsetup context for %s: %m", dm_name);
+        else {
+                log_info("Discovered used LUKS device %s.", dm_node);
+
+                crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
+
+                r = crypt_deactivate(cd, dm_name);
+                if (IN_SET(r, -ENODEV, -EINVAL, -ENOENT)) {
+                        log_debug_errno(r, "LUKS device %s is already detached.", dm_node);
+                        we_detached = false;
+                } else if (r < 0)
+                        return log_info_errno(r, "LUKS device %s couldn't be deactivated: %m", dm_node);
+                else {
+                        log_info("LUKS device detaching completed.");
+                        we_detached = true;
+                }
+        }
 
-        log_info("Discovered used LUKS device %s.", dm_node);
+        if (user_record_luks_offline_discard(h))
+                log_debug("Not allocating on logout.");
+        else
+                (void) run_fallocate_by_path(user_record_image_path(h));
 
-        crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
+        return we_detached;
+}
 
-        r = crypt_deactivate(cd, dm_name);
-        if (IN_SET(r, -ENODEV, -EINVAL, -ENOENT))
-                log_debug_errno(r, "LUKS device %s is already detached.", dm_node);
-        else if (r < 0)
-                return log_info_errno(r, "LUKS device %s couldn't be deactivated: %m", dm_node);
+int home_trim_luks(UserRecord *h) {
+        assert(h);
+
+        if (!user_record_luks_offline_discard(h)) {
+                log_debug("Not trimming on logout.");
+                return 0;
+        }
 
-        log_info("LUKS device detaching completed.");
-        return true;
+        (void) run_fitrim_by_path(user_record_home_directory(h));
+        return 0;
 }
 
 static int run_mkfs(
@@ -1918,7 +1968,9 @@ int home_create_luks(
                 if (asprintf(&disk_uuid_path, "/dev/disk/by-uuid/" SD_ID128_UUID_FORMAT_STR, SD_ID128_FORMAT_VAL(luks_uuid)) < 0)
                         return log_oom();
 
-                if (user_record_luks_discard(h)) {
+                if (user_record_luks_discard(h) || user_record_luks_offline_discard(h)) {
+                        /* If we want online or offline discard, discard once before we start using things. */
+
                         if (ioctl(image_fd, BLKDISCARD, (uint64_t[]) { 0, block_device_size }) < 0)
                                 log_full_errno(errno == EOPNOTSUPP ? LOG_DEBUG : LOG_WARNING, errno,
                                                "Failed to issue full-device BLKDISCARD on device, ignoring: %m");
@@ -2004,7 +2056,7 @@ int home_create_luks(
                         user_record_user_name_and_realm(h),
                         pkcs11_decrypted_passwords,
                         effective_passwords,
-                        user_record_luks_discard(h),
+                        user_record_luks_discard(h) || user_record_luks_offline_discard(h),
                         h,
                         &cd);
         if (r < 0)
@@ -2084,6 +2136,12 @@ int home_create_luks(
                 goto fail;
         }
 
+        if (user_record_luks_offline_discard(h)) {
+                r = run_fitrim(root_fd);
+                if (r < 0)
+                        goto fail;
+        }
+
         root_fd = safe_close(root_fd);
 
         r = umount_verbose("/run/systemd/user-home-mount");
@@ -2102,6 +2160,12 @@ int home_create_luks(
 
         loop = loop_device_unref(loop);
 
+        if (!user_record_luks_offline_discard(h)) {
+                r = run_fallocate(image_fd, NULL /* refresh stat() data */);
+                if (r < 0)
+                        goto fail;
+        }
+
         if (disk_uuid_path)
                 (void) ioctl(image_fd, BLKRRPART, 0);
 
index 581255a223aba392168fdfe221821143f632a4fe..bd51f5da50ae753065ca216fbd98350892e749ab 100644 (file)
@@ -9,6 +9,7 @@ int home_prepare_luks(UserRecord *h, bool already_activated, const char *force_i
 
 int home_activate_luks(UserRecord *h, char ***pkcs11_decrypted_passwords, UserRecord **ret_home);
 int home_deactivate_luks(UserRecord *h);
+int home_trim_luks(UserRecord *h);
 
 int home_store_header_identity_luks(UserRecord *h, HomeSetup *setup, UserRecord *old_home);
 
@@ -36,3 +37,8 @@ static inline uint64_t luks_volume_key_size_convert(struct crypt_device *cd) {
 
         return (uint64_t) k;
 }
+
+int run_fitrim(int root_fd);
+int run_fitrim_by_path(const char *root_path);
+int run_fallocate(int backing_fd, const struct stat *st);
+int run_fallocate_by_path(const char *backing_path);
index 38b740729c505394c79c8af3b073ec2273dbafcf..76fd79fc2a02ded993f478f6ef863da59bbf2e9d 100644 (file)
@@ -7,6 +7,7 @@
 #include "copy.h"
 #include "fd-util.h"
 #include "fileio.h"
+#include "fs-util.h"
 #include "home-util.h"
 #include "homework-cifs.h"
 #include "homework-directory.h"
@@ -163,7 +164,15 @@ int home_setup_undo(HomeSetup *setup) {
 
         assert(setup);
 
-        setup->root_fd = safe_close(setup->root_fd);
+        if (setup->root_fd >= 0) {
+                if (setup->do_offline_fitrim) {
+                        q = run_fitrim(setup->root_fd);
+                        if (q < 0)
+                                r = q;
+                }
+
+                setup->root_fd = safe_close(setup->root_fd);
+        }
 
         if (setup->undo_mount) {
                 q = umount_verbose("/run/systemd/user-home-mount");
@@ -177,8 +186,20 @@ int home_setup_undo(HomeSetup *setup) {
                         r = q;
         }
 
+        if (setup->image_fd >= 0) {
+                if (setup->do_offline_fallocate) {
+                        q = run_fallocate(setup->image_fd, NULL);
+                        if (q < 0)
+                                r = q;
+                }
+
+                setup->image_fd = safe_close(setup->image_fd);
+        }
+
         setup->undo_mount = false;
         setup->undo_dm = false;
+        setup->do_offline_fitrim = false;
+        setup->do_offline_fallocate = false;
 
         setup->dm_name = mfree(setup->dm_name);
         setup->dm_node = mfree(setup->dm_node);
@@ -666,6 +687,12 @@ static int home_deactivate(UserRecord *h, bool force) {
         if (r < 0)
                 return r;
         if (r == USER_TEST_MOUNTED) {
+                if (user_record_storage(h) == USER_LUKS) {
+                        r = home_trim_luks(h);
+                        if (r < 0)
+                                return r;
+                }
+
                 if (umount2(user_record_home_directory(h), UMOUNT_NOFOLLOW | (force ? MNT_FORCE|MNT_DETACH : 0)) < 0)
                         return log_error_errno(errno, "Failed to unmount %s: %m", user_record_home_directory(h));
 
@@ -836,9 +863,68 @@ static int user_record_compile_effective_passwords(
         return 0;
 }
 
+static int determine_default_storage(UserStorage *ret) {
+        UserStorage storage = _USER_STORAGE_INVALID;
+        const char *e;
+        int r;
+
+        assert(ret);
+
+        /* homed tells us via an environment variable which default storage to use */
+        e = getenv("SYSTEMD_HOME_DEFAULT_STORAGE");
+        if (e) {
+                storage = user_storage_from_string(e);
+                if (storage < 0)
+                        log_warning("$SYSTEMD_HOME_DEFAULT_STORAGE set to invalid storage type, ignoring: %s", e);
+                else {
+                        log_info("Using configured default storage '%s'.", user_storage_to_string(storage));
+                        *ret = storage;
+                        return 0;
+                }
+        }
+
+        /* When neither user nor admin specified the storage type to use, fix it to be LUKS — unless we run
+         * in a container where loopback devices and LUKS/DM are not available. Also, if /home is encrypted
+         * anyway, let's avoid duplicate encryption. Note that we typically default to the assumption of
+         * "classic" storage for most operations. However, if we create a new home, then let's user LUKS if
+         * nothing is specified. */
+
+        r = detect_container();
+        if (r < 0)
+                return log_error_errno(r, "Failed to determine whether we are in a container: %m");
+        if (r == 0) {
+                r = path_is_encrypted("/home");
+                if (r < 0)
+                        log_warning_errno(r, "Failed to determine if /home is encrypted, ignoring: %m");
+                if (r <= 0) {
+                        log_info("Using automatic default storage of '%s'.", user_storage_to_string(USER_LUKS));
+                        *ret = USER_LUKS;
+                        return 0;
+                }
+
+                log_info("/home is encrypted, not using '%s' storage, in order to avoid double encryption.", user_storage_to_string(USER_LUKS));
+        } else
+                log_info("Running in container, not using '%s' storage.", user_storage_to_string(USER_LUKS));
+
+        r = path_is_fs_type("/home", BTRFS_SUPER_MAGIC);
+        if (r < 0)
+                log_warning_errno(r, "Failed to determine file system of /home, ignoring: %m");
+        if (r > 0) {
+                log_info("/home is on btrfs, using '%s' as storage.", user_storage_to_string(USER_SUBVOLUME));
+                *ret = USER_SUBVOLUME;
+        } else {
+                log_info("/home is on simple file system, using '%s' as storage.", user_storage_to_string(USER_DIRECTORY));
+                *ret = USER_DIRECTORY;
+        }
+
+        return 0;
+}
+
 static int home_create(UserRecord *h, UserRecord **ret_home) {
         _cleanup_(strv_free_erasep) char **effective_passwords = NULL, **pkcs11_decrypted_passwords = NULL;
         _cleanup_(user_record_unrefp) UserRecord *new_home = NULL;
+        UserStorage new_storage = _USER_STORAGE_INVALID;
+        const char *new_fs = NULL;
         int r;
 
         assert(h);
@@ -858,27 +944,18 @@ static int home_create(UserRecord *h, UserRecord **ret_home) {
         if (r != USER_TEST_ABSENT)
                 return log_error_errno(SYNTHETIC_ERRNO(EEXIST), "Home directory %s already exists, refusing.", user_record_home_directory(h));
 
-        /* When the user didn't specify the storage type to use, fix it to be LUKS -- unless we run in a
-         * container where loopback devices and LUKS/DM are not available. Note that we typically default to
-         * the assumption of "classic" storage for most operations. However, if we create a new home, then
-         * let's user LUKS if nothing is specified. */
         if (h->storage < 0) {
-                UserStorage new_storage;
-
-                r = detect_container();
+                r = determine_default_storage(&new_storage);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to determine whether we are in a container: %m");
-                if (r > 0) {
-                        new_storage = USER_DIRECTORY;
-
-                        r = path_is_fs_type("/home", BTRFS_SUPER_MAGIC);
-                        if (r < 0)
-                                log_debug_errno(r, "Failed to determine file system of /home, ignoring: %m");
+                        return r;
+        }
 
-                        new_storage = r > 0 ? USER_SUBVOLUME : USER_DIRECTORY;
-                } else
-                        new_storage = USER_LUKS;
+        if ((h->storage == USER_LUKS ||
+             (h->storage < 0 && new_storage == USER_LUKS)) &&
+            !h->file_system_type)
+                new_fs = getenv("SYSTEMD_HOME_DEFAULT_FILE_SYSTEM_TYPE");
 
+        if (new_storage >= 0 || new_fs) {
                 r = user_record_add_binding(
                                 h,
                                 new_storage,
@@ -889,18 +966,12 @@ static int home_create(UserRecord *h, UserRecord **ret_home) {
                                 NULL,
                                 NULL,
                                 UINT64_MAX,
-                                NULL,
+                                new_fs,
                                 NULL,
                                 UID_INVALID,
                                 GID_INVALID);
                 if (r < 0)
                         return log_error_errno(r, "Failed to change storage type to LUKS: %m");
-
-                if (!h->image_path_auto) {
-                        h->image_path_auto = strjoin("/home/", user_record_user_name_and_realm(h), new_storage == USER_LUKS ? ".home" : ".homedir");
-                        if (!h->image_path_auto)
-                                return log_oom();
-                }
         }
 
         r = user_record_test_image_path_and_warn(h);
@@ -980,7 +1051,7 @@ static int home_remove(UserRecord *h) {
                 assert(ip);
 
                 if (stat(ip, &st) < 0) {
-                        if (errno != -ENOENT)
+                        if (errno != ENOENT)
                                 return log_error_errno(errno, "Failed to stat() %s: %m", ip);
 
                 } else {
index 81698b760149dc78dc7ee8b0342cbb82a41b013d..3bcf3ad9b01a0ac43fbd4253edd2354cecc5a4c5 100644 (file)
@@ -17,6 +17,7 @@ typedef struct HomeSetup {
         LoopDevice *loop;
         struct crypt_device *crypt_device;
         int root_fd;
+        int image_fd;
         sd_id128_t found_partition_uuid;
         sd_id128_t found_luks_uuid;
         sd_id128_t found_fs_uuid;
@@ -28,6 +29,8 @@ typedef struct HomeSetup {
 
         bool undo_dm;
         bool undo_mount;
+        bool do_offline_fitrim;
+        bool do_offline_fallocate;
 
         uint64_t partition_offset;
         uint64_t partition_size;
@@ -36,6 +39,7 @@ typedef struct HomeSetup {
 #define HOME_SETUP_INIT                                 \
         {                                               \
                 .root_fd = -1,                          \
+                .image_fd = -1,                         \
                 .partition_offset = UINT64_MAX,         \
                 .partition_size = UINT64_MAX,           \
         }
index eb6da0b6969b5865bc9a30e42abf684900b40a68..2c5664aae1d9702b1b3d808921c06e6afc1503b3 100644 (file)
@@ -31,6 +31,8 @@ systemd_homed_sources = files('''
         home-util.h
         homed-bus.c
         homed-bus.h
+        homed-conf.c
+        homed-conf.h
         homed-home-bus.c
         homed-home-bus.h
         homed-home.c
@@ -52,6 +54,14 @@ systemd_homed_sources = files('''
         user-record-util.h
 '''.split())
 
+homed_gperf_c = custom_target(
+        'homed_gperf.c',
+        input : 'homed-gperf.gperf',
+        output : 'homed-gperf.c',
+        command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@'])
+
+systemd_homed_sources += [homed_gperf_c]
+
 homectl_sources = files('''
         home-util.c
         home-util.h
@@ -78,4 +88,7 @@ if conf.get('ENABLE_HOMED') == 1
                      install_dir : dbussystemservicedir)
         install_data('org.freedesktop.home1.policy',
                      install_dir : polkitpolicydir)
+
+        install_data('homed.conf',
+                     install_dir : pkgsysconfdir)
 endif
index 3d7ccdf3c24976898dc0fe59074f1d53d2d59b14..baa3586bf7a2eee79d6cf9ced4fc93e43514bcf5 100644 (file)
 #include "user-record.h"
 #include "user-util.h"
 
-/* Used for the "systemd-user-record-is-homed" PAM data field, to indicate whether we know whether this user
- * record is managed by homed or by something else. */
-#define USER_RECORD_IS_HOMED INT_TO_PTR(1)
-#define USER_RECORD_IS_OTHER INT_TO_PTR(2)
-
-static const BusLocator home_mgr = {
-        .destination = "org.freedesktop.home1",
-        .path = "/org/freedesktop/home1",
-        .interface = "org.freedesktop.home1.Manager",
-};
-
 static int parse_argv(
                 pam_handle_t *handle,
                 int argc, const char **argv,
@@ -71,29 +60,61 @@ static int parse_argv(
         return 0;
 }
 
+static int parse_env(
+                pam_handle_t *handle,
+                bool *please_suspend) {
+
+        const char *v;
+        int r;
+
+        /* Let's read the suspend setting from an env var in addition to the PAM command line. That makes it
+         * easy to declare the features of a display manager in code rather than configuration, and this is
+         * really a feature of code */
+
+        v = pam_getenv(handle, "SYSTEMD_HOME_SUSPEND");
+        if (!v) {
+                /* Also check the process env block, so that people can control this via an env var from the
+                 * outside of our process. */
+                v = secure_getenv("SYSTEMD_HOME_SUSPEND");
+                if (!v)
+                        return 0;
+        }
+
+        r = parse_boolean(v);
+        if (r < 0)
+                pam_syslog(handle, LOG_WARNING, "Failed to parse $SYSTEMD_HOME_SUSPEND argument, ignoring: %s", v);
+        else if (please_suspend)
+                *please_suspend = r;
+
+        return 0;
+}
+
 static int acquire_user_record(
                 pam_handle_t *handle,
+                const char *username,
                 UserRecord **ret_record) {
 
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
         _cleanup_(user_record_unrefp) UserRecord *ur = NULL;
         _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
-        const char *username = NULL, *json = NULL;
-        const void *b = NULL;
+        _cleanup_free_ char *homed_field = NULL;
+        const char *json = NULL;
         int r;
 
         assert(handle);
 
-        r = pam_get_user(handle, &username, NULL);
-        if (r != PAM_SUCCESS) {
-                pam_syslog(handle, LOG_ERR, "Failed to get user name: %s", pam_strerror(handle, r));
-                return r;
-        }
+        if (!username) {
+                r = pam_get_user(handle, &username, NULL);
+                if (r != PAM_SUCCESS) {
+                        pam_syslog(handle, LOG_ERR, "Failed to get user name: %s", pam_strerror(handle, r));
+                        return r;
+                }
 
-        if (isempty(username)) {
-                pam_syslog(handle, LOG_ERR, "User name not set.");
-                return PAM_SERVICE_ERR;
+                if (isempty(username)) {
+                        pam_syslog(handle, LOG_ERR, "User name not set.");
+                        return PAM_SERVICE_ERR;
+                }
         }
 
         /* Let's bypass all IPC complexity for the two user names we know for sure we don't manage, and for
@@ -101,37 +122,36 @@ static int acquire_user_record(
         if (STR_IN_SET(username, "root", NOBODY_USER_NAME) || !valid_user_group_name(username, 0))
                 return PAM_USER_UNKNOWN;
 
-        /* Let's check if a previous run determined that this user is not managed by homed. If so, let's exit early */
-        r = pam_get_data(handle, "systemd-user-record-is-homed", &b);
+        /* We cache the user record in the PAM context. We use a field name that includes the username, since
+         * clients might change the user name associated with a PAM context underneath us. Notably, 'sudo'
+         * creates a single PAM context and first authenticates it with the user set to the originating user,
+         * then updates the user for the destination user and issues the session stack with the same PAM
+         * context. We thus must be prepared that the user record changes between calls and we keep any
+         * caching separate. */
+        homed_field = strjoin("systemd-home-user-record-", username);
+        if (!homed_field)
+                return pam_log_oom(handle);
+
+        /* Let's use the cache, so that we can share it between the session and the authentication hooks */
+        r = pam_get_data(handle, homed_field, (const void**) &json);
         if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) {
-                /* Failure */
-                pam_syslog(handle, LOG_ERR, "Failed to get PAM user-record-is-homed flag: %s", pam_strerror(handle, r));
+                pam_syslog(handle, LOG_ERR, "Failed to get PAM user record data: %s", pam_strerror(handle, r));
                 return r;
-        } else if (b == NULL)
-                /* Nothing cached yet, need to acquire fresh */
-                json = NULL;
-        else if (b != USER_RECORD_IS_HOMED)
-                /* Definitely not a homed record */
-                return PAM_USER_UNKNOWN;
-        else {
-                /* It's a homed record, let's use the cache, so that we can share it between the session and
-                 * the authentication hooks */
-                r = pam_get_data(handle, "systemd-user-record", (const void**) &json);
-                if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) {
-                        pam_syslog(handle, LOG_ERR, "Failed to get PAM user record data: %s", pam_strerror(handle, r));
-                        return r;
-                }
         }
-
-        if (!json) {
+        if (r == PAM_SUCCESS && json) {
+                /* We determined earlier that this is not a homed user? Then exit early. (We use -1 as
+                 * negative cache indicator) */
+                if (json == (void*) -1)
+                        return PAM_USER_UNKNOWN;
+        } else {
                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-                _cleanup_free_ char *json_copy = NULL;
+                _cleanup_free_ char *generic_field = NULL, *json_copy = NULL;
 
                 r = pam_acquire_bus_connection(handle, &bus);
                 if (r != PAM_SUCCESS)
                         return r;
 
-                r = bus_call_method(bus, &home_mgr, "GetUserRecordByName", &error, &reply, "s", username);
+                r = bus_call_method(bus, bus_home_mgr, "GetUserRecordByName", &error, &reply, "s", username);
                 if (r < 0) {
                         if (sd_bus_error_has_name(&error, SD_BUS_ERROR_SERVICE_UNKNOWN) ||
                             sd_bus_error_has_name(&error, SD_BUS_ERROR_NAME_HAS_NO_OWNER)) {
@@ -152,23 +172,38 @@ static int acquire_user_record(
                 if (r < 0)
                         return pam_bus_log_parse_error(handle, r);
 
+                /* First copy: for the homed-specific data field, i.e. where we know the user record is from
+                 * homed */
                 json_copy = strdup(json);
                 if (!json_copy)
                         return pam_log_oom(handle);
 
-                r = pam_set_data(handle, "systemd-user-record", json_copy, pam_cleanup_free);
+                r = pam_set_data(handle, homed_field, json_copy, pam_cleanup_free);
                 if (r != PAM_SUCCESS) {
-                        pam_syslog(handle, LOG_ERR, "Failed to set PAM user record data: %s", pam_strerror(handle, r));
+                        pam_syslog(handle, LOG_ERR, "Failed to set PAM user record data '%s': %s",
+                                   homed_field, pam_strerror(handle, r));
                         return r;
                 }
 
-                TAKE_PTR(json_copy);
+                /* Take a second copy: for the generic data field, the one which we share with
+                 * pam_systemd. While we insist on only reusing homed records, pam_systemd is fine with homed
+                 * and non-homed user records. */
+                json_copy = strdup(json);
+                if (!json_copy)
+                        return pam_log_oom(handle);
+
+                generic_field = strjoin("systemd-user-record-", username);
+                if (!generic_field)
+                        return pam_log_oom(handle);
 
-                r = pam_set_data(handle, "systemd-user-record-is-homed", USER_RECORD_IS_HOMED, NULL);
+                r = pam_set_data(handle, generic_field, json_copy, pam_cleanup_free);
                 if (r != PAM_SUCCESS) {
-                        pam_syslog(handle, LOG_ERR, "Failed to set PAM user record is homed flag: %s", pam_strerror(handle, r));
+                        pam_syslog(handle, LOG_ERR, "Failed to set PAM user record data '%s': %s",
+                                   homed_field, pam_strerror(handle, r));
                         return r;
                 }
+
+                TAKE_PTR(json_copy);
         }
 
         r = json_parse(json, JSON_PARSE_SENSITIVE, &v, NULL, NULL);
@@ -187,6 +222,7 @@ static int acquire_user_record(
                 return PAM_SERVICE_ERR;
         }
 
+        /* Safety check if cached record actually matches what we are looking for */
         if (!streq_ptr(username, ur->user_name)) {
                 pam_syslog(handle, LOG_ERR, "Acquired user record does not match user name.");
                 return PAM_SERVICE_ERR;
@@ -199,23 +235,36 @@ static int acquire_user_record(
 
 user_unknown:
         /* Cache this, so that we don't check again */
-        r = pam_set_data(handle, "systemd-user-record-is-homed", USER_RECORD_IS_OTHER, NULL);
+        r = pam_set_data(handle, homed_field, (void*) -1, NULL);
         if (r != PAM_SUCCESS)
-                pam_syslog(handle, LOG_ERR, "Failed to set PAM user-record-is-homed flag, ignoring: %s", pam_strerror(handle, r));
+                pam_syslog(handle, LOG_ERR, "Failed to set PAM user record data '%s' to invalid, ignoring: %s",
+                           homed_field, pam_strerror(handle, r));
 
         return PAM_USER_UNKNOWN;
 }
 
-static int release_user_record(pam_handle_t *handle) {
+static int release_user_record(pam_handle_t *handle, const char *username) {
+        _cleanup_free_ char *homed_field = NULL, *generic_field = NULL;
         int r, k;
 
-        r = pam_set_data(handle, "systemd-user-record", NULL, NULL);
+        assert(handle);
+        assert(username);
+
+        homed_field = strjoin("systemd-home-user-record-", username);
+        if (!homed_field)
+                return pam_log_oom(handle);
+
+        r = pam_set_data(handle, homed_field, NULL, NULL);
         if (r != PAM_SUCCESS)
-                pam_syslog(handle, LOG_ERR, "Failed to release PAM user record data: %s", pam_strerror(handle, r));
+                pam_syslog(handle, LOG_ERR, "Failed to release PAM user record data '%s': %s", homed_field, pam_strerror(handle, r));
 
-        k = pam_set_data(handle, "systemd-user-record-is-homed", NULL, NULL);
+        generic_field = strjoin("systemd-user-record-", username);
+        if (!generic_field)
+                return pam_log_oom(handle);
+
+        k = pam_set_data(handle, generic_field, NULL, NULL);
         if (k != PAM_SUCCESS)
-                pam_syslog(handle, LOG_ERR, "Failed to release PAM user-record-is-homed flag: %s", pam_strerror(handle, k));
+                pam_syslog(handle, LOG_ERR, "Failed to release PAM user record data '%s': %s", generic_field, pam_strerror(handle, k));
 
         return IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA) ? k : r;
 }
@@ -256,8 +305,10 @@ static int handle_generic_user_record_error(
 
                 if (strv_isempty(secret->password))
                         r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Password: ");
-                else
-                        r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Password incorrect or not sufficient for authentication of user %s, please try again: ", user_name);
+                else {
+                        (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Password incorrect or not sufficient for authentication of user %s.", user_name);
+                        r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Sorry, try again: ");
+                }
                 if (r != PAM_SUCCESS)
                         return PAM_CONV_ERR; /* no logging here */
 
@@ -275,10 +326,13 @@ static int handle_generic_user_record_error(
         } else if (sd_bus_error_has_name(error, BUS_ERROR_BAD_PASSWORD_AND_NO_TOKEN)) {
                 _cleanup_(erase_and_freep) char *newp = NULL;
 
-                if (strv_isempty(secret->password))
-                        r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Security token of user %s not inserted, please enter password: ", user_name);
-                else
-                        r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Password incorrect or not sufficient, and configured security token of user %s not inserted, please enter password: ", user_name);
+                if (strv_isempty(secret->password)) {
+                        (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Security token of user %s not inserted.", user_name);
+                        r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Try again with password: ");
+                } else {
+                        (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Password incorrect or not sufficient, and configured security token of user %s not inserted.", user_name);
+                        r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Try again with password: ");
+                }
                 if (r != PAM_SUCCESS)
                         return PAM_CONV_ERR; /* no logging here */
 
@@ -296,7 +350,7 @@ static int handle_generic_user_record_error(
         } else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_PIN_NEEDED)) {
                 _cleanup_(erase_and_freep) char *newp = NULL;
 
-                r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Please enter security token PIN: ");
+                r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Security token PIN: ");
                 if (r != PAM_SUCCESS)
                         return PAM_CONV_ERR; /* no logging here */
 
@@ -324,7 +378,8 @@ static int handle_generic_user_record_error(
         } else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_BAD_PIN)) {
                 _cleanup_(erase_and_freep) char *newp = NULL;
 
-                r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Security token PIN incorrect, please enter PIN for security token of user %s again: ", user_name);
+                (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Security token PIN incorrect for user %s.", user_name);
+                r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Sorry, retry security token PIN: ");
                 if (r != PAM_SUCCESS)
                         return PAM_CONV_ERR; /* no logging here */
 
@@ -342,7 +397,8 @@ static int handle_generic_user_record_error(
         } else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_BAD_PIN_FEW_TRIES_LEFT)) {
                 _cleanup_(erase_and_freep) char *newp = NULL;
 
-                r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Security token PIN incorrect (only a few tries left!), please enter PIN for security token of user %s again: ", user_name);
+                (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Security token PIN of user %s incorrect (only a few tries left!)", user_name);
+                r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Sorry, retry security token PIN: ");
                 if (r != PAM_SUCCESS)
                         return PAM_CONV_ERR; /* no logging here */
 
@@ -360,7 +416,8 @@ static int handle_generic_user_record_error(
         } else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_BAD_PIN_ONE_TRY_LEFT)) {
                 _cleanup_(erase_and_freep) char *newp = NULL;
 
-                r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Security token PIN incorrect (only one try left!), please enter PIN for security token of user %s again: ", user_name);
+                (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Security token PIN of user %s incorrect (only one try left!)", user_name);
+                r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Sorry, retry security token PIN: ");
                 if (r != PAM_SUCCESS)
                         return PAM_CONV_ERR; /* no logging here */
 
@@ -393,7 +450,9 @@ static int acquire_home(
         bool do_auth = please_authenticate, home_not_active = false, home_locked = false;
         _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
         _cleanup_close_ int acquired_fd = -1;
+        _cleanup_free_ char *fd_field = NULL;
         const void *home_fd_ptr = NULL;
+        const char *username = NULL;
         unsigned n_attempts = 0;
         int r;
 
@@ -407,16 +466,35 @@ static int acquire_home(
          * authenticates, while the other PAM hooks unset it so that they can a ref of their own without
          * authentication if possible, but with authentication if necessary. */
 
+        r = pam_get_user(handle, &username, NULL);
+        if (r != PAM_SUCCESS) {
+                pam_syslog(handle, LOG_ERR, "Failed to get user name: %s", pam_strerror(handle, r));
+                return r;
+        }
+
+        if (isempty(username)) {
+                pam_syslog(handle, LOG_ERR, "User name not set.");
+                return PAM_SERVICE_ERR;
+        }
+
         /* If we already have acquired the fd, let's shortcut this */
-        r = pam_get_data(handle, "systemd-home-fd", &home_fd_ptr);
-        if (r == PAM_SUCCESS && PTR_TO_INT(home_fd_ptr) >= 0)
+        fd_field = strjoin("systemd-home-fd-", username);
+        if (!fd_field)
+                return pam_log_oom(handle);
+
+        r = pam_get_data(handle, fd_field, &home_fd_ptr);
+        if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) {
+                pam_syslog(handle, LOG_ERR, "Failed to retrieve PAM home reference fd: %s", pam_strerror(handle, r));
+                return r;
+        }
+        if (r == PAM_SUCCESS && PTR_TO_FD(home_fd_ptr) >= 0)
                 return PAM_SUCCESS;
 
         r = pam_acquire_bus_connection(handle, &bus);
         if (r != PAM_SUCCESS)
                 return r;
 
-        r = acquire_user_record(handle, &ur);
+        r = acquire_user_record(handle, username, &ur);
         if (r != PAM_SUCCESS)
                 return r;
 
@@ -457,7 +535,7 @@ static int acquire_home(
                         }
                 }
 
-                r = bus_message_new_method_call(bus, &m, &home_mgr, do_auth ? "AcquireHome" : "RefHome");
+                r = bus_message_new_method_call(bus, &m, bus_home_mgr, do_auth ? "AcquireHome" : "RefHome");
                 if (r < 0)
                         return pam_bus_log_create_error(handle, r);
 
@@ -532,7 +610,7 @@ static int acquire_home(
                 do_auth = true;
         }
 
-        r = pam_set_data(handle, "systemd-home-fd", FD_TO_PTR(acquired_fd), cleanup_home_fd);
+        r = pam_set_data(handle, fd_field, FD_TO_PTR(acquired_fd), cleanup_home_fd);
         if (r < 0) {
                 pam_syslog(handle, LOG_ERR, "Failed to set PAM bus data: %s", pam_strerror(handle, r));
                 return r;
@@ -543,7 +621,7 @@ static int acquire_home(
                 /* We likely just activated the home directory, let's flush out the user record, since a
                  * newer embedded user record might have been acquired from the activation. */
 
-                r = release_user_record(handle);
+                r = release_user_record(handle, ur->user_name);
                 if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
                         return r;
         }
@@ -553,15 +631,27 @@ static int acquire_home(
         return PAM_SUCCESS;
 }
 
-static int release_home_fd(pam_handle_t *handle) {
+static int release_home_fd(pam_handle_t *handle, const char *username) {
+        _cleanup_free_ char *fd_field = NULL;
         const void *home_fd_ptr = NULL;
         int r;
 
-        r = pam_get_data(handle, "systemd-home-fd", &home_fd_ptr);
-        if (r == PAM_NO_MODULE_DATA || PTR_TO_FD(home_fd_ptr) < 0)
+        assert(handle);
+        assert(username);
+
+        fd_field = strjoin("systemd-home-fd-", username);
+        if (!fd_field)
+                return pam_log_oom(handle);
+
+        r = pam_get_data(handle, fd_field, &home_fd_ptr);
+        if (r == PAM_NO_MODULE_DATA || (r == PAM_SUCCESS && PTR_TO_FD(home_fd_ptr) < 0))
                 return PAM_NO_MODULE_DATA;
+        if (r != PAM_SUCCESS) {
+                pam_syslog(handle, LOG_ERR, "Failed to retrieve PAM home reference fd: %s", pam_strerror(handle, r));
+                return r;
+        }
 
-        r = pam_set_data(handle, "systemd-home-fd", NULL, NULL);
+        r = pam_set_data(handle, fd_field, NULL, NULL);
         if (r != PAM_SUCCESS)
                 pam_syslog(handle, LOG_ERR, "Failed to release PAM home reference fd: %s", pam_strerror(handle, r));
 
@@ -575,6 +665,9 @@ _public_ PAM_EXTERN int pam_sm_authenticate(
 
         bool debug = false, suspend_please = false;
 
+        if (parse_env(handle, &suspend_please) < 0)
+                return PAM_AUTH_ERR;
+
         if (parse_argv(handle,
                        argc, argv,
                        &suspend_please,
@@ -599,6 +692,9 @@ _public_ PAM_EXTERN int pam_sm_open_session(
         bool debug = false, suspend_please = false;
         int r;
 
+        if (parse_env(handle, &suspend_please) < 0)
+                return PAM_SESSION_ERR;
+
         if (parse_argv(handle,
                        argc, argv,
                        &suspend_please,
@@ -620,6 +716,12 @@ _public_ PAM_EXTERN int pam_sm_open_session(
                 return r;
         }
 
+        r = pam_putenv(handle, suspend_please ? "SYSTEMD_HOME_SUSPEND=1" : "SYSTEMD_HOME_SUSPEND=0");
+        if (r != PAM_SUCCESS) {
+                pam_syslog(handle, LOG_ERR, "Failed to set PAM environment variable $SYSTEMD_HOME_SUSPEND: %s", pam_strerror(handle, r));
+                return r;
+        }
+
         /* 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. */
@@ -648,25 +750,30 @@ _public_ PAM_EXTERN int pam_sm_close_session(
         if (debug)
                 pam_syslog(handle, LOG_DEBUG, "pam-systemd-homed session end");
 
+        r = pam_get_user(handle, &username, NULL);
+        if (r != PAM_SUCCESS) {
+                pam_syslog(handle, LOG_ERR, "Failed to get user name: %s", pam_strerror(handle, r));
+                return r;
+        }
+
+        if (isempty(username)) {
+                pam_syslog(handle, LOG_ERR, "User name not set.");
+                return PAM_SERVICE_ERR;
+        }
+
         /* Let's explicitly drop the reference to the homed session, so that the subsequent ReleaseHome()
          * call will be able to do its thing. */
-        r = release_home_fd(handle);
+        r = release_home_fd(handle, username);
         if (r == PAM_NO_MODULE_DATA) /* Nothing to do, we never acquired an fd */
                 return PAM_SUCCESS;
         if (r != PAM_SUCCESS)
                 return r;
 
-        r = pam_get_user(handle, &username, NULL);
-        if (r != PAM_SUCCESS) {
-                pam_syslog(handle, LOG_ERR, "Failed to get user name: %s", pam_strerror(handle, r));
-                return r;
-        }
-
         r = pam_acquire_bus_connection(handle, &bus);
         if (r != PAM_SUCCESS)
                 return r;
 
-        r = bus_message_new_method_call(bus, &m, &home_mgr, "ReleaseHome");
+        r = bus_message_new_method_call(bus, &m, bus_home_mgr, "ReleaseHome");
         if (r < 0)
                 return pam_bus_log_create_error(handle, r);
 
@@ -698,6 +805,9 @@ _public_ PAM_EXTERN int pam_sm_acct_mgmt(
         usec_t t;
         int r;
 
+        if (parse_env(handle, &please_suspend) < 0)
+                return PAM_AUTH_ERR;
+
         if (parse_argv(handle,
                        argc, argv,
                        &please_suspend,
@@ -713,7 +823,7 @@ _public_ PAM_EXTERN int pam_sm_acct_mgmt(
         if (r != PAM_SUCCESS)
                 return r;
 
-        r = acquire_user_record(handle, &ur);
+        r = acquire_user_record(handle, NULL, &ur);
         if (r != PAM_SUCCESS)
                 return r;
 
@@ -821,7 +931,7 @@ _public_ PAM_EXTERN int pam_sm_chauthtok(
         if (r != PAM_SUCCESS)
                 return r;
 
-        r = acquire_user_record(handle, &ur);
+        r = acquire_user_record(handle, NULL, &ur);
         if (r != PAM_SUCCESS)
                 return r;
 
@@ -892,7 +1002,7 @@ _public_ PAM_EXTERN int pam_sm_chauthtok(
                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
 
-                r = bus_message_new_method_call(bus, &m, &home_mgr, "ChangePasswordHome");
+                r = bus_message_new_method_call(bus, &m, bus_home_mgr, "ChangePasswordHome");
                 if (r < 0)
                         return pam_bus_log_create_error(handle, r);
 
index 5863a229b80850a557a5a88be139fb1ab8d2b457..fbf6f6c8cc90cff44c80ef0e4dce69cec89b22fa 100644 (file)
@@ -148,7 +148,7 @@ int suggest_passwords(void) {
 
         pwquality_maybe_disable_dictionary(pwq);
 
-        suggestions = new0(char*, N_SUGGESTIONS);
+        suggestions = new0(char*, N_SUGGESTIONS+1);
         if (!suggestions)
                 return log_oom();
 
index c4a0d95081496fa0f547614deb187fe17b3d60b1..8f51f8d6e82ea40442abf1cee632814d0566bdba 100644 (file)
@@ -276,7 +276,7 @@ int user_record_add_binding(
 
         _cleanup_(json_variant_unrefp) JsonVariant *new_binding_entry = NULL, *binding = NULL;
         char smid[SD_ID128_STRING_MAX], partition_uuids[37], luks_uuids[37], fs_uuids[37];
-        _cleanup_free_ char *ip = NULL, *hd = NULL;
+        _cleanup_free_ char *ip = NULL, *hd = NULL, *ip_auto = NULL, *lc = NULL, *lcm = NULL, *fst = NULL;
         sd_id128_t mid;
         int r;
 
@@ -294,6 +294,10 @@ int user_record_add_binding(
                 ip = strdup(image_path);
                 if (!ip)
                         return -ENOMEM;
+        } else if (!h->image_path && storage >= 0) {
+                r = user_record_build_image_path(storage, user_record_user_name_and_realm(h), &ip_auto);
+                if (r < 0)
+                        return r;
         }
 
         if (home_directory) {
@@ -302,6 +306,24 @@ int user_record_add_binding(
                         return -ENOMEM;
         }
 
+        if (file_system_type) {
+                fst = strdup(file_system_type);
+                if (!fst)
+                        return -ENOMEM;
+        }
+
+        if (luks_cipher) {
+                lc = strdup(luks_cipher);
+                if (!lc)
+                        return -ENOMEM;
+        }
+
+        if (luks_cipher_mode) {
+                lcm = strdup(luks_cipher_mode);
+                if (!lcm)
+                        return -ENOMEM;
+        }
+
         r = json_build(&new_binding_entry,
                        JSON_BUILD_OBJECT(
                                        JSON_BUILD_PAIR_CONDITION(!!image_path, "imagePath", JSON_BUILD_STRING(image_path)),
@@ -348,6 +370,8 @@ int user_record_add_binding(
 
         if (ip)
                 free_and_replace(h->image_path, ip);
+        if (ip_auto)
+                free_and_replace(h->image_path_auto, ip_auto);
 
         if (!sd_id128_is_null(partition_uuid))
                 h->partition_uuid = partition_uuid;
@@ -358,11 +382,22 @@ int user_record_add_binding(
         if (!sd_id128_is_null(fs_uuid))
                 h->file_system_uuid = fs_uuid;
 
+        if (lc)
+                free_and_replace(h->luks_cipher, lc);
+        if (lcm)
+                free_and_replace(h->luks_cipher_mode, lcm);
+        if (luks_volume_key_size != UINT64_MAX)
+                h->luks_volume_key_size = luks_volume_key_size;
+
+        if (fst)
+                free_and_replace(h->file_system_type, fst);
         if (hd)
                 free_and_replace(h->home_directory, hd);
 
         if (uid_is_valid(uid))
                 h->uid = uid;
+        if (gid_is_valid(gid))
+                h->gid = gid;
 
         h->mask |= USER_RECORD_BINDING;
         return 1;
@@ -840,6 +875,8 @@ int user_record_set_password(UserRecord *h, char **password, bool prepend) {
         if (r < 0)
                 return r;
 
+        json_variant_sensitive(w);
+
         r = json_variant_set_field(&h->json, "secret", w);
         if (r < 0)
                 return r;
@@ -900,6 +937,8 @@ int user_record_set_pkcs11_pin(UserRecord *h, char **pin, bool prepend) {
         if (r < 0)
                 return r;
 
+        json_variant_sensitive(w);
+
         r = json_variant_set_field(&h->json, "secret", w);
         if (r < 0)
                 return r;
@@ -927,8 +966,11 @@ int user_record_set_pkcs11_protected_authentication_path_permitted(UserRecord *h
 
         if (json_variant_is_blank_object(w))
                 r = json_variant_filter(&h->json, STRV_MAKE("secret"));
-        else
+        else {
+                json_variant_sensitive(w);
+
                 r = json_variant_set_field(&h->json, "secret", w);
+        }
         if (r < 0)
                 return r;
 
index 5b4c74e299d71d8ce4173c9aca4d032f414177fe..e694a95a0411327e422b3001904f2f59c0904356 100644 (file)
@@ -26,6 +26,7 @@
 #include "parse-util.h"
 #include "path-util.h"
 #include "selinux-util.h"
+#include "service-util.h"
 #include "signal-util.h"
 #include "strv.h"
 #include "user-util.h"
@@ -42,9 +43,6 @@ enum {
         PROP_CHASSIS,
         PROP_DEPLOYMENT,
         PROP_LOCATION,
-        PROP_KERNEL_NAME,
-        PROP_KERNEL_RELEASE,
-        PROP_KERNEL_VERSION,
         PROP_OS_PRETTY_NAME,
         PROP_OS_CPE_NAME,
         PROP_HOME_URL,
@@ -54,8 +52,6 @@ enum {
 typedef struct Context {
         char *data[_PROP_MAX];
         Hashmap *polkit_registry;
-        sd_id128_t uuid;
-        bool has_uuid;
 } Context;
 
 static void context_reset(Context *c) {
@@ -67,7 +63,7 @@ static void context_reset(Context *c) {
                 c->data[p] = mfree(c->data[p]);
 }
 
-static void context_clear(Context *c) {
+static void context_destroy(Context *c) {
         assert(c);
 
         context_reset(c);
@@ -76,20 +72,11 @@ static void context_clear(Context *c) {
 
 static int context_read_data(Context *c) {
         int r;
-        struct utsname u;
 
         assert(c);
 
         context_reset(c);
 
-        assert_se(uname(&u) >= 0);
-        c->data[PROP_KERNEL_NAME] = strdup(u.sysname);
-        c->data[PROP_KERNEL_RELEASE] = strdup(u.release);
-        c->data[PROP_KERNEL_VERSION] = strdup(u.version);
-        if (!c->data[PROP_KERNEL_NAME] || !c->data[PROP_KERNEL_RELEASE] ||
-            !c->data[PROP_KERNEL_VERSION])
-                return -ENOMEM;
-
         c->data[PROP_HOSTNAME] = gethostname_malloc();
         if (!c->data[PROP_HOSTNAME])
                 return -ENOMEM;
@@ -115,17 +102,6 @@ static int context_read_data(Context *c) {
         if (r < 0 && r != -ENOENT)
                 return r;
 
-        r = id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, &c->uuid);
-        if (r == -ENOENT)
-                r = id128_read("/sys/firmware/devicetree/base/vm,uuid", ID128_UUID, &c->uuid);
-        if (r < 0)
-                log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
-                               "Failed to read product UUID, ignoring: %m");
-        else if (sd_id128_is_null(c->uuid) || sd_id128_is_allf(c->uuid))
-                log_debug("DMI product UUID " SD_ID128_FORMAT_STR " is all 0x00 or all 0xFF, ignoring.", SD_ID128_FORMAT_VAL(c->uuid));
-        else
-                c->has_uuid = true;
-
         return 0;
 }
 
@@ -281,7 +257,7 @@ static int context_update_kernel_hostname(Context *c) {
         if (hostname_is_useful(static_hn))
                 hn = static_hn;
 
-        /* ... the transient host name, (ie: DHCP) comes next ... */
+        /* ... the transient hostname, (ie: DHCP) comes next ... */
         else if (!isempty(c->data[PROP_HOSTNAME]))
                 hn = c->data[PROP_HOSTNAME];
 
@@ -410,6 +386,22 @@ static int property_get_chassis(
         return sd_bus_message_append(reply, "s", name);
 }
 
+static int property_get_uname_field(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        struct utsname u;
+
+        assert_se(uname(&u) >= 0);
+
+        return sd_bus_message_append(reply, "s", (char*) &u + PTR_TO_SIZE(userdata));
+}
+
 static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
         Context *c = userdata;
         const char *name;
@@ -455,11 +447,11 @@ static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *
 
         r = context_update_kernel_hostname(c);
         if (r < 0) {
-                log_error_errno(r, "Failed to set host name: %m");
+                log_error_errno(r, "Failed to set hostname: %m");
                 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
         }
 
-        log_info("Changed host name to '%s'", strna(c->data[PROP_HOSTNAME]));
+        log_info("Changed hostname to '%s'", strna(c->data[PROP_HOSTNAME]));
 
         (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "Hostname", NULL);
 
@@ -507,17 +499,17 @@ static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_
 
         r = context_update_kernel_hostname(c);
         if (r < 0) {
-                log_error_errno(r, "Failed to set host name: %m");
+                log_error_errno(r, "Failed to set hostname: %m");
                 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
         }
 
         r = context_write_data_static_hostname(c);
         if (r < 0) {
-                log_error_errno(r, "Failed to write static host name: %m");
+                log_error_errno(r, "Failed to write static hostname: %m");
                 return sd_bus_error_set_errnof(error, r, "Failed to set static hostname: %m");
         }
 
-        log_info("Changed static host name to '%s'", strna(c->data[PROP_STATIC_HOSTNAME]));
+        log_info("Changed static hostname to '%s'", strna(c->data[PROP_STATIC_HOSTNAME]));
 
         (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "StaticHostname", NULL);
 
@@ -548,7 +540,7 @@ static int set_machine_info(Context *c, sd_bus_message *m, int prop, sd_bus_mess
                 if (prop == PROP_ICON_NAME && !filename_is_valid(name))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid icon name '%s'", name);
                 if (prop == PROP_PRETTY_HOSTNAME && string_has_cc(name, NULL))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty host name '%s'", name);
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty hostname '%s'", name);
                 if (prop == PROP_CHASSIS && !valid_chassis(name))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid chassis '%s'", name);
                 if (prop == PROP_DEPLOYMENT && !valid_deployment(name))
@@ -586,7 +578,7 @@ static int set_machine_info(Context *c, sd_bus_message *m, int prop, sd_bus_mess
         }
 
         log_info("Changed %s to '%s'",
-                 prop == PROP_PRETTY_HOSTNAME ? "pretty host name" :
+                 prop == PROP_PRETTY_HOSTNAME ? "pretty hostname" :
                  prop == PROP_DEPLOYMENT ? "deployment" :
                  prop == PROP_LOCATION ? "location" :
                  prop == PROP_CHASSIS ? "chassis" : "icon name", strna(c->data[prop]));
@@ -626,13 +618,27 @@ static int method_set_location(sd_bus_message *m, void *userdata, sd_bus_error *
 static int method_get_product_uuid(sd_bus_message *m, void *userdata, sd_bus_error *error) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         Context *c = userdata;
+        bool has_uuid = false;
         int interactive, r;
+        sd_id128_t uuid;
 
         assert(m);
         assert(c);
 
-        if (!c->has_uuid)
-                return sd_bus_error_set(error, BUS_ERROR_NO_PRODUCT_UUID, "Failed to read product UUID from /sys/class/dmi/id/product_uuid");
+        r = id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, &uuid);
+        if (r == -ENOENT)
+                r = id128_read("/sys/firmware/devicetree/base/vm,uuid", ID128_UUID, &uuid);
+        if (r < 0)
+                log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
+                               "Failed to read product UUID, ignoring: %m");
+        else if (sd_id128_is_null(uuid) || sd_id128_is_allf(uuid))
+                log_debug("DMI product UUID " SD_ID128_FORMAT_STR " is all 0x00 or all 0xFF, ignoring.", SD_ID128_FORMAT_VAL(uuid));
+        else
+                has_uuid = true;
+
+        if (!has_uuid)
+                return sd_bus_error_set(error, BUS_ERROR_NO_PRODUCT_UUID,
+                                        "Failed to read product UUID from firmware.");
 
         r = sd_bus_message_read(m, "b", &interactive);
         if (r < 0)
@@ -656,7 +662,7 @@ static int method_get_product_uuid(sd_bus_message *m, void *userdata, sd_bus_err
         if (r < 0)
                 return r;
 
-        r = sd_bus_message_append_array(reply, 'y', &c->uuid, sizeof(c->uuid));
+        r = sd_bus_message_append_array(reply, 'y', &uuid, sizeof(uuid));
         if (r < 0)
                 return r;
 
@@ -672,9 +678,9 @@ static const sd_bus_vtable hostname_vtable[] = {
         SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("Deployment", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_DEPLOYMENT, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("Location", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_LOCATION, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
-        SD_BUS_PROPERTY("KernelName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("KernelRelease", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_RELEASE, SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("KernelVersion", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_VERSION, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("KernelName", "s", property_get_uname_field, offsetof(struct utsname, sysname), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("KernelRelease", "s", property_get_uname_field, offsetof(struct utsname, release), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("KernelVersion", "s", property_get_uname_field, offsetof(struct utsname, version), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_PRETTY_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("OperatingSystemCPEName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_CPE_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("HomeURL", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_HOME_URL, SD_BUS_VTABLE_PROPERTY_CONST),
@@ -739,6 +745,12 @@ static const sd_bus_vtable hostname_vtable[] = {
         SD_BUS_VTABLE_END,
 };
 
+static const BusObjectImplementation manager_object = {
+        "/org/freedesktop/hostname1",
+        "org.freedesktop.hostname1",
+        .vtables = BUS_VTABLES(hostname_vtable),
+};
+
 static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
         int r;
@@ -751,9 +763,9 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
         if (r < 0)
                 return log_error_errno(r, "Failed to get system bus connection: %m");
 
-        r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", hostname_vtable, c);
+        r = bus_add_implementation(bus, &manager_object, c);
         if (r < 0)
-                return log_error_errno(r, "Failed to register object: %m");
+                return r;
 
         r = bus_log_control_api_register(bus);
         if (r < 0)
@@ -773,21 +785,24 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
 }
 
 static int run(int argc, char *argv[]) {
-        _cleanup_(context_clear) Context context = {};
+        _cleanup_(context_destroy) Context context = {};
         _cleanup_(sd_event_unrefp) sd_event *event = NULL;
         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
         int r;
 
         log_setup_service();
 
+        r = service_parse_argv("systemd-hostnamed.service",
+                               "Manage the system hostname and related metadata.",
+                               BUS_IMPLEMENTATIONS(&manager_object,
+                                                   &log_control_object),
+                               argc, argv);
+        if (r <= 0)
+                return r;
+
         umask(0022);
         mac_selinux_init();
 
-        if (argc != 1) {
-                log_error("This program takes no arguments.");
-                return -EINVAL;
-        }
-
         assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
 
         r = sd_event_default(&event);
index 5bedc0b6942a37d4f06ac40ff21e8cd824b3aef9..5969a82b29917547b337e7cddc2a0b5fc8d8c863 100644 (file)
@@ -17,8 +17,8 @@
         <vendor_url>http://www.freedesktop.org/wiki/Software/systemd</vendor_url>
 
         <action id="org.freedesktop.hostname1.set-hostname">
-                <description gettext-domain="systemd">Set host name</description>
-                <message gettext-domain="systemd">Authentication is required to set the local host name.</message>
+                <description gettext-domain="systemd">Set hostname</description>
+                <message gettext-domain="systemd">Authentication is required to set the local hostname.</message>
                 <defaults>
                         <allow_any>auth_admin_keep</allow_any>
                         <allow_inactive>auth_admin_keep</allow_inactive>
@@ -27,8 +27,8 @@
         </action>
 
         <action id="org.freedesktop.hostname1.set-static-hostname">
-                <description gettext-domain="systemd">Set static host name</description>
-                <message gettext-domain="systemd">Authentication is required to set the statically configured local host name, as well as the pretty host name.</message>
+                <description gettext-domain="systemd">Set static hostname</description>
+                <message gettext-domain="systemd">Authentication is required to set the statically configured local hostname, as well as the pretty hostname.</message>
                 <defaults>
                         <allow_any>auth_admin_keep</allow_any>
                         <allow_inactive>auth_admin_keep</allow_inactive>
index 468303a6dce70773752467be2c3df405dbdb80d7..db55fa50d5d9f2cc8dffb75922c5b68b5ddecfb5 100644 (file)
@@ -172,8 +172,8 @@ static int import_fs(int argc, char *argv[], void *userdata) {
         progress.limit = (RateLimit) { 200*USEC_PER_MSEC, 1 };
 
         /* Hook into SIGINT/SIGTERM, so that we can cancel things then */
-        assert(sigaction(SIGINT, &sa, &old_sigint_sa) >= 0);
-        assert(sigaction(SIGTERM, &sa, &old_sigterm_sa) >= 0);
+        assert_se(sigaction(SIGINT, &sa, &old_sigint_sa) >= 0);
+        assert_se(sigaction(SIGTERM, &sa, &old_sigterm_sa) >= 0);
 
         r = btrfs_subvol_snapshot_fd_full(
                         fd,
@@ -220,8 +220,8 @@ static int import_fs(int argc, char *argv[], void *userdata) {
 
 finish:
         /* Put old signal handlers into place */
-        assert(sigaction(SIGINT, &old_sigint_sa, NULL) >= 0);
-        assert(sigaction(SIGTERM, &old_sigterm_sa, NULL) >= 0);
+        assert_se(sigaction(SIGINT, &old_sigint_sa, NULL) >= 0);
+        assert_se(sigaction(SIGTERM, &old_sigterm_sa, NULL) >= 0);
 
         return 0;
 }
index 8977ebd8352e2c54d6e78cf99ba127b36969d6e3..d799a10f94b24d3f931ab7ae19ed9e1b0fe7332e 100644 (file)
@@ -8,6 +8,7 @@
 #include "alloc-util.h"
 #include "bus-common-errors.h"
 #include "bus-log-control-api.h"
+#include "bus-util.h"
 #include "bus-polkit.h"
 #include "def.h"
 #include "fd-util.h"
@@ -22,6 +23,7 @@
 #include "path-util.h"
 #include "process-util.h"
 #include "signal-util.h"
+#include "service-util.h"
 #include "socket-util.h"
 #include "stat-util.h"
 #include "string-table.h"
@@ -488,11 +490,13 @@ static int transfer_start(Transfer *t) {
 
         t->stdin_fd = safe_close(t->stdin_fd);
 
-        r = sd_event_add_child(t->manager->event, &t->pid_event_source, t->pid, WEXITED, transfer_on_pid, t);
+        r = sd_event_add_child(t->manager->event, &t->pid_event_source,
+                               t->pid, WEXITED, transfer_on_pid, t);
         if (r < 0)
                 return r;
 
-        r = sd_event_add_io(t->manager->event, &t->log_event_source, t->log_fd, EPOLLIN, transfer_on_log, t);
+        r = sd_event_add_io(t->manager->event, &t->log_event_source,
+                            t->log_fd, EPOLLIN, transfer_on_log, t);
         if (r < 0)
                 return r;
 
@@ -546,47 +550,36 @@ static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void
                 .iov_base = buf,
                 .iov_len = sizeof(buf)-1,
         };
-        union {
-                struct cmsghdr cmsghdr;
-                uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
-                            CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)];
-        } control = {};
+        CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred)) +
+                         CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)) control;
         struct msghdr msghdr = {
                 .msg_iov = &iovec,
                 .msg_iovlen = 1,
                 .msg_control = &control,
                 .msg_controllen = sizeof(control),
         };
-        struct ucred *ucred = NULL;
+        struct ucred *ucred;
         Manager *m = userdata;
-        struct cmsghdr *cmsg;
         char *p, *e;
         Transfer *t;
         Iterator i;
         ssize_t n;
         int r;
 
-        n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
-        if (n < 0) {
-                if (IN_SET(errno, EAGAIN, EINTR))
-                        return 0;
-
-                return -errno;
-        }
+        n = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
+        if (IN_SET(n, -EAGAIN, -EINTR))
+                return 0;
+        if (n < 0)
+                return (int) n;
 
         cmsg_close_all(&msghdr);
 
-        CMSG_FOREACH(cmsg, &msghdr)
-                if (cmsg->cmsg_level == SOL_SOCKET &&
-                    cmsg->cmsg_type == SCM_CREDENTIALS &&
-                    cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
-                        ucred = (struct ucred*) CMSG_DATA(cmsg);
-
         if (msghdr.msg_flags & MSG_TRUNC) {
                 log_warning("Got overly long notification datagram, ignoring.");
                 return 0;
         }
 
+        ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred);
         if (!ucred || ucred->pid <= 0) {
                 log_warning("Got notification datagram lacking credential information, ignoring.");
                 return 0;
@@ -665,7 +658,8 @@ static int manager_new(Manager **ret) {
         if (r < 0)
                 return r;
 
-        r = sd_event_add_io(m->event, &m->notify_event_source, m->notify_fd, EPOLLIN, manager_on_notify, m);
+        r = sd_event_add_io(m->event, &m->notify_event_source,
+                            m->notify_fd, EPOLLIN, manager_on_notify, m);
         if (r < 0)
                 return r;
 
@@ -726,13 +720,15 @@ static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_
                 return -EINVAL;
 
         if (!machine_name_is_valid(local))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local);
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                         "Local name %s is invalid", local);
 
         r = setup_machine_directory(error);
         if (r < 0)
                 return r;
 
-        type = streq_ptr(sd_bus_message_get_member(msg), "ImportTar") ? TRANSFER_IMPORT_TAR : TRANSFER_IMPORT_RAW;
+        type = streq_ptr(sd_bus_message_get_member(msg), "ImportTar") ?
+                TRANSFER_IMPORT_TAR : TRANSFER_IMPORT_RAW;
 
         r = transfer_new(m, &t);
         if (r < 0)
@@ -794,7 +790,8 @@ static int method_import_fs(sd_bus_message *msg, void *userdata, sd_bus_error *e
                 return r;
 
         if (!machine_name_is_valid(local))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local);
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                         "Local name %s is invalid", local);
 
         r = setup_machine_directory(error);
         if (r < 0)
@@ -858,7 +855,8 @@ static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_
                 return r;
 
         if (!machine_name_is_valid(local))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local);
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                         "Local name %s is invalid", local);
 
         if (fstat(fd, &st) < 0)
                 return -errno;
@@ -866,7 +864,8 @@ static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_
         if (!S_ISREG(st.st_mode) && !S_ISFIFO(st.st_mode))
                 return -EINVAL;
 
-        type = streq_ptr(sd_bus_message_get_member(msg), "ExportTar") ? TRANSFER_EXPORT_TAR : TRANSFER_EXPORT_RAW;
+        type = streq_ptr(sd_bus_message_get_member(msg), "ExportTar") ?
+                TRANSFER_EXPORT_TAR : TRANSFER_EXPORT_RAW;
 
         r = transfer_new(m, &t);
         if (r < 0)
@@ -930,28 +929,33 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er
                 return r;
 
         if (!http_url_is_valid(remote))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "URL %s is invalid", remote);
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                         "URL %s is invalid", remote);
 
         if (isempty(local))
                 local = NULL;
         else if (!machine_name_is_valid(local))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local);
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                         "Local name %s is invalid", local);
 
         if (isempty(verify))
                 v = IMPORT_VERIFY_SIGNATURE;
         else
                 v = import_verify_from_string(verify);
         if (v < 0)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown verification mode %s", verify);
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                         "Unknown verification mode %s", verify);
 
         r = setup_machine_directory(error);
         if (r < 0)
                 return r;
 
-        type = streq_ptr(sd_bus_message_get_member(msg), "PullTar") ? TRANSFER_PULL_TAR : TRANSFER_PULL_RAW;
+        type = streq_ptr(sd_bus_message_get_member(msg), "PullTar") ?
+                TRANSFER_PULL_TAR : TRANSFER_PULL_RAW;
 
         if (manager_find(m, type, remote))
-                return sd_bus_error_setf(error, BUS_ERROR_TRANSFER_IN_PROGRESS, "Transfer for %s already in progress.", remote);
+                return sd_bus_error_setf(error, BUS_ERROR_TRANSFER_IN_PROGRESS,
+                                         "Transfer for %s already in progress.", remote);
 
         r = transfer_new(m, &t);
         if (r < 0)
@@ -1111,6 +1115,73 @@ static int property_get_progress(
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, transfer_type, TransferType);
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_verify, import_verify, ImportVerify);
 
+static int transfer_object_find(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                void *userdata,
+                void **found,
+                sd_bus_error *error) {
+
+        Manager *m = userdata;
+        Transfer *t;
+        const char *p;
+        uint32_t id;
+        int r;
+
+        assert(bus);
+        assert(path);
+        assert(interface);
+        assert(found);
+        assert(m);
+
+        p = startswith(path, "/org/freedesktop/import1/transfer/_");
+        if (!p)
+                return 0;
+
+        r = safe_atou32(p, &id);
+        if (r < 0 || id == 0)
+                return 0;
+
+        t = hashmap_get(m->transfers, UINT32_TO_PTR(id));
+        if (!t)
+                return 0;
+
+        *found = t;
+        return 1;
+}
+
+static int transfer_node_enumerator(
+                sd_bus *bus,
+                const char *path,
+                void *userdata,
+                char ***nodes,
+                sd_bus_error *error) {
+
+        _cleanup_strv_free_ char **l = NULL;
+        Manager *m = userdata;
+        Transfer *t;
+        unsigned k = 0;
+        Iterator i;
+
+        l = new0(char*, hashmap_size(m->transfers) + 1);
+        if (!l)
+                return -ENOMEM;
+
+        HASHMAP_FOREACH(t, m->transfers, i) {
+
+                l[k] = strdup(t->object_path);
+                if (!l[k])
+                        return -ENOMEM;
+
+                k++;
+        }
+
+        *nodes = TAKE_PTR(l);
+
+        return 1;
+}
+
 static const sd_bus_vtable transfer_vtable[] = {
         SD_BUS_VTABLE_START(0),
 
@@ -1132,6 +1203,13 @@ static const sd_bus_vtable transfer_vtable[] = {
         SD_BUS_VTABLE_END,
 };
 
+static const BusObjectImplementation transfer_object = {
+        "/org/freedesktop/import1/transfer",
+        "org.freedesktop.import1.Transfer",
+        .fallback_vtables = BUS_FALLBACK_VTABLES({transfer_vtable, transfer_object_find}),
+        .node_enumerator = transfer_node_enumerator,
+};
+
 static const sd_bus_vtable manager_vtable[] = {
         SD_BUS_VTABLE_START(0),
 
@@ -1238,76 +1316,21 @@ static const sd_bus_vtable manager_vtable[] = {
         SD_BUS_VTABLE_END,
 };
 
-static int transfer_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
-        Manager *m = userdata;
-        Transfer *t;
-        const char *p;
-        uint32_t id;
-        int r;
-
-        assert(bus);
-        assert(path);
-        assert(interface);
-        assert(found);
-        assert(m);
-
-        p = startswith(path, "/org/freedesktop/import1/transfer/_");
-        if (!p)
-                return 0;
-
-        r = safe_atou32(p, &id);
-        if (r < 0 || id == 0)
-                return 0;
-
-        t = hashmap_get(m->transfers, UINT32_TO_PTR(id));
-        if (!t)
-                return 0;
-
-        *found = t;
-        return 1;
-}
-
-static int transfer_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
-        _cleanup_strv_free_ char **l = NULL;
-        Manager *m = userdata;
-        Transfer *t;
-        unsigned k = 0;
-        Iterator i;
-
-        l = new0(char*, hashmap_size(m->transfers) + 1);
-        if (!l)
-                return -ENOMEM;
-
-        HASHMAP_FOREACH(t, m->transfers, i) {
-
-                l[k] = strdup(t->object_path);
-                if (!l[k])
-                        return -ENOMEM;
-
-                k++;
-        }
-
-        *nodes = TAKE_PTR(l);
-
-        return 1;
-}
+static const BusObjectImplementation manager_object = {
+        "/org/freedesktop/import1",
+        "org.freedesktop.import1.Manager",
+        .vtables = BUS_VTABLES(manager_vtable),
+        .children = BUS_IMPLEMENTATIONS(&transfer_object),
+};
 
 static int manager_add_bus_objects(Manager *m) {
         int r;
 
         assert(m);
 
-        r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/import1", "org.freedesktop.import1.Manager", manager_vtable, m);
-        if (r < 0)
-                return log_error_errno(r, "Failed to register object: %m");
-
-        r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/import1/transfer", "org.freedesktop.import1.Transfer", transfer_vtable, transfer_object_find, m);
+        r = bus_add_implementation(m->bus, &manager_object, m);
         if (r < 0)
-                return log_error_errno(r, "Failed to register object: %m");
-
-        r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/import1/transfer", transfer_node_enumerator, m);
-        if (r < 0)
-                return log_error_errno(r, "Failed to add transfer enumerator: %m");
+                return r;
 
         r = bus_log_control_api_register(m->bus);
         if (r < 0)
@@ -1348,12 +1371,15 @@ static int run(int argc, char *argv[]) {
 
         log_setup_service();
 
-        umask(0022);
+        r = service_parse_argv("systemd-importd.service",
+                               "VM and container image import and export service.",
+                               BUS_IMPLEMENTATIONS(&manager_object,
+                                                   &log_control_object),
+                               argc, argv);
+        if (r <= 0)
+                return r;
 
-        if (argc != 1) {
-                log_error("This program takes no arguments.");
-                return -EINVAL;
-        }
+        umask(0022);
 
         assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
 
index 150d0fb1990950b303f674493cbca21350d4317c..7505512fe7e4f5a5f1185545d2f7005ebab2b88f 100644 (file)
@@ -246,9 +246,10 @@ static int server_init(Server *s, unsigned n_sockets) {
         assert(s);
         assert(n_sockets > 0);
 
-        zero(*s);
+        *s = (struct Server) {
+                .epoll_fd = epoll_create1(EPOLL_CLOEXEC),
+        };
 
-        s->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
         if (s->epoll_fd < 0) {
                 r = log_error_errno(errno,
                                     "Failed to create epoll object: %m");
@@ -256,7 +257,6 @@ static int server_init(Server *s, unsigned n_sockets) {
         }
 
         for (i = 0; i < n_sockets; i++) {
-                struct epoll_event ev;
                 Fifo *f;
                 int fd;
 
@@ -283,9 +283,11 @@ static int server_init(Server *s, unsigned n_sockets) {
 
                 f->fd = -1;
 
-                zero(ev);
-                ev.events = EPOLLIN;
-                ev.data.ptr = f;
+                struct epoll_event ev = {
+                        .events = EPOLLIN,
+                        .data.ptr = f,
+                };
+
                 if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
                         r = -errno;
                         fifo_free(f);
index 5bfe5acadcebc54159089ff342c84597c5feb4d5..da37b3416ff4ce1b4bee2daf122cfc8b9e5f3819 100644 (file)
@@ -410,5 +410,5 @@ int open_journal_for_upload(Uploader *u,
                                                cursor);
         }
 
-        return process_journal_input(u, 1 + !!after_cursor);
+        return process_journal_input(u, !!after_cursor);
 }
index 2f9585df564220f51a59d224ba72198ce550690b..bf656ac670617c7ff740450c73ef30d168b1ee0d 100644 (file)
@@ -720,7 +720,7 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_FILE:
-                        r = glob_extend(&arg_file, optarg);
+                        r = glob_extend(&arg_file, optarg, GLOB_NOCHECK);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to add paths: %m");
                         break;
index 4e00e4fc5e721c07f922905abd03dce6b62abc02..2bbfc7644aed53c58d8d57bda085de47f5b03c33 100644 (file)
 #include <lz4frame.h>
 #endif
 
+#if HAVE_ZSTD
+#include <zstd.h>
+#include <zstd_errors.h>
+#endif
+
 #include "alloc-util.h"
 #include "compress.h"
 #include "fd-util.h"
@@ -33,6 +38,22 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(LZ4F_compressionContext_t, LZ4F_freeCompressionConte
 DEFINE_TRIVIAL_CLEANUP_FUNC(LZ4F_decompressionContext_t, LZ4F_freeDecompressionContext);
 #endif
 
+#if HAVE_ZSTD
+DEFINE_TRIVIAL_CLEANUP_FUNC(ZSTD_CCtx *, ZSTD_freeCCtx);
+DEFINE_TRIVIAL_CLEANUP_FUNC(ZSTD_DCtx *, ZSTD_freeDCtx);
+
+static int zstd_ret_to_errno(size_t ret) {
+        switch (ZSTD_getErrorCode(ret)) {
+        case ZSTD_error_dstSize_tooSmall:
+                return -ENOBUFS;
+        case ZSTD_error_memory_allocation:
+                return -ENOMEM;
+        default:
+                return -EBADMSG;
+        }
+}
+#endif
+
 #define ALIGN_8(l) ALIGN_TO(l, sizeof(size_t))
 
 static const char* const object_compressed_table[_OBJECT_COMPRESSED_MAX] = {
@@ -668,12 +689,230 @@ int decompress_stream_lz4(int in, int out, uint64_t max_bytes) {
 #endif
 }
 
+int compress_stream_zstd(int fdf, int fdt, uint64_t max_bytes) {
+#if HAVE_ZSTD
+        _cleanup_(ZSTD_freeCCtxp) ZSTD_CCtx *cctx = NULL;
+        _cleanup_free_ void *in_buff = NULL, *out_buff = NULL;
+        size_t in_allocsize, out_allocsize;
+        size_t z;
+        uint64_t left = max_bytes, in_bytes = 0;
+        /* This can be used in the future to add uncompressed size to the header */
+        uint64_t in_totalsize = 0;
+
+        assert(fdf >= 0);
+        assert(fdt >= 0);
+
+        /* Create the context and buffers */
+        in_allocsize = ZSTD_CStreamInSize();
+        out_allocsize = ZSTD_CStreamOutSize();
+        in_buff = malloc(in_allocsize);
+        out_buff = malloc(out_allocsize);
+        cctx = ZSTD_createCCtx();
+        if (!cctx || !out_buff || !in_buff)
+                return -ENOMEM;
+
+        if (in_totalsize) {
+                z = ZSTD_CCtx_setPledgedSrcSize(cctx, in_totalsize);
+                if (z)
+                        log_debug("Failed to enable ZSTD input size, ignoring: %s", ZSTD_getErrorName(z));
+        }
+        z = ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1);
+        if (ZSTD_isError(z))
+                log_debug("Failed to enable ZSTD checksum, ignoring: %s", ZSTD_getErrorName(z));
+
+        /* This loop read from the input file, compresses that entire chunk,
+         * and writes all output produced to the output file.
+         */
+        for (;;) {
+                bool is_last_chunk;
+                ZSTD_inBuffer input = {
+                        .src = in_buff,
+                        .size = 0,
+                        .pos = 0
+                };
+                ssize_t red;
+
+                red = loop_read(fdf, in_buff, in_allocsize, true);
+                if (red < 0)
+                        return red;
+                is_last_chunk = red == 0;
+
+                in_bytes += (size_t) red;
+                input.size = (size_t) red;
+
+                for (bool finished = false; !finished;) {
+                        ZSTD_outBuffer output = {
+                                .dst = out_buff,
+                                .size = out_allocsize,
+                                .pos = 0
+                        };
+                        size_t remaining;
+                        ssize_t wrote;
+
+                        /* Compress into the output buffer and write all of the
+                         * output to the file so we can reuse the buffer next
+                         * iteration.
+                         */
+                        remaining = ZSTD_compressStream2(
+                                cctx, &output, &input,
+                                is_last_chunk ? ZSTD_e_end : ZSTD_e_continue);
+
+                        if (ZSTD_isError(remaining)) {
+                                log_debug("ZSTD encoder failed: %s", ZSTD_getErrorName(remaining));
+                                return zstd_ret_to_errno(remaining);
+                        }
+
+                        if (left < output.pos)
+                                return -EFBIG;
+
+                        wrote = loop_write(fdt, output.dst, output.pos, 1);
+                        if (wrote < 0)
+                                return wrote;
+
+                        left -= output.pos;
+
+                        /* If we're on the last chunk we're finished when zstd
+                         * returns 0, which means its consumed all the input AND
+                         * finished the frame. Otherwise, we're finished when
+                         * we've consumed all the input.
+                         */
+                        finished = is_last_chunk ? (remaining == 0) : (input.pos == input.size);
+                }
+
+                /* zstd only returns 0 when the input is completely consumed */
+                assert(input.pos == input.size);
+                if (is_last_chunk)
+                        break;
+        }
+
+        log_debug(
+                "ZSTD compression finished (%" PRIu64 " -> %" PRIu64 " bytes, %.1f%%)",
+                in_bytes,
+                max_bytes - left,
+                (double) (max_bytes - left) / in_bytes * 100);
+
+        return 0;
+#else
+        return -EPROTONOSUPPORT;
+#endif
+}
+
+int decompress_stream_zstd(int fdf, int fdt, uint64_t max_bytes) {
+#if HAVE_ZSTD
+        _cleanup_(ZSTD_freeDCtxp) ZSTD_DCtx *dctx = NULL;
+        _cleanup_free_ void *in_buff = NULL, *out_buff = NULL;
+        size_t in_allocsize, out_allocsize;
+        size_t last_result = 0;
+        uint64_t left = max_bytes, in_bytes = 0;
+
+        assert(fdf >= 0);
+        assert(fdt >= 0);
+
+        /* Create the context and buffers */
+        in_allocsize = ZSTD_DStreamInSize();
+        out_allocsize = ZSTD_DStreamOutSize();
+        in_buff = malloc(in_allocsize);
+        out_buff = malloc(out_allocsize);
+        dctx = ZSTD_createDCtx();
+        if (!dctx || !out_buff || !in_buff)
+                return -ENOMEM;
+
+        /* This loop assumes that the input file is one or more concatenated
+         * zstd streams. This example won't work if there is trailing non-zstd
+         * data at the end, but streaming decompression in general handles this
+         * case. ZSTD_decompressStream() returns 0 exactly when the frame is
+         * completed, and doesn't consume input after the frame.
+         */
+        for (;;) {
+                bool has_error = false;
+                ZSTD_inBuffer input = {
+                        .src = in_buff,
+                        .size = 0,
+                        .pos = 0
+                };
+                ssize_t red;
+
+                red = loop_read(fdf, in_buff, in_allocsize, true);
+                if (red < 0)
+                        return red;
+                if (red == 0)
+                        break;
+
+                in_bytes += (size_t) red;
+                input.size = (size_t) red;
+                input.pos = 0;
+
+                /* Given a valid frame, zstd won't consume the last byte of the
+                 * frame until it has flushed all of the decompressed data of
+                 * the frame. So input.pos < input.size means frame is not done
+                 * or there is still output available.
+                 */
+                while (input.pos < input.size) {
+                        ZSTD_outBuffer output = {
+                                .dst = out_buff,
+                                .size = out_allocsize,
+                                .pos = 0
+                        };
+                        ssize_t wrote;
+                        /* The return code is zero if the frame is complete, but
+                         * there may be multiple frames concatenated together.
+                         * Zstd will automatically reset the context when a
+                         * frame is complete. Still, calling ZSTD_DCtx_reset()
+                         * can be useful to reset the context to a clean state,
+                         * for instance if the last decompression call returned
+                         * an error.
+                         */
+                        last_result = ZSTD_decompressStream(dctx, &output, &input);
+                        if (ZSTD_isError(last_result)) {
+                                has_error = true;
+                                break;
+                        }
+
+                        if (left < output.pos)
+                                return -EFBIG;
+
+                        wrote = loop_write(fdt, output.dst, output.pos, 1);
+                        if (wrote < 0)
+                                return wrote;
+
+                        left -= output.pos;
+                }
+                if (has_error)
+                        break;
+        }
+
+        if (in_bytes == 0)
+                return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "ZSTD decoder failed: no data read");
+
+        if (last_result != 0) {
+                /* The last return value from ZSTD_decompressStream did not end
+                 * on a frame, but we reached the end of the file! We assume
+                 * this is an error, and the input was truncated.
+                 */
+                log_debug("ZSTD decoder failed: %s", ZSTD_getErrorName(last_result));
+                return zstd_ret_to_errno(last_result);
+        }
+
+        log_debug(
+                "ZSTD decompression finished (%" PRIu64 " -> %" PRIu64 " bytes, %.1f%%)",
+                in_bytes,
+                max_bytes - left,
+                (double) (max_bytes - left) / in_bytes * 100);
+        return 0;
+#else
+        log_debug("Cannot decompress file. Compiled without ZSTD support.");
+        return -EPROTONOSUPPORT;
+#endif
+}
+
 int decompress_stream(const char *filename, int fdf, int fdt, uint64_t max_bytes) {
 
         if (endswith(filename, ".lz4"))
                 return decompress_stream_lz4(fdf, fdt, max_bytes);
         else if (endswith(filename, ".xz"))
                 return decompress_stream_xz(fdf, fdt, max_bytes);
+        else if (endswith(filename, ".zst"))
+                return decompress_stream_zstd(fdf, fdt, max_bytes);
         else
                 return -EPROTONOSUPPORT;
 }
index 56411484cee71acc7e448e274ea0d91488c1f395..74ef592f4374d8e74385af34d119f3fa657e0eba 100644 (file)
@@ -52,11 +52,16 @@ int decompress_startswith(int compression,
 
 int compress_stream_xz(int fdf, int fdt, uint64_t max_bytes);
 int compress_stream_lz4(int fdf, int fdt, uint64_t max_bytes);
+int compress_stream_zstd(int fdf, int fdt, uint64_t max_bytes);
 
 int decompress_stream_xz(int fdf, int fdt, uint64_t max_size);
 int decompress_stream_lz4(int fdf, int fdt, uint64_t max_size);
+int decompress_stream_zstd(int fdf, int fdt, uint64_t max_size);
 
-#if HAVE_LZ4
+#if HAVE_ZSTD
+#  define compress_stream compress_stream_zstd
+#  define COMPRESSED_EXT ".zst"
+#elif HAVE_LZ4
 #  define compress_stream compress_stream_lz4
 #  define COMPRESSED_EXT ".lz4"
 #else
index 1dda2149d46ffcd14fc260874bc23f58729c3171..0ef3df89df264a1040d770c293ac951c94df1c8d 100644 (file)
@@ -60,7 +60,7 @@ static void mpi_export(void *buf, size_t buflen, const gcry_mpi_t x) {
 
 static gcry_mpi_t mpi_import(const void *buf, size_t buflen) {
         gcry_mpi_t h;
-        unsigned len;
+        _unused_ unsigned len;
 
         assert_se(gcry_mpi_scan(&h, GCRYMPI_FMT_USG, buf, buflen, NULL) == 0);
         len = (gcry_mpi_get_nbits(h) + 7) / 8;
index 912ecef73cce0d13a5a8967e0752d1acc624fa15..b07bb592add44df9e485c9c74a7df374fdc99cbd 100644 (file)
@@ -15,6 +15,7 @@
 #include "errno-util.h"
 #include "fd-util.h"
 #include "io-util.h"
+#include "fileio.h"
 #include "memfd-util.h"
 #include "socket-util.h"
 #include "stdio-util.h"
@@ -73,12 +74,12 @@ _public_ int sd_journal_print(int priority, const char *format, ...) {
 }
 
 _public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
-
-        /* FIXME: Instead of limiting things to LINE_MAX we could do a
-           C99 variable-length array on the stack here in a loop. */
-
-        char buffer[8 + LINE_MAX], p[STRLEN("PRIORITY=") + DECIMAL_STR_MAX(int) + 1];
+        char p[STRLEN("PRIORITY=") + DECIMAL_STR_MAX(int) + 1];
+        char sbuf[LINE_MAX + 8] = "MESSAGE=";
         struct iovec iov[2];
+        int len;
+        va_list aq;
+        char *buffer = sbuf;
 
         assert_return(priority >= 0, -EINVAL);
         assert_return(priority <= 7, -EINVAL);
@@ -86,14 +87,27 @@ _public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
 
         xsprintf(p, "PRIORITY=%i", priority & LOG_PRIMASK);
 
-        memcpy(buffer, "MESSAGE=", 8);
-        vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
+        va_copy(aq, ap);
+        len = vsnprintf(buffer + 8, LINE_MAX, format, aq);
+        va_end(aq);
+
+        if (len >= (int)LONG_LINE_MAX - 8)
+                return -ENOBUFS;
+
+        /* Allocate large buffer to accomodate big message */
+        if (len >= LINE_MAX) {
+                int rlen;
+                buffer = alloca(len + 9);
+                memcpy(buffer, "MESSAGE=", 8);
+                rlen = vsnprintf(buffer + 8, len + 1, format, ap);
+                assert(len == rlen);
+        }
 
         /* Strip trailing whitespace, keep prefix whitespace. */
         (void) strstrip(buffer);
 
         /* Suppress empty lines */
-        if (isempty(buffer+8))
+        if (isempty(buffer + 8))
                 return 0;
 
         iov[0] = IOVEC_MAKE_STRING(buffer);
@@ -437,9 +451,13 @@ _public_ int sd_journal_print_with_location(int priority, const char *file, cons
 }
 
 _public_ int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) {
-        char buffer[8 + LINE_MAX], p[STRLEN("PRIORITY=") + DECIMAL_STR_MAX(int) + 1];
+        char p[STRLEN("PRIORITY=") + DECIMAL_STR_MAX(int) + 1];
+        char sbuf[LINE_MAX + 8] = "MESSAGE=";
         struct iovec iov[5];
         char *f;
+        int len;
+        char *buffer = sbuf;
+        va_list aq;
 
         assert_return(priority >= 0, -EINVAL);
         assert_return(priority <= 7, -EINVAL);
@@ -447,14 +465,27 @@ _public_ int sd_journal_printv_with_location(int priority, const char *file, con
 
         xsprintf(p, "PRIORITY=%i", priority & LOG_PRIMASK);
 
-        memcpy(buffer, "MESSAGE=", 8);
-        vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
+        va_copy(aq, ap);
+        len = vsnprintf(buffer + 8, LINE_MAX, format, aq);
+        va_end(aq);
+
+        if (len >= (int)LONG_LINE_MAX - 8)
+                return -ENOBUFS;
+
+        /* Allocate large buffer to accomodate big message */
+        if (len >= LINE_MAX) {
+                int rlen;
+                buffer = alloca(len + 9);
+                memcpy(buffer, "MESSAGE=", 8);
+                rlen = vsnprintf(buffer + 8, len + 1, format, ap);
+                assert(len == rlen);
+        }
 
         /* Strip trailing whitespace, keep prefixing whitespace */
         (void) strstrip(buffer);
 
         /* Suppress empty lines */
-        if (isempty(buffer+8))
+        if (isempty(buffer + 8))
                 return 0;
 
         /* func is initialized from __func__ which is not a macro, but
index 7dc48fdb63d570fdc06be954283aefe0b068fd45..a082995498f993e07b269a0fb26291ed22e9e5b9 100644 (file)
@@ -705,7 +705,7 @@ static int parse_argv(int argc, char *argv[]) {
                                  * STDIN. To avoid confusion we hence don't document this feature. */
                                 arg_file_stdin = true;
                         else {
-                                r = glob_extend(&arg_file, optarg);
+                                r = glob_extend(&arg_file, optarg, GLOB_NOCHECK);
                                 if (r < 0)
                                         return log_error_errno(r, "Failed to add paths: %m");
                         }
@@ -1783,7 +1783,6 @@ static int setup_keys(void) {
         int fd = -1, r;
         sd_id128_t machine, boot;
         char *p = NULL, *k = NULL;
-        struct FSSHeader h;
         uint64_t n;
         struct stat st;
 
@@ -1873,15 +1872,17 @@ static int setup_keys(void) {
         if (r < 0)
                 log_warning_errno(r, "Failed to set file attributes: %m");
 
-        zero(h);
+        struct FSSHeader h = {
+                .machine_id = machine,
+                .boot_id = boot,
+                .header_size = htole64(sizeof(h)),
+                .start_usec = htole64(n * arg_interval),
+                .interval_usec = htole64(arg_interval),
+                .fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR),
+                .fsprg_state_size = htole64(state_size),
+        };
+
         memcpy(h.signature, "KSHHRHLP", 8);
-        h.machine_id = machine;
-        h.boot_id = boot;
-        h.header_size = htole64(sizeof(h));
-        h.start_usec = htole64(n * arg_interval);
-        h.interval_usec = htole64(arg_interval);
-        h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
-        h.fsprg_state_size = htole64(state_size);
 
         r = loop_write(fd, &h, sizeof(h), false);
         if (r < 0) {
index 64cb3279f64f6efcdbfc79a76eb277b24b22b79a..9efa65a29427d88882b567411edda70218431e50 100644 (file)
@@ -1268,21 +1268,14 @@ int server_process_datagram(
         int *fds = NULL, v = 0;
         size_t n_fds = 0;
 
-        union {
-                struct cmsghdr cmsghdr;
-
-                /* We use NAME_MAX space for the SELinux label
-                 * here. The kernel currently enforces no
-                 * limit, but according to suggestions from
-                 * the SELinux people this will change and it
-                 * will probably be identical to NAME_MAX. For
-                 * now we use that, but this should be updated
-                 * one day when the final limit is known. */
-                uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
-                            CMSG_SPACE(sizeof(struct timeval)) +
-                            CMSG_SPACE(sizeof(int)) + /* fd */
-                            CMSG_SPACE(NAME_MAX)]; /* selinux label */
-        } control = {};
+        /* We use NAME_MAX space for the SELinux label here. The kernel currently enforces no limit, but
+         * according to suggestions from the SELinux people this will change and it will probably be
+         * identical to NAME_MAX. For now we use that, but this should be updated one day when the final
+         * limit is known. */
+        CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred)) +
+                         CMSG_SPACE(sizeof(struct timeval)) +
+                         CMSG_SPACE(sizeof(int)) + /* fd */
+                         CMSG_SPACE(NAME_MAX) /* selinux label */) control;
 
         union sockaddr_union sa = {};
 
@@ -1317,29 +1310,35 @@ int server_process_datagram(
 
         iovec = IOVEC_MAKE(s->buffer, s->buffer_size - 1); /* Leave room for trailing NUL we add later */
 
-        n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
-        if (n < 0) {
-                if (IN_SET(errno, EINTR, EAGAIN))
-                        return 0;
-
-                return log_error_errno(errno, "recvmsg() failed: %m");
+        n = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
+        if (IN_SET(n, -EINTR, -EAGAIN))
+                return 0;
+        if (n == -EXFULL) {
+                log_warning("Got message with truncated control data (too many fds sent?), ignoring.");
+                return 0;
         }
+        if (n < 0)
+                return log_error_errno(n, "recvmsg() failed: %m");
 
         CMSG_FOREACH(cmsg, &msghdr)
                 if (cmsg->cmsg_level == SOL_SOCKET &&
                     cmsg->cmsg_type == SCM_CREDENTIALS &&
-                    cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
+                    cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
+                        assert(!ucred);
                         ucred = (struct ucred*) CMSG_DATA(cmsg);
-                else if (cmsg->cmsg_level == SOL_SOCKET &&
+                else if (cmsg->cmsg_level == SOL_SOCKET &&
                          cmsg->cmsg_type == SCM_SECURITY) {
+                        assert(!label);
                         label = (char*) CMSG_DATA(cmsg);
                         label_len = cmsg->cmsg_len - CMSG_LEN(0);
                 } else if (cmsg->cmsg_level == SOL_SOCKET &&
                            cmsg->cmsg_type == SO_TIMESTAMP &&
-                           cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval)))
+                           cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval))) {
+                        assert(!tv);
                         tv = (struct timeval*) CMSG_DATA(cmsg);
-                else if (cmsg->cmsg_level == SOL_SOCKET &&
+                else if (cmsg->cmsg_level == SOL_SOCKET &&
                          cmsg->cmsg_type == SCM_RIGHTS) {
+                        assert(!fds);
                         fds = (int*) CMSG_DATA(cmsg);
                         n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
                 }
@@ -1746,7 +1745,7 @@ static int server_open_hostname(Server *s) {
 
         r = sd_event_source_set_priority(s->hostname_event_source, SD_EVENT_PRIORITY_IMPORTANT-10);
         if (r < 0)
-                return log_error_errno(r, "Failed to adjust priority of host name event source: %m");
+                return log_error_errno(r, "Failed to adjust priority of hostname event source: %m");
 
         return 0;
 }
index 609af506a429d12ebca2e91bab88703485a940c7..241e2572e6de40702cd3b6dca744a52cc262ee1f 100644 (file)
@@ -58,6 +58,9 @@ typedef enum LineBreak {
         LINE_BREAK_NUL,
         LINE_BREAK_LINE_MAX,
         LINE_BREAK_EOF,
+        LINE_BREAK_PID_CHANGE,
+        _LINE_BREAK_MAX,
+        _LINE_BREAK_INVALID = -1,
 } LineBreak;
 
 struct StdoutStream {
@@ -238,7 +241,11 @@ fail:
         return log_error_errno(r, "Failed to save stream data %s: %m", s->state_file);
 }
 
-static int stdout_stream_log(StdoutStream *s, const char *p, LineBreak line_break) {
+static int stdout_stream_log(
+                StdoutStream *s,
+                const char *p,
+                LineBreak line_break) {
+
         struct iovec *iovec;
         int priority;
         char syslog_priority[] = "PRIORITY=\0";
@@ -250,6 +257,9 @@ static int stdout_stream_log(StdoutStream *s, const char *p, LineBreak line_brea
         assert(s);
         assert(p);
 
+        assert(line_break >= 0);
+        assert(line_break < _LINE_BREAK_MAX);
+
         if (s->context)
                 (void) client_context_maybe_refresh(s->server, s->context, NULL, NULL, 0, NULL, USEC_INFINITY);
         else if (pid_is_valid(s->ucred.pid)) {
@@ -301,17 +311,20 @@ static int stdout_stream_log(StdoutStream *s, const char *p, LineBreak line_brea
                         iovec[n++] = IOVEC_MAKE_STRING(syslog_identifier);
         }
 
-        if (line_break != LINE_BREAK_NEWLINE) {
-                const char *c;
+        static const char * const line_break_field_table[_LINE_BREAK_MAX] = {
+                [LINE_BREAK_NEWLINE]    = NULL, /* Do not add field if traditional newline */
+                [LINE_BREAK_NUL]        = "_LINE_BREAK=nul",
+                [LINE_BREAK_LINE_MAX]   = "_LINE_BREAK=line-max",
+                [LINE_BREAK_EOF]        = "_LINE_BREAK=eof",
+                [LINE_BREAK_PID_CHANGE] = "_LINE_BREAK=pid-change",
+        };
 
-                /* If this log message was generated due to an uncommon line break then mention this in the log
-                 * entry */
+        const char *c = line_break_field_table[line_break];
 
-                c =     line_break == LINE_BREAK_NUL ?      "_LINE_BREAK=nul" :
-                        line_break == LINE_BREAK_LINE_MAX ? "_LINE_BREAK=line-max" :
-                                                            "_LINE_BREAK=eof";
+        /* If this log message was generated due to an uncommon line break then mention this in the log
+         * entry */
+        if (c)
                 iovec[n++] = IOVEC_MAKE_STRING(c);
-        }
 
         message = strjoin("MESSAGE=", p);
         if (message)
@@ -322,8 +335,8 @@ static int stdout_stream_log(StdoutStream *s, const char *p, LineBreak line_brea
 }
 
 static int stdout_stream_line(StdoutStream *s, char *p, LineBreak line_break) {
-        int r;
         char *orig;
+        int r;
 
         assert(s);
         assert(p);
@@ -332,10 +345,9 @@ static int stdout_stream_line(StdoutStream *s, char *p, LineBreak line_break) {
         p = strstrip(p);
 
         /* line breaks by NUL, line max length or EOF are not permissible during the negotiation part of the protocol */
-        if (line_break != LINE_BREAK_NEWLINE && s->state != STDOUT_STREAM_RUNNING) {
-                log_warning("Control protocol line not properly terminated.");
-                return -EINVAL;
-        }
+        if (line_break != LINE_BREAK_NEWLINE && s->state != STDOUT_STREAM_RUNNING)
+                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+                                         "Control protocol line not properly terminated.");
 
         switch (s->state) {
 
@@ -425,21 +437,43 @@ static int stdout_stream_line(StdoutStream *s, char *p, LineBreak line_break) {
         assert_not_reached("Unknown stream state");
 }
 
-static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
-        char *p;
-        size_t remaining;
+static int stdout_stream_found(
+                StdoutStream *s,
+                char *p,
+                size_t l,
+                LineBreak line_break) {
+
+        char saved;
         int r;
 
         assert(s);
+        assert(p);
+
+        /* Let's NUL terminate the specified buffer for this call, and revert back afterwards */
+        saved = p[l];
+        p[l] = 0;
+        r = stdout_stream_line(s, p, line_break);
+        p[l] = saved;
+
+        return r;
+}
+
+static int stdout_stream_scan(
+                StdoutStream *s,
+                char *p,
+                size_t remaining,
+                LineBreak force_flush,
+                size_t *ret_consumed) {
 
-        p = s->buffer;
-        remaining = s->length;
+        size_t consumed = 0;
+        int r;
 
-        /* XXX: This function does nothing if (s->length == 0) */
+        assert(s);
+        assert(p);
 
         for (;;) {
                 LineBreak line_break;
-                size_t skip;
+                size_t skip, found;
                 char *end1, *end2;
 
                 end1 = memchr(p, '\n', remaining);
@@ -447,62 +481,59 @@ static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
 
                 if (end2) {
                         /* We found a NUL terminator */
-                        skip = end2 - p + 1;
+                        found = end2 - p;
+                        skip = found + 1;
                         line_break = LINE_BREAK_NUL;
                 } else if (end1) {
                         /* We found a \n terminator */
-                        *end1 = 0;
-                        skip = end1 - p + 1;
+                        found = end1 - p;
+                        skip = found + 1;
                         line_break = LINE_BREAK_NEWLINE;
                 } else if (remaining >= s->server->line_max) {
                         /* Force a line break after the maximum line length */
-                        *(p + s->server->line_max) = 0;
-                        skip = remaining;
+                        found = skip = s->server->line_max;
                         line_break = LINE_BREAK_LINE_MAX;
                 } else
                         break;
 
-                r = stdout_stream_line(s, p, line_break);
+                r = stdout_stream_found(s, p, found, line_break);
                 if (r < 0)
                         return r;
 
-                remaining -= skip;
                 p += skip;
+                consumed += skip;
+                remaining -= skip;
         }
 
-        if (force_flush && remaining > 0) {
-                p[remaining] = 0;
-                r = stdout_stream_line(s, p, LINE_BREAK_EOF);
+        if (force_flush >= 0 && remaining > 0) {
+                r = stdout_stream_found(s, p, remaining, force_flush);
                 if (r < 0)
                         return r;
 
-                p += remaining;
-                remaining = 0;
+                consumed += remaining;
         }
 
-        if (p > s->buffer) {
-                memmove(s->buffer, p, remaining);
-                s->length = remaining;
-        }
+        if (ret_consumed)
+                *ret_consumed = consumed;
 
         return 0;
 }
 
 static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
-        uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
+        CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
         StdoutStream *s = userdata;
-        struct ucred *ucred = NULL;
-        struct cmsghdr *cmsg;
+        size_t limit, consumed;
+        struct ucred *ucred;
         struct iovec iovec;
-        size_t limit;
         ssize_t l;
+        char *p;
         int r;
 
         struct msghdr msghdr = {
                 .msg_iov = &iovec,
                 .msg_iovlen = 1,
-                .msg_control = buf,
-                .msg_controllen = sizeof(buf),
+                .msg_control = &control,
+                .msg_controllen = sizeof(control),
         };
 
         assert(s);
@@ -512,8 +543,8 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents,
                 goto terminate;
         }
 
-        /* If the buffer is full already (discounting the extra NUL we need), add room for another 1K */
-        if (s->length + 1 >= s->allocated) {
+        /* If the buffer is almost full, add room for another 1K */
+        if (s->length + 512 >= s->allocated) {
                 if (!GREEDY_REALLOC(s->buffer, s->allocated, s->length + 1 + 1024)) {
                         log_oom();
                         goto terminate;
@@ -523,7 +554,7 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents,
         /* Try to make use of the allocated buffer in full, but never read more than the configured line size. Also,
          * always leave room for a terminating NUL we might need to add. */
         limit = MIN(s->allocated - 1, s->server->line_max);
-
+        assert(s->length <= limit);
         iovec = IOVEC_MAKE(s->buffer + s->length, limit - s->length);
 
         l = recvmsg(s->fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
@@ -537,42 +568,42 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents,
         cmsg_close_all(&msghdr);
 
         if (l == 0) {
-                stdout_stream_scan(s, true);
+                (void) stdout_stream_scan(s, s->buffer, s->length, /* force_flush = */ LINE_BREAK_EOF, NULL);
                 goto terminate;
         }
 
-        CMSG_FOREACH(cmsg, &msghdr)
-                if (cmsg->cmsg_level == SOL_SOCKET &&
-                    cmsg->cmsg_type == SCM_CREDENTIALS &&
-                    cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
-                        ucred = (struct ucred *)CMSG_DATA(cmsg);
-                        break;
-                }
-
-        /* Invalidate the context if the pid of the sender changed.
-         * This happens when a forked process inherits stdout / stderr
-         * from a parent. In this case getpeercred returns the ucred
-         * of the parent, which can be invalid if the parent has exited
-         * in the meantime.
-         */
+        /* Invalidate the context if the PID of the sender changed. This happens when a forked process
+         * inherits stdout/stderr from a parent. In this case getpeercred() returns the ucred of the parent,
+         * which can be invalid if the parent has exited in the meantime. */
+        ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred);
         if (ucred && ucred->pid != s->ucred.pid) {
-                /* force out any previously half-written lines from a
-                 * different process, before we switch to the new ucred
-                 * structure for everything we just added */
-                r = stdout_stream_scan(s, true);
+                /* Force out any previously half-written lines from a different process, before we switch to
+                 * the new ucred structure for everything we just added */
+                r = stdout_stream_scan(s, s->buffer, s->length, /* force_flush = */ LINE_BREAK_PID_CHANGE, NULL);
                 if (r < 0)
                         goto terminate;
 
-                s->ucred = *ucred;
-                client_context_release(s->server, s->context);
-                s->context = NULL;
+                s->context = client_context_release(s->server, s->context);
+
+                p = s->buffer + s->length;
+        } else {
+                p = s->buffer;
+                l += s->length;
         }
 
-        s->length += l;
-        r = stdout_stream_scan(s, false);
+        /* Always copy in the new credentials */
+        if (ucred)
+                s->ucred = *ucred;
+
+        r = stdout_stream_scan(s, p, l, _LINE_BREAK_INVALID, &consumed);
         if (r < 0)
                 goto terminate;
 
+        /* Move what wasn't consumed to the front of the buffer */
+        assert(consumed <= (size_t) l);
+        s->length = l - consumed;
+        memmove(s->buffer, p + consumed, s->length);
+
         return 1;
 
 terminate:
index 1325b563854f6f5da2f9b41def2dc3abdb7712c6..46013c38784d2f1c88b7278bac8f70839f702114 100644 (file)
@@ -39,10 +39,7 @@ static void forward_syslog_iovec(
                 .msg_iovlen = n_iovec,
         };
         struct cmsghdr *cmsg;
-        union {
-                struct cmsghdr cmsghdr;
-                uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
-        } control;
+        CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
         const char *j;
         int r;
 
index e2f7bd7ec45761e2e9369f9f256a9c1ef802d425..9eb3e1a62625d5510f2480c8e7bff55e61ee7ba2 100644 (file)
@@ -162,7 +162,7 @@ static Window *window_add(MMapCache *m, MMapFileDescriptor *f, int prot, bool ke
         if (!m->last_unused || m->n_windows <= WINDOWS_MIN) {
 
                 /* Allocate a new window */
-                w = new0(Window, 1);
+                w = new(Window, 1);
                 if (!w)
                         return NULL;
                 m->n_windows++;
@@ -171,16 +171,17 @@ static Window *window_add(MMapCache *m, MMapFileDescriptor *f, int prot, bool ke
                 /* Reuse an existing one */
                 w = m->last_unused;
                 window_unlink(w);
-                zero(*w);
         }
 
-        w->cache = m;
-        w->fd = f;
-        w->prot = prot;
-        w->keep_always = keep_always;
-        w->offset = offset;
-        w->size = size;
-        w->ptr = ptr;
+        *w = (Window) {
+                .cache = m,
+                .fd = f,
+                .prot = prot,
+                .keep_always = keep_always,
+                .offset = offset,
+                .size = size,
+                .ptr = ptr,
+        };
 
         LIST_PREPEND(by_fd, f->windows, w);
 
index dc3e61e48934e10f328315894097d9005f1987b9..9b6c425285e3825ff5c20f1a4a7be458ff375168 100644 (file)
@@ -1635,9 +1635,10 @@ static int add_directory(
             !((dirname && dirname_is_machine_id(dirname) > 0) || path_has_prefix(j, path, "/run")))
                 return 0;
 
-        if (!(FLAGS_SET(j->flags, SD_JOURNAL_ALL_NAMESPACES) ||
-              dirname_has_namespace(dirname, j->namespace) > 0 ||
-              (FLAGS_SET(j->flags, SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE) && dirname_has_namespace(dirname, NULL) > 0)))
+        if (dirname &&
+            (!(FLAGS_SET(j->flags, SD_JOURNAL_ALL_NAMESPACES) ||
+               dirname_has_namespace(dirname, j->namespace) > 0 ||
+               (FLAGS_SET(j->flags, SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE) && dirname_has_namespace(dirname, NULL) > 0))))
                 return 0;
 
         r = directory_open(j, path, &d);
index 20e654b59940815b531294ef63db34ada07fe001..a8315d0633e87af830b764a8d3ac04393318ab91 100644 (file)
@@ -22,4 +22,5 @@ static void test_audit_type(void) {
 
 int main(int argc, char **argv) {
         test_audit_type();
+        return 0;
 }
index fac2b43c4731ab45d105642efc27ec5b79bc7193..c9d295b3c1cfa5e08ac0d768488fe9dd0a36b36b 100644 (file)
@@ -29,6 +29,8 @@
 # define LZ4_OK -EPROTONOSUPPORT
 #endif
 
+#define HUGE_SIZE (4096*1024)
+
 typedef int (compress_blob_t)(const void *src, uint64_t src_size,
                               void *dst, size_t dst_alloc_size, size_t *dst_size);
 typedef int (decompress_blob_t)(const void *src, uint64_t src_size,
@@ -42,20 +44,20 @@ typedef int (decompress_sw_t)(const void *src, uint64_t src_size,
 typedef int (compress_stream_t)(int fdf, int fdt, uint64_t max_bytes);
 typedef int (decompress_stream_t)(int fdf, int fdt, uint64_t max_size);
 
-#if HAVE_XZ || HAVE_LZ4
-static void test_compress_decompress(int compression,
-                                     compress_blob_t compress,
-                                     decompress_blob_t decompress,
-                                     const char *data,
-                                     size_t data_len,
-                                     bool may_fail) {
+#if HAVE_XZ || HAVE_LZ4 || HAVE_ZSTD
+_unused_ static void test_compress_decompress(const char *compression,
+                                              compress_blob_t compress,
+                                              decompress_blob_t decompress,
+                                              const char *data,
+                                              size_t data_len,
+                                              bool may_fail) {
         char compressed[512];
         size_t csize, usize = 0;
         _cleanup_free_ char *decompressed = NULL;
         int r;
 
         log_info("/* testing %s %s blob compression/decompression */",
-                 object_compressed_to_string(compression), data);
+                 compression, data);
 
         r = compress(data, data_len, compressed, sizeof(compressed), &csize);
         if (r == -ENOBUFS) {
@@ -86,12 +88,12 @@ static void test_compress_decompress(int compression,
         memzero(decompressed, usize);
 }
 
-static void test_decompress_startswith(int compression,
-                                       compress_blob_t compress,
-                                       decompress_sw_t decompress_sw,
-                                       const char *data,
-                                       size_t data_len,
-                                       bool may_fail) {
+_unused_ static void test_decompress_startswith(const char *compression,
+                                                compress_blob_t compress,
+                                                decompress_sw_t decompress_sw,
+                                                const char *data,
+                                                size_t data_len,
+                                                bool may_fail) {
 
         char *compressed;
         _cleanup_free_ char *compressed1 = NULL, *compressed2 = NULL, *decompressed = NULL;
@@ -99,7 +101,7 @@ static void test_decompress_startswith(int compression,
         int r;
 
         log_info("/* testing decompress_startswith with %s on %.20s text */",
-                 object_compressed_to_string(compression), data);
+                 compression, data);
 
 #define BUFSIZE_1 512
 #define BUFSIZE_2 20000
@@ -134,9 +136,9 @@ static void test_decompress_startswith(int compression,
         assert_se(r > 0);
 }
 
-static void test_decompress_startswith_short(int compression,
-                                             compress_blob_t compress,
-                                             decompress_sw_t decompress_sw) {
+_unused_ static void test_decompress_startswith_short(const char *compression,
+                                                      compress_blob_t compress,
+                                                      decompress_sw_t decompress_sw) {
 
 #define TEXT "HUGE=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
 
@@ -144,7 +146,7 @@ static void test_decompress_startswith_short(int compression,
         size_t i, csize;
         int r;
 
-        log_info("/* %s with %s */", __func__, object_compressed_to_string(compression));
+        log_info("/* %s with %s */", __func__, compression);
 
         r = compress(TEXT, sizeof TEXT, buf, sizeof buf, &csize);
         assert_se(r == 0);
@@ -160,11 +162,11 @@ static void test_decompress_startswith_short(int compression,
         }
 }
 
-static void test_compress_stream(int compression,
-                                 const char* cat,
-                                 compress_stream_t compress,
-                                 decompress_stream_t decompress,
-                                 const char *srcfile) {
+_unused_ static void test_compress_stream(const char *compression,
+                                          const char *cat,
+                                          compress_stream_t compress,
+                                          decompress_stream_t decompress,
+                                          const char *srcfile) {
 
         _cleanup_close_ int src = -1, dst = -1, dst2 = -1;
         _cleanup_(unlink_tempfilep) char
@@ -180,8 +182,7 @@ static void test_compress_stream(int compression,
                 return;
         }
 
-        log_debug("/* testing %s compression */",
-                  object_compressed_to_string(compression));
+        log_debug("/* testing %s compression */", compression);
 
         log_debug("/* create source from %s */", srcfile);
 
@@ -231,10 +232,10 @@ static void test_lz4_decompress_partial(void) {
         int r;
         _cleanup_free_ char *huge = NULL;
 
-#define HUGE_SIZE (4096*1024)
         assert_se(huge = malloc(HUGE_SIZE));
-        memset(huge, 'x', HUGE_SIZE);
-        memcpy(huge, "HUGE=", 5);
+        memcpy(huge, "HUGE=", STRLEN("HUGE="));
+        memset(&huge[STRLEN("HUGE=")], 'x', HUGE_SIZE - STRLEN("HUGE=") - 1);
+        huge[HUGE_SIZE - 1] = '\0';
 
         r = LZ4_compress_default(huge, buf, HUGE_SIZE, buf_size);
         assert_se(r >= 0);
@@ -264,8 +265,8 @@ static void test_lz4_decompress_partial(void) {
 #endif
 
 int main(int argc, char *argv[]) {
-#if HAVE_XZ || HAVE_LZ4
-        const char text[] =
+#if HAVE_XZ || HAVE_LZ4 || HAVE_ZSTD
+        _unused_ const char text[] =
                 "text\0foofoofoofoo AAAA aaaaaaaaa ghost busters barbarbar FFF"
                 "foofoofoofoo AAAA aaaaaaaaa ghost busters barbarbar FFF";
 
@@ -274,70 +275,79 @@ int main(int argc, char *argv[]) {
 
         char data[512] = "random\0";
 
-        char huge[4096*1024];
-        memset(huge, 'x', sizeof(huge));
-        memcpy(huge, "HUGE=", 5);
-        char_array_0(huge);
+        _cleanup_free_ char *huge = NULL;
+
+        assert_se(huge = malloc(HUGE_SIZE));
+        memcpy(huge, "HUGE=", STRLEN("HUGE="));
+        memset(&huge[STRLEN("HUGE=")], 'x', HUGE_SIZE - STRLEN("HUGE=") - 1);
+        huge[HUGE_SIZE - 1] = '\0';
 
         test_setup_logging(LOG_DEBUG);
 
         random_bytes(data + 7, sizeof(data) - 7);
 
 #if HAVE_XZ
-        test_compress_decompress(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_blob_xz,
+        test_compress_decompress("XZ", compress_blob_xz, decompress_blob_xz,
                                  text, sizeof(text), false);
-        test_compress_decompress(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_blob_xz,
+        test_compress_decompress("XZ", compress_blob_xz, decompress_blob_xz,
                                  data, sizeof(data), true);
 
-        test_decompress_startswith(OBJECT_COMPRESSED_XZ,
+        test_decompress_startswith("XZ",
                                    compress_blob_xz, decompress_startswith_xz,
                                    text, sizeof(text), false);
-        test_decompress_startswith(OBJECT_COMPRESSED_XZ,
+        test_decompress_startswith("XZ",
                                    compress_blob_xz, decompress_startswith_xz,
                                    data, sizeof(data), true);
-        test_decompress_startswith(OBJECT_COMPRESSED_XZ,
+        test_decompress_startswith("XZ",
                                    compress_blob_xz, decompress_startswith_xz,
-                                   huge, sizeof(huge), true);
+                                   huge, HUGE_SIZE, true);
 
-        test_compress_stream(OBJECT_COMPRESSED_XZ, "xzcat",
+        test_compress_stream("XZ", "xzcat",
                              compress_stream_xz, decompress_stream_xz, srcfile);
 
-        test_decompress_startswith_short(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_startswith_xz);
+        test_decompress_startswith_short("XZ", compress_blob_xz, decompress_startswith_xz);
 
 #else
         log_info("/* XZ test skipped */");
 #endif
 
 #if HAVE_LZ4
-        test_compress_decompress(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_blob_lz4,
+        test_compress_decompress("LZ4", compress_blob_lz4, decompress_blob_lz4,
                                  text, sizeof(text), false);
-        test_compress_decompress(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_blob_lz4,
+        test_compress_decompress("LZ4", compress_blob_lz4, decompress_blob_lz4,
                                  data, sizeof(data), true);
 
-        test_decompress_startswith(OBJECT_COMPRESSED_LZ4,
+        test_decompress_startswith("LZ4",
                                    compress_blob_lz4, decompress_startswith_lz4,
                                    text, sizeof(text), false);
-        test_decompress_startswith(OBJECT_COMPRESSED_LZ4,
+        test_decompress_startswith("LZ4",
                                    compress_blob_lz4, decompress_startswith_lz4,
                                    data, sizeof(data), true);
-        test_decompress_startswith(OBJECT_COMPRESSED_LZ4,
+        test_decompress_startswith("LZ4",
                                    compress_blob_lz4, decompress_startswith_lz4,
-                                   huge, sizeof(huge), true);
+                                   huge, HUGE_SIZE, true);
 
-        test_compress_stream(OBJECT_COMPRESSED_LZ4, "lz4cat",
+        test_compress_stream("LZ4", "lz4cat",
                              compress_stream_lz4, decompress_stream_lz4, srcfile);
 
         test_lz4_decompress_partial();
 
-        test_decompress_startswith_short(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_startswith_lz4);
+        test_decompress_startswith_short("LZ4", compress_blob_lz4, decompress_startswith_lz4);
 
 #else
         log_info("/* LZ4 test skipped */");
 #endif
 
+#if HAVE_ZSTD
+        test_compress_stream("ZSTD", "zstdcat",
+                             compress_stream_zstd, decompress_stream_zstd, srcfile);
+#else
+        log_info("/* ZSTD test skipped */");
+#endif
+
         return 0;
 #else
-        log_info("/* XZ and LZ4 tests skipped */");
+        log_info("/* XZ, LZ4 and ZSTD tests skipped */");
         return EXIT_TEST_SKIP;
 #endif
 }
index 484308e56ebe6568f5ef549b9dfeccf42a0e7714..4265735f0f167b7c616e4037ed1141bd61721854 100644 (file)
@@ -5,11 +5,23 @@
 #include <unistd.h>
 
 #include "sd-journal.h"
-
+#include "fileio.h"
 #include "macro.h"
+#include "memory-util.h"
+
+static void test_journal_print(void) {
+        assert_se(sd_journal_print(LOG_INFO, "XXX") == 0);
+        assert_se(sd_journal_print(LOG_INFO, "%s", "YYY") == 0);
+        assert_se(sd_journal_print(LOG_INFO, "X%4094sY", "ZZZ") == 0);
+        assert_se(sd_journal_print(LOG_INFO, "X%*sY", LONG_LINE_MAX - 8 - 3, "ZZZ") == 0);
+        assert_se(sd_journal_print(LOG_INFO, "X%*sY", LONG_LINE_MAX - 8 - 2, "ZZZ") == -ENOBUFS);
+}
 
-int main(int argc, char *argv[]) {
-        char huge[4096*1024];
+static void test_journal_send(void) {
+        _cleanup_free_ char *huge = NULL;
+
+#define HUGE_SIZE (4096*1024)
+        assert_se(huge = malloc(HUGE_SIZE));
 
         /* utf-8 and non-utf-8, message-less and message-ful iovecs */
         struct iovec graph1[] = {
@@ -36,9 +48,9 @@ int main(int argc, char *argv[]) {
 
         assert_se(sd_journal_perror("") == 0);
 
-        memset(huge, 'x', sizeof(huge));
-        memcpy(huge, "HUGE=", 5);
-        char_array_0(huge);
+        memcpy(huge, "HUGE=", STRLEN("HUGE="));
+        memset(&huge[STRLEN("HUGE=")], 'x', HUGE_SIZE - STRLEN("HUGE=") - 1);
+        huge[HUGE_SIZE - 1] = '\0';
 
         assert_se(sd_journal_send("MESSAGE=Huge field attached",
                                   huge,
@@ -78,7 +90,13 @@ int main(int argc, char *argv[]) {
         assert_se(sd_journal_sendv(graph2, 1) == 0);
         assert_se(sd_journal_sendv(message1, 1) == 0);
         assert_se(sd_journal_sendv(message2, 1) == 0);
+}
+
+int main(int argc, char *argv[]) {
+        test_journal_print();
+        test_journal_send();
 
+        /* Sleep a bit to make it easy for journald to collect metadata. */
         sleep(1);
 
         return 0;
index c01c1cf6d6f50b5177ccfe65b175896075e8c020..d0610a32e23d5defcca83889ea716bfb2a4e491e 100644 (file)
@@ -15,7 +15,6 @@
 #include "udev-util.h"
 #include "virt.h"
 
-#define SYSTEMD_PEN    43793
 #define HASH_KEY       SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
 #define APPLICATION_ID SD_ID128_MAKE(a5,0a,d1,12,bf,60,45,77,a2,fb,74,1a,b1,95,5b,03)
 #define USEC_2000       ((usec_t) 946684800000000) /* 2000-01-01 00:00:00 UTC */
index b3115125d9ab1ae59043388e9355ab32763afc54..76abd6583e3a3905ed2cd3349a6040f56e96d5b2 100644 (file)
@@ -8,6 +8,8 @@
 #include "time-util.h"
 #include "unaligned.h"
 
+#define SYSTEMD_PEN    43793
+
 typedef enum DUIDType {
         DUID_TYPE_LLT       = 1,
         DUID_TYPE_EN        = 2,
index a45167b198e986821550c21dfe2d84eea6004237..fb42f2f80c92d76d0bf7bc763382c4f34d67bf0e 100644 (file)
@@ -19,6 +19,7 @@ typedef enum DHCPRawOption {
         DHCP_RAW_OPTION_DATA_UINT32,
         DHCP_RAW_OPTION_DATA_STRING,
         DHCP_RAW_OPTION_DATA_IPV4ADDRESS,
+        DHCP_RAW_OPTION_DATA_IPV6ADDRESS,
         _DHCP_RAW_OPTION_DATA_MAX,
         _DHCP_RAW_OPTION_DATA_INVALID,
 } DHCPRawOption;
@@ -56,7 +57,7 @@ struct sd_dhcp_server {
         char *timezone;
 
         struct in_addr *ntp, *dns, *sip, *pop3_server, *smtp_server, *lpr_server;
-        unsigned n_ntp, n_dns, n_sip, n_pop3_server, n_smtp_server, n_lpr_server;
+        size_t n_ntp, n_dns, n_sip, n_pop3_server, n_smtp_server, n_lpr_server;
 
         OrderedHashmap *extra_options;
         OrderedHashmap *vendor_options;
index 517e357d3df22b6c251d0dd1fc38a79588d2fb0f..ced85fd3afe7a0a26b3baeb68a81654cc4774eb3 100644 (file)
 #include "macro.h"
 #include "sparse-endian.h"
 
+typedef struct sd_dhcp6_option {
+        unsigned n_ref;
+
+        uint16_t option;
+        void *data;
+        size_t length;
+} sd_dhcp6_option;
+
+extern const struct hash_ops dhcp6_option_hash_ops;
+
 /* Common option header */
 typedef struct DHCP6Option {
         be16_t code;
@@ -87,6 +97,8 @@ int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
 int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia);
 int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix);
 int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn);
+int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char **user_class);
+int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char **user_class);
 int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode,
                        size_t *optlen, uint8_t **optvalue);
 int dhcp6_option_parse_status(DHCP6Option *option, size_t len);
index ed684d44f30ffe92e2b864bad56de54cb71cff31..0ec36507cd46cae97004c42c83e56bb86613f6e9 100644 (file)
@@ -9,6 +9,7 @@
 #include "sd-dhcp6-client.h"
 
 #include "alloc-util.h"
+#include "dhcp-identifier.h"
 #include "dhcp6-internal.h"
 #include "dhcp6-lease-internal.h"
 #include "dhcp6-protocol.h"
@@ -167,6 +168,75 @@ int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn) {
         return r;
 }
 
+int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char **user_class) {
+        _cleanup_free_ uint8_t *p = NULL;
+        size_t total = 0, offset = 0;
+        char **s;
+
+        assert_return(buf && *buf && buflen && user_class, -EINVAL);
+
+        STRV_FOREACH(s, user_class) {
+                size_t len = strlen(*s);
+                uint8_t *q;
+
+                if (len > 0xffff)
+                        return -ENAMETOOLONG;
+                q = realloc(p, total + len + 2);
+                if (!q)
+                        return -ENOMEM;
+
+                p = q;
+
+                unaligned_write_be16(&p[offset], len);
+                memcpy(&p[offset + 2], *s, len);
+
+                offset += 2 + len;
+                total += 2 + len;
+        }
+
+        return dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_USER_CLASS, total, p);
+}
+
+int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char **vendor_class) {
+        _cleanup_free_ uint8_t *p = NULL;
+        uint32_t enterprise_identifier;
+        size_t total, offset;
+        char **s;
+
+        assert(buf);
+        assert(*buf);
+        assert(buflen);
+        assert(vendor_class);
+
+        enterprise_identifier = htobe32(SYSTEMD_PEN);
+
+        p = memdup(&enterprise_identifier, sizeof(enterprise_identifier));
+        if (!p)
+                return -ENOMEM;
+
+        total = sizeof(enterprise_identifier);
+        offset = total;
+
+        STRV_FOREACH(s, vendor_class) {
+                size_t len = strlen(*s);
+                uint8_t *q;
+
+                q = realloc(p, total + len + 2);
+                if (!q)
+                        return -ENOMEM;
+
+                p = q;
+
+                unaligned_write_be16(&p[offset], len);
+                memcpy(&p[offset + 2], *s, len);
+
+                offset += 2 + len;
+                total += 2 + len;
+        }
+
+        return dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_VENDOR_CLASS, total, p);
+}
+
 int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix) {
         DHCP6Option *option = (DHCP6Option *)buf;
         size_t i = sizeof(*option) + sizeof(pd->ia_pd);
@@ -597,3 +667,43 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char *
 
         return idx;
 }
+
+static sd_dhcp6_option* dhcp6_option_free(sd_dhcp6_option *i) {
+        if (!i)
+                return NULL;
+
+        free(i->data);
+        return mfree(i);
+}
+
+int sd_dhcp6_option_new(uint16_t option, const void *data, size_t length, sd_dhcp6_option **ret) {
+        assert_return(ret, -EINVAL);
+        assert_return(length == 0 || data, -EINVAL);
+
+        _cleanup_free_ void *q = memdup(data, length);
+        if (!q)
+                return -ENOMEM;
+
+        sd_dhcp6_option *p = new(sd_dhcp6_option, 1);
+        if (!p)
+                return -ENOMEM;
+
+        *p = (sd_dhcp6_option) {
+                .n_ref = 1,
+                .option = option,
+                .length = length,
+                .data = TAKE_PTR(q),
+        };
+
+        *ret = p;
+        return 0;
+}
+
+DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_option, sd_dhcp6_option, dhcp6_option_free);
+DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
+                dhcp6_option_hash_ops,
+                void,
+                trivial_hash_func,
+                trivial_compare_func,
+                sd_dhcp6_option,
+                sd_dhcp6_option_unref);
index dbb1e51a0e0d9567d59706d4591d551d34f4cdb6..bdd94867ac33b88c79e0622eaefa151605e26021 100644 (file)
@@ -147,11 +147,9 @@ int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
 
 int icmp6_receive(int fd, void *buffer, size_t size, struct in6_addr *dst,
                   triple_timestamp *timestamp) {
-        union {
-                struct cmsghdr cmsghdr;
-                uint8_t buf[CMSG_SPACE(sizeof(int)) + /* ttl */
-                            CMSG_SPACE(sizeof(struct timeval))];
-        } control = {};
+
+        CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int)) + /* ttl */
+                         CMSG_SPACE(sizeof(struct timeval))) control;
         struct iovec iov = {};
         union sockaddr_union sa = {};
         struct msghdr msg = {
@@ -167,9 +165,9 @@ int icmp6_receive(int fd, void *buffer, size_t size, struct in6_addr *dst,
 
         iov = IOVEC_MAKE(buffer, size);
 
-        len = recvmsg(fd, &msg, MSG_DONTWAIT);
+        len = recvmsg_safe(fd, &msg, MSG_DONTWAIT);
         if (len < 0)
-                return -errno;
+                return (int) len;
 
         if ((size_t) len != size)
                 return -EINVAL;
index a59ae4767e2b6acd9256b05c600b7cfa0f4ad94c..ce83a86aa9a7e916d7bb0c74ee721376748b028b 100644 (file)
@@ -87,6 +87,7 @@ struct sd_dhcp_client {
         char *mudurl;
         char **user_class;
         uint32_t mtu;
+        uint32_t fallback_lease_lifetime;
         uint32_t xid;
         usec_t start_time;
         uint64_t attempt;
@@ -612,6 +613,15 @@ int sd_dhcp_client_set_service_type(sd_dhcp_client *client, int type) {
         return 0;
 }
 
+int sd_dhcp_client_set_fallback_lease_lifetime(sd_dhcp_client *client, uint32_t fallback_lease_lifetime) {
+        assert_return(client, -EINVAL);
+        assert_return(fallback_lease_lifetime > 0, -EINVAL);
+
+        client->fallback_lease_lifetime = fallback_lease_lifetime;
+
+        return 0;
+}
+
 static int client_notify(sd_dhcp_client *client, int event) {
         assert(client);
 
@@ -850,36 +860,12 @@ static int dhcp_client_send_raw(
                                             packet, len);
 }
 
-static int client_send_discover(sd_dhcp_client *client) {
-        _cleanup_free_ DHCPPacket *discover = NULL;
-        size_t optoffset, optlen;
+static int client_append_common_discover_request_options(sd_dhcp_client *client, DHCPPacket *packet, size_t *optoffset, size_t optlen) {
         sd_dhcp_option *j;
         Iterator i;
         int r;
 
         assert(client);
-        assert(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_SELECTING));
-
-        r = client_message_init(client, &discover, DHCP_DISCOVER,
-                                &optlen, &optoffset);
-        if (r < 0)
-                return r;
-
-        /* the client may suggest values for the network address
-           and lease time in the DHCPDISCOVER message. The client may include
-           the ’requested IP address’ option to suggest that a particular IP
-           address be assigned, and may include the ’IP address lease time’
-           option to suggest the lease time it would like.
-         */
-        /* RFC7844 section 3:
-           SHOULD NOT contain any other option. */
-        if (!client->anonymize && client->last_addr != INADDR_ANY) {
-                r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
-                                       SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
-                                       4, &client->last_addr);
-                if (r < 0)
-                        return r;
-        }
 
         if (client->hostname) {
                 /* According to RFC 4702 "clients that send the Client FQDN option in
@@ -890,18 +876,18 @@ static int client_send_discover(sd_dhcp_client *client) {
                         /* it is unclear from RFC 2131 if client should send hostname in
                            DHCPDISCOVER but dhclient does and so we do as well
                         */
-                        r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
+                        r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
                                                SD_DHCP_OPTION_HOST_NAME,
                                                strlen(client->hostname), client->hostname);
                 } else
-                        r = client_append_fqdn_option(&discover->dhcp, optlen, &optoffset,
+                        r = client_append_fqdn_option(&packet->dhcp, optlen, optoffset,
                                                       client->hostname);
                 if (r < 0)
                         return r;
         }
 
         if (client->vendor_class_identifier) {
-                r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
+                r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
                                        SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
                                        strlen(client->vendor_class_identifier),
                                        client->vendor_class_identifier);
@@ -910,7 +896,7 @@ static int client_send_discover(sd_dhcp_client *client) {
         }
 
         if (client->mudurl) {
-                r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
+                r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
                                        SD_DHCP_OPTION_MUD_URL,
                                        strlen(client->mudurl),
                                        client->mudurl);
@@ -919,7 +905,7 @@ static int client_send_discover(sd_dhcp_client *client) {
         }
 
         if (client->user_class) {
-                r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
+                r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
                                        SD_DHCP_OPTION_USER_CLASS,
                                        strv_length(client->user_class),
                                        client->user_class);
@@ -928,7 +914,7 @@ static int client_send_discover(sd_dhcp_client *client) {
         }
 
         ORDERED_HASHMAP_FOREACH(j, client->extra_options, i) {
-                r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
+                r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
                                        j->option, j->length, j->data);
                 if (r < 0)
                         return r;
@@ -936,13 +922,50 @@ static int client_send_discover(sd_dhcp_client *client) {
 
         if (!ordered_hashmap_isempty(client->vendor_options)) {
                 r = dhcp_option_append(
-                                &discover->dhcp, optlen, &optoffset, 0,
+                                &packet->dhcp, optlen, optoffset, 0,
                                 SD_DHCP_OPTION_VENDOR_SPECIFIC,
                                 ordered_hashmap_size(client->vendor_options), client->vendor_options);
                 if (r < 0)
                         return r;
         }
 
+
+        return 0;
+}
+
+static int client_send_discover(sd_dhcp_client *client) {
+        _cleanup_free_ DHCPPacket *discover = NULL;
+        size_t optoffset, optlen;
+        int r;
+
+        assert(client);
+        assert(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_SELECTING));
+
+        r = client_message_init(client, &discover, DHCP_DISCOVER,
+                                &optlen, &optoffset);
+        if (r < 0)
+                return r;
+
+        /* the client may suggest values for the network address
+           and lease time in the DHCPDISCOVER message. The client may include
+           the ’requested IP address’ option to suggest that a particular IP
+           address be assigned, and may include the ’IP address lease time’
+           option to suggest the lease time it would like.
+         */
+        /* RFC7844 section 3:
+           SHOULD NOT contain any other option. */
+        if (!client->anonymize && client->last_addr != INADDR_ANY) {
+                r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
+                                       SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
+                                       4, &client->last_addr);
+                if (r < 0)
+                        return r;
+        }
+
+        r = client_append_common_discover_request_options(client, discover, &optoffset, optlen);
+        if (r < 0)
+                return r;
+
         r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
                                SD_DHCP_OPTION_END, 0, NULL);
         if (r < 0)
@@ -1034,36 +1057,9 @@ static int client_send_request(sd_dhcp_client *client) {
                 return -EINVAL;
         }
 
-        if (client->hostname) {
-                if (dns_name_is_single_label(client->hostname))
-                        r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
-                                               SD_DHCP_OPTION_HOST_NAME,
-                                               strlen(client->hostname), client->hostname);
-                else
-                        r = client_append_fqdn_option(&request->dhcp, optlen, &optoffset,
-                                                      client->hostname);
-                if (r < 0)
-                        return r;
-        }
-
-        if (client->vendor_class_identifier) {
-                r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
-                                       SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
-                                       strlen(client->vendor_class_identifier),
-                                       client->vendor_class_identifier);
-                if (r < 0)
-                        return r;
-        }
-
-        if (client->mudurl) {
-                r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
-                                       SD_DHCP_OPTION_MUD_URL,
-                                       strlen(client->mudurl),
-                                       client->mudurl);
-                if (r < 0)
-                        return r;
-        }
-
+        r = client_append_common_discover_request_options(client, request, &optoffset, optlen);
+        if (r < 0)
+                return r;
 
         r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
                                SD_DHCP_OPTION_END, 0, NULL);
@@ -1419,6 +1415,9 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, size_
         lease->next_server = offer->siaddr;
         lease->address = offer->yiaddr;
 
+        if (lease->lifetime == 0 && client->fallback_lease_lifetime > 0)
+                lease->lifetime = client->fallback_lease_lifetime;
+
         if (lease->address == 0 ||
             lease->server_address == 0 ||
             lease->lifetime == 0) {
@@ -1899,13 +1898,13 @@ static int client_receive_message_raw(
 
         sd_dhcp_client *client = userdata;
         _cleanup_free_ DHCPPacket *packet = NULL;
-        uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
+        CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct tpacket_auxdata))) control;
         struct iovec iov = {};
         struct msghdr msg = {
                 .msg_iov = &iov,
                 .msg_iovlen = 1,
-                .msg_control = cmsgbuf,
-                .msg_controllen = sizeof(cmsgbuf),
+                .msg_control = &control,
+                .msg_controllen = sizeof(control),
         };
         struct cmsghdr *cmsg;
         bool checksum = true;
@@ -1927,25 +1926,21 @@ static int client_receive_message_raw(
 
         iov = IOVEC_MAKE(packet, buflen);
 
-        len = recvmsg(fd, &msg, 0);
-        if (len < 0) {
-                if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
-                        return 0;
-
-                return log_dhcp_client_errno(client, errno,
-                                             "Could not receive message from raw socket: %m");
-        } else if ((size_t)len < sizeof(DHCPPacket))
+        len = recvmsg_safe(fd, &msg, 0);
+        if (IN_SET(len, -EAGAIN, -EINTR, -ENETDOWN))
                 return 0;
+        if (len < 0)
+                return log_dhcp_client_errno(client, len,
+                                             "Could not receive message from raw socket: %m");
 
-        CMSG_FOREACH(cmsg, &msg)
-                if (cmsg->cmsg_level == SOL_PACKET &&
-                    cmsg->cmsg_type == PACKET_AUXDATA &&
-                    cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
-                        struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
+        if ((size_t) len < sizeof(DHCPPacket))
+                return 0;
 
-                        checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
-                        break;
-                }
+        cmsg = cmsg_find(&msg, SOL_PACKET, PACKET_AUXDATA, CMSG_LEN(sizeof(struct tpacket_auxdata)));
+        if (cmsg) {
+                struct tpacket_auxdata *aux = (struct tpacket_auxdata*) CMSG_DATA(cmsg);
+                checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
+        }
 
         r = dhcp_packet_verify_headers(packet, len, checksum, client->port);
         if (r < 0)
index 29688f2d4fe56c8f4228b3127eeed38b391222bd..3b02530e242f0d76c3fae391caabb6de7fc9e92b 100644 (file)
@@ -700,7 +700,7 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void
         case SD_DHCP_OPTION_HOST_NAME:
                 r = lease_parse_domain(option, len, &lease->hostname);
                 if (r < 0) {
-                        log_debug_errno(r, "Failed to parse host name, ignoring: %m");
+                        log_debug_errno(r, "Failed to parse hostname, ignoring: %m");
                         return 0;
                 }
 
index 57eed765eea364062a0a35c009776320d2a62766..9db583a7a800d1915ef265daee69c69ffb443e08 100644 (file)
@@ -33,7 +33,13 @@ static DHCPLease *dhcp_lease_free(DHCPLease *lease) {
  * the whole pool must fit into the subnet, and may not contain the first (any) nor last (broadcast) address
  * moreover, the server's own address may be in the pool, and is in that case reserved in order not to
  * accidentally hand it out */
-int sd_dhcp_server_configure_pool(sd_dhcp_server *server, struct in_addr *address, unsigned char prefixlen, uint32_t offset, uint32_t size) {
+int sd_dhcp_server_configure_pool(
+                sd_dhcp_server *server,
+                const struct in_addr *address,
+                unsigned char prefixlen,
+                uint32_t offset,
+                uint32_t size) {
+
         struct in_addr netmask_addr;
         be32_t netmask;
         uint32_t server_off, broadcast_off, size_max;
@@ -267,14 +273,14 @@ static int dhcp_server_send_udp(sd_dhcp_server *server, be32_t destination,
                 .iov_base = message,
                 .iov_len = len,
         };
-        uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))] = {};
+        CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct in_pktinfo))) control = {};
         struct msghdr msg = {
                 .msg_name = &dest,
                 .msg_namelen = sizeof(dest.in),
                 .msg_iov = &iov,
                 .msg_iovlen = 1,
-                .msg_control = cmsgbuf,
-                .msg_controllen = sizeof(cmsgbuf),
+                .msg_control = &control,
+                .msg_controllen = sizeof(control),
         };
         struct cmsghdr *cmsg;
         struct in_pktinfo *pktinfo;
@@ -970,14 +976,14 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
 static int server_receive_message(sd_event_source *s, int fd,
                                   uint32_t revents, void *userdata) {
         _cleanup_free_ DHCPMessage *message = NULL;
-        uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))];
+        CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct in_pktinfo))) control;
         sd_dhcp_server *server = userdata;
         struct iovec iov = {};
         struct msghdr msg = {
                 .msg_iov = &iov,
                 .msg_iovlen = 1,
-                .msg_control = cmsgbuf,
-                .msg_controllen = sizeof(cmsgbuf),
+                .msg_control = &control,
+                .msg_controllen = sizeof(control),
         };
         struct cmsghdr *cmsg;
         ssize_t buflen, len;
@@ -995,14 +1001,12 @@ static int server_receive_message(sd_event_source *s, int fd,
 
         iov = IOVEC_MAKE(message, buflen);
 
-        len = recvmsg(fd, &msg, 0);
-        if (len < 0) {
-                if (IN_SET(errno, EAGAIN, EINTR))
-                        return 0;
-
-                return -errno;
-        }
-        if ((size_t)len < sizeof(DHCPMessage))
+        len = recvmsg_safe(fd, &msg, 0);
+        if (IN_SET(len, -EAGAIN, -EINTR))
+                return 0;
+        if (len < 0)
+                return len;
+        if ((size_t) len < sizeof(DHCPMessage))
                 return 0;
 
         CMSG_FOREACH(cmsg, &msg) {
@@ -1137,13 +1141,13 @@ int sd_dhcp_server_set_servers(
                 sd_dhcp_server *server,
                 sd_dhcp_lease_info what,
                 const struct in_addr addresses[],
-                unsigned n_addresses) {
+                size_t n_addresses) {
 
         assert_return(server, -EINVAL);
         assert_return(addresses || n_addresses == 0, -EINVAL);
 
         struct in_addr **a;
-        unsigned *n_a;
+        size_t *n_a;
 
         switch (what) {
         case SD_DHCP_LEASE_DNS_SERVERS:
@@ -1199,22 +1203,22 @@ int sd_dhcp_server_set_servers(
         return 1;
 }
 
-int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr dns[], unsigned n) {
+int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr dns[], size_t n) {
         return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_DNS_SERVERS, dns, n);
 }
-int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr ntp[], unsigned n) {
+int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr ntp[], size_t n) {
         return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_NTP_SERVERS, ntp, n);
 }
-int sd_dhcp_server_set_sip(sd_dhcp_server *server, const struct in_addr sip[], unsigned n) {
+int sd_dhcp_server_set_sip(sd_dhcp_server *server, const struct in_addr sip[], size_t n) {
         return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_SIP_SERVERS, sip, n);
 }
-int sd_dhcp_server_set_pop3_server(sd_dhcp_server *server, const struct in_addr pop3[], unsigned n) {
+int sd_dhcp_server_set_pop3(sd_dhcp_server *server, const struct in_addr pop3[], size_t n) {
         return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_POP3_SERVERS, pop3, n);
 }
-int sd_dhcp_server_set_smtp_server(sd_dhcp_server *server, const struct in_addr smtp[], unsigned n) {
+int sd_dhcp_server_set_smtp(sd_dhcp_server *server, const struct in_addr smtp[], size_t n) {
         return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_SMTP_SERVERS, smtp, n);
 }
-int sd_dhcp_server_set_lpr(sd_dhcp_server *server, const struct in_addr lpr[], unsigned n) {
+int sd_dhcp_server_set_lpr(sd_dhcp_server *server, const struct in_addr lpr[], size_t n) {
         return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_LPR_SERVERS, lpr, n);
 }
 
index 6c017e0ff982d3f55a22842476f83c489146292d..13d8f652888a1ce9c116bf4231eae31f31b6fa8b 100644 (file)
@@ -67,6 +67,8 @@ struct sd_dhcp6_client {
         size_t req_opts_len;
         char *fqdn;
         char *mudurl;
+        char **user_class;
+        char **vendor_class;
         sd_event_source *receive_message;
         usec_t retransmit_time;
         uint8_t retransmit_count;
@@ -78,6 +80,7 @@ struct sd_dhcp6_client {
         size_t duid_len;
         usec_t information_request_time_usec;
         usec_t information_refresh_time_usec;
+        OrderedHashmap *extra_options;
 };
 
 static const uint16_t default_req_opts[] = {
@@ -252,7 +255,8 @@ static int dhcp6_client_set_duid_internal(
                         r = dhcp_validate_duid_len(duid_type, duid_len, false);
                         if (r < 0)
                                 return log_dhcp6_client_errno(client, r, "Failed to validate length of DUID: %m");
-                        log_dhcp6_client(client, "Setting DUID of type %u with unexpected content", duid_type);
+
+                        log_dhcp6_client(client, "Using DUID of type %u of incorrect length, proceeding.", duid_type);
                 }
 
                 client->duid.type = htobe16(duid_type);
@@ -356,18 +360,8 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option)
         assert_return(client, -EINVAL);
         assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
 
-        switch(option) {
-
-        case SD_DHCP6_OPTION_DNS_SERVERS:
-        case SD_DHCP6_OPTION_DOMAIN_LIST:
-        case SD_DHCP6_OPTION_SNTP_SERVERS:
-        case SD_DHCP6_OPTION_NTP_SERVER:
-        case SD_DHCP6_OPTION_RAPID_COMMIT:
-                break;
-
-        default:
+        if (option <= 0 || option >= UINT8_MAX)
                 return -EINVAL;
-        }
 
         for (t = 0; t < client->req_opts_len; t++)
                 if (client->req_opts[t] == htobe16(option))
@@ -382,17 +376,60 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option)
         return 0;
 }
 
-int sd_dhcp6_client_set_request_mud_url(sd_dhcp6_client *client, char *mudurl) {
+int sd_dhcp6_client_set_request_mud_url(sd_dhcp6_client *client, const char *mudurl) {
 
         assert_return(client, -EINVAL);
         assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
         assert_return(mudurl, -EINVAL);
-        assert_return(strlen(mudurl) <= 255, -EINVAL);
+        assert_return(strlen(mudurl) <= UINT8_MAX, -EINVAL);
         assert_return(http_url_is_valid(mudurl), -EINVAL);
 
         return free_and_strdup(&client->mudurl, mudurl);
 }
 
+int sd_dhcp6_client_set_request_user_class(sd_dhcp6_client *client, char **user_class) {
+        _cleanup_strv_free_ char **s = NULL;
+        char **p;
+
+        assert_return(client, -EINVAL);
+        assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
+
+        assert_return(user_class, -EINVAL);
+
+        STRV_FOREACH(p, user_class)
+                if (strlen(*p) > UINT16_MAX)
+                        return -ENAMETOOLONG;
+
+        s = strv_copy(user_class);
+        if (!s)
+                return -ENOMEM;
+
+        client->user_class = TAKE_PTR(s);
+
+        return 0;
+}
+
+int sd_dhcp6_client_set_request_vendor_class(sd_dhcp6_client *client, char **vendor_class) {
+        _cleanup_strv_free_ char **s = NULL;
+        char **p;
+
+        assert_return(client, -EINVAL);
+        assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
+        assert_return(vendor_class, -EINVAL);
+
+        STRV_FOREACH(p, vendor_class)
+                if (strlen(*p) > UINT8_MAX)
+                        return -ENAMETOOLONG;
+
+        s = strv_copy(vendor_class);
+        if (!s)
+                return -ENOMEM;
+
+        client->vendor_class = TAKE_PTR(s);
+
+        return 0;
+}
+
 int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client, int *delegation) {
         assert_return(client, -EINVAL);
         assert_return(delegation, -EINVAL);
@@ -447,6 +484,24 @@ int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) {
         return 0;
 }
 
+int sd_dhcp6_client_add_option(sd_dhcp6_client *client, sd_dhcp6_option *v) {
+        int r;
+
+        assert_return(client, -EINVAL);
+        assert_return(v, -EINVAL);
+
+        r = ordered_hashmap_ensure_allocated(&client->extra_options, &dhcp6_option_hash_ops);
+        if (r < 0)
+                return r;
+
+        r = ordered_hashmap_put(client->extra_options, UINT_TO_PTR(v->option), v);
+        if (r < 0)
+                return r;
+
+        sd_dhcp6_option_ref(v);
+        return 0;
+}
+
 static void client_notify(sd_dhcp6_client *client, int event) {
         assert(client);
 
@@ -492,7 +547,9 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
         _cleanup_free_ DHCP6Message *message = NULL;
         struct in6_addr all_servers =
                 IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT;
+        struct sd_dhcp6_option *j;
         size_t len, optlen = 512;
+        Iterator i;
         uint8_t *opt;
         int r;
         usec_t elapsed_usec;
@@ -553,6 +610,18 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                                 return r;
                 }
 
+                if (client->user_class) {
+                        r = dhcp6_option_append_user_class(&opt, &optlen, client->user_class);
+                        if (r < 0)
+                                return r;
+                }
+
+                if (client->vendor_class) {
+                        r = dhcp6_option_append_vendor_class(&opt, &optlen, client->vendor_class);
+                        if (r < 0)
+                                return r;
+                }
+
                 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
                         r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd, &client->hint_pd_prefix);
                         if (r < 0)
@@ -599,6 +668,18 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                                 return r;
                 }
 
+                if (client->user_class) {
+                        r = dhcp6_option_append_user_class(&opt, &optlen, client->user_class);
+                        if (r < 0)
+                                return r;
+                }
+
+                if (client->vendor_class) {
+                        r = dhcp6_option_append_vendor_class(&opt, &optlen, client->vendor_class);
+                        if (r < 0)
+                                return r;
+                }
+
                 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
                         r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL);
                         if (r < 0)
@@ -633,6 +714,18 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                                 return r;
                 }
 
+                if (client->user_class) {
+                        r = dhcp6_option_append_user_class(&opt, &optlen, client->user_class);
+                        if (r < 0)
+                                return r;
+                }
+
+                if (client->vendor_class) {
+                        r = dhcp6_option_append_vendor_class(&opt, &optlen, client->vendor_class);
+                        if (r < 0)
+                                return r;
+                }
+
                 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
                         r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL);
                         if (r < 0)
@@ -672,6 +765,12 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
         if (r < 0)
                 return r;
 
+        ORDERED_HASHMAP_FOREACH(j, client->extra_options, i) {
+                r = dhcp6_option_append(&opt, &optlen, j->option, j->length, j->data);
+                if (r < 0)
+                        return r;
+        }
+
         r = dhcp6_network_send_udp_socket(client->fd, &all_servers, message,
                                           len - optlen);
         if (r < 0)
@@ -1584,6 +1683,11 @@ static sd_dhcp6_client *dhcp6_client_free(sd_dhcp6_client *client) {
         free(client->req_opts);
         free(client->fqdn);
         free(client->mudurl);
+
+        ordered_hashmap_free(client->extra_options);
+        strv_free(client->user_class);
+        strv_free(client->vendor_class);
+
         return mfree(client);
 }
 
index e7ffe879a82ac7da212fb34782f69842f8d59dc2..7ea6f0d5612d7c3070f5e804e485a296e5506d2b 100644 (file)
@@ -590,8 +590,7 @@ _public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p, int dynamic) {
         cur->valid_until = valid_until;
         cur->preferred_until = preferred_until;
 
-        log_radv("%s prefix %s/%u preferred %s valid %s",
-                 cur? "Updated": "Added",
+        log_radv("Updated prefix %s/%u preferred %s valid %s",
                  addr_p, p->opt.prefixlen,
                  format_timespan(time_string_preferred, FORMAT_TIMESPAN_MAX,
                                  preferred, USEC_PER_SEC),
@@ -691,8 +690,7 @@ _public_ int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p, int
         if (valid_until == USEC_INFINITY)
                 return -EOVERFLOW;
 
-        log_radv("%s route prefix %s/%u valid %s",
-                 cur? "Updated": "Added",
+        log_radv("Updated route prefix %s/%u valid %s",
                  strempty(pretty), p->opt.prefixlen,
                  format_timespan(time_string_valid, FORMAT_TIMESPAN_MAX, valid, USEC_PER_SEC));
 
index 4b89b320b756cf67d06f4bb9aa5408b576db3aae..3a68f1fe718619e7011c5e8a79df41b3e0a36599 100644 (file)
@@ -61,12 +61,12 @@ static int test_client_basic(sd_event *e) {
         assert_se(sd_dhcp6_client_set_fqdn(client, "~host") == -EINVAL);
         assert_se(sd_dhcp6_client_set_fqdn(client, "~host.domain") == -EINVAL);
 
-        assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_CLIENTID) == -EINVAL);
+        assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_CLIENTID) == 0);
         assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DNS_SERVERS) == -EEXIST);
         assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_NTP_SERVER) == -EEXIST);
         assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_SNTP_SERVERS) == -EEXIST);
         assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DOMAIN_LIST) == -EEXIST);
-        assert_se(sd_dhcp6_client_set_request_option(client, 10) == -EINVAL);
+        assert_se(sd_dhcp6_client_set_request_option(client, 10) == 0);
 
         assert_se(sd_dhcp6_client_set_information_request(client, 1) >= 0);
         v = 0;
index 0f881809ab2a516e195b8211d5ac314dafb3eca3..534cc7856401db6fb750ff3b332511c90fc70747 100644 (file)
@@ -87,4 +87,5 @@ int main(int argc, char *argv[]) {
         test_dhcp_lease_parse_search_domains_no_data();
         test_dhcp_lease_parse_search_domains_loops();
         test_dhcp_lease_parse_search_domains_wrong_len();
+        return 0;
 }
index e5f92b9ec261e3c669cf502348ffc6b2625a9967..dc58f88bbd5cc667712e295dea9d2bf170e4f87c 100644 (file)
@@ -29,6 +29,7 @@
 #define BUS_ERROR_DISK_FULL "org.freedesktop.systemd1.DiskFull"
 #define BUS_ERROR_NOTHING_TO_CLEAN "org.freedesktop.systemd1.NothingToClean"
 #define BUS_ERROR_UNIT_BUSY "org.freedesktop.systemd1.UnitBusy"
+#define BUS_ERROR_UNIT_INACTIVE "org.freedesktop.systemd1.UnitInactive"
 
 #define BUS_ERROR_NO_SUCH_MACHINE "org.freedesktop.machine1.NoSuchMachine"
 #define BUS_ERROR_NO_SUCH_IMAGE "org.freedesktop.machine1.NoSuchImage"
index e8934489b581f1b07a35609cbedeb35fb628aea6..734abcf3fdedac8b15304f62102fd828adee7ad0 100644 (file)
 #include "memory-util.h"
 #include "string-util.h"
 
+#define BUS_INTROSPECT_DOCTYPE                                       \
+        "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n" \
+        "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
+
+#define BUS_INTROSPECT_INTERFACE_PEER                                \
+        " <interface name=\"org.freedesktop.DBus.Peer\">\n"             \
+        "  <method name=\"Ping\"/>\n"                                   \
+        "  <method name=\"GetMachineId\">\n"                            \
+        "   <arg type=\"s\" name=\"machine_uuid\" direction=\"out\"/>\n" \
+        "  </method>\n"                                                 \
+        " </interface>\n"
+
+#define BUS_INTROSPECT_INTERFACE_INTROSPECTABLE                      \
+        " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"   \
+        "  <method name=\"Introspect\">\n"                              \
+        "   <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"        \
+        "  </method>\n"                                                 \
+        " </interface>\n"
+
+#define BUS_INTROSPECT_INTERFACE_PROPERTIES                          \
+        " <interface name=\"org.freedesktop.DBus.Properties\">\n"       \
+        "  <method name=\"Get\">\n"                                     \
+        "   <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n"    \
+        "   <arg name=\"property\" direction=\"in\" type=\"s\"/>\n"     \
+        "   <arg name=\"value\" direction=\"out\" type=\"v\"/>\n"       \
+        "  </method>\n"                                                 \
+        "  <method name=\"GetAll\">\n"                                  \
+        "   <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n"    \
+        "   <arg name=\"properties\" direction=\"out\" type=\"a{sv}\"/>\n" \
+        "  </method>\n"                                                 \
+        "  <method name=\"Set\">\n"                                     \
+        "   <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n"    \
+        "   <arg name=\"property\" direction=\"in\" type=\"s\"/>\n"     \
+        "   <arg name=\"value\" direction=\"in\" type=\"v\"/>\n"        \
+        "  </method>\n"                                                 \
+        "  <signal name=\"PropertiesChanged\">\n"                       \
+        "   <arg type=\"s\" name=\"interface\"/>\n"                     \
+        "   <arg type=\"a{sv}\" name=\"changed_properties\"/>\n"        \
+        "   <arg type=\"as\" name=\"invalidated_properties\"/>\n"       \
+        "  </signal>\n"                                                 \
+        " </interface>\n"
+
+#define BUS_INTROSPECT_INTERFACE_OBJECT_MANAGER                      \
+        " <interface name=\"org.freedesktop.DBus.ObjectManager\">\n"    \
+        "  <method name=\"GetManagedObjects\">\n"                       \
+        "   <arg type=\"a{oa{sa{sv}}}\" name=\"object_paths_interfaces_and_properties\" direction=\"out\"/>\n" \
+        "  </method>\n"                                                 \
+        "  <signal name=\"InterfacesAdded\">\n"                         \
+        "   <arg type=\"o\" name=\"object_path\"/>\n"                   \
+        "   <arg type=\"a{sa{sv}}\" name=\"interfaces_and_properties\"/>\n" \
+        "  </signal>\n"                                                 \
+        "  <signal name=\"InterfacesRemoved\">\n"                       \
+        "   <arg type=\"o\" name=\"object_path\"/>\n"                   \
+        "   <arg type=\"as\" name=\"interfaces\"/>\n"                   \
+        "  </signal>\n"                                                 \
+        " </interface>\n"
+
 int introspect_begin(struct introspect *i, bool trusted) {
         assert(i);
 
-        zero(*i);
-        i->trusted = trusted;
+        *i = (struct introspect) {
+                .trusted = trusted,
+        };
 
         i->f = open_memstream_unlocked(&i->introspection, &i->size);
         if (!i->f)
@@ -39,12 +97,27 @@ int introspect_write_default_interfaces(struct introspect *i, bool object_manage
         return 0;
 }
 
+static int set_interface_name(struct introspect *intro, const char *interface_name) {
+        if (streq_ptr(intro->interface_name, interface_name))
+                return 0;
+
+        if (intro->interface_name)
+                fputs(" </interface>\n", intro->f);
+
+        if (interface_name)
+                fprintf(intro->f, " <interface name=\"%s\">\n", interface_name);
+
+        return free_and_strdup(&intro->interface_name, interface_name);
+}
+
 int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix) {
         char *node;
 
         assert(i);
         assert(prefix);
 
+        assert_se(set_interface_name(i, NULL) >= 0);
+
         while ((node = set_steal_first(s))) {
                 const char *e;
 
@@ -114,13 +187,23 @@ static int introspect_write_arguments(struct introspect *i, const char *signatur
         }
 }
 
-int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v) {
+int introspect_write_interface(
+                struct introspect *i,
+                const char *interface_name,
+                const sd_bus_vtable *v) {
+
         const sd_bus_vtable *vtable = v;
         const char *names = "";
+        int r;
 
         assert(i);
+        assert(interface_name);
         assert(v);
 
+        r = set_interface_name(i, interface_name);
+        if (r < 0)
+                return r;
+
         for (; v->type != _SD_BUS_VTABLE_END; v = bus_vtable_next(vtable, v)) {
 
                 /* Ignore methods, signals and properties that are
@@ -177,6 +260,8 @@ int introspect_finish(struct introspect *i, char **ret) {
 
         assert(i);
 
+        assert_se(set_interface_name(i, NULL) >= 0);
+
         fputs("</node>\n", i->f);
 
         r = fflush_and_check(i->f);
@@ -195,5 +280,6 @@ void introspect_free(struct introspect *i) {
         /* Normally introspect_finish() does all the work, this is just a backup for error paths */
 
         safe_fclose(i->f);
+        free(i->interface_name);
         free(i->introspection);
 }
index ccbb543d0c9d491133fae5327885ba4a2d950365..19d39923e5d7922c8a1cd0bfaf75e641df192ece 100644 (file)
@@ -9,6 +9,7 @@
 
 struct introspect {
         FILE *f;
+        char *interface_name;
         char *introspection;
         size_t size;
         bool trusted;
@@ -17,6 +18,9 @@ struct introspect {
 int introspect_begin(struct introspect *i, bool trusted);
 int introspect_write_default_interfaces(struct introspect *i, bool object_manager);
 int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix);
-int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v);
+int introspect_write_interface(
+                struct introspect *i,
+                const char *interface_name,
+                const sd_bus_vtable *v);
 int introspect_finish(struct introspect *i, char **ret);
 void introspect_free(struct introspect *i);
index e18957e3545afaffde4ef6a15d390011923388c6..97b732ae425274585e4b5bb0cbd05698b58a987b 100644 (file)
@@ -451,7 +451,7 @@ int bus_message_from_header(
         if (!IN_SET(h->version, 1, 2))
                 return -EBADMSG;
 
-        if (h->type == _SD_BUS_MESSAGE_TYPE_INVALID)
+        if (h->type <= _SD_BUS_MESSAGE_TYPE_INVALID || h->type >= _SD_BUS_MESSAGE_TYPE_MAX)
                 return -EBADMSG;
 
         if (!IN_SET(h->endian, BUS_LITTLE_ENDIAN, BUS_BIG_ENDIAN))
@@ -589,7 +589,7 @@ _public_ int sd_bus_message_new(
         assert_return(bus = bus_resolve(bus), -ENOPKG);
         assert_return(bus->state != BUS_UNSET, -ENOTCONN);
         assert_return(m, -EINVAL);
-        assert_return(type < _SD_BUS_MESSAGE_TYPE_MAX, -EINVAL);
+        assert_return(type > _SD_BUS_MESSAGE_TYPE_INVALID && type < _SD_BUS_MESSAGE_TYPE_MAX, -EINVAL);
 
         sd_bus_message *t = malloc0(ALIGN(sizeof(sd_bus_message)) + sizeof(struct bus_header));
         if (!t)
@@ -1298,19 +1298,18 @@ static int message_add_offset(sd_bus_message *m, size_t offset) {
 }
 
 static void message_extend_containers(sd_bus_message *m, size_t expand) {
-        struct bus_container *c;
-
         assert(m);
 
         if (expand <= 0)
                 return;
 
-        /* Update counters */
-        for (c = m->containers; c < m->containers + m->n_containers; c++) {
+        if (m->n_containers <= 0)
+                return;
 
+        /* Update counters */
+        for (struct bus_container *c = m->containers; c < m->containers + m->n_containers; c++)
                 if (c->array_size)
                         *c->array_size += expand;
-        }
 }
 
 static void *message_extend_body(
@@ -1373,7 +1372,6 @@ static void *message_extend_body(
                         if (r < 0)
                                 return NULL;
                 } else {
-                        struct bus_container *c;
                         void *op;
                         size_t os, start_part, end_part;
 
@@ -1394,8 +1392,9 @@ static void *message_extend_body(
                         }
 
                         /* Readjust pointers */
-                        for (c = m->containers; c < m->containers + m->n_containers; c++)
-                                c->array_size = adjust_pointer(c->array_size, op, os, part->data);
+                        if (m->n_containers > 0)
+                                for (struct bus_container *c = m->containers; c < m->containers + m->n_containers; c++)
+                                        c->array_size = adjust_pointer(c->array_size, op, os, part->data);
 
                         m->error.message = (const char*) adjust_pointer(m->error.message, op, os, part->data);
                 }
@@ -5203,29 +5202,34 @@ int bus_message_parse_fields(sd_bus_message *m) {
                  * table */
                 m->user_body_size = m->body_size - ((char*) m->footer + m->footer_accessible - p);
 
-                /* Pull out the offset table for the fields array */
-                sz = bus_gvariant_determine_word_size(m->fields_size, 0);
-                if (sz > 0) {
-                        size_t framing;
-                        void *q;
+                /* Pull out the offset table for the fields array, if any */
+                if (m->fields_size > 0) {
+                        sz = bus_gvariant_determine_word_size(m->fields_size, 0);
+                        if (sz > 0) {
+                                size_t framing;
+                                void *q;
 
-                        ri = m->fields_size - sz;
-                        r = message_peek_fields(m, &ri, 1, sz, &q);
-                        if (r < 0)
-                                return r;
+                                if (m->fields_size < sz)
+                                        return -EBADMSG;
 
-                        framing = bus_gvariant_read_word_le(q, sz);
-                        if (framing >= m->fields_size - sz)
-                                return -EBADMSG;
-                        if ((m->fields_size - framing) % sz != 0)
-                                return -EBADMSG;
+                                ri = m->fields_size - sz;
+                                r = message_peek_fields(m, &ri, 1, sz, &q);
+                                if (r < 0)
+                                        return r;
 
-                        ri = framing;
-                        r = message_peek_fields(m, &ri, 1, m->fields_size - framing, &offsets);
-                        if (r < 0)
-                                return r;
+                                framing = bus_gvariant_read_word_le(q, sz);
+                                if (framing >= m->fields_size - sz)
+                                        return -EBADMSG;
+                                if ((m->fields_size - framing) % sz != 0)
+                                        return -EBADMSG;
 
-                        n_offsets = (m->fields_size - framing) / sz;
+                                ri = framing;
+                                r = message_peek_fields(m, &ri, 1, m->fields_size - framing, &offsets);
+                                if (r < 0)
+                                        return r;
+
+                                n_offsets = (m->fields_size - framing) / sz;
+                        }
                 }
         } else
                 m->user_body_size = m->body_size;
@@ -5493,6 +5497,9 @@ int bus_message_parse_fields(sd_bus_message *m) {
                 if (m->reply_cookie == 0 || !m->error.name)
                         return -EBADMSG;
                 break;
+
+        default:
+                assert_not_reached("Bad message type");
         }
 
         /* Refuse non-local messages that claim they are local */
index 12ade498a97aa630bfc794c2b0a4f6654cd1729a..6abac8822c6eed5792529f5ca7cb09b67af58f7d 100644 (file)
@@ -56,12 +56,18 @@ static int node_vtable_get_userdata(
 static void *vtable_method_convert_userdata(const sd_bus_vtable *p, void *u) {
         assert(p);
 
+        if (!u || FLAGS_SET(p->flags, SD_BUS_VTABLE_ABSOLUTE_OFFSET))
+                return SIZE_TO_PTR(p->x.method.offset); /* don't add offset on NULL, to make ubsan happy */
+
         return (uint8_t*) u + p->x.method.offset;
 }
 
 static void *vtable_property_convert_userdata(const sd_bus_vtable *p, void *u) {
         assert(p);
 
+        if (!u || FLAGS_SET(p->flags, SD_BUS_VTABLE_ABSOLUTE_OFFSET))
+                return SIZE_TO_PTR(p->x.property.offset); /* as above */
+
         return (uint8_t*) u + p->x.property.offset;
 }
 
@@ -821,10 +827,10 @@ static int property_get_all_callbacks_run(
         if (r < 0)
                 return r;
 
-        found_interface = !iface ||
-                streq(iface, "org.freedesktop.DBus.Properties") ||
-                streq(iface, "org.freedesktop.DBus.Peer") ||
-                streq(iface, "org.freedesktop.DBus.Introspectable");
+        found_interface = !iface || STR_IN_SET(iface,
+                                               "org.freedesktop.DBus.Properties",
+                                               "org.freedesktop.DBus.Peer",
+                                               "org.freedesktop.DBus.Introspectable");
 
         LIST_FOREACH(vtables, c, first) {
                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -933,7 +939,6 @@ int introspect_path(
                 sd_bus_error *error) {
 
         _cleanup_set_free_free_ Set *s = NULL;
-        const char *previous_interface = NULL;
         _cleanup_(introspect_free) struct introspect intro = {};
         struct node_vtable *c;
         bool empty;
@@ -978,23 +983,11 @@ int introspect_path(
                 if (c->vtable[0].flags & SD_BUS_VTABLE_HIDDEN)
                         continue;
 
-                if (!streq_ptr(previous_interface, c->interface)) {
-                        if (previous_interface)
-                                fputs(" </interface>\n", intro.f);
-
-                        fprintf(intro.f, " <interface name=\"%s\">\n", c->interface);
-                }
-
-                r = introspect_write_interface(&intro, c->vtable);
+                r = introspect_write_interface(&intro, c->interface, c->vtable);
                 if (r < 0)
                         return r;
-
-                previous_interface = c->interface;
         }
 
-        if (previous_interface)
-                fputs(" </interface>\n", intro.f);
-
         if (empty) {
                 /* Nothing?, let's see if we exist at all, and if not
                  * refuse to do anything */
index d01fd8e6a3fd71f3c91b3d141e8d3dc94a1b11b1..7e1cd3c31e33d288d268596529e62af81f41ee7d 100644 (file)
@@ -103,60 +103,3 @@ enum {
         BUS_START_REPLY_SUCCESS = 1,
         BUS_START_REPLY_ALREADY_RUNNING = 2,
 };
-
-#define BUS_INTROSPECT_DOCTYPE                                       \
-        "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n" \
-        "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
-
-#define BUS_INTROSPECT_INTERFACE_PEER                                \
-        " <interface name=\"org.freedesktop.DBus.Peer\">\n"             \
-        "  <method name=\"Ping\"/>\n"                                   \
-        "  <method name=\"GetMachineId\">\n"                            \
-        "   <arg type=\"s\" name=\"machine_uuid\" direction=\"out\"/>\n" \
-        "  </method>\n"                                                 \
-        " </interface>\n"
-
-#define BUS_INTROSPECT_INTERFACE_INTROSPECTABLE                      \
-        " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"   \
-        "  <method name=\"Introspect\">\n"                              \
-        "   <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"        \
-        "  </method>\n"                                                 \
-        " </interface>\n"
-
-#define BUS_INTROSPECT_INTERFACE_PROPERTIES                          \
-        " <interface name=\"org.freedesktop.DBus.Properties\">\n"       \
-        "  <method name=\"Get\">\n"                                     \
-        "   <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n"    \
-        "   <arg name=\"property\" direction=\"in\" type=\"s\"/>\n"     \
-        "   <arg name=\"value\" direction=\"out\" type=\"v\"/>\n"       \
-        "  </method>\n"                                                 \
-        "  <method name=\"GetAll\">\n"                                  \
-        "   <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n"    \
-        "   <arg name=\"properties\" direction=\"out\" type=\"a{sv}\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"Set\">\n"                                     \
-        "   <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n"    \
-        "   <arg name=\"property\" direction=\"in\" type=\"s\"/>\n"     \
-        "   <arg name=\"value\" direction=\"in\" type=\"v\"/>\n"        \
-        "  </method>\n"                                                 \
-        "  <signal name=\"PropertiesChanged\">\n"                       \
-        "   <arg type=\"s\" name=\"interface\"/>\n"                     \
-        "   <arg type=\"a{sv}\" name=\"changed_properties\"/>\n"        \
-        "   <arg type=\"as\" name=\"invalidated_properties\"/>\n"       \
-        "  </signal>\n"                                                 \
-        " </interface>\n"
-
-#define BUS_INTROSPECT_INTERFACE_OBJECT_MANAGER                      \
-        " <interface name=\"org.freedesktop.DBus.ObjectManager\">\n"    \
-        "  <method name=\"GetManagedObjects\">\n"                       \
-        "   <arg type=\"a{oa{sa{sv}}}\" name=\"object_paths_interfaces_and_properties\" direction=\"out\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <signal name=\"InterfacesAdded\">\n"                         \
-        "   <arg type=\"o\" name=\"object_path\"/>\n"                   \
-        "   <arg type=\"a{sa{sv}}\" name=\"interfaces_and_properties\"/>\n" \
-        "  </signal>\n"                                                 \
-        "  <signal name=\"InterfacesRemoved\">\n"                       \
-        "   <arg type=\"o\" name=\"object_path\"/>\n"                   \
-        "   <arg type=\"as\" name=\"interfaces\"/>\n"                   \
-        "  </signal>\n"                                                 \
-        " </interface>\n"
index 18d30d010a20439340e5315f90aca88cbbbf9477..acc313d164bf59fc149e757b79ef1b7e81a6eb49 100644 (file)
@@ -136,11 +136,10 @@ static int bus_socket_write_auth(sd_bus *b) {
         if (b->prefer_writev)
                 k = writev(b->output_fd, b->auth_iovec + b->auth_index, ELEMENTSOF(b->auth_iovec) - b->auth_index);
         else {
-                struct msghdr mh;
-                zero(mh);
-
-                mh.msg_iov = b->auth_iovec + b->auth_index;
-                mh.msg_iovlen = ELEMENTSOF(b->auth_iovec) - b->auth_index;
+                struct msghdr mh = {
+                        .msg_iov = b->auth_iovec + b->auth_index,
+                        .msg_iovlen = ELEMENTSOF(b->auth_iovec) - b->auth_index,
+                };
 
                 k = sendmsg(b->output_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL);
                 if (k < 0 && errno == ENOTSOCK) {
@@ -519,10 +518,7 @@ static int bus_socket_read_auth(sd_bus *b) {
         ssize_t k;
         int r;
         void *p;
-        union {
-                struct cmsghdr cmsghdr;
-                uint8_t buf[CMSG_SPACE(sizeof(int) * BUS_FDS_MAX)];
-        } control;
+        CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int) * BUS_FDS_MAX)) control;
         bool handle_cmsg = false;
 
         assert(b);
@@ -551,23 +547,31 @@ static int bus_socket_read_auth(sd_bus *b) {
         if (b->prefer_readv)
                 k = readv(b->input_fd, &iov, 1);
         else {
-                zero(mh);
-                mh.msg_iov = &iov;
-                mh.msg_iovlen = 1;
-                mh.msg_control = &control;
-                mh.msg_controllen = sizeof(control);
+                mh = (struct msghdr) {
+                        .msg_iov = &iov,
+                        .msg_iovlen = 1,
+                        .msg_control = &control,
+                        .msg_controllen = sizeof(control),
+                };
 
-                k = recvmsg(b->input_fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
-                if (k < 0 && errno == ENOTSOCK) {
+                k = recvmsg_safe(b->input_fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
+                if (k == -ENOTSOCK) {
                         b->prefer_readv = true;
                         k = readv(b->input_fd, &iov, 1);
+                        if (k < 0)
+                                k = -errno;
                 } else
                         handle_cmsg = true;
         }
+        if (k == -EAGAIN)
+                return 0;
         if (k < 0)
-                return errno == EAGAIN ? 0 : -errno;
-        if (k == 0)
+                return (int) k;
+        if (k == 0) {
+                if (handle_cmsg)
+                        cmsg_close_all(&mh); /* paranoia, we shouldn't have gotten any fds on EOF */
                 return -ECONNRESET;
+        }
 
         b->rbuffer_size += k;
 
@@ -1030,8 +1034,10 @@ int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) {
                 if (m->n_fds > 0 && *idx == 0) {
                         struct cmsghdr *control;
 
-                        mh.msg_control = control = alloca(CMSG_SPACE(sizeof(int) * m->n_fds));
-                        mh.msg_controllen = control->cmsg_len = CMSG_LEN(sizeof(int) * m->n_fds);
+                        mh.msg_controllen = CMSG_SPACE(sizeof(int) * m->n_fds);
+                        mh.msg_control = alloca0(mh.msg_controllen);
+                        control = CMSG_FIRSTHDR(&mh);
+                        control->cmsg_len = CMSG_LEN(sizeof(int) * m->n_fds);
                         control->cmsg_level = SOL_SOCKET;
                         control->cmsg_type = SCM_RIGHTS;
                         memcpy(CMSG_DATA(control), m->fds, sizeof(int) * m->n_fds);
@@ -1160,10 +1166,7 @@ int bus_socket_read_message(sd_bus *bus) {
         size_t need;
         int r;
         void *b;
-        union {
-                struct cmsghdr cmsghdr;
-                uint8_t buf[CMSG_SPACE(sizeof(int) * BUS_FDS_MAX)];
-        } control;
+        CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int) * BUS_FDS_MAX)) control;
         bool handle_cmsg = false;
 
         assert(bus);
@@ -1187,23 +1190,31 @@ int bus_socket_read_message(sd_bus *bus) {
         if (bus->prefer_readv)
                 k = readv(bus->input_fd, &iov, 1);
         else {
-                zero(mh);
-                mh.msg_iov = &iov;
-                mh.msg_iovlen = 1;
-                mh.msg_control = &control;
-                mh.msg_controllen = sizeof(control);
+                mh = (struct msghdr) {
+                        .msg_iov = &iov,
+                        .msg_iovlen = 1,
+                        .msg_control = &control,
+                        .msg_controllen = sizeof(control),
+                };
 
-                k = recvmsg(bus->input_fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
-                if (k < 0 && errno == ENOTSOCK) {
+                k = recvmsg_safe(bus->input_fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
+                if (k == -ENOTSOCK) {
                         bus->prefer_readv = true;
                         k = readv(bus->input_fd, &iov, 1);
+                        if (k < 0)
+                                k = -errno;
                 } else
                         handle_cmsg = true;
         }
+        if (k == -EAGAIN)
+                return 0;
         if (k < 0)
-                return errno == EAGAIN ? 0 : -errno;
-        if (k == 0)
+                return (int) k;
+        if (k == 0) {
+                if (handle_cmsg)
+                        cmsg_close_all(&mh); /* On EOF we shouldn't have gotten an fd, but let's make sure */
                 return -ECONNRESET;
+        }
 
         bus->rbuffer_size += k;
 
index 05127f0e0ce4930fbdd0c83d6a4421698bb145bd..2c1fbbefc341a2acca08e17adcee3c5d07c56189 100644 (file)
@@ -317,7 +317,7 @@ static void* client1(void *p) {
 
 finish:
         if (bus) {
-                _cleanup_(sd_bus_message_unrefp) sd_bus_message *q;
+                _cleanup_(sd_bus_message_unrefp) sd_bus_message *q = NULL;
 
                 r = sd_bus_message_new_method_call(
                                 bus,
@@ -485,7 +485,7 @@ static void* client2(void *p) {
 
 finish:
         if (bus) {
-                _cleanup_(sd_bus_message_unrefp) sd_bus_message *q;
+                _cleanup_(sd_bus_message_unrefp) sd_bus_message *q = NULL;
 
                 r = sd_bus_message_new_method_call(
                                 bus,
index 9c8d1434b139565c8888e77832d2f6a58ae8bdcb..cbc31589241c14b1517c6ae0b9017987e65d0025 100644 (file)
@@ -14,11 +14,11 @@ static void test_manual_introspection(const sd_bus_vtable vtable[]) {
 
         assert_se(introspect_begin(&intro, false) >= 0);
 
-        fprintf(intro.f, " <interface name=\"org.foo\">\n");
-        assert_se(introspect_write_interface(&intro, vtable) >= 0);
-        fputs(" </interface>\n", intro.f);
-
+        assert_se(introspect_write_interface(&intro, "org.foo", vtable) >= 0);
+        /* write again to check if output looks OK for a different interface */
+        assert_se(introspect_write_interface(&intro, "org.foo.bar", vtable) >= 0);
         assert_se(introspect_finish(&intro, &s) == 0);
+
         fputs(s, stdout);
         fputs("\n", stdout);
 }
index 4cd71cb2d3a022e6534fce90e6f0a89b589d5dfa..587a1f2595bfe19da4248985aa0d1a75a319c18d 100644 (file)
@@ -4,6 +4,7 @@
 #include <limits.h>
 #include <mqueue.h>
 #include <netinet/in.h>
+#include <poll.h>
 #include <stdarg.h>
 #include <stddef.h>
 #include <stdio.h>
@@ -23,6 +24,7 @@
 #include "process-util.h"
 #include "socket-util.h"
 #include "strv.h"
+#include "time-util.h"
 #include "util.h"
 
 #define SNDBUF_SIZE (8*1024*1024)
@@ -551,6 +553,34 @@ finish:
         return r;
 }
 
+_public_ int sd_notify_barrier(int unset_environment, uint64_t timeout) {
+        _cleanup_close_pair_ int pipe_fd[2] = { -1, -1 };
+        struct timespec ts;
+        int r;
+
+        if (pipe2(pipe_fd, O_CLOEXEC) < 0)
+                return -errno;
+
+        r = sd_pid_notify_with_fds(0, unset_environment, "BARRIER=1", &pipe_fd[1], 1);
+        if (r <= 0)
+                return r;
+
+        pipe_fd[1] = safe_close(pipe_fd[1]);
+
+        struct pollfd pfd = {
+                .fd = pipe_fd[0],
+                /* POLLHUP is implicit */
+                .events = 0,
+        };
+        r = ppoll(&pfd, 1, timeout == UINT64_MAX ? NULL : timespec_store(&ts, timeout), NULL);
+        if (r < 0)
+                return -errno;
+        if (r == 0)
+                return -ETIMEDOUT;
+
+        return 1;
+}
+
 _public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state) {
         return sd_pid_notify_with_fds(pid, unset_environment, state, NULL, 0);
 }
index a1932f41f9b7f811085dc1e2ecff36b8d028d426..95dfc2f07782f9f6c700e71a0082c45776a8c333 100644 (file)
@@ -71,14 +71,14 @@ static sd_device_enumerator *device_enumerator_free(sd_device_enumerator *enumer
                 sd_device_unref(enumerator->devices[i]);
 
         free(enumerator->devices);
-        set_free_free(enumerator->match_subsystem);
-        set_free_free(enumerator->nomatch_subsystem);
-        hashmap_free_free_free(enumerator->match_sysattr);
-        hashmap_free_free_free(enumerator->nomatch_sysattr);
-        hashmap_free_free_free(enumerator->match_property);
-        set_free_free(enumerator->match_sysname);
-        set_free_free(enumerator->match_tag);
-        set_free_free(enumerator->match_parent);
+        set_free(enumerator->match_subsystem);
+        set_free(enumerator->nomatch_subsystem);
+        hashmap_free(enumerator->match_sysattr);
+        hashmap_free(enumerator->nomatch_sysattr);
+        hashmap_free(enumerator->match_property);
+        set_free(enumerator->match_sysname);
+        set_free(enumerator->match_tag);
+        set_free(enumerator->match_parent);
 
         return mfree(enumerator);
 }
@@ -97,89 +97,49 @@ _public_ int sd_device_enumerator_add_match_subsystem(sd_device_enumerator *enum
         else
                 set = &enumerator->nomatch_subsystem;
 
-        r = set_ensure_allocated(set, NULL);
-        if (r < 0)
-                return r;
-
-        r = set_put_strdup(*set, subsystem);
-        if (r < 0)
+        r = set_put_strdup(set, subsystem);
+        if (r <= 0)
                 return r;
 
         enumerator->scan_uptodate = false;
 
-        return 0;
+        return 1;
 }
 
-_public_ int sd_device_enumerator_add_match_sysattr(sd_device_enumerator *enumerator, const char *_sysattr, const char *_value, int match) {
-        _cleanup_free_ char *sysattr = NULL, *value = NULL;
+_public_ int sd_device_enumerator_add_match_sysattr(sd_device_enumerator *enumerator, const char *sysattr, const char *value, int match) {
         Hashmap **hashmap;
         int r;
 
         assert_return(enumerator, -EINVAL);
-        assert_return(_sysattr, -EINVAL);
+        assert_return(sysattr, -EINVAL);
 
         if (match)
                 hashmap = &enumerator->match_sysattr;
         else
                 hashmap = &enumerator->nomatch_sysattr;
 
-        r = hashmap_ensure_allocated(hashmap, NULL);
-        if (r < 0)
-                return r;
-
-        sysattr = strdup(_sysattr);
-        if (!sysattr)
-                return -ENOMEM;
-
-        if (_value) {
-                value = strdup(_value);
-                if (!value)
-                        return -ENOMEM;
-        }
-
-        r = hashmap_put(*hashmap, sysattr, value);
-        if (r < 0)
+        r = hashmap_put_strdup(hashmap, sysattr, value);
+        if (r <= 0)
                 return r;
 
-        sysattr = NULL;
-        value = NULL;
-
         enumerator->scan_uptodate = false;
 
-        return 0;
+        return 1;
 }
 
-_public_ int sd_device_enumerator_add_match_property(sd_device_enumerator *enumerator, const char *_property, const char *_value) {
-        _cleanup_free_ char *property = NULL, *value = NULL;
+_public_ int sd_device_enumerator_add_match_property(sd_device_enumerator *enumerator, const char *property, const char *value) {
         int r;
 
         assert_return(enumerator, -EINVAL);
-        assert_return(_property, -EINVAL);
-
-        r = hashmap_ensure_allocated(&enumerator->match_property, NULL);
-        if (r < 0)
-                return r;
-
-        property = strdup(_property);
-        if (!property)
-                return -ENOMEM;
-
-        if (_value) {
-                value = strdup(_value);
-                if (!value)
-                        return -ENOMEM;
-        }
+        assert_return(property, -EINVAL);
 
-        r = hashmap_put(enumerator->match_property, property, value);
-        if (r < 0)
+        r = hashmap_put_strdup(&enumerator->match_property, property, value);
+        if (r <= 0)
                 return r;
 
-        property = NULL;
-        value = NULL;
-
         enumerator->scan_uptodate = false;
 
-        return 0;
+        return 1;
 }
 
 _public_ int sd_device_enumerator_add_match_sysname(sd_device_enumerator *enumerator, const char *sysname) {
@@ -188,17 +148,13 @@ _public_ int sd_device_enumerator_add_match_sysname(sd_device_enumerator *enumer
         assert_return(enumerator, -EINVAL);
         assert_return(sysname, -EINVAL);
 
-        r = set_ensure_allocated(&enumerator->match_sysname, NULL);
-        if (r < 0)
-                return r;
-
-        r = set_put_strdup(enumerator->match_sysname, sysname);
-        if (r < 0)
+        r = set_put_strdup(&enumerator->match_sysname, sysname);
+        if (r <= 0)
                 return r;
 
         enumerator->scan_uptodate = false;
 
-        return 0;
+        return 1;
 }
 
 _public_ int sd_device_enumerator_add_match_tag(sd_device_enumerator *enumerator, const char *tag) {
@@ -207,52 +163,41 @@ _public_ int sd_device_enumerator_add_match_tag(sd_device_enumerator *enumerator
         assert_return(enumerator, -EINVAL);
         assert_return(tag, -EINVAL);
 
-        r = set_ensure_allocated(&enumerator->match_tag, NULL);
-        if (r < 0)
-                return r;
-
-        r = set_put_strdup(enumerator->match_tag, tag);
-        if (r < 0)
+        r = set_put_strdup(&enumerator->match_tag, tag);
+        if (r <= 0)
                 return r;
 
         enumerator->scan_uptodate = false;
 
-        return 0;
-}
-
-static void device_enumerator_clear_match_parent(sd_device_enumerator *enumerator) {
-        if (!enumerator)
-                return;
-
-        set_clear_free(enumerator->match_parent);
+        return 1;
 }
 
 int device_enumerator_add_match_parent_incremental(sd_device_enumerator *enumerator, sd_device *parent) {
         const char *path;
         int r;
 
-        assert_return(enumerator, -EINVAL);
-        assert_return(parent, -EINVAL);
+        assert(enumerator);
+        assert(parent);
 
         r = sd_device_get_syspath(parent, &path);
         if (r < 0)
                 return r;
 
-        r = set_ensure_allocated(&enumerator->match_parent, NULL);
-        if (r < 0)
-                return r;
-
-        r = set_put_strdup(enumerator->match_parent, path);
-        if (r < 0)
+        r = set_put_strdup(&enumerator->match_parent, path);
+        if (r <= 0)
                 return r;
 
         enumerator->scan_uptodate = false;
 
-        return 0;
+        return 1;
 }
 
 _public_ int sd_device_enumerator_add_match_parent(sd_device_enumerator *enumerator, sd_device *parent) {
-        device_enumerator_clear_match_parent(enumerator);
+        assert_return(enumerator, -EINVAL);
+        assert_return(parent, -EINVAL);
+
+        set_clear(enumerator->match_parent);
+
         return device_enumerator_add_match_parent_incremental(enumerator, parent);
 }
 
@@ -263,7 +208,7 @@ _public_ int sd_device_enumerator_allow_uninitialized(sd_device_enumerator *enum
 
         enumerator->scan_uptodate = false;
 
-        return 0;
+        return 1;
 }
 
 int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator) {
@@ -273,7 +218,7 @@ int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator)
 
         enumerator->scan_uptodate = false;
 
-        return 0;
+        return 1;
 }
 
 static int device_compare(sd_device * const *_a, sd_device * const *_b) {
index 42753abe0834aa3dbe8744c0694461de09dbe1f3..20a422c77cf347add270c7d417b486ab2ee62c70 100644 (file)
@@ -361,13 +361,13 @@ int device_monitor_receive_device(sd_device_monitor *m, sd_device **ret) {
                 .iov_base = &buf,
                 .iov_len = sizeof(buf)
         };
-        char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
+        CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
         union sockaddr_union snl;
         struct msghdr smsg = {
                 .msg_iov = &iov,
                 .msg_iovlen = 1,
-                .msg_control = cred_msg,
-                .msg_controllen = sizeof(cred_msg),
+                .msg_control = &control,
+                .msg_controllen = sizeof(control),
                 .msg_name = &snl,
                 .msg_namelen = sizeof(snl),
         };
index 1f2451f8e1b4e4d851571a19d858aedc9d1e9196..24f34dc18236783069f4c976297acefee6ab68de 100644 (file)
@@ -68,9 +68,9 @@ static sd_device *device_free(sd_device *device) {
         ordered_hashmap_free_free_free(device->properties);
         ordered_hashmap_free_free_free(device->properties_db);
         hashmap_free_free_free(device->sysattr_values);
-        set_free_free(device->sysattrs);
-        set_free_free(device->tags);
-        set_free_free(device->devlinks);
+        set_free(device->sysattrs);
+        set_free(device->tags);
+        set_free(device->devlinks);
 
         return mfree(device);
 }
@@ -1078,11 +1078,7 @@ int device_add_tag(sd_device *device, const char *tag) {
         if (!is_valid_tag(tag))
                 return -EINVAL;
 
-        r = set_ensure_allocated(&device->tags, &string_hash_ops);
-        if (r < 0)
-                return r;
-
-        r = set_put_strdup(device->tags, tag);
+        r = set_put_strdup(&device->tags, tag);
         if (r < 0)
                 return r;
 
@@ -1098,11 +1094,7 @@ int device_add_devlink(sd_device *device, const char *devlink) {
         assert(device);
         assert(devlink);
 
-        r = set_ensure_allocated(&device->devlinks, &string_hash_ops);
-        if (r < 0)
-                return r;
-
-        r = set_put_strdup(device->devlinks, devlink);
+        r = set_put_strdup(&device->devlinks, devlink);
         if (r < 0)
                 return r;
 
@@ -1591,10 +1583,6 @@ static int device_sysattrs_read_all(sd_device *device) {
         if (!dir)
                 return -errno;
 
-        r = set_ensure_allocated(&device->sysattrs, &string_hash_ops);
-        if (r < 0)
-                return r;
-
         FOREACH_DIRENT_ALL(dent, dir, return -errno) {
                 _cleanup_free_ char *path = NULL;
                 struct stat statbuf;
@@ -1613,7 +1601,7 @@ static int device_sysattrs_read_all(sd_device *device) {
                 if (!(statbuf.st_mode & S_IRUSR))
                         continue;
 
-                r = set_put_strdup(device->sysattrs, dent->d_name);
+                r = set_put_strdup(&device->sysattrs, dent->d_name);
                 if (r < 0)
                         return r;
         }
index 93f495f2593b3b013428efdbe6ed9165366d27d0..b14ce435eefb10e74ce2c19073e8c6a2b5b9c282 100644 (file)
@@ -12,7 +12,6 @@
 
 #define RTNL_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC))
 
-#define RTNL_WQUEUE_MAX 1024
 #define RTNL_RQUEUE_MAX 64*1024
 
 #define RTNL_CONTAINER_DEPTH 32
index a5871c73197f634844785960801abb8900f426f0..d6bf31efc7a196f3708fcbb2db1ea6c8f9700e65 100644 (file)
@@ -15,8 +15,7 @@
 #include "socket-util.h"
 #include "strv.h"
 
-#define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset) : NULL)
-#define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
+#define GET_CONTAINER(m, i) ((struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset))
 
 #define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
 #define RTA_FLAGS(rta) ((rta)->rta_type & ~NLA_TYPE_MASK)
@@ -520,7 +519,8 @@ int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type
 
         assert_return(m, -EINVAL);
         assert_return(!m->sealed, -EPERM);
-        assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -ERANGE);
+        /* m->containers[m->n_containers + 1] is accessed both in read and write. Prevent access out of bound */
+        assert_return(m->n_containers < (RTNL_CONTAINER_DEPTH - 1), -ERANGE);
 
         r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_NESTED);
         if (r < 0) {
@@ -567,6 +567,7 @@ int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned shor
 
         assert_return(m, -EINVAL);
         assert_return(!m->sealed, -EPERM);
+        assert_return(m->n_containers < (RTNL_CONTAINER_DEPTH - 1), -ERANGE);
 
         r = type_system_get_type_system_union(m->containers[m->n_containers].type_system, &type_system_union, type);
         if (r < 0)
@@ -609,6 +610,7 @@ int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type) {
 
         assert_return(m, -EINVAL);
         assert_return(!m->sealed, -EPERM);
+        assert_return(m->n_containers < (RTNL_CONTAINER_DEPTH - 1), -ERANGE);
 
         r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
         if (r < 0)
@@ -1007,7 +1009,7 @@ int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short typ
         int r;
 
         assert_return(m, -EINVAL);
-        assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
+        assert_return(m->n_containers < (RTNL_CONTAINER_DEPTH - 1), -EINVAL);
 
         r = type_system_get_type(m->containers[m->n_containers].type_system,
                                  &nl_type,
@@ -1098,7 +1100,7 @@ int sd_netlink_message_enter_array(sd_netlink_message *m, unsigned short type_id
         int r;
 
         assert_return(m, -EINVAL);
-        assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
+        assert_return(m->n_containers < (RTNL_CONTAINER_DEPTH - 1), -EINVAL);
 
         r = netlink_message_read_internal(m, type_id, &container, NULL);
         if (r < 0)
index 9401c43d05309d50733edb12dacede3295fd0393..71b3d1e2f1f4affebe4a85308655fb89b07cd635 100644 (file)
 #include "socket-util.h"
 #include "util.h"
 
+/* For some reason we need some extra cmsg space on some kernels. It's not clear why, and one of those days
+ * we need to track this down. See: https://github.com/systemd/systemd/pull/15457 */
+#define EXTRA_CMSG_SPACE 1024
+
 int socket_open(int family) {
         int fd;
 
@@ -238,34 +242,29 @@ int socket_write_message(sd_netlink *nl, sd_netlink_message *m) {
         return k;
 }
 
-static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool peek) {
+static int socket_recv_message(int fd, struct iovec *iov, uint32_t *ret_mcast_group, bool peek) {
         union sockaddr_union sender;
-        uint8_t cmsg_buffer[CMSG_SPACE(sizeof(struct nl_pktinfo))];
+        CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct nl_pktinfo)) + EXTRA_CMSG_SPACE) control;
         struct msghdr msg = {
                 .msg_iov = iov,
                 .msg_iovlen = 1,
                 .msg_name = &sender,
                 .msg_namelen = sizeof(sender),
-                .msg_control = cmsg_buffer,
-                .msg_controllen = sizeof(cmsg_buffer),
+                .msg_control = &control,
+                .msg_controllen = sizeof(control),
         };
-        struct cmsghdr *cmsg;
-        uint32_t group = 0;
         ssize_t n;
 
         assert(fd >= 0);
         assert(iov);
 
-        n = recvmsg(fd, &msg, MSG_TRUNC | (peek ? MSG_PEEK : 0));
-        if (n < 0) {
-                /* no data */
-                if (errno == ENOBUFS)
-                        log_debug("rtnl: kernel receive buffer overrun");
-                else if (errno == EAGAIN)
-                        log_debug("rtnl: no data in socket");
-
-                return IN_SET(errno, EAGAIN, EINTR) ? 0 : -errno;
-        }
+        n = recvmsg_safe(fd, &msg, MSG_TRUNC | (peek ? MSG_PEEK : 0));
+        if (n == -ENOBUFS)
+                return log_debug_errno(n, "rtnl: kernel receive buffer overrun");
+        if (IN_SET(n, -EAGAIN, -EINTR))
+                return 0;
+        if (n < 0)
+                return (int) n;
 
         if (sender.nl.nl_pid != 0) {
                 /* not from the kernel, ignore */
@@ -273,28 +272,24 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool
 
                 if (peek) {
                         /* drop the message */
-                        n = recvmsg(fd, &msg, 0);
+                        n = recvmsg_safe(fd, &msg, 0);
                         if (n < 0)
-                                return IN_SET(errno, EAGAIN, EINTR) ? 0 : -errno;
+                                return (int) n;
                 }
 
                 return 0;
         }
 
-        CMSG_FOREACH(cmsg, &msg) {
-                if (cmsg->cmsg_level == SOL_NETLINK &&
-                    cmsg->cmsg_type == NETLINK_PKTINFO &&
-                    cmsg->cmsg_len == CMSG_LEN(sizeof(struct nl_pktinfo))) {
-                        struct nl_pktinfo *pktinfo = (void *)CMSG_DATA(cmsg);
+        if (ret_mcast_group) {
+                struct nl_pktinfo *pi;
 
-                        /* multi-cast group */
-                        group = pktinfo->group;
-                }
+                pi = CMSG_FIND_DATA(&msg, SOL_NETLINK, NETLINK_PKTINFO, struct nl_pktinfo);
+                if (pi)
+                        *ret_mcast_group = pi->group;
+                else
+                        *ret_mcast_group = 0;
         }
 
-        if (_group)
-                *_group = group;
-
         return (int) n;
 }
 
index e03302bbec6d7ea9c52b906fc7c98f90f9774dfd..9598ad8e026e7d9d2e1f16763177e80864f3170c 100644 (file)
@@ -128,7 +128,7 @@ static void test_address_get(sd_netlink *rtnl, int ifindex) {
 }
 
 static void test_route(sd_netlink *rtnl) {
-        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req;
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         struct in_addr addr, addr_data;
         uint32_t index = 2, u32_data;
         int r;
index 6f2d37d2226f22c01c32db1260792f43d3211dda..b7548a0f7f561c69382f90858a98d30a349400a8 100644 (file)
@@ -163,13 +163,7 @@ static int set_locale(int argc, char **argv, void *userdata) {
 
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &m,
-                        "org.freedesktop.locale1",
-                        "/org/freedesktop/locale1",
-                        "org.freedesktop.locale1",
-                        "SetLocale");
+        r = bus_message_new_method_call(bus, &m, bus_locale, "SetLocale");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -215,11 +209,9 @@ static int set_vconsole_keymap(int argc, char **argv, void *userdata) {
         map = argv[1];
         toggle_map = argc > 2 ? argv[2] : "";
 
-        r = sd_bus_call_method(
+        r = bus_call_method(
                         bus,
-                        "org.freedesktop.locale1",
-                        "/org/freedesktop/locale1",
-                        "org.freedesktop.locale1",
+                        bus_locale,
                         "SetVConsoleKeyboard",
                         &error,
                         NULL,
@@ -258,11 +250,9 @@ static int set_x11_keymap(int argc, char **argv, void *userdata) {
         variant = argc > 3 ? argv[3] : "";
         options = argc > 4 ? argv[4] : "";
 
-        r = sd_bus_call_method(
+        r = bus_call_method(
                         bus,
-                        "org.freedesktop.locale1",
-                        "/org/freedesktop/locale1",
-                        "org.freedesktop.locale1",
+                        bus_locale,
                         "SetX11Keyboard",
                         &error,
                         NULL,
index 7315d93a9822c19c6bad0ee7eb9bc3bfc827322f..a6aa3bae8c86c418d154a8448b1a8bd0f0c67d19 100644 (file)
@@ -25,6 +25,7 @@
 #include "missing_capability.h"
 #include "path-util.h"
 #include "selinux-util.h"
+#include "service-util.h"
 #include "signal-util.h"
 #include "string-util.h"
 #include "strv.h"
@@ -257,18 +258,57 @@ static int property_get_xkb(
         return -EINVAL;
 }
 
+static int process_locale_list_item(
+                const char *assignment,
+                char *new_locale[static _VARIABLE_LC_MAX],
+                sd_bus_error *error) {
+
+        assert(assignment);
+        assert(new_locale);
+
+        for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) {
+                const char *name, *e;
+
+                assert_se(name = locale_variable_to_string(p));
+
+                e = startswith(assignment, name);
+                if (!e)
+                        continue;
+
+                if (*e != '=')
+                        continue;
+
+                e++;
+
+                if (!locale_is_valid(e))
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Locale %s is not valid, refusing.", e);
+                if (locale_is_installed(e) <= 0)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Locale %s not installed, refusing.", e);
+                if (new_locale[p])
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Locale variable %s set twice, refusing.", name);
+
+                new_locale[p] = strdup(e);
+                if (!new_locale[p])
+                        return -ENOMEM;
+
+                return 0;
+        }
+
+        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Locale assignment %s not valid, refusing.", assignment);
+}
+
 static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *error) {
         _cleanup_(locale_variables_freep) char *new_locale[_VARIABLE_LC_MAX] = {};
         _cleanup_strv_free_ char **settings = NULL, **l = NULL;
         Context *c = userdata;
         bool modified = false;
-        int interactive, p, r;
+        int interactive, r;
         char **i;
 
         assert(m);
         assert(c);
 
-        r = bus_message_read_strv_extend(m, &l);
+        r = sd_bus_message_read_strv(m, &l);
         if (r < 0)
                 return r;
 
@@ -277,11 +317,13 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er
                 return r;
 
         /* If single locale without variable name is provided, then we assume it is LANG=. */
-        if (strv_length(l) == 1 && !strchr(*l, '=')) {
-                if (!locale_is_valid(*l))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid Locale data.");
+        if (strv_length(l) == 1 && !strchr(l[0], '=')) {
+                if (!locale_is_valid(l[0]))
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid locale specification: %s", l[0]);
+                if (locale_is_installed(l[0]) <= 0)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified locale is not installed: %s", l[0]);
 
-                new_locale[VARIABLE_LANG] = strdup(*l);
+                new_locale[VARIABLE_LANG] = strdup(l[0]);
                 if (!new_locale[VARIABLE_LANG])
                         return -ENOMEM;
 
@@ -290,31 +332,9 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er
 
         /* Check whether a variable is valid */
         STRV_FOREACH(i, l) {
-                bool valid = false;
-
-                for (p = 0; p < _VARIABLE_LC_MAX; p++) {
-                        size_t k;
-                        const char *name;
-
-                        name = locale_variable_to_string(p);
-                        assert(name);
-
-                        k = strlen(name);
-                        if (startswith(*i, name) &&
-                            (*i)[k] == '=' &&
-                            locale_is_valid((*i) + k + 1)) {
-                                valid = true;
-
-                                new_locale[p] = strdup((*i) + k + 1);
-                                if (!new_locale[p])
-                                        return -ENOMEM;
-
-                                break;
-                        }
-                }
-
-                if (!valid)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid Locale data.");
+                r = process_locale_list_item(*i, new_locale, error);
+                if (r < 0)
+                        return r;
         }
 
         /* If LANG was specified, but not LANGUAGE, check if we should
@@ -337,7 +357,7 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er
         }
 
         /* Merge with the current settings */
-        for (p = 0; p < _VARIABLE_LC_MAX; p++)
+        for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++)
                 if (!isempty(c->locale[p]) && isempty(new_locale[p])) {
                         new_locale[p] = strdup(c->locale[p]);
                         if (!new_locale[p])
@@ -346,7 +366,7 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er
 
         locale_simplify(new_locale);
 
-        for (p = 0; p < _VARIABLE_LC_MAX; p++)
+        for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++)
                 if (!streq_ptr(c->locale[p], new_locale[p])) {
                         modified = true;
                         break;
@@ -371,7 +391,7 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er
         if (r == 0)
                 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
 
-        for (p = 0; p < _VARIABLE_LC_MAX; p++)
+        for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++)
                 free_and_replace(c->locale[p], new_locale[p]);
 
         r = locale_write_data(c, &settings);
@@ -709,6 +729,12 @@ static const sd_bus_vtable locale_vtable[] = {
         SD_BUS_VTABLE_END
 };
 
+static const BusObjectImplementation manager_object = {
+        "/org/freedesktop/locale1",
+        "org.freedesktop.locale1",
+        .vtables = BUS_VTABLES(locale_vtable),
+};
+
 static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
         int r;
@@ -721,9 +747,9 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
         if (r < 0)
                 return log_error_errno(r, "Failed to get system bus connection: %m");
 
-        r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/locale1", "org.freedesktop.locale1", locale_vtable, c);
+        r = bus_add_implementation(bus, &manager_object, c);
         if (r < 0)
-                return log_error_errno(r, "Failed to register object: %m");
+                return r;
 
         r = bus_log_control_api_register(bus);
         if (r < 0)
@@ -754,12 +780,17 @@ static int run(int argc, char *argv[]) {
 
         log_setup_service();
 
+        r = service_parse_argv("systemd-localed.service",
+                               "Manage system locale settings and key mappings.",
+                               BUS_IMPLEMENTATIONS(&manager_object,
+                                                   &log_control_object),
+                               argc, argv);
+        if (r <= 0)
+                return r;
+
         umask(0022);
         mac_selinux_init();
 
-        if (argc != 1)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments.");
-
         assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
 
         r = sd_event_default(&event);
index 9067ba41536cf154fed8308dccd2e55c19b23136..7e33fd6ec25bce75bc9db2068d20f26a5ad577ab 100644 (file)
@@ -64,14 +64,7 @@ static int get_session_path(sd_bus *bus, const char *session_id, sd_bus_error *e
         int r;
         char *ans;
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.login1",
-                        "/org/freedesktop/login1",
-                        "org.freedesktop.login1.Manager",
-                        "GetSession",
-                        error, &reply,
-                        "s", session_id);
+        r = bus_call_method(bus, bus_login_mgr, "GetSession", error, &reply, "s", session_id);
         if (r < 0)
                 return r;
 
@@ -130,14 +123,7 @@ static int list_sessions(int argc, char *argv[], void *userdata) {
 
         (void) pager_open(arg_pager_flags);
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.login1",
-                        "/org/freedesktop/login1",
-                        "org.freedesktop.login1.Manager",
-                        "ListSessions",
-                        &error, &reply,
-                        NULL);
+        r = bus_call_method(bus, bus_login_mgr, "ListSessions", &error, &reply, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to list sessions: %s", bus_error_message(&error, r));
 
@@ -211,14 +197,7 @@ static int list_users(int argc, char *argv[], void *userdata) {
 
         (void) pager_open(arg_pager_flags);
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.login1",
-                        "/org/freedesktop/login1",
-                        "org.freedesktop.login1.Manager",
-                        "ListUsers",
-                        &error, &reply,
-                        NULL);
+        r = bus_call_method(bus, bus_login_mgr, "ListUsers", &error, &reply, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to list users: %s", bus_error_message(&error, r));
 
@@ -268,14 +247,7 @@ static int list_seats(int argc, char *argv[], void *userdata) {
 
         (void) pager_open(arg_pager_flags);
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.login1",
-                        "/org/freedesktop/login1",
-                        "org.freedesktop.login1.Manager",
-                        "ListSeats",
-                        &error, &reply,
-                        NULL);
+        r = bus_call_method(bus, bus_login_mgr, "ListSeats", &error, &reply, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to list seats: %s", bus_error_message(&error, r));
 
@@ -961,14 +933,7 @@ static int show_seat(int argc, char *argv[], void *userdata) {
                 _cleanup_(sd_bus_message_unrefp) sd_bus_message * reply = NULL;
                 const char *path = NULL;
 
-                r = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.login1",
-                                "/org/freedesktop/login1",
-                                "org.freedesktop.login1.Manager",
-                                "GetSeat",
-                                &error, &reply,
-                                "s", argv[i]);
+                r = bus_call_method(bus, bus_login_mgr, "GetSeat", &error, &reply, "s", argv[i]);
                 if (r < 0)
                         return log_error_errno(r, "Failed to get seat: %s", bus_error_message(&error, r));
 
@@ -1017,11 +982,9 @@ static int activate(int argc, char *argv[], void *userdata) {
 
         for (i = 1; i < argc; i++) {
 
-                r = sd_bus_call_method(
+                r = bus_call_method(
                                 bus,
-                                "org.freedesktop.login1",
-                                "/org/freedesktop/login1",
-                                "org.freedesktop.login1.Manager",
+                                bus_login_mgr,
                                 streq(argv[0], "lock-session")      ? "LockSession" :
                                 streq(argv[0], "unlock-session")    ? "UnlockSession" :
                                 streq(argv[0], "terminate-session") ? "TerminateSession" :
@@ -1050,14 +1013,12 @@ static int kill_session(int argc, char *argv[], void *userdata) {
 
         for (i = 1; i < argc; i++) {
 
-                r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.login1",
-                        "/org/freedesktop/login1",
-                        "org.freedesktop.login1.Manager",
-                        "KillSession",
-                        &error, NULL,
-                        "ssi", argv[i], arg_kill_who, arg_signal);
+                r = bus_call_method(
+                                bus,
+                                bus_login_mgr,
+                                "KillSession",
+                                &error, NULL,
+                                "ssi", argv[i], arg_kill_who, arg_signal);
                 if (r < 0)
                         return log_error_errno(r, "Could not kill session: %s", bus_error_message(&error, -r));
         }
@@ -1101,14 +1062,12 @@ static int enable_linger(int argc, char *argv[], void *userdata) {
                                 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
                 }
 
-                r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.login1",
-                        "/org/freedesktop/login1",
-                        "org.freedesktop.login1.Manager",
-                        "SetUserLinger",
-                        &error, NULL,
-                        "ubb", (uint32_t) uid, b, true);
+                r = bus_call_method(
+                                bus,
+                                bus_login_mgr,
+                                "SetUserLinger",
+                                &error, NULL,
+                                "ubb", (uint32_t) uid, b, true);
                 if (r < 0)
                         return log_error_errno(r, "Could not enable linger: %s", bus_error_message(&error, -r));
         }
@@ -1133,14 +1092,7 @@ static int terminate_user(int argc, char *argv[], void *userdata) {
                 if (r < 0)
                         return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
 
-                r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.login1",
-                        "/org/freedesktop/login1",
-                        "org.freedesktop.login1.Manager",
-                        "TerminateUser",
-                        &error, NULL,
-                        "u", (uint32_t) uid);
+                r = bus_call_method(bus, bus_login_mgr, "TerminateUser", &error, NULL, "u", (uint32_t) uid);
                 if (r < 0)
                         return log_error_errno(r, "Could not terminate user: %s", bus_error_message(&error, -r));
         }
@@ -1168,11 +1120,9 @@ static int kill_user(int argc, char *argv[], void *userdata) {
                 if (r < 0)
                         return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
 
-                r = sd_bus_call_method(
+                r = bus_call_method(
                         bus,
-                        "org.freedesktop.login1",
-                        "/org/freedesktop/login1",
-                        "org.freedesktop.login1.Manager",
+                        bus_login_mgr,
                         "KillUser",
                         &error, NULL,
                         "ui", (uint32_t) uid, arg_signal);
@@ -1195,15 +1145,12 @@ static int attach(int argc, char *argv[], void *userdata) {
 
         for (i = 2; i < argc; i++) {
 
-                r = sd_bus_call_method(
+                r = bus_call_method(
                         bus,
-                        "org.freedesktop.login1",
-                        "/org/freedesktop/login1",
-                        "org.freedesktop.login1.Manager",
+                        bus_login_mgr,
                         "AttachDevice",
                         &error, NULL,
                         "ssb", argv[1], argv[i], true);
-
                 if (r < 0)
                         return log_error_errno(r, "Could not attach device: %s", bus_error_message(&error, -r));
         }
@@ -1221,14 +1168,7 @@ static int flush_devices(int argc, char *argv[], void *userdata) {
 
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.login1",
-                        "/org/freedesktop/login1",
-                        "org.freedesktop.login1.Manager",
-                        "FlushDevices",
-                        &error, NULL,
-                        "b", true);
+        r = bus_call_method(bus, bus_login_mgr, "FlushDevices", &error, NULL, "b", true);
         if (r < 0)
                 return log_error_errno(r, "Could not flush devices: %s", bus_error_message(&error, -r));
 
@@ -1245,11 +1185,9 @@ static int lock_sessions(int argc, char *argv[], void *userdata) {
 
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
-        r = sd_bus_call_method(
+        r = bus_call_method(
                         bus,
-                        "org.freedesktop.login1",
-                        "/org/freedesktop/login1",
-                        "org.freedesktop.login1.Manager",
+                        bus_login_mgr,
                         streq(argv[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
                         &error, NULL,
                         NULL);
@@ -1271,14 +1209,7 @@ static int terminate_seat(int argc, char *argv[], void *userdata) {
 
         for (i = 1; i < argc; i++) {
 
-                r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.login1",
-                        "/org/freedesktop/login1",
-                        "org.freedesktop.login1.Manager",
-                        "TerminateSeat",
-                        &error, NULL,
-                        "s", argv[i]);
+                r = bus_call_method(bus, bus_login_mgr, "TerminateSeat", &error, NULL, "s", argv[i]);
                 if (r < 0)
                         return log_error_errno(r, "Could not terminate seat: %s", bus_error_message(&error, -r));
         }
index ff192c53eb962f650fe7a9bee162b55601169d66..76af208af1a417687cdb055cc9bfc806750dc9ac 100644 (file)
@@ -206,7 +206,7 @@ int devnode_acl_all(const char *seat,
                         continue;
 
                 log_device_debug(d, "Found udev node %s for seat %s", node, seat);
-                r = set_put_strdup(nodes, node);
+                r = set_put_strdup(&nodes, node);
                 if (r < 0)
                         return r;
         }
index 985c58cc63ff068fb7498ac8cfa5a40c60e07e71..451fe2875487a04b19a6ac5f7116cfe57aae0b89 100644 (file)
@@ -885,7 +885,7 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
         if (r < 0)
                 goto fail;
 
-        session->type = t;
+        session->original_type = session->type = t;
         session->class = c;
         session->remote = remote;
         session->vtnr = vtnr;
@@ -1625,11 +1625,9 @@ static int execute_shutdown_or_sleep(
         if (w == INHIBIT_SHUTDOWN)
                 bus_manager_log_shutdown(m, unit_name);
 
-        r = sd_bus_call_method(
+        r = bus_call_method(
                         m->bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
+                        bus_systemd_mgr,
                         "StartUnit",
                         error,
                         &reply,
@@ -2567,7 +2565,7 @@ static int method_can_reboot_parameter(
                 void *userdata,
                 sd_bus_error *error) {
 
-        Manager *m = userdata;
+        _unused_ Manager *m = userdata;
         int r;
 
         assert(message);
@@ -2699,7 +2697,7 @@ static int method_can_reboot_to_firmware_setup(
                 void *userdata,
                 sd_bus_error *error) {
 
-        Manager *m = userdata;
+        _unused_ Manager *m = userdata;
         int r;
 
         assert(message);
@@ -2888,7 +2886,7 @@ static int method_can_reboot_to_boot_loader_menu(
                 void *userdata,
                 sd_bus_error *error) {
 
-        Manager *m = userdata;
+        _unused_ Manager *m = userdata;
         int r;
 
         assert(message);
@@ -3079,7 +3077,7 @@ static int method_can_reboot_to_boot_loader_entry(
                 void *userdata,
                 sd_bus_error *error) {
 
-        Manager *m = userdata;
+        _unused_ Manager *m = userdata;
         int r;
 
         assert(message);
@@ -3322,7 +3320,7 @@ fail:
         return r;
 }
 
-const sd_bus_vtable manager_vtable[] = {
+static const sd_bus_vtable manager_vtable[] = {
         SD_BUS_VTABLE_START(0),
 
         SD_BUS_WRITABLE_PROPERTY("EnableWallMessages", "b", NULL, NULL, offsetof(Manager, enable_wall_messages), 0),
@@ -3754,6 +3752,15 @@ const sd_bus_vtable manager_vtable[] = {
         SD_BUS_VTABLE_END
 };
 
+const BusObjectImplementation manager_object = {
+        "/org/freedesktop/login1",
+        "org.freedesktop.login1.Manager",
+        .vtables = BUS_VTABLES(manager_vtable),
+        .children = BUS_IMPLEMENTATIONS(&seat_object,
+                                        &session_object,
+                                        &user_object),
+};
+
 static int session_jobs_reply(Session *s, uint32_t jid, const char *unit, const char *result) {
         assert(s);
         assert(unit);
@@ -3972,13 +3979,7 @@ int manager_start_scope(
         assert(pid > 1);
         assert(job);
 
-        r = sd_bus_message_new_method_call(
-                        manager->bus,
-                        &m,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "StartTransientUnit");
+        r = bus_message_new_method_call(manager->bus, &m, bus_systemd_mgr, "StartTransientUnit");
         if (r < 0)
                 return r;
 
@@ -4065,11 +4066,9 @@ int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error,
         assert(unit);
         assert(job);
 
-        r = sd_bus_call_method(
+        r = bus_call_method(
                         manager->bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
+                        bus_systemd_mgr,
                         "StartUnit",
                         error,
                         &reply,
@@ -4088,11 +4087,9 @@ int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, c
         assert(unit);
         assert(job);
 
-        r = sd_bus_call_method(
+        r = bus_call_method(
                         manager->bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
+                        bus_systemd_mgr,
                         "StopUnit",
                         error,
                         &reply,
@@ -4150,11 +4147,9 @@ int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo
         assert(manager);
         assert(unit);
 
-        return sd_bus_call_method(
+        return bus_call_method(
                         manager->bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
+                        bus_systemd_mgr,
                         "KillUnit",
                         error,
                         NULL,
index 6c73a9654f69cb8eca6798c4b80556ca4f3703c3..6a3ee82f1c9ec198dc1c3e76025b5cac842f1dfb 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "sd-bus.h"
 
+#include "bus-util.h"
 #include "logind.h"
 #include "logind-session.h"
 #include "logind-user.h"
@@ -29,3 +30,5 @@ int manager_abandon_scope(Manager *manager, const char *scope, sd_bus_error *err
 int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error);
 int manager_unit_is_active(Manager *manager, const char *unit, sd_bus_error *error);
 int manager_job_is_active(Manager *manager, const char *path, sd_bus_error *error);
+
+extern const BusObjectImplementation manager_object;
index 7e811e9745241d8d4b266b3425214224b755f336..e72f265185b03d60f47a07040bf9d05d1a02b953 100644 (file)
@@ -291,41 +291,7 @@ static int method_switch_to_previous(sd_bus_message *message, void *userdata, sd
         return sd_bus_reply_method_return(message, NULL);
 }
 
-const sd_bus_vtable seat_vtable[] = {
-        SD_BUS_VTABLE_START(0),
-
-        SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Seat, id), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("ActiveSession", "(so)", property_get_active_session, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
-        SD_BUS_PROPERTY("CanMultiSession", "b", property_get_const_true, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
-        SD_BUS_PROPERTY("CanTTY", "b", property_get_can_tty, 0, SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("CanGraphical", "b", property_get_can_graphical, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
-        SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, 0),
-        SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
-        SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
-        SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
-
-        SD_BUS_METHOD("Terminate", NULL, NULL, bus_seat_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
-
-        SD_BUS_METHOD_WITH_NAMES("ActivateSession",
-                                 "s",
-                                 SD_BUS_PARAM(session_id),
-                                 NULL,,
-                                 method_activate_session,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SwitchTo",
-                                 "u",
-                                 SD_BUS_PARAM(vtnr),
-                                 NULL,,
-                                 method_switch_to,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-
-        SD_BUS_METHOD("SwitchToNext", NULL, NULL, method_switch_to_next, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("SwitchToPrevious", NULL, NULL, method_switch_to_previous, SD_BUS_VTABLE_UNPRIVILEGED),
-
-        SD_BUS_VTABLE_END
-};
-
-int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
+static int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
         _cleanup_free_ char *e = NULL;
         sd_bus_message *message;
         Manager *m = userdata;
@@ -373,7 +339,7 @@ char *seat_bus_path(Seat *s) {
         return strjoin("/org/freedesktop/login1/seat/", t);
 }
 
-int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
+static int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
         _cleanup_strv_free_ char **l = NULL;
         sd_bus_message *message;
         Manager *m = userdata;
@@ -478,3 +444,44 @@ int seat_send_changed(Seat *s, const char *properties, ...) {
 
         return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Seat", l);
 }
+
+static const sd_bus_vtable seat_vtable[] = {
+        SD_BUS_VTABLE_START(0),
+
+        SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Seat, id), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("ActiveSession", "(so)", property_get_active_session, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("CanMultiSession", "b", property_get_const_true, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
+        SD_BUS_PROPERTY("CanTTY", "b", property_get_can_tty, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("CanGraphical", "b", property_get_can_graphical, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, 0),
+        SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+
+        SD_BUS_METHOD("Terminate", NULL, NULL, bus_seat_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
+
+        SD_BUS_METHOD_WITH_NAMES("ActivateSession",
+                                 "s",
+                                 SD_BUS_PARAM(session_id),
+                                 NULL,,
+                                 method_activate_session,
+                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_NAMES("SwitchTo",
+                                 "u",
+                                 SD_BUS_PARAM(vtnr),
+                                 NULL,,
+                                 method_switch_to,
+                                 SD_BUS_VTABLE_UNPRIVILEGED),
+
+        SD_BUS_METHOD("SwitchToNext", NULL, NULL, method_switch_to_next, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SwitchToPrevious", NULL, NULL, method_switch_to_previous, SD_BUS_VTABLE_UNPRIVILEGED),
+
+        SD_BUS_VTABLE_END
+};
+
+const BusObjectImplementation seat_object = {
+        "/org/freedesktop/login1/seat",
+        "org.freedesktop.login1.Seat",
+        .fallback_vtables = BUS_FALLBACK_VTABLES({seat_vtable, seat_object_find}),
+        .node_enumerator = seat_node_enumerator,
+};
index 2590f64922b8e4f831e779ca2daad8a04c5f46fa..5fc857584ef04571a414bc7e8fdb105939ae388b 100644 (file)
@@ -4,11 +4,10 @@
 #include "sd-bus.h"
 
 #include "logind-seat.h"
+#include "bus-util.h"
 
-extern const sd_bus_vtable seat_vtable[];
+extern const BusObjectImplementation seat_object;
 
-int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error);
-int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error);
 char *seat_bus_path(Seat *s);
 
 int seat_send_signal(Seat *s, bool new_seat);
index 69bf0986f2f2cfda950209309dda2f276f7ed4f6..3857f4ab7d45120c0815235c32803f199be9680b 100644 (file)
@@ -393,6 +393,32 @@ static int method_release_control(sd_bus_message *message, void *userdata, sd_bu
         return sd_bus_reply_method_return(message, NULL);
 }
 
+static int method_set_type(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        Session *s = userdata;
+        const char *t;
+        SessionType type;
+        int r;
+
+        assert(message);
+        assert(s);
+
+        r = sd_bus_message_read(message, "s", &t);
+        if (r < 0)
+                return r;
+
+        type = session_type_from_string(t);
+        if (type < 0)
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                         "Invalid session type '%s'", t);
+
+        if (!session_is_controller(s, sd_bus_message_get_sender(message)))
+                return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You must be in control of this session to set type");
+
+        session_set_type(s, type);
+
+        return sd_bus_reply_method_return(message, NULL);
+}
+
 static int method_take_device(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Session *s = userdata;
         uint32_t major, minor;
@@ -555,135 +581,7 @@ static int method_set_brightness(sd_bus_message *message, void *userdata, sd_bus
         return 1;
 }
 
-const sd_bus_vtable session_vtable[] = {
-        SD_BUS_VTABLE_START(0),
-
-        SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Session, id), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("User", "(uo)", property_get_user, 0, SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("Name", "s", property_get_name, 0, SD_BUS_VTABLE_PROPERTY_CONST),
-        BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Session, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("VTNr", "u", NULL, offsetof(Session, vtnr), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("Seat", "(so)", property_get_seat, 0, SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("TTY", "s", NULL, offsetof(Session, tty), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("Display", "s", NULL, offsetof(Session, display), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("Remote", "b", bus_property_get_bool, offsetof(Session, remote), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("RemoteHost", "s", NULL, offsetof(Session, remote_host), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("RemoteUser", "s", NULL, offsetof(Session, remote_user), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Session, service), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("Desktop", "s", NULL, offsetof(Session, desktop), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Session, scope), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid, offsetof(Session, leader), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("Audit", "u", NULL, offsetof(Session, audit_id), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Session, type), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Session, class), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("Active", "b", property_get_active, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
-        SD_BUS_PROPERTY("State", "s", property_get_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
-        SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
-        SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
-        SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
-        SD_BUS_PROPERTY("LockedHint", "b", property_get_locked_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
-
-        SD_BUS_METHOD("Terminate",
-                      NULL,
-                      NULL,
-                      bus_session_method_terminate,
-                      SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("Activate",
-                      NULL,
-                      NULL,
-                      bus_session_method_activate,
-                      SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("Lock",
-                      NULL,
-                      NULL,
-                      bus_session_method_lock,
-                      SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("Unlock",
-                      NULL,
-                      NULL,
-                      bus_session_method_lock,
-                      SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetIdleHint",
-                                 "b",
-                                 SD_BUS_PARAM(idle),
-                                 NULL,,
-                                 method_set_idle_hint,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetLockedHint",
-                                 "b",
-                                 SD_BUS_PARAM(locked),
-                                 NULL,,
-                                 method_set_locked_hint,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("Kill",
-                                 "si",
-                                 SD_BUS_PARAM(who)
-                                 SD_BUS_PARAM(signal_number),
-                                 NULL,,
-                                 bus_session_method_kill,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("TakeControl",
-                                 "b",
-                                 SD_BUS_PARAM(force),
-                                 NULL,,
-                                 method_take_control,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("ReleaseControl",
-                      NULL,
-                      NULL,
-                      method_release_control,
-                      SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("TakeDevice",
-                                 "uu",
-                                 SD_BUS_PARAM(major)
-                                 SD_BUS_PARAM(minor),
-                                 "hb",
-                                 SD_BUS_PARAM(fd)
-                                 SD_BUS_PARAM(inactive),
-                                 method_take_device,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("ReleaseDevice",
-                                 "uu",
-                                 SD_BUS_PARAM(major)
-                                 SD_BUS_PARAM(minor),
-                                 NULL,,
-                                 method_release_device,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("PauseDeviceComplete",
-                                 "uu",
-                                 SD_BUS_PARAM(major)
-                                 SD_BUS_PARAM(minor),
-                                 NULL,,
-                                 method_pause_device_complete,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetBrightness",
-                                 "ssu",
-                                 SD_BUS_PARAM(subsystem)
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(brightness),
-                                 NULL,,
-                                 method_set_brightness,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-
-        SD_BUS_SIGNAL_WITH_NAMES("PauseDevice",
-                                 "uus",
-                                 SD_BUS_PARAM(major)
-                                 SD_BUS_PARAM(minor)
-                                 SD_BUS_PARAM(type),
-                                 0),
-        SD_BUS_SIGNAL_WITH_NAMES("ResumeDevice",
-                                 "uuh",
-                                 SD_BUS_PARAM(major)
-                                 SD_BUS_PARAM(minor)
-                                 SD_BUS_PARAM(fd),
-                                 0),
-        SD_BUS_SIGNAL("Lock", NULL, 0),
-        SD_BUS_SIGNAL("Unlock", NULL, 0),
-
-        SD_BUS_VTABLE_END
-};
-
-int session_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
+static int session_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
         _cleanup_free_ char *e = NULL;
         sd_bus_message *message;
         Manager *m = userdata;
@@ -731,7 +629,7 @@ char *session_bus_path(Session *s) {
         return strjoin("/org/freedesktop/login1/session/", t);
 }
 
-int session_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
+static int session_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
         _cleanup_strv_free_ char **l = NULL;
         sd_bus_message *message;
         Manager *m = userdata;
@@ -932,3 +830,144 @@ int session_send_create_reply(Session *s, sd_bus_error *error) {
                         (uint32_t) s->vtnr,
                         false);
 }
+
+static const sd_bus_vtable session_vtable[] = {
+        SD_BUS_VTABLE_START(0),
+
+        SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Session, id), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("User", "(uo)", property_get_user, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Name", "s", property_get_name, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+        BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Session, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("VTNr", "u", NULL, offsetof(Session, vtnr), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Seat", "(so)", property_get_seat, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("TTY", "s", NULL, offsetof(Session, tty), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Display", "s", NULL, offsetof(Session, display), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Remote", "b", bus_property_get_bool, offsetof(Session, remote), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("RemoteHost", "s", NULL, offsetof(Session, remote_host), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("RemoteUser", "s", NULL, offsetof(Session, remote_user), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Session, service), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Desktop", "s", NULL, offsetof(Session, desktop), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Session, scope), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid, offsetof(Session, leader), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Audit", "u", NULL, offsetof(Session, audit_id), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Session, type), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Session, class), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Active", "b", property_get_active, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("State", "s", property_get_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("LockedHint", "b", property_get_locked_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+
+        SD_BUS_METHOD("Terminate",
+                      NULL,
+                      NULL,
+                      bus_session_method_terminate,
+                      SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("Activate",
+                      NULL,
+                      NULL,
+                      bus_session_method_activate,
+                      SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("Lock",
+                      NULL,
+                      NULL,
+                      bus_session_method_lock,
+                      SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("Unlock",
+                      NULL,
+                      NULL,
+                      bus_session_method_lock,
+                      SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_NAMES("SetIdleHint",
+                                 "b",
+                                 SD_BUS_PARAM(idle),
+                                 NULL,,
+                                 method_set_idle_hint,
+                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_NAMES("SetLockedHint",
+                                 "b",
+                                 SD_BUS_PARAM(locked),
+                                 NULL,,
+                                 method_set_locked_hint,
+                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_NAMES("Kill",
+                                 "si",
+                                 SD_BUS_PARAM(who)
+                                 SD_BUS_PARAM(signal_number),
+                                 NULL,,
+                                 bus_session_method_kill,
+                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_NAMES("TakeControl",
+                                 "b",
+                                 SD_BUS_PARAM(force),
+                                 NULL,,
+                                 method_take_control,
+                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("ReleaseControl",
+                      NULL,
+                      NULL,
+                      method_release_control,
+                      SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_NAMES("SetType",
+                                 "s",
+                                 SD_BUS_PARAM(type),
+                                 NULL,,
+                                 method_set_type,
+                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_NAMES("TakeDevice",
+                                 "uu",
+                                 SD_BUS_PARAM(major)
+                                 SD_BUS_PARAM(minor),
+                                 "hb",
+                                 SD_BUS_PARAM(fd)
+                                 SD_BUS_PARAM(inactive),
+                                 method_take_device,
+                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_NAMES("ReleaseDevice",
+                                 "uu",
+                                 SD_BUS_PARAM(major)
+                                 SD_BUS_PARAM(minor),
+                                 NULL,,
+                                 method_release_device,
+                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_NAMES("PauseDeviceComplete",
+                                 "uu",
+                                 SD_BUS_PARAM(major)
+                                 SD_BUS_PARAM(minor),
+                                 NULL,,
+                                 method_pause_device_complete,
+                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_NAMES("SetBrightness",
+                                 "ssu",
+                                 SD_BUS_PARAM(subsystem)
+                                 SD_BUS_PARAM(name)
+                                 SD_BUS_PARAM(brightness),
+                                 NULL,,
+                                 method_set_brightness,
+                                 SD_BUS_VTABLE_UNPRIVILEGED),
+
+        SD_BUS_SIGNAL_WITH_NAMES("PauseDevice",
+                                 "uus",
+                                 SD_BUS_PARAM(major)
+                                 SD_BUS_PARAM(minor)
+                                 SD_BUS_PARAM(type),
+                                 0),
+        SD_BUS_SIGNAL_WITH_NAMES("ResumeDevice",
+                                 "uuh",
+                                 SD_BUS_PARAM(major)
+                                 SD_BUS_PARAM(minor)
+                                 SD_BUS_PARAM(fd),
+                                 0),
+        SD_BUS_SIGNAL("Lock", NULL, 0),
+        SD_BUS_SIGNAL("Unlock", NULL, 0),
+
+        SD_BUS_VTABLE_END
+};
+
+const BusObjectImplementation session_object = {
+        "/org/freedesktop/login1/session",
+        "org.freedesktop.login1.Session",
+        .fallback_vtables = BUS_FALLBACK_VTABLES({session_vtable, session_object_find}),
+        .node_enumerator = session_node_enumerator,
+};
index 9d2315cc60d482dfffdc956d81e7d462e2227e2d..6df96e06b2d8d4b200e8440f770dea7aee878c39 100644 (file)
@@ -5,9 +5,8 @@
 
 #include "logind-session.h"
 
-extern const sd_bus_vtable session_vtable[];
-int session_node_enumerator(sd_bus *bus, const char *path,void *userdata, char ***nodes, sd_bus_error *error);
-int session_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error);
+extern const BusObjectImplementation session_object;
+
 char *session_bus_path(Session *s);
 
 int session_send_signal(Session *s, bool new_session);
index 48505122a9decf670e04c1ea6401cc97131b8e1d..5c4149e1bd377328496ab2c423fe7b47bdeb3562 100644 (file)
@@ -240,6 +240,9 @@ int session_save(Session *s) {
         if (s->type >= 0)
                 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
 
+        if (s->original_type >= 0)
+                fprintf(f, "ORIGINAL_TYPE=%s\n", session_type_to_string(s->original_type));
+
         if (s->class >= 0)
                 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
 
@@ -402,6 +405,7 @@ int session_load(Session *s) {
                 *position = NULL,
                 *leader = NULL,
                 *type = NULL,
+                *original_type = NULL,
                 *class = NULL,
                 *uid = NULL,
                 *realtime = NULL,
@@ -433,6 +437,7 @@ int session_load(Session *s) {
                            "POSITION",       &position,
                            "LEADER",         &leader,
                            "TYPE",           &type,
+                           "ORIGINAL_TYPE",  &original_type,
                            "CLASS",          &class,
                            "UID",            &uid,
                            "REALTIME",       &realtime,
@@ -529,6 +534,16 @@ int session_load(Session *s) {
                         s->type = t;
         }
 
+        if (original_type) {
+                SessionType ot;
+
+                ot = session_type_from_string(original_type);
+                if (ot >= 0)
+                        s->original_type = ot;
+        } else
+                /* Pre-v246 compat: initialize original_type if not set in the state file */
+                s->original_type = s->type;
+
         if (class) {
                 SessionClass c;
 
@@ -1018,6 +1033,18 @@ void session_set_locked_hint(Session *s, bool b) {
         session_send_changed(s, "LockedHint", NULL);
 }
 
+void session_set_type(Session *s, SessionType t) {
+        assert(s);
+
+        if (s->type == t)
+                return;
+
+        s->type = t;
+        session_save(s);
+
+        session_send_changed(s, "Type", NULL);
+}
+
 static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
         Session *s = userdata;
 
@@ -1385,6 +1412,7 @@ void session_drop_controller(Session *s) {
                 return;
 
         s->track = sd_bus_track_unref(s->track);
+        session_set_type(s, s->original_type);
         session_release_controller(s, false);
         session_save(s);
         session_restore_vt(s);
index c51392bef655ef533c8d5ed95313aeabab69d269..b87c7316721353360db6a7df0c3b4198e8726d8f 100644 (file)
@@ -61,6 +61,7 @@ struct Session {
         const char *id;
         unsigned position;
         SessionType type;
+        SessionType original_type;
         SessionClass class;
 
         char *state_file;
@@ -135,6 +136,7 @@ int session_get_idle_hint(Session *s, dual_timestamp *t);
 int session_set_idle_hint(Session *s, bool b);
 int session_get_locked_hint(Session *s);
 void session_set_locked_hint(Session *s, bool b);
+void session_set_type(Session *s, SessionType t);
 int session_create_fifo(Session *s);
 int session_start(Session *s, sd_bus_message *properties, sd_bus_error *error);
 int session_stop(Session *s, bool force);
index f2475679354586380eac9bac5d558b814fdfcf69..63c77cab396f426fe1a5d5b01c34afa77e902246 100644 (file)
@@ -258,36 +258,7 @@ int bus_user_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *
         return sd_bus_reply_method_return(message, NULL);
 }
 
-const sd_bus_vtable user_vtable[] = {
-        SD_BUS_VTABLE_START(0),
-
-        SD_BUS_PROPERTY("UID", "u", property_get_uid, 0, SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("GID", "u", property_get_gid, 0, SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("Name", "s", property_get_name, 0, SD_BUS_VTABLE_PROPERTY_CONST),
-        BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(User, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("RuntimePath", "s", NULL, offsetof(User, runtime_path), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("Service", "s", NULL, offsetof(User, service), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("Slice", "s", NULL, offsetof(User, slice), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("Display", "(so)", property_get_display, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
-        SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
-        SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, 0),
-        SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
-        SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
-        SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
-        SD_BUS_PROPERTY("Linger", "b", property_get_linger, 0, 0),
-
-        SD_BUS_METHOD("Terminate", NULL, NULL, bus_user_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("Kill",
-                                 "i",
-                                 SD_BUS_PARAM(signal_number),
-                                 NULL,,
-                                 bus_user_method_kill,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-
-        SD_BUS_VTABLE_END
-};
-
-int user_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
+static int user_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
         Manager *m = userdata;
         uid_t uid;
         User *user;
@@ -342,7 +313,7 @@ char *user_bus_path(User *u) {
         return s;
 }
 
-int user_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
+static int user_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
         _cleanup_strv_free_ char **l = NULL;
         sd_bus_message *message;
         Manager *m = userdata;
@@ -391,6 +362,42 @@ int user_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***
         return 1;
 }
 
+static const sd_bus_vtable user_vtable[] = {
+        SD_BUS_VTABLE_START(0),
+
+        SD_BUS_PROPERTY("UID", "u", property_get_uid, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("GID", "u", property_get_gid, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Name", "s", property_get_name, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+        BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(User, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("RuntimePath", "s", NULL, offsetof(User, runtime_path), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Service", "s", NULL, offsetof(User, service), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Slice", "s", NULL, offsetof(User, slice), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("Display", "(so)", property_get_display, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
+        SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, 0),
+        SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("Linger", "b", property_get_linger, 0, 0),
+
+        SD_BUS_METHOD("Terminate", NULL, NULL, bus_user_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_NAMES("Kill",
+                                 "i",
+                                 SD_BUS_PARAM(signal_number),
+                                 NULL,,
+                                 bus_user_method_kill,
+                                 SD_BUS_VTABLE_UNPRIVILEGED),
+
+        SD_BUS_VTABLE_END
+};
+
+const BusObjectImplementation user_object = {
+        "/org/freedesktop/login1/user",
+        "org.freedesktop.login1.User",
+        .fallback_vtables = BUS_FALLBACK_VTABLES({user_vtable, user_object_find}),
+        .node_enumerator = user_node_enumerator,
+};
+
 int user_send_signal(User *u, bool new_user) {
         _cleanup_free_ char *p = NULL;
 
index acfcb981cf3639de55cd1ef90e7d1eb0f5360d66..b3f990c5af720e608f689f28834a4387b6ae7ae3 100644 (file)
@@ -5,9 +5,8 @@
 
 #include "logind-user.h"
 
-extern const sd_bus_vtable user_vtable[];
-int user_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error);
-int user_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error);
+extern const BusObjectImplementation user_object;
+
 char *user_bus_path(User *s);
 
 int user_send_signal(User *u, bool new_user);
index 75958189ac803451ff207e6cdfa6474b8387c876..d167080c2665ff7028d15c83644974cc137c2cc2 100644 (file)
@@ -11,6 +11,7 @@
 #include "bus-error.h"
 #include "bus-log-control-api.h"
 #include "bus-polkit.h"
+#include "bus-util.h"
 #include "cgroup-util.h"
 #include "def.h"
 #include "device-util.h"
@@ -27,6 +28,7 @@
 #include "parse-util.h"
 #include "process-util.h"
 #include "selinux-util.h"
+#include "service-util.h"
 #include "signal-util.h"
 #include "strv.h"
 #include "terminal-util.h"
@@ -623,53 +625,19 @@ static int manager_connect_bus(Manager *m) {
         if (r < 0)
                 return log_error_errno(r, "Failed to connect to system bus: %m");
 
-        r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/login1", "org.freedesktop.login1.Manager", manager_vtable, m);
+        r = bus_add_implementation(m->bus, &manager_object, m);
         if (r < 0)
-                return log_error_errno(r, "Failed to add manager object vtable: %m");
-
-        r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/login1/seat", "org.freedesktop.login1.Seat", seat_vtable, seat_object_find, m);
-        if (r < 0)
-                return log_error_errno(r, "Failed to add seat object vtable: %m");
-
-        r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/login1/seat", seat_node_enumerator, m);
-        if (r < 0)
-                return log_error_errno(r, "Failed to add seat enumerator: %m");
-
-        r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/login1/session", "org.freedesktop.login1.Session", session_vtable, session_object_find, m);
-        if (r < 0)
-                return log_error_errno(r, "Failed to add session object vtable: %m");
-
-        r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/login1/session", session_node_enumerator, m);
-        if (r < 0)
-                return log_error_errno(r, "Failed to add session enumerator: %m");
-
-        r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/login1/user", "org.freedesktop.login1.User", user_vtable, user_object_find, m);
-        if (r < 0)
-                return log_error_errno(r, "Failed to add user object vtable: %m");
+                return r;
 
-        r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/login1/user", user_node_enumerator, m);
+        r = bus_log_control_api_register(m->bus);
         if (r < 0)
-                return log_error_errno(r, "Failed to add user enumerator: %m");
+                return r;
 
-        r = sd_bus_match_signal_async(
-                        m->bus,
-                        NULL,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "JobRemoved",
-                        match_job_removed, NULL, m);
+        r = bus_match_signal_async(m->bus, NULL, bus_systemd_mgr, "JobRemoved", match_job_removed, NULL, m);
         if (r < 0)
                 return log_error_errno(r, "Failed to request match for JobRemoved: %m");
 
-        r = sd_bus_match_signal_async(
-                        m->bus,
-                        NULL,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "UnitRemoved",
-                        match_unit_removed, NULL, m);
+        r = bus_match_signal_async(m->bus, NULL, bus_systemd_mgr, "UnitRemoved", match_unit_removed, NULL, m);
         if (r < 0)
                 return log_error_errno(r, "Failed to request match for UnitRemoved: %m");
 
@@ -684,33 +652,14 @@ static int manager_connect_bus(Manager *m) {
         if (r < 0)
                 return log_error_errno(r, "Failed to request match for PropertiesChanged: %m");
 
-        r = sd_bus_match_signal_async(
-                        m->bus,
-                        NULL,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "Reloading",
-                        match_reloading, NULL, m);
+        r = bus_match_signal_async(m->bus, NULL, bus_systemd_mgr, "Reloading", match_reloading, NULL, m);
         if (r < 0)
                 return log_error_errno(r, "Failed to request match for Reloading: %m");
 
-        r = sd_bus_call_method_async(
-                        m->bus,
-                        NULL,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "Subscribe",
-                        NULL, NULL,
-                        NULL);
+        r = bus_call_method_async(m->bus, NULL, bus_systemd_mgr, "Subscribe", NULL, NULL, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to enable subscription: %m");
 
-        r = bus_log_control_api_register(m->bus);
-        if (r < 0)
-                return r;
-
         r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.login1", 0, NULL, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to request name: %m");
@@ -1201,12 +1150,15 @@ static int run(int argc, char *argv[]) {
         log_set_facility(LOG_AUTH);
         log_setup_service();
 
-        umask(0022);
+        r = service_parse_argv("systemd-logind.service",
+                               "Manager for user logins and devices and privileged operations.",
+                               BUS_IMPLEMENTATIONS(&manager_object,
+                                                   &log_control_object),
+                               argc, argv);
+        if (r <= 0)
+                return r;
 
-        if (argc != 1) {
-                log_error("This program takes no arguments.");
-                return -EINVAL;
-        }
+        umask(0022);
 
         r = mac_selinux_init();
         if (r < 0)
index 7e4673d27d3c28b851643b137362a94f208f4e9d..d3f5b28078e83d271e3db433df495eac56b5c06a 100644 (file)
@@ -157,8 +157,6 @@ int manager_read_utmp(Manager *m);
 void manager_connect_utmp(Manager *m);
 void manager_reconnect_utmp(Manager *m);
 
-extern const sd_bus_vtable manager_vtable[];
-
 /* gperf lookup function */
 const struct ConfigPerfItem* logind_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
 
index 124a25810e313f2ab13c4d13f4b0fd4ad494dcc2..df46e417c8fc7baa59a02b878de4bacb4c1a5fd3 100644 (file)
                        send_interface="org.freedesktop.login1.Session"
                        send_member="ReleaseControl"/>
 
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Session"
+                       send_member="SetType"/>
+
                 <allow send_destination="org.freedesktop.login1"
                        send_interface="org.freedesktop.login1.Session"
                        send_member="TakeDevice"/>
index 84bea21ab7be0777899a2d35c5b56cecaab00471..64771153cd960d2ba471805cf4ce4a5267bd7f01 100644 (file)
@@ -99,6 +99,7 @@ static int acquire_user_record(
 
         _cleanup_(user_record_unrefp) UserRecord *ur = NULL;
         const char *username = NULL, *json = NULL;
+        _cleanup_free_ char *field = NULL;
         int r;
 
         assert(handle);
@@ -114,39 +115,18 @@ static int acquire_user_record(
                 return PAM_SERVICE_ERR;
         }
 
-        /* If pam_systemd_homed (or some other module) already acqired the user record we can reuse it
+        /* If pam_systemd_homed (or some other module) already acquired the user record we can reuse it
          * here. */
-        r = pam_get_data(handle, "systemd-user-record", (const void**) &json);
-        if (r != PAM_SUCCESS || !json) {
-                _cleanup_free_ char *formatted = NULL;
-
-                if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) {
-                        pam_syslog(handle, LOG_ERR, "Failed to get PAM user record data: %s", pam_strerror(handle, r));
-                        return r;
-                }
-
-                /* Request the record ourselves */
-                r = userdb_by_name(username, 0, &ur);
-                if (r < 0) {
-                        pam_syslog(handle, LOG_ERR, "Failed to get user record: %s", strerror_safe(r));
-                        return PAM_USER_UNKNOWN;
-                }
-
-                r = json_variant_format(ur->json, 0, &formatted);
-                if (r < 0) {
-                        pam_syslog(handle, LOG_ERR, "Failed to format user JSON: %s", strerror_safe(r));
-                        return PAM_SERVICE_ERR;
-                }
-
-                /* And cache it for everyone else */
-                r = pam_set_data(handle, "systemd-user-record", formatted, pam_cleanup_free);
-                if (r < 0) {
-                        pam_syslog(handle, LOG_ERR, "Failed to set PAM user record data: %s", pam_strerror(handle, r));
-                        return r;
-                }
+        field = strjoin("systemd-user-record-", username);
+        if (!field)
+                return pam_log_oom(handle);
 
-                TAKE_PTR(formatted);
-        } else {
+        r = pam_get_data(handle, field, (const void**) &json);
+        if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) {
+                pam_syslog(handle, LOG_ERR, "Failed to get PAM user record data: %s", pam_strerror(handle, r));
+                return r;
+        }
+        if (r == PAM_SUCCESS && json) {
                 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
 
                 /* Parse cached record */
@@ -171,6 +151,31 @@ static int acquire_user_record(
                         pam_syslog(handle, LOG_ERR, "Acquired user record does not match user name.");
                         return PAM_SERVICE_ERR;
                 }
+        } else {
+                _cleanup_free_ char *formatted = NULL;
+
+                /* Request the record ourselves */
+                r = userdb_by_name(username, 0, &ur);
+                if (r < 0) {
+                        pam_syslog(handle, LOG_ERR, "Failed to get user record: %s", strerror_safe(r));
+                        return PAM_USER_UNKNOWN;
+                }
+
+                r = json_variant_format(ur->json, 0, &formatted);
+                if (r < 0) {
+                        pam_syslog(handle, LOG_ERR, "Failed to format user JSON: %s", strerror_safe(r));
+                        return PAM_SERVICE_ERR;
+                }
+
+                /* And cache it for everyone else */
+                r = pam_set_data(handle, field, formatted, pam_cleanup_free);
+                if (r < 0) {
+                        pam_syslog(handle, LOG_ERR, "Failed to set PAM user record data '%s': %s",
+                                   field, pam_strerror(handle, r));
+                        return r;
+                }
+
+                TAKE_PTR(formatted);
         }
 
         if (!uid_is_valid(ur->uid)) {
@@ -280,7 +285,6 @@ static int get_seat_from_display(const char *display, const char **seat, uint32_
 
 static int export_legacy_dbus_address(
                 pam_handle_t *handle,
-                uid_t uid,
                 const char *runtime) {
 
         const char *s;
@@ -580,9 +584,9 @@ static int apply_user_record_settings(pam_handle_t *handle, UserRecord *ur, bool
                 if (pam_getenv(handle, "LANG")) {
                         if (debug)
                                 pam_syslog(handle, LOG_DEBUG, "PAM environment variable $LANG already set, not changing based on user record.");
-                } else if (!locale_is_valid(ur->preferred_language)) {
+                } else if (locale_is_installed(ur->preferred_language) <= 0) {
                         if (debug)
-                                pam_syslog(handle, LOG_DEBUG, "Preferred language specified in user record is not valid locally, not setting $LANG.");
+                                pam_syslog(handle, LOG_DEBUG, "Preferred language specified in user record is not valid or not installed, not setting $LANG.");
                 } else {
                         _cleanup_free_ char *joined = NULL;
 
@@ -643,10 +647,6 @@ _public_ PAM_EXTERN int pam_sm_open_session(
 
         assert(handle);
 
-        /* Make this a NOP on non-logind systems */
-        if (!logind_running())
-                return PAM_SUCCESS;
-
         if (parse_argv(handle,
                        argc, argv,
                        &class_pam,
@@ -662,6 +662,10 @@ _public_ PAM_EXTERN int pam_sm_open_session(
         if (r != PAM_SUCCESS)
                 return r;
 
+        /* Make most of this a NOP on non-logind systems */
+        if (!logind_running())
+                goto success;
+
         /* Make sure we don't enter a loop by talking to
          * systemd-logind when it is actually waiting for the
          * background to finish start-up. If the service is
@@ -681,15 +685,11 @@ _public_ PAM_EXTERN int pam_sm_open_session(
                         }
                 }
 
-                r = export_legacy_dbus_address(handle, ur->uid, rt);
+                r = export_legacy_dbus_address(handle, rt);
                 if (r != PAM_SUCCESS)
                         return r;
 
-                r = apply_user_record_settings(handle, ur, debug);
-                if (r != PAM_SUCCESS)
-                        return r;
-
-                return PAM_SUCCESS;
+                goto success;
         }
 
         /* Otherwise, we ask logind to create a session for us */
@@ -789,13 +789,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
                            strna(memory_max), strna(tasks_max), strna(cpu_weight), strna(io_weight), strna(runtime_max_sec));
         }
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &m,
-                        "org.freedesktop.login1",
-                        "/org/freedesktop/login1",
-                        "org.freedesktop.login1.Manager",
-                        "CreateSession");
+        r = bus_message_new_method_call(bus, &m, bus_login_mgr, "CreateSession");
         if (r < 0)
                 return pam_bus_log_create_error(handle, r);
 
@@ -849,7 +843,9 @@ _public_ PAM_EXTERN int pam_sm_open_session(
                 if (sd_bus_error_has_name(&error, BUS_ERROR_SESSION_BUSY)) {
                         if (debug)
                                 pam_syslog(handle, LOG_DEBUG, "Not creating session: %s", bus_error_message(&error, r));
-                        return PAM_SUCCESS;
+
+                        /* We are already in a session, don't do anything */
+                        goto success;
                 } else {
                         pam_syslog(handle, LOG_ERR, "Failed to create session: %s", bus_error_message(&error, r));
                         return PAM_SESSION_ERR;
@@ -891,7 +887,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
                                 return r;
                 }
 
-                r = export_legacy_dbus_address(handle, ur->uid, runtime_path);
+                r = export_legacy_dbus_address(handle, runtime_path);
                 if (r != PAM_SUCCESS)
                         return r;
         }
@@ -946,6 +942,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
                 }
         }
 
+success:
         r = apply_user_record_settings(handle, ur, debug);
         if (r != PAM_SUCCESS)
                 return r;
@@ -963,11 +960,23 @@ _public_ PAM_EXTERN int pam_sm_close_session(
                 int argc, const char **argv) {
 
         const void *existing = NULL;
+        bool debug = false;
         const char *id;
         int r;
 
         assert(handle);
 
+        if (parse_argv(handle,
+                       argc, argv,
+                       NULL,
+                       NULL,
+                       NULL,
+                       &debug) < 0)
+                return PAM_SESSION_ERR;
+
+        if (debug)
+                pam_syslog(handle, LOG_DEBUG, "pam-systemd shutting down");
+
         /* Only release session if it wasn't pre-existing when we
          * tried to create it */
         (void) pam_get_data(handle, "systemd.existing", &existing);
@@ -984,15 +993,7 @@ _public_ PAM_EXTERN int pam_sm_close_session(
                 if (r != PAM_SUCCESS)
                         return r;
 
-                r = sd_bus_call_method(bus,
-                                       "org.freedesktop.login1",
-                                       "/org/freedesktop/login1",
-                                       "org.freedesktop.login1.Manager",
-                                       "ReleaseSession",
-                                       &error,
-                                       NULL,
-                                       "s",
-                                       id);
+                r = bus_call_method(bus, bus_login_mgr, "ReleaseSession", &error, NULL, "s", id);
                 if (r < 0) {
                         pam_syslog(handle, LOG_ERR, "Failed to release session: %s", bus_error_message(&error, r));
                         return PAM_SESSION_ERR;
index 4f85b4b7fe89af767e96f5f1e3d9ae1b09107e35..f6313f79fe18d9344d75581f097339d1b23b95db 100644 (file)
@@ -2,11 +2,19 @@
 #
 # Used by systemd --user instances.
 
-account required pam_unix.so
+m4_ifdef(`ENABLE_HOMED',
+-account sufficient pam_systemd_home.so
+)m4_dnl
+account sufficient pam_unix.so
+account required pam_permit.so
+
 m4_ifdef(`HAVE_SELINUX',
 session required pam_selinux.so close
 session required pam_selinux.so nottys open
 )m4_dnl
 session required pam_loginuid.so
 session optional pam_keyinit.so force revoke
+m4_ifdef(`ENABLE_HOMED',
+-session optional pam_systemd_home.so
+)m4_dnl
 session optional pam_systemd.so
index 294ef349321f4c0397d9d9aecc9a3dfa8b1484b6..4305f4915224ac4f4910bcf6bbad4dfc1c571f83 100644 (file)
@@ -354,30 +354,6 @@ int bus_image_method_get_os_release(
         return bus_reply_pair_array(message, image->os_release);
 }
 
-const sd_bus_vtable image_vtable[] = {
-        SD_BUS_VTABLE_START(0),
-        SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Image, name), 0),
-        SD_BUS_PROPERTY("Path", "s", NULL, offsetof(Image, path), 0),
-        SD_BUS_PROPERTY("Type", "s", property_get_type,  offsetof(Image, type), 0),
-        SD_BUS_PROPERTY("ReadOnly", "b", bus_property_get_bool, offsetof(Image, read_only), 0),
-        SD_BUS_PROPERTY("CreationTimestamp", "t", NULL, offsetof(Image, crtime), 0),
-        SD_BUS_PROPERTY("ModificationTimestamp", "t", NULL, offsetof(Image, mtime), 0),
-        SD_BUS_PROPERTY("Usage", "t", NULL, offsetof(Image, usage), 0),
-        SD_BUS_PROPERTY("Limit", "t", NULL, offsetof(Image, limit), 0),
-        SD_BUS_PROPERTY("UsageExclusive", "t", NULL, offsetof(Image, usage_exclusive), 0),
-        SD_BUS_PROPERTY("LimitExclusive", "t", NULL, offsetof(Image, limit_exclusive), 0),
-        SD_BUS_METHOD("Remove", NULL, NULL, bus_image_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("Rename", "s", NULL, bus_image_method_rename, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("Clone", "sb", NULL, bus_image_method_clone, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("MarkReadOnly", "b", NULL, bus_image_method_mark_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("SetLimit", "t", NULL, bus_image_method_set_limit, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("GetHostname", NULL, "s", bus_image_method_get_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("GetMachineID", NULL, "ay", bus_image_method_get_machine_id, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("GetMachineInfo", NULL, "a{ss}", bus_image_method_get_machine_info, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_image_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_VTABLE_END
-};
-
 static int image_flush_cache(sd_event_source *s, void *userdata) {
         Manager *m = userdata;
 
@@ -388,7 +364,7 @@ static int image_flush_cache(sd_event_source *s, void *userdata) {
         return 0;
 }
 
-int image_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
+static int image_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
         _cleanup_free_ char *e = NULL;
         Manager *m = userdata;
         Image *image = NULL;
@@ -462,7 +438,7 @@ char *image_bus_path(const char *name) {
         return strjoin("/org/freedesktop/machine1/image/", e);
 }
 
-int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
+static int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
         _cleanup_hashmap_free_ Hashmap *images = NULL;
         _cleanup_strv_free_ char **l = NULL;
         Image *image;
@@ -497,3 +473,34 @@ int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char **
 
         return 1;
 }
+
+const sd_bus_vtable image_vtable[] = {
+        SD_BUS_VTABLE_START(0),
+        SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Image, name), 0),
+        SD_BUS_PROPERTY("Path", "s", NULL, offsetof(Image, path), 0),
+        SD_BUS_PROPERTY("Type", "s", property_get_type,  offsetof(Image, type), 0),
+        SD_BUS_PROPERTY("ReadOnly", "b", bus_property_get_bool, offsetof(Image, read_only), 0),
+        SD_BUS_PROPERTY("CreationTimestamp", "t", NULL, offsetof(Image, crtime), 0),
+        SD_BUS_PROPERTY("ModificationTimestamp", "t", NULL, offsetof(Image, mtime), 0),
+        SD_BUS_PROPERTY("Usage", "t", NULL, offsetof(Image, usage), 0),
+        SD_BUS_PROPERTY("Limit", "t", NULL, offsetof(Image, limit), 0),
+        SD_BUS_PROPERTY("UsageExclusive", "t", NULL, offsetof(Image, usage_exclusive), 0),
+        SD_BUS_PROPERTY("LimitExclusive", "t", NULL, offsetof(Image, limit_exclusive), 0),
+        SD_BUS_METHOD("Remove", NULL, NULL, bus_image_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("Rename", "s", NULL, bus_image_method_rename, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("Clone", "sb", NULL, bus_image_method_clone, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("MarkReadOnly", "b", NULL, bus_image_method_mark_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetLimit", "t", NULL, bus_image_method_set_limit, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("GetHostname", NULL, "s", bus_image_method_get_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("GetMachineID", NULL, "ay", bus_image_method_get_machine_id, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("GetMachineInfo", NULL, "a{ss}", bus_image_method_get_machine_info, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_image_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_VTABLE_END
+};
+
+const BusObjectImplementation image_object = {
+        "/org/freedesktop/machine1/image",
+        "org.freedesktop.machine1.Image",
+        .fallback_vtables = BUS_FALLBACK_VTABLES({image_vtable, image_object_find}),
+        .node_enumerator = image_node_enumerator,
+};
index a918b77d38e21ee6dc7bbeabb16f5fedc7176778..43f5f34d209ee16af8623b74298de9d2de6be2e4 100644 (file)
@@ -1,15 +1,13 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include "bus-util.h"
 #include "machined.h"
 
-extern const sd_bus_vtable image_vtable[];
+extern const BusObjectImplementation image_object;
 
 char *image_bus_path(const char *name);
 
-int image_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error);
-int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error);
-
 int bus_image_method_remove(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_image_method_rename(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_image_method_clone(sd_bus_message *message, void *userdata, sd_bus_error *error);
index c75467cadf059dbf054ce0f1d740dcf7cd7fe3c3..903dd8f161770bee2e8c318ed6165567bf2d4ba8 100644 (file)
@@ -552,14 +552,7 @@ int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bu
 
         getty = strjoina("container-getty@", p, ".service");
 
-        r = sd_bus_call_method(
-                        container_bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "StartUnit",
-                        error, NULL,
-                        "ss", getty, "replace");
+        r = bus_call_method(container_bus, bus_systemd_mgr, "StartUnit", error, NULL, "ss", getty, "replace");
         if (r < 0)
                 return r;
 
@@ -668,13 +661,7 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
 
         container_bus = allocated_bus ?: m->manager->bus;
 
-        r = sd_bus_message_new_method_call(
-                        container_bus,
-                        &tm,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "StartTransientUnit");
+        r = bus_message_new_method_call(container_bus, &tm, bus_systemd_mgr, "StartTransientUnit");
         if (r < 0)
                 return r;
 
@@ -1321,7 +1308,99 @@ int bus_machine_method_get_uid_shift(sd_bus_message *message, void *userdata, sd
         return sd_bus_reply_method_return(message, "u", (uint32_t) shift);
 }
 
-const sd_bus_vtable machine_vtable[] = {
+static int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
+        Manager *m = userdata;
+        Machine *machine;
+        int r;
+
+        assert(bus);
+        assert(path);
+        assert(interface);
+        assert(found);
+        assert(m);
+
+        if (streq(path, "/org/freedesktop/machine1/machine/self")) {
+                _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
+                sd_bus_message *message;
+                pid_t pid;
+
+                message = sd_bus_get_current_message(bus);
+                if (!message)
+                        return 0;
+
+                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_creds_get_pid(creds, &pid);
+                if (r < 0)
+                        return r;
+
+                r = manager_get_machine_by_pid(m, pid, &machine);
+                if (r <= 0)
+                        return 0;
+        } else {
+                _cleanup_free_ char *e = NULL;
+                const char *p;
+
+                p = startswith(path, "/org/freedesktop/machine1/machine/");
+                if (!p)
+                        return 0;
+
+                e = bus_label_unescape(p);
+                if (!e)
+                        return -ENOMEM;
+
+                machine = hashmap_get(m->machines, e);
+                if (!machine)
+                        return 0;
+        }
+
+        *found = machine;
+        return 1;
+}
+
+char *machine_bus_path(Machine *m) {
+        _cleanup_free_ char *e = NULL;
+
+        assert(m);
+
+        e = bus_label_escape(m->name);
+        if (!e)
+                return NULL;
+
+        return strjoin("/org/freedesktop/machine1/machine/", e);
+}
+
+static int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
+        _cleanup_strv_free_ char **l = NULL;
+        Machine *machine = NULL;
+        Manager *m = userdata;
+        Iterator i;
+        int r;
+
+        assert(bus);
+        assert(path);
+        assert(nodes);
+
+        HASHMAP_FOREACH(machine, m->machines, i) {
+                char *p;
+
+                p = machine_bus_path(machine);
+                if (!p)
+                        return -ENOMEM;
+
+                r = strv_consume(&l, p);
+                if (r < 0)
+                        return r;
+        }
+
+        *nodes = TAKE_PTR(l);
+
+        return 1;
+}
+
+static const sd_bus_vtable machine_vtable[] = {
         SD_BUS_VTABLE_START(0),
         SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("Id", "ay", bus_property_get_id128, offsetof(Machine, id), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -1423,97 +1502,12 @@ const sd_bus_vtable machine_vtable[] = {
         SD_BUS_VTABLE_END
 };
 
-int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
-        Manager *m = userdata;
-        Machine *machine;
-        int r;
-
-        assert(bus);
-        assert(path);
-        assert(interface);
-        assert(found);
-        assert(m);
-
-        if (streq(path, "/org/freedesktop/machine1/machine/self")) {
-                _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
-                sd_bus_message *message;
-                pid_t pid;
-
-                message = sd_bus_get_current_message(bus);
-                if (!message)
-                        return 0;
-
-                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
-                if (r < 0)
-                        return r;
-
-                r = sd_bus_creds_get_pid(creds, &pid);
-                if (r < 0)
-                        return r;
-
-                r = manager_get_machine_by_pid(m, pid, &machine);
-                if (r <= 0)
-                        return 0;
-        } else {
-                _cleanup_free_ char *e = NULL;
-                const char *p;
-
-                p = startswith(path, "/org/freedesktop/machine1/machine/");
-                if (!p)
-                        return 0;
-
-                e = bus_label_unescape(p);
-                if (!e)
-                        return -ENOMEM;
-
-                machine = hashmap_get(m->machines, e);
-                if (!machine)
-                        return 0;
-        }
-
-        *found = machine;
-        return 1;
-}
-
-char *machine_bus_path(Machine *m) {
-        _cleanup_free_ char *e = NULL;
-
-        assert(m);
-
-        e = bus_label_escape(m->name);
-        if (!e)
-                return NULL;
-
-        return strjoin("/org/freedesktop/machine1/machine/", e);
-}
-
-int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
-        _cleanup_strv_free_ char **l = NULL;
-        Machine *machine = NULL;
-        Manager *m = userdata;
-        Iterator i;
-        int r;
-
-        assert(bus);
-        assert(path);
-        assert(nodes);
-
-        HASHMAP_FOREACH(machine, m->machines, i) {
-                char *p;
-
-                p = machine_bus_path(machine);
-                if (!p)
-                        return -ENOMEM;
-
-                r = strv_consume(&l, p);
-                if (r < 0)
-                        return r;
-        }
-
-        *nodes = TAKE_PTR(l);
-
-        return 1;
-}
+const BusObjectImplementation machine_object = {
+        "/org/freedesktop/machine1/machine",
+        "org.freedesktop.machine1.Machine",
+        .fallback_vtables = BUS_FALLBACK_VTABLES({machine_vtable, machine_object_find}),
+        .node_enumerator = machine_node_enumerator,
+};
 
 int machine_send_signal(Machine *m, bool new_machine) {
         _cleanup_free_ char *p = NULL;
index d9f3c59cead7417f17a7c4f5b17628c69eee424c..7080092bcf78cdfc731a079e5487b87bc942037f 100644 (file)
@@ -3,13 +3,12 @@
 
 #include "sd-bus.h"
 
+#include "bus-util.h"
 #include "machine.h"
 
-extern const sd_bus_vtable machine_vtable[];
+extern const BusObjectImplementation machine_object;
 
 char *machine_bus_path(Machine *s);
-int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error);
-int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error);
 
 int bus_machine_method_unregister(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_machine_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error);
index 61234582a3405e50b3700bb7926f256c86e66d77..d88b2651d2c5118bf57ee7648aa85dac8dad82f3 100644 (file)
@@ -108,14 +108,7 @@ static int call_get_os_release(sd_bus *bus, const char *method, const char *name
                 awaited_args++;
         query_res = newa0(const char *, awaited_args);
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.machine1",
-                        "/org/freedesktop/machine1",
-                        "org.freedesktop.machine1.Manager",
-                        method,
-                        &error,
-                        &reply, "s", name);
+        r = bus_call_method(bus, bus_machine_mgr, method, &error, &reply, "s", name);
         if (r < 0)
                 return log_debug_errno(r, "Failed to call '%s()': %s", method, bus_error_message(&error, r));
 
@@ -179,14 +172,7 @@ static int call_get_addresses(
         assert(prefix);
         assert(prefix2);
 
-        r = sd_bus_call_method(bus,
-                               "org.freedesktop.machine1",
-                               "/org/freedesktop/machine1",
-                               "org.freedesktop.machine1.Manager",
-                               "GetMachineAddresses",
-                               NULL,
-                               &reply,
-                               "s", name);
+        r = bus_call_method(bus, bus_machine_mgr, "GetMachineAddresses", NULL, &reply, "s", name);
         if (r < 0)
                 return log_debug_errno(r, "Could not get addresses: %s", bus_error_message(&error, r));
 
@@ -283,14 +269,7 @@ static int list_machines(int argc, char *argv[], void *userdata) {
 
         (void) pager_open(arg_pager_flags);
 
-        r = sd_bus_call_method(bus,
-                               "org.freedesktop.machine1",
-                               "/org/freedesktop/machine1",
-                               "org.freedesktop.machine1.Manager",
-                               "ListMachines",
-                               &error,
-                               &reply,
-                               NULL);
+        r = bus_call_method(bus, bus_machine_mgr, "ListMachines", &error, &reply, NULL);
         if (r < 0)
                 return log_error_errno(r, "Could not get machines: %s", bus_error_message(&error, r));
 
@@ -369,14 +348,7 @@ static int list_images(int argc, char *argv[], void *userdata) {
 
         (void) pager_open(arg_pager_flags);
 
-        r = sd_bus_call_method(bus,
-                               "org.freedesktop.machine1",
-                               "/org/freedesktop/machine1",
-                               "org.freedesktop.machine1.Manager",
-                               "ListImages",
-                               &error,
-                               &reply,
-                               NULL);
+        r = bus_call_method(bus, bus_machine_mgr, "ListImages", &error, &reply, NULL);
         if (r < 0)
                 return log_error_errno(r, "Could not get images: %s", bus_error_message(&error, r));
 
@@ -493,14 +465,7 @@ static int print_uid_shift(sd_bus *bus, const char *name) {
         assert(bus);
         assert(name);
 
-        r = sd_bus_call_method(bus,
-                               "org.freedesktop.machine1",
-                               "/org/freedesktop/machine1",
-                               "org.freedesktop.machine1.Manager",
-                               "GetMachineUIDShift",
-                               &error,
-                               &reply,
-                               "s", name);
+        r = bus_call_method(bus, bus_machine_mgr, "GetMachineUIDShift", &error, &reply, "s", name);
         if (r < 0)
                 return log_debug_errno(r, "Failed to query UID/GID shift: %s", bus_error_message(&error, r));
 
@@ -751,14 +716,7 @@ static int show_machine(int argc, char *argv[], void *userdata) {
         for (int i = 1; i < argc; i++) {
                 const char *path = NULL;
 
-                r = sd_bus_call_method(bus,
-                                       "org.freedesktop.machine1",
-                                       "/org/freedesktop/machine1",
-                                       "org.freedesktop.machine1.Manager",
-                                       "GetMachine",
-                                       &error,
-                                       &reply,
-                                       "s", argv[i]);
+                r = bus_call_method(bus, bus_machine_mgr, "GetMachine", &error, &reply, "s", argv[i]);
                 if (r < 0)
                         return log_error_errno(r, "Could not get path to machine: %s", bus_error_message(&error, -r));
 
@@ -780,13 +738,7 @@ static int print_image_hostname(sd_bus *bus, const char *name) {
         const char *hn;
         int r;
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.machine1",
-                        "/org/freedesktop/machine1",
-                        "org.freedesktop.machine1.Manager",
-                        "GetImageHostname",
-                        NULL, &reply, "s", name);
+        r = bus_call_method(bus, bus_machine_mgr, "GetImageHostname", NULL, &reply, "s", name);
         if (r < 0)
                 return r;
 
@@ -807,13 +759,7 @@ static int print_image_machine_id(sd_bus *bus, const char *name) {
         size_t size;
         int r;
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.machine1",
-                        "/org/freedesktop/machine1",
-                        "org.freedesktop.machine1.Manager",
-                        "GetImageMachineID",
-                        NULL, &reply, "s", name);
+        r = bus_call_method(bus, bus_machine_mgr, "GetImageMachineID", NULL, &reply, "s", name);
         if (r < 0)
                 return r;
 
@@ -834,13 +780,7 @@ static int print_image_machine_info(sd_bus *bus, const char *name) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         int r;
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.machine1",
-                        "/org/freedesktop/machine1",
-                        "org.freedesktop.machine1.Manager",
-                        "GetImageMachineInfo",
-                        NULL, &reply, "s", name);
+        r = bus_call_method(bus, bus_machine_mgr, "GetImageMachineInfo", NULL, &reply, "s", name);
         if (r < 0)
                 return r;
 
@@ -1093,15 +1033,7 @@ static int show_image(int argc, char *argv[], void *userdata) {
         for (int i = 1; i < argc; i++) {
                 const char *path = NULL;
 
-                r = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.machine1",
-                                "/org/freedesktop/machine1",
-                                "org.freedesktop.machine1.Manager",
-                                "GetImage",
-                                &error,
-                                &reply,
-                                "s", argv[i]);
+                r = bus_call_method(bus, bus_machine_mgr, "GetImage", &error, &reply, "s", argv[i]);
                 if (r < 0)
                         return log_error_errno(r, "Could not get path to image: %s", bus_error_message(&error, -r));
 
@@ -1131,11 +1063,9 @@ static int kill_machine(int argc, char *argv[], void *userdata) {
                 arg_kill_who = "all";
 
         for (int i = 1; i < argc; i++) {
-                r = sd_bus_call_method(
+                r = bus_call_method(
                                 bus,
-                                "org.freedesktop.machine1",
-                                "/org/freedesktop/machine1",
-                                "org.freedesktop.machine1.Manager",
+                                bus_machine_mgr,
                                 "KillMachine",
                                 &error,
                                 NULL,
@@ -1171,15 +1101,7 @@ static int terminate_machine(int argc, char *argv[], void *userdata) {
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
         for (int i = 1; i < argc; i++) {
-                r = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.machine1",
-                                "/org/freedesktop/machine1",
-                                "org.freedesktop.machine1.Manager",
-                                "TerminateMachine",
-                                &error,
-                                NULL,
-                                "s", argv[i]);
+                r = bus_call_method(bus, bus_machine_mgr, "TerminateMachine", &error, NULL, "s", argv[i]);
                 if (r < 0)
                         return log_error_errno(r, "Could not terminate machine: %s", bus_error_message(&error, -r));
         }
@@ -1213,12 +1135,10 @@ static int copy_files(int argc, char *argv[], void *userdata) {
                 host_path = abs_host_path;
         }
 
-        r = sd_bus_message_new_method_call(
+        r = bus_message_new_method_call(
                         bus,
                         &m,
-                        "org.freedesktop.machine1",
-                        "/org/freedesktop/machine1",
-                        "org.freedesktop.machine1.Manager",
+                        bus_machine_mgr,
                         copy_from ? "CopyFromMachine" : "CopyToMachine");
         if (r < 0)
                 return bus_log_create_error(r);
@@ -1249,11 +1169,9 @@ static int bind_mount(int argc, char *argv[], void *userdata) {
 
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
-        r = sd_bus_call_method(
+        r = bus_call_method(
                         bus,
-                        "org.freedesktop.machine1",
-                        "/org/freedesktop/machine1",
-                        "org.freedesktop.machine1.Manager",
+                        bus_machine_mgr,
                         "BindMountMachine",
                         &error,
                         NULL,
@@ -1425,15 +1343,7 @@ static int login_machine(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return log_error_errno(r, "Failed to request machine removal match: %m");
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.machine1",
-                        "/org/freedesktop/machine1",
-                        "org.freedesktop.machine1.Manager",
-                        "OpenMachineLogin",
-                        &error,
-                        &reply,
-                        "s", machine);
+        r = bus_call_method(bus, bus_machine_mgr, "OpenMachineLogin", &error, &reply, "s", machine);
         if (r < 0)
                 return log_error_errno(r, "Failed to get login PTY: %s", bus_error_message(&error, -r));
 
@@ -1498,13 +1408,7 @@ static int shell_machine(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return log_error_errno(r, "Failed to request machine removal match: %m");
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &m,
-                        "org.freedesktop.machine1",
-                        "/org/freedesktop/machine1",
-                        "org.freedesktop.machine1.Manager",
-                        "OpenMachineShell");
+        r = bus_message_new_method_call(bus, &m, bus_machine_mgr, "OpenMachineShell");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -1545,13 +1449,7 @@ static int remove_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 *m = NULL;
 
-                r = sd_bus_message_new_method_call(
-                                bus,
-                                &m,
-                                "org.freedesktop.machine1",
-                                "/org/freedesktop/machine1",
-                                "org.freedesktop.machine1.Manager",
-                                "RemoveImage");
+                r = bus_message_new_method_call(bus, &m, bus_machine_mgr, "RemoveImage");
                 if (r < 0)
                         return bus_log_create_error(r);
 
@@ -1577,11 +1475,9 @@ static int rename_image(int argc, char *argv[], void *userdata) {
 
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
-        r = sd_bus_call_method(
+        r = bus_call_method(
                         bus,
-                        "org.freedesktop.machine1",
-                        "/org/freedesktop/machine1",
-                        "org.freedesktop.machine1.Manager",
+                        bus_machine_mgr,
                         "RenameImage",
                         &error,
                         NULL,
@@ -1602,13 +1498,7 @@ static int clone_image(int argc, char *argv[], void *userdata) {
 
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &m,
-                        "org.freedesktop.machine1",
-                        "/org/freedesktop/machine1",
-                        "org.freedesktop.machine1.Manager",
-                        "CloneImage");
+        r = bus_message_new_method_call(bus, &m, bus_machine_mgr, "CloneImage");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -1641,15 +1531,7 @@ static int read_only_image(int argc, char *argv[], void *userdata) {
 
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.machine1",
-                        "/org/freedesktop/machine1",
-                        "org.freedesktop.machine1.Manager",
-                        "MarkImageReadOnly",
-                        &error,
-                        NULL,
-                        "sb", argv[1], b);
+        r = bus_call_method(bus, bus_machine_mgr, "MarkImageReadOnly", &error, NULL, "sb", argv[1], b);
         if (r < 0)
                 return log_error_errno(r, "Could not mark image read-only: %s", bus_error_message(&error, -r));
 
@@ -1663,15 +1545,7 @@ static int image_exists(sd_bus *bus, const char *name) {
         assert(bus);
         assert(name);
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.machine1",
-                        "/org/freedesktop/machine1",
-                        "org.freedesktop.machine1.Manager",
-                        "GetImage",
-                        &error,
-                        NULL,
-                        "s", name);
+        r = bus_call_method(bus, bus_machine_mgr, "GetImage", &error, NULL, "s", name);
         if (r < 0) {
                 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_IMAGE))
                         return 0;
@@ -1933,12 +1807,10 @@ static int transfer_image_common(sd_bus *bus, sd_bus_message *m) {
         if (r < 0)
                 return log_error_errno(r, "Failed to attach bus to event loop: %m");
 
-        r = sd_bus_match_signal_async(
+        r = bus_match_signal_async(
                         bus,
                         &slot_job_removed,
-                        "org.freedesktop.import1",
-                        "/org/freedesktop/import1",
-                        "org.freedesktop.import1.Manager",
+                        bus_import_mgr,
                         "TransferRemoved",
                         match_transfer_removed, NULL, &path);
         if (r < 0)
@@ -2022,13 +1894,7 @@ static int import_tar(int argc, char *argv[], void *userdata) {
                         return log_error_errno(errno, "Failed to open %s: %m", path);
         }
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &m,
-                        "org.freedesktop.import1",
-                        "/org/freedesktop/import1",
-                        "org.freedesktop.import1.Manager",
-                        "ImportTar");
+        r = bus_message_new_method_call(bus, &m, bus_import_mgr, "ImportTar");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -2089,13 +1955,7 @@ static int import_raw(int argc, char *argv[], void *userdata) {
                         return log_error_errno(errno, "Failed to open %s: %m", path);
         }
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &m,
-                        "org.freedesktop.import1",
-                        "/org/freedesktop/import1",
-                        "org.freedesktop.import1.Manager",
-                        "ImportRaw");
+        r = bus_message_new_method_call(bus, &m, bus_import_mgr, "ImportRaw");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -2150,13 +2010,7 @@ static int import_fs(int argc, char *argv[], void *userdata) {
                         return log_error_errno(errno, "Failed to open directory '%s': %m", path);
         }
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &m,
-                        "org.freedesktop.import1",
-                        "/org/freedesktop/import1",
-                        "org.freedesktop.import1.Manager",
-                        "ImportFileSystem");
+        r = bus_message_new_method_call(bus, &m, bus_import_mgr, "ImportFileSystem");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -2215,13 +2069,7 @@ static int export_tar(int argc, char *argv[], void *userdata) {
                         return log_error_errno(errno, "Failed to open %s: %m", path);
         }
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &m,
-                        "org.freedesktop.import1",
-                        "/org/freedesktop/import1",
-                        "org.freedesktop.import1.Manager",
-                        "ExportTar");
+        r = bus_message_new_method_call(bus, &m, bus_import_mgr, "ExportTar");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -2264,13 +2112,7 @@ static int export_raw(int argc, char *argv[], void *userdata) {
                         return log_error_errno(errno, "Failed to open %s: %m", path);
         }
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &m,
-                        "org.freedesktop.import1",
-                        "/org/freedesktop/import1",
-                        "org.freedesktop.import1.Manager",
-                        "ExportRaw");
+        r = bus_message_new_method_call(bus, &m, bus_import_mgr, "ExportRaw");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -2326,13 +2168,7 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
                 }
         }
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &m,
-                        "org.freedesktop.import1",
-                        "/org/freedesktop/import1",
-                        "org.freedesktop.import1.Manager",
-                        "PullTar");
+        r = bus_message_new_method_call(bus, &m, bus_import_mgr, "PullTar");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -2389,13 +2225,7 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
                 }
         }
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &m,
-                        "org.freedesktop.import1",
-                        "/org/freedesktop/import1",
-                        "org.freedesktop.import1.Manager",
-                        "PullRaw");
+        r = bus_message_new_method_call(bus, &m, bus_import_mgr, "PullRaw");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -2438,14 +2268,7 @@ static int list_transfers(int argc, char *argv[], void *userdata) {
 
         (void) pager_open(arg_pager_flags);
 
-        r = sd_bus_call_method(bus,
-                               "org.freedesktop.import1",
-                               "/org/freedesktop/import1",
-                               "org.freedesktop.import1.Manager",
-                               "ListTransfers",
-                               &error,
-                               &reply,
-                               NULL);
+        r = bus_call_method(bus, bus_import_mgr, "ListTransfers", &error, &reply, NULL);
         if (r < 0)
                 return log_error_errno(r, "Could not get transfers: %s", bus_error_message(&error, -r));
 
@@ -2542,15 +2365,7 @@ static int cancel_transfer(int argc, char *argv[], void *userdata) {
                 if (r < 0)
                         return log_error_errno(r, "Failed to parse transfer id: %s", argv[i]);
 
-                r = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.import1",
-                                "/org/freedesktop/import1",
-                                "org.freedesktop.import1.Manager",
-                                "CancelTransfer",
-                                &error,
-                                NULL,
-                                "u", id);
+                r = bus_call_method(bus, bus_import_mgr, "CancelTransfer", &error, NULL, "u", id);
                 if (r < 0)
                         return log_error_errno(r, "Could not cancel transfer: %s", bus_error_message(&error, -r));
         }
@@ -2577,26 +2392,10 @@ static int set_limit(int argc, char *argv[], void *userdata) {
         if (argc > 2)
                 /* With two arguments changes the quota limit of the
                  * specified image */
-                r = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.machine1",
-                                "/org/freedesktop/machine1",
-                                "org.freedesktop.machine1.Manager",
-                                "SetImageLimit",
-                                &error,
-                                NULL,
-                                "st", argv[1], limit);
+                r = bus_call_method(bus, bus_machine_mgr, "SetImageLimit", &error, NULL, "st", argv[1], limit);
         else
                 /* With one argument changes the pool quota limit */
-                r = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.machine1",
-                                "/org/freedesktop/machine1",
-                                "org.freedesktop.machine1.Manager",
-                                "SetPoolLimit",
-                                &error,
-                                NULL,
-                                "t", limit);
+                r = bus_call_method(bus, bus_machine_mgr, "SetPoolLimit", &error, NULL, "t", limit);
 
         if (r < 0)
                 return log_error_errno(r, "Could not set limit: %s", bus_error_message(&error, r));
@@ -2616,13 +2415,7 @@ static int clean_images(int argc, char *argv[], void *userdata) {
 
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &m,
-                        "org.freedesktop.machine1",
-                        "/org/freedesktop/machine1",
-                        "org.freedesktop.machine1.Manager",
-                        "CleanPool");
+        r = bus_message_new_method_call(bus, &m, bus_machine_mgr, "CleanPool");
         if (r < 0)
                 return bus_log_create_error(r);
 
index 76d5119089d86ed527210f5850c6d985cc6011ae..cbc549cb768cbb79bfcbff259ae3db487e5891df 100644 (file)
@@ -112,7 +112,7 @@ static int method_get_machine(sd_bus_message *message, void *userdata, sd_bus_er
 
 static int method_get_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_free_ char *p = NULL;
-        Manager *m = userdata;
+        _unused_ Manager *m = userdata;
         const char *name;
         int r;
 
@@ -471,7 +471,7 @@ static int method_get_machine_os_release(sd_bus_message *message, void *userdata
 static int method_list_images(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         _cleanup_hashmap_free_ Hashmap *images = NULL;
-        Manager *m = userdata;
+        _unused_ Manager *m = userdata;
         Image *image;
         Iterator i;
         int r;
@@ -1440,6 +1440,14 @@ const sd_bus_vtable manager_vtable[] = {
         SD_BUS_VTABLE_END
 };
 
+const BusObjectImplementation manager_object = {
+        "/org/freedesktop/machine1",
+        "org.freedesktop.machine1.Manager",
+        .vtables = BUS_VTABLES(manager_vtable),
+        .children = BUS_IMPLEMENTATIONS( &machine_object,
+                                         &image_object ),
+};
+
 int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         const char *path, *result, *unit;
         Manager *m = userdata;
@@ -1569,16 +1577,7 @@ int manager_unref_unit(
         assert(m);
         assert(unit);
 
-        return sd_bus_call_method(
-                        m->bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "UnrefUnit",
-                        error,
-                        NULL,
-                        "s",
-                        unit);
+        return bus_call_method(m->bus, bus_systemd_mgr, "UnrefUnit", error, NULL, "s", unit);
 }
 
 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
@@ -1588,15 +1587,7 @@ int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, c
         assert(manager);
         assert(unit);
 
-        r = sd_bus_call_method(
-                        manager->bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "StopUnit",
-                        error,
-                        &reply,
-                        "ss", unit, "fail");
+        r = bus_call_method(manager->bus, bus_systemd_mgr, "StopUnit", error, &reply, "ss", unit, "fail");
         if (r < 0) {
                 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
                     sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
@@ -1633,15 +1624,7 @@ int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_erro
         assert(manager);
         assert(unit);
 
-        return sd_bus_call_method(
-                        manager->bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "KillUnit",
-                        error,
-                        NULL,
-                        "ssi", unit, "all", signo);
+        return bus_call_method(manager->bus, bus_systemd_mgr, "KillUnit", error, NULL, "ssi", unit, "all", signo);
 }
 
 int manager_unit_is_active(Manager *manager, const char *unit) {
index a93bfc42be2560698730cb1364bbf20b213313e1..015622761cbdea4824f9dc3f66c9c76052518d82 100644 (file)
@@ -12,6 +12,7 @@
 #include "bus-error.h"
 #include "bus-log-control-api.h"
 #include "bus-polkit.h"
+#include "bus-util.h"
 #include "cgroup-util.h"
 #include "dirent-util.h"
 #include "fd-util.h"
@@ -22,6 +23,7 @@
 #include "machined.h"
 #include "main-func.h"
 #include "process-util.h"
+#include "service-util.h"
 #include "signal-util.h"
 #include "special.h"
 
@@ -188,45 +190,15 @@ static int manager_connect_bus(Manager *m) {
         if (r < 0)
                 return log_error_errno(r, "Failed to connect to system bus: %m");
 
-        r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m);
+        r = bus_add_implementation(m->bus, &manager_object, m);
         if (r < 0)
-                return log_error_errno(r, "Failed to add manager object vtable: %m");
-
-        r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable, machine_object_find, m);
-        if (r < 0)
-                return log_error_errno(r, "Failed to add machine object vtable: %m");
-
-        r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/machine", machine_node_enumerator, m);
-        if (r < 0)
-                return log_error_errno(r, "Failed to add machine enumerator: %m");
-
-        r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/machine1/image", "org.freedesktop.machine1.Image", image_vtable, image_object_find, m);
-        if (r < 0)
-                return log_error_errno(r, "Failed to add image object vtable: %m");
-
-        r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/image", image_node_enumerator, m);
-        if (r < 0)
-                return log_error_errno(r, "Failed to add image enumerator: %m");
+                return r;
 
-        r = sd_bus_match_signal_async(
-                        m->bus,
-                        NULL,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "JobRemoved",
-                        match_job_removed, NULL, m);
+        r = bus_match_signal_async(m->bus, NULL, bus_systemd_mgr, "JobRemoved", match_job_removed, NULL, m);
         if (r < 0)
                 return log_error_errno(r, "Failed to add match for JobRemoved: %m");
 
-        r = sd_bus_match_signal_async(
-                        m->bus,
-                        NULL,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "UnitRemoved",
-                        match_unit_removed, NULL, m);
+        r = bus_match_signal_async(m->bus, NULL, bus_systemd_mgr, "UnitRemoved", match_unit_removed, NULL, m);
         if (r < 0)
                 return log_error_errno(r, "Failed to request match for UnitRemoved: %m");
 
@@ -241,26 +213,11 @@ static int manager_connect_bus(Manager *m) {
         if (r < 0)
                 return log_error_errno(r, "Failed to request match for PropertiesChanged: %m");
 
-        r = sd_bus_match_signal_async(
-                        m->bus,
-                        NULL,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "Reloading",
-                        match_reloading, NULL, m);
+        r = bus_match_signal_async(m->bus, NULL, bus_systemd_mgr, "Reloading", match_reloading, NULL, m);
         if (r < 0)
                 return log_error_errno(r, "Failed to request match for Reloading: %m");
 
-        r = sd_bus_call_method_async(
-                        m->bus,
-                        NULL,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "Subscribe",
-                        NULL, NULL,
-                        NULL);
+        r = bus_call_method_async(m->bus, NULL, bus_systemd_mgr, "Subscribe", NULL, NULL, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to enable subscription: %m");
 
@@ -357,12 +314,15 @@ static int run(int argc, char *argv[]) {
         log_set_facility(LOG_AUTH);
         log_setup_service();
 
-        umask(0022);
+        r = service_parse_argv("systemd-machined.service",
+                               "Manage registrations of local VMs and containers.",
+                               BUS_IMPLEMENTATIONS(&manager_object,
+                                                   &log_control_object),
+                               argc, argv);
+        if (r <= 0)
+                return r;
 
-        if (argc != 1) {
-                log_error("This program takes no arguments.");
-                return -EINVAL;
-        }
+        umask(0022);
 
         /* Always create the directories people can create inotify watches in. Note that some applications might check
          * for the existence of /run/systemd/machines/ to determine whether machined is available, so please always
index 205d90f83dfd646ec4306265924097fae499f653..0ec3fb9326f5b9f8b0558203ffa92a6295d549f4 100644 (file)
@@ -42,7 +42,7 @@ struct Manager {
 int manager_add_machine(Manager *m, const char *name, Machine **_machine);
 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine);
 
-extern const sd_bus_vtable manager_vtable[];
+extern const BusObjectImplementation manager_object;
 
 int match_reloading(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int match_unit_removed(sd_bus_message *message, void *userdata, sd_bus_error *error);
index 982e0a285e386e97b1a539413ba335e55001253f..469c14271c2201920a5371e6d3daba62558e6724 100644 (file)
@@ -551,13 +551,7 @@ static int start_transient_mount(
         if (r < 0)
                 return log_error_errno(r, "Failed to make mount unit name: %m");
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &m,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "StartTransientUnit");
+        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "StartTransientUnit");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -638,13 +632,7 @@ static int start_transient_automount(
         if (r < 0)
                 return log_error_errno(r, "Failed to make mount unit name: %m");
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &m,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "StartTransientUnit");
+        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "StartTransientUnit");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -854,13 +842,7 @@ static int stop_mount(
         if (r < 0)
                 return log_error_errno(r, "Failed to make %s unit name from path %s: %m", suffix + 1, where);
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &m,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "StopUnit");
+        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "StopUnit");
         if (r < 0)
                 return bus_log_create_error(r);
 
index 8df39e35843f625af265483a35811bdf014a8bae..23bd3e1e46476451e8110dd17f70a797ebebedde 100644 (file)
@@ -2,13 +2,13 @@
 
 #include "alloc-util.h"
 #include "bond.h"
+#include "bond-util.h"
 #include "conf-parser.h"
 #include "ether-addr-util.h"
 #include "extract-word.h"
 #include "netlink-util.h"
 #include "networkd-manager.h"
 #include "string-table.h"
-#include "string-util.h"
 
 /*
  * Number of seconds between instances where the bonding
 #define GRATUITOUS_ARP_MAX        255
 #define GRATUITOUS_ARP_DEFAULT    1
 
-static const char* const bond_mode_table[_NETDEV_BOND_MODE_MAX] = {
-        [NETDEV_BOND_MODE_BALANCE_RR] = "balance-rr",
-        [NETDEV_BOND_MODE_ACTIVE_BACKUP] = "active-backup",
-        [NETDEV_BOND_MODE_BALANCE_XOR] = "balance-xor",
-        [NETDEV_BOND_MODE_BROADCAST] = "broadcast",
-        [NETDEV_BOND_MODE_802_3AD] = "802.3ad",
-        [NETDEV_BOND_MODE_BALANCE_TLB] = "balance-tlb",
-        [NETDEV_BOND_MODE_BALANCE_ALB] = "balance-alb",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(bond_mode, BondMode);
 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_mode, bond_mode, BondMode, "Failed to parse bond mode");
-
-static const char* const bond_xmit_hash_policy_table[_NETDEV_BOND_XMIT_HASH_POLICY_MAX] = {
-        [NETDEV_BOND_XMIT_HASH_POLICY_LAYER2] = "layer2",
-        [NETDEV_BOND_XMIT_HASH_POLICY_LAYER34] = "layer3+4",
-        [NETDEV_BOND_XMIT_HASH_POLICY_LAYER23] = "layer2+3",
-        [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23] = "encap2+3",
-        [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34] = "encap3+4",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(bond_xmit_hash_policy, BondXmitHashPolicy);
 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_xmit_hash_policy,
                          bond_xmit_hash_policy,
                          BondXmitHashPolicy,
-                         "Failed to parse bond transmit hash policy")
-
-static const char* const bond_lacp_rate_table[_NETDEV_BOND_LACP_RATE_MAX] = {
-        [NETDEV_BOND_LACP_RATE_SLOW] = "slow",
-        [NETDEV_BOND_LACP_RATE_FAST] = "fast",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(bond_lacp_rate, BondLacpRate);
-DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_lacp_rate, bond_lacp_rate, BondLacpRate, "Failed to parse bond lacp rate")
-
-static const char* const bond_ad_select_table[_NETDEV_BOND_AD_SELECT_MAX] = {
-        [NETDEV_BOND_AD_SELECT_STABLE] = "stable",
-        [NETDEV_BOND_AD_SELECT_BANDWIDTH] = "bandwidth",
-        [NETDEV_BOND_AD_SELECT_COUNT] = "count",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(bond_ad_select, BondAdSelect);
+                         "Failed to parse bond transmit hash policy");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_lacp_rate, bond_lacp_rate, BondLacpRate, "Failed to parse bond lacp rate");
 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_ad_select, bond_ad_select, BondAdSelect, "Failed to parse bond AD select");
-
-static const char* const bond_fail_over_mac_table[_NETDEV_BOND_FAIL_OVER_MAC_MAX] = {
-        [NETDEV_BOND_FAIL_OVER_MAC_NONE] = "none",
-        [NETDEV_BOND_FAIL_OVER_MAC_ACTIVE] = "active",
-        [NETDEV_BOND_FAIL_OVER_MAC_FOLLOW] = "follow",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(bond_fail_over_mac, BondFailOverMac);
 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_fail_over_mac, bond_fail_over_mac, BondFailOverMac, "Failed to parse bond fail over MAC");
-
-static const char *const bond_arp_validate_table[_NETDEV_BOND_ARP_VALIDATE_MAX] = {
-        [NETDEV_BOND_ARP_VALIDATE_NONE] = "none",
-        [NETDEV_BOND_ARP_VALIDATE_ACTIVE]= "active",
-        [NETDEV_BOND_ARP_VALIDATE_BACKUP]= "backup",
-        [NETDEV_BOND_ARP_VALIDATE_ALL]= "all",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(bond_arp_validate, BondArpValidate);
 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_validate, bond_arp_validate, BondArpValidate, "Failed to parse bond arp validate");
-
-static const char *const bond_arp_all_targets_table[_NETDEV_BOND_ARP_ALL_TARGETS_MAX] = {
-        [NETDEV_BOND_ARP_ALL_TARGETS_ANY] = "any",
-        [NETDEV_BOND_ARP_ALL_TARGETS_ALL] = "all",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(bond_arp_all_targets, BondArpAllTargets);
 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_all_targets, bond_arp_all_targets, BondArpAllTargets, "Failed to parse bond Arp all targets");
-
-static const char *const bond_primary_reselect_table[_NETDEV_BOND_PRIMARY_RESELECT_MAX] = {
-        [NETDEV_BOND_PRIMARY_RESELECT_ALWAYS] = "always",
-        [NETDEV_BOND_PRIMARY_RESELECT_BETTER]= "better",
-        [NETDEV_BOND_PRIMARY_RESELECT_FAILURE]= "failure",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(bond_primary_reselect, BondPrimaryReselect);
 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_primary_reselect, bond_primary_reselect, BondPrimaryReselect, "Failed to parse bond primary reselect");
 
 static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
index 28796a3a8be1d40ff75893c64c4a2b9442830b49..64b2dd04a2bc56e27e381e29022a08c0564ef673 100644 (file)
@@ -4,85 +4,11 @@
 #include <netinet/in.h>
 #include <linux/if_bonding.h>
 
-#include "in-addr-util.h"
+#include "bond-util.h"
+#include "macro.h"
 #include "netdev.h"
 #include "ordered-set.h"
 
-/*
- * Maximum number of targets supported by the kernel for a single
- * bond netdev.
- */
-#define NETDEV_BOND_ARP_TARGETS_MAX 16
-
-typedef enum BondMode {
-        NETDEV_BOND_MODE_BALANCE_RR    = BOND_MODE_ROUNDROBIN,
-        NETDEV_BOND_MODE_ACTIVE_BACKUP = BOND_MODE_ACTIVEBACKUP,
-        NETDEV_BOND_MODE_BALANCE_XOR   = BOND_MODE_XOR,
-        NETDEV_BOND_MODE_BROADCAST     = BOND_MODE_BROADCAST,
-        NETDEV_BOND_MODE_802_3AD       = BOND_MODE_8023AD,
-        NETDEV_BOND_MODE_BALANCE_TLB   = BOND_MODE_TLB,
-        NETDEV_BOND_MODE_BALANCE_ALB   = BOND_MODE_ALB,
-        _NETDEV_BOND_MODE_MAX,
-        _NETDEV_BOND_MODE_INVALID      = -1
-} BondMode;
-
-typedef enum BondXmitHashPolicy {
-        NETDEV_BOND_XMIT_HASH_POLICY_LAYER2   = BOND_XMIT_POLICY_LAYER2,
-        NETDEV_BOND_XMIT_HASH_POLICY_LAYER34  = BOND_XMIT_POLICY_LAYER34,
-        NETDEV_BOND_XMIT_HASH_POLICY_LAYER23  = BOND_XMIT_POLICY_LAYER23,
-        NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23  = BOND_XMIT_POLICY_ENCAP23,
-        NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34  = BOND_XMIT_POLICY_ENCAP34,
-        _NETDEV_BOND_XMIT_HASH_POLICY_MAX,
-        _NETDEV_BOND_XMIT_HASH_POLICY_INVALID = -1
-} BondXmitHashPolicy;
-
-typedef enum BondLacpRate {
-        NETDEV_BOND_LACP_RATE_SLOW,
-        NETDEV_BOND_LACP_RATE_FAST,
-        _NETDEV_BOND_LACP_RATE_MAX,
-        _NETDEV_BOND_LACP_RATE_INVALID = -1,
-} BondLacpRate;
-
-typedef enum BondAdSelect {
-        NETDEV_BOND_AD_SELECT_STABLE,
-        NETDEV_BOND_AD_SELECT_BANDWIDTH,
-        NETDEV_BOND_AD_SELECT_COUNT,
-        _NETDEV_BOND_AD_SELECT_MAX,
-        _NETDEV_BOND_AD_SELECT_INVALID = -1,
-} BondAdSelect;
-
-typedef enum BondFailOverMac {
-        NETDEV_BOND_FAIL_OVER_MAC_NONE,
-        NETDEV_BOND_FAIL_OVER_MAC_ACTIVE,
-        NETDEV_BOND_FAIL_OVER_MAC_FOLLOW,
-        _NETDEV_BOND_FAIL_OVER_MAC_MAX,
-        _NETDEV_BOND_FAIL_OVER_MAC_INVALID = -1,
-} BondFailOverMac;
-
-typedef enum BondArpValidate {
-        NETDEV_BOND_ARP_VALIDATE_NONE,
-        NETDEV_BOND_ARP_VALIDATE_ACTIVE,
-        NETDEV_BOND_ARP_VALIDATE_BACKUP,
-        NETDEV_BOND_ARP_VALIDATE_ALL,
-        _NETDEV_BOND_ARP_VALIDATE_MAX,
-        _NETDEV_BOND_ARP_VALIDATE_INVALID = -1,
-} BondArpValidate;
-
-typedef enum BondArpAllTargets {
-        NETDEV_BOND_ARP_ALL_TARGETS_ANY,
-        NETDEV_BOND_ARP_ALL_TARGETS_ALL,
-        _NETDEV_BOND_ARP_ALL_TARGETS_MAX,
-        _NETDEV_BOND_ARP_ALL_TARGETS_INVALID = -1,
-} BondArpAllTargets;
-
-typedef enum BondPrimaryReselect {
-        NETDEV_BOND_PRIMARY_RESELECT_ALWAYS,
-        NETDEV_BOND_PRIMARY_RESELECT_BETTER,
-        NETDEV_BOND_PRIMARY_RESELECT_FAILURE,
-        _NETDEV_BOND_PRIMARY_RESELECT_MAX,
-        _NETDEV_BOND_PRIMARY_RESELECT_INVALID = -1,
-} BondPrimaryReselect;
-
 typedef struct Bond {
         NetDev meta;
 
@@ -122,30 +48,6 @@ extern const NetDevVTable bond_vtable;
 
 int link_set_bond(Link *link);
 
-const char *bond_mode_to_string(BondMode d) _const_;
-BondMode bond_mode_from_string(const char *d) _pure_;
-
-const char *bond_xmit_hash_policy_to_string(BondXmitHashPolicy d) _const_;
-BondXmitHashPolicy bond_xmit_hash_policy_from_string(const char *d) _pure_;
-
-const char *bond_lacp_rate_to_string(BondLacpRate d) _const_;
-BondLacpRate bond_lacp_rate_from_string(const char *d) _pure_;
-
-const char *bond_fail_over_mac_to_string(BondFailOverMac d) _const_;
-BondFailOverMac bond_fail_over_mac_from_string(const char *d) _pure_;
-
-const char *bond_ad_select_to_string(BondAdSelect d) _const_;
-BondAdSelect bond_ad_select_from_string(const char *d) _pure_;
-
-const char *bond_arp_validate_to_string(BondArpValidate d) _const_;
-BondArpValidate bond_arp_validate_from_string(const char *d) _pure_;
-
-const char *bond_arp_all_targets_to_string(BondArpAllTargets d) _const_;
-BondArpAllTargets bond_arp_all_targets_from_string(const char *d) _pure_;
-
-const char *bond_primary_reselect_to_string(BondPrimaryReselect d) _const_;
-BondPrimaryReselect bond_primary_reselect_from_string(const char *d) _pure_;
-
 CONFIG_PARSER_PROTOTYPE(config_parse_bond_mode);
 CONFIG_PARSER_PROTOTYPE(config_parse_bond_xmit_hash_policy);
 CONFIG_PARSER_PROTOTYPE(config_parse_bond_lacp_rate);
index 6b8f9944612ea39765f4a3ead0ceee9813d6099f..de492c5eeb2a66ed1e65b7e4f97f47b3492ed8af 100644 (file)
@@ -126,6 +126,12 @@ static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_mess
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_VLAN_FILTERING attribute: %m");
         }
 
+        if (b->vlan_protocol >= 0) {
+                r = sd_netlink_message_append_u16(req, IFLA_BR_VLAN_PROTOCOL, b->vlan_protocol);
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_VLAN_PROTOCOL attribute: %m");
+        }
+
         if (b->stp >= 0) {
                 r = sd_netlink_message_append_u32(req, IFLA_BR_STP_STATE, b->stp);
                 if (r < 0)
@@ -346,6 +352,7 @@ static void bridge_init(NetDev *n) {
         b->mcast_querier = -1;
         b->mcast_snooping = -1;
         b->vlan_filtering = -1;
+        b->vlan_protocol = -1;
         b->stp = -1;
         b->default_pvid = VLANID_INVALID;
         b->forward_delay = USEC_INFINITY;
index b0a728e5a40df76fab3c2e94c87e1fbd6ced4ac1..ed4f484c946457966dc010fc862e1543bfb18e84 100644 (file)
@@ -13,6 +13,7 @@ typedef struct Bridge {
         int mcast_querier;
         int mcast_snooping;
         int vlan_filtering;
+        int vlan_protocol;
         int stp;
         uint16_t priority;
         uint16_t group_fwd_mask;
index 1d87cfa865a13f853a35e491e4beea3ad87e7ea1..bd14f625deaa0a95842f75abd203c2a32dcd1d81 100644 (file)
@@ -4,25 +4,11 @@
 
 #include "conf-parser.h"
 #include "ipvlan.h"
+#include "ipvlan-util.h"
 #include "networkd-link.h"
-#include "string-table.h"
+#include "string-util.h"
 
-static const char* const ipvlan_mode_table[_NETDEV_IPVLAN_MODE_MAX] = {
-        [NETDEV_IPVLAN_MODE_L2] = "L2",
-        [NETDEV_IPVLAN_MODE_L3] = "L3",
-        [NETDEV_IPVLAN_MODE_L3S] = "L3S",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(ipvlan_mode, IPVlanMode);
 DEFINE_CONFIG_PARSE_ENUM(config_parse_ipvlan_mode, ipvlan_mode, IPVlanMode, "Failed to parse ipvlan mode");
-
-static const char* const ipvlan_flags_table[_NETDEV_IPVLAN_FLAGS_MAX] = {
-        [NETDEV_IPVLAN_FLAGS_BRIGDE] = "bridge",
-        [NETDEV_IPVLAN_FLAGS_PRIVATE] = "private",
-        [NETDEV_IPVLAN_FLAGS_VEPA] = "vepa",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(ipvlan_flags, IPVlanFlags);
 DEFINE_CONFIG_PARSE_ENUM(config_parse_ipvlan_flags, ipvlan_flags, IPVlanFlags, "Failed to parse ipvlan flags");
 
 static int netdev_ipvlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) {
index 171407b7c4bfb17c3cd526c3ec2aed7bde5e8e26..8e658184ffce2c7fc3e7a06fadac38de32032687 100644 (file)
@@ -4,24 +4,9 @@
 #include <netinet/in.h>
 #include <linux/if_link.h>
 
+#include "ipvlan-util.h"
 #include "netdev.h"
 
-typedef enum IPVlanMode {
-        NETDEV_IPVLAN_MODE_L2 = IPVLAN_MODE_L2,
-        NETDEV_IPVLAN_MODE_L3 = IPVLAN_MODE_L3,
-        NETDEV_IPVLAN_MODE_L3S = IPVLAN_MODE_L3S,
-        _NETDEV_IPVLAN_MODE_MAX,
-        _NETDEV_IPVLAN_MODE_INVALID = -1
-} IPVlanMode;
-
-typedef enum IPVlanFlags {
-        NETDEV_IPVLAN_FLAGS_BRIGDE,
-        NETDEV_IPVLAN_FLAGS_PRIVATE = IPVLAN_F_PRIVATE,
-        NETDEV_IPVLAN_FLAGS_VEPA = IPVLAN_F_VEPA,
-        _NETDEV_IPVLAN_FLAGS_MAX,
-        _NETDEV_IPVLAN_FLAGS_INVALID = -1
-} IPVlanFlags;
-
 typedef struct IPVlan {
         NetDev meta;
 
@@ -34,12 +19,6 @@ DEFINE_NETDEV_CAST(IPVTAP, IPVlan);
 extern const NetDevVTable ipvlan_vtable;
 extern const NetDevVTable ipvtap_vtable;
 
-const char *ipvlan_mode_to_string(IPVlanMode d) _const_;
-IPVlanMode ipvlan_mode_from_string(const char *d) _pure_;
-
-const char *ipvlan_flags_to_string(IPVlanFlags d) _const_;
-IPVlanFlags ipvlan_flags_from_string(const char *d) _pure_;
-
 CONFIG_PARSER_PROTOTYPE(config_parse_ipvlan_mode);
 CONFIG_PARSER_PROTOTYPE(config_parse_ipvlan_flags);
 
index 7d1fec3afe6ddc8c7aaf5f49c7a1d1b6aa377236..3542f9652a38239a45c27d58a754f4231094c02b 100644 (file)
@@ -828,7 +828,7 @@ int config_parse_macsec_key_id(
 
         _cleanup_(macsec_transmit_association_free_or_set_invalidp) TransmitAssociation *a = NULL;
         _cleanup_(macsec_receive_association_free_or_set_invalidp) ReceiveAssociation *b = NULL;
-        _cleanup_free_ void *p;
+        _cleanup_free_ void *p = NULL;
         MACsec *s = userdata;
         uint8_t *dest;
         size_t l;
index dbe25e9e34fb103e9cee6e060004e5335171d5d3..e41ed9e6ed7a062d0303dc8878f9ad8477c82e39 100644 (file)
@@ -4,16 +4,8 @@
 
 #include "conf-parser.h"
 #include "macvlan.h"
-#include "string-table.h"
+#include "macvlan-util.h"
 
-static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = {
-        [NETDEV_MACVLAN_MODE_PRIVATE] = "private",
-        [NETDEV_MACVLAN_MODE_VEPA] = "vepa",
-        [NETDEV_MACVLAN_MODE_BRIDGE] = "bridge",
-        [NETDEV_MACVLAN_MODE_PASSTHRU] = "passthru",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(macvlan_mode, MacVlanMode);
 DEFINE_CONFIG_PARSE_ENUM(config_parse_macvlan_mode, macvlan_mode, MacVlanMode, "Failed to parse macvlan mode");
 
 static int netdev_macvlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) {
index 5d81be32da291e038bc556c7a7912eb09cc04d93..7e4d685bdbafaec5534329d8b806bcbf9a77436b 100644 (file)
@@ -3,17 +3,9 @@
 
 typedef struct MacVlan MacVlan;
 
+#include "macvlan-util.h"
 #include "netdev.h"
 
-typedef enum MacVlanMode {
-        NETDEV_MACVLAN_MODE_PRIVATE = MACVLAN_MODE_PRIVATE,
-        NETDEV_MACVLAN_MODE_VEPA = MACVLAN_MODE_VEPA,
-        NETDEV_MACVLAN_MODE_BRIDGE = MACVLAN_MODE_BRIDGE,
-        NETDEV_MACVLAN_MODE_PASSTHRU = MACVLAN_MODE_PASSTHRU,
-        _NETDEV_MACVLAN_MODE_MAX,
-        _NETDEV_MACVLAN_MODE_INVALID = -1
-} MacVlanMode;
-
 struct MacVlan {
         NetDev meta;
 
@@ -25,7 +17,4 @@ DEFINE_NETDEV_CAST(MACVTAP, MacVlan);
 extern const NetDevVTable macvlan_vtable;
 extern const NetDevVTable macvtap_vtable;
 
-const char *macvlan_mode_to_string(MacVlanMode d) _const_;
-MacVlanMode macvlan_mode_from_string(const char *d) _pure_;
-
 CONFIG_PARSER_PROTOTYPE(config_parse_macvlan_mode);
index 09a5f4822e03dc39b32e7fe8072ecaf89bc2cc04..b14835c313eb74f05a1a5a0b6a66f035a4c28084 100644 (file)
@@ -206,6 +206,7 @@ Bridge.DefaultPVID,                       config_parse_default_port_vlanid,
 Bridge.MulticastQuerier,                  config_parse_tristate,                     0,                             offsetof(Bridge, mcast_querier)
 Bridge.MulticastSnooping,                 config_parse_tristate,                     0,                             offsetof(Bridge, mcast_snooping)
 Bridge.VLANFiltering,                     config_parse_tristate,                     0,                             offsetof(Bridge, vlan_filtering)
+Bridge.VLANProtocol,                      config_parse_vlanprotocol,                 0,                             offsetof(Bridge, vlan_protocol)
 Bridge.STP,                               config_parse_tristate,                     0,                             offsetof(Bridge, stp)
 Bridge.MulticastIGMPVersion,              config_parse_uint8,                        0,                             offsetof(Bridge, igmp_version)
 VRF.TableId,                              config_parse_uint32,                       0,                             offsetof(Vrf, table) /* deprecated */
index bc85d4babb734a411beae9aa62c085ba2dd1e287..997dafa719f124dd5606a565b5a423877466befb 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <net/if.h>
 #include <netinet/in.h>
+#include <unistd.h>
 
 #include "alloc-util.h"
 #include "bond.h"
@@ -693,7 +694,7 @@ int netdev_load_one(Manager *manager, const char *filename) {
                 return r;
 
         /* skip out early if configuration does not match the environment */
-        if (!condition_test_list(netdev_raw->conditions, NULL, NULL, NULL)) {
+        if (!condition_test_list(netdev_raw->conditions, environ, NULL, NULL, NULL)) {
                 log_debug("%s: Conditions in the file do not match the system environment, skipping.", filename);
                 return 0;
         }
index cb04807f3a972f6a8dc13335b0461f96941c4f58..2761ba774c4c4035e32c64ca4b91b49d62769f3c 100644 (file)
@@ -18,6 +18,7 @@
 #include "sd-network.h"
 
 #include "alloc-util.h"
+#include "bond-util.h"
 #include "bus-common-errors.h"
 #include "bus-error.h"
 #include "bus-util.h"
 #include "geneve-util.h"
 #include "glob-util.h"
 #include "hwdb-util.h"
+#include "ipvlan-util.h"
 #include "local-addresses.h"
 #include "locale-util.h"
 #include "logs-show.h"
 #include "macro.h"
+#include "macvlan-util.h"
 #include "main-func.h"
 #include "netlink-util.h"
 #include "network-internal.h"
@@ -114,6 +117,14 @@ typedef struct VxLanInfo {
 
         uint16_t dest_port;
 
+        uint8_t proxy;
+        uint8_t learning;
+        uint8_t inerit;
+        uint8_t rsc;
+        uint8_t l2miss;
+        uint8_t l3miss;
+        uint8_t tos;
+        uint8_t ttl;
 } VxLanInfo;
 
 typedef struct LinkInfo {
@@ -179,6 +190,13 @@ typedef struct LinkInfo {
         uint32_t updelay;
         uint32_t downdelay;
 
+        /* macvlan and macvtap info */
+        uint32_t macvlan_mode;
+
+        /* ipvlan info */
+        uint16_t ipvlan_mode;
+        uint16_t ipvlan_flags;
+
         /* ethtool info */
         int autonegotiation;
         uint64_t speed;
@@ -278,6 +296,13 @@ static int decode_netdev(sd_netlink_message *m, LinkInfo *info) {
 
                 (void) sd_netlink_message_read_u32(m, IFLA_VXLAN_LINK, &info->vxlan_info.link);
                 (void) sd_netlink_message_read_u16(m, IFLA_VXLAN_PORT, &info->vxlan_info.dest_port);
+                (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_PROXY, &info->vxlan_info.proxy);
+                (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_LEARNING, &info->vxlan_info.learning);
+                (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_RSC, &info->vxlan_info.rsc);
+                (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_L3MISS, &info->vxlan_info.l3miss);
+                (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_L2MISS, &info->vxlan_info.l2miss);
+                (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_TOS, &info->vxlan_info.tos);
+                (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_TTL, &info->vxlan_info.ttl);
         } else if (streq(received_kind, "vlan"))
                 (void) sd_netlink_message_read_u16(m, IFLA_VLAN_ID, &info->vlan_id);
         else if (STR_IN_SET(received_kind, "ipip", "sit")) {
@@ -313,6 +338,11 @@ static int decode_netdev(sd_netlink_message *m, LinkInfo *info) {
         } else if (streq(received_kind, "vti6")) {
                 (void) sd_netlink_message_read_in6_addr(m, IFLA_VTI_LOCAL, &info->local.in6);
                 (void) sd_netlink_message_read_in6_addr(m, IFLA_VTI_REMOTE, &info->remote.in6);
+        } else if (STR_IN_SET(received_kind, "macvlan", "macvtap"))
+                (void) sd_netlink_message_read_u32(m, IFLA_MACVLAN_MODE, &info->macvlan_mode);
+        else if (streq(received_kind, "ipvlan")) {
+                (void) sd_netlink_message_read_u16(m, IFLA_IPVLAN_MODE, &info->ipvlan_mode);
+                (void) sd_netlink_message_read_u16(m, IFLA_IPVLAN_FLAGS, &info->ipvlan_flags);
         }
 
         strncpy(info->netdev_kind, received_kind, IFNAMSIZ);
@@ -1511,22 +1541,10 @@ static int link_status_one(
                                            TABLE_STRING, bridge_state_to_string(info->port_state));
                 }
         } else if (streq_ptr(info->netdev_kind, "bond")) {
-                static const struct {
-                        const char *mode;
-                } mode_table[] = {
-                        { "balance-rr" },
-                        { "active-backup" },
-                        { "balance-xor" },
-                        { "broadcast" },
-                        { "802.3ad" },
-                        { "balance-tlb" },
-                        { "balance-alb" },
-                };
-
                 r = table_add_many(table,
                                    TABLE_EMPTY,
                                    TABLE_STRING, "Mode:",
-                                   TABLE_STRING, mode_table[info->mode],
+                                   TABLE_STRING,  bond_mode_to_string(info->mode),
                                    TABLE_EMPTY,
                                    TABLE_STRING, "Miimon:",
                                    TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->miimon),
@@ -1540,6 +1558,8 @@ static int link_status_one(
                         return table_log_add_error(r);
 
         } else if (streq_ptr(info->netdev_kind, "vxlan")) {
+                char ttl[CONST_MAX(STRLEN("auto") + 1, DECIMAL_STR_MAX(uint8_t))];
+
                 if (info->vxlan_info.vni > 0) {
                         r = table_add_many(table,
                                            TABLE_EMPTY,
@@ -1594,6 +1614,55 @@ static int link_status_one(
                         if (r < 0)
                                  return table_log_add_error(r);
                 }
+
+                r = table_add_many(table,
+                                   TABLE_EMPTY,
+                                   TABLE_STRING, "Learning:",
+                                   TABLE_BOOLEAN, info->vxlan_info.learning);
+                if (r < 0)
+                        return table_log_add_error(r);
+
+                r = table_add_many(table,
+                                   TABLE_EMPTY,
+                                   TABLE_STRING, "RSC:",
+                                   TABLE_BOOLEAN, info->vxlan_info.rsc);
+                if (r < 0)
+                        return table_log_add_error(r);
+
+                r = table_add_many(table,
+                                   TABLE_EMPTY,
+                                   TABLE_STRING, "L3MISS:",
+                                   TABLE_BOOLEAN, info->vxlan_info.l3miss);
+                if (r < 0)
+                        return table_log_add_error(r);
+
+                r = table_add_many(table,
+                                   TABLE_EMPTY,
+                                   TABLE_STRING, "L2MISS:",
+                                   TABLE_BOOLEAN, info->vxlan_info.l2miss);
+                if (r < 0)
+                        return table_log_add_error(r);
+
+                if (info->vxlan_info.tos > 1) {
+                        r = table_add_many(table,
+                                           TABLE_EMPTY,
+                                           TABLE_STRING, "TOS:",
+                                           TABLE_UINT8, info->vxlan_info.tos);
+                        if (r < 0)
+                                return table_log_add_error(r);
+                }
+
+                if (info->vxlan_info.ttl > 0)
+                        xsprintf(ttl, "%" PRIu8, info->vxlan_info.ttl);
+                else
+                        strcpy(ttl, "auto");
+
+                r = table_add_many(table,
+                                   TABLE_EMPTY,
+                                   TABLE_STRING, "TTL:",
+                                   TABLE_STRING, ttl);
+                if (r < 0)
+                        return table_log_add_error(r);
         } else if (streq_ptr(info->netdev_kind, "vlan") && info->vlan_id > 0) {
                 r = table_add_many(table,
                                    TABLE_EMPTY,
@@ -1731,6 +1800,35 @@ static int link_status_one(
                         if (r < 0)
                                 return table_log_add_error(r);
                 }
+        } else if (STRPTR_IN_SET(info->netdev_kind, "macvlan", "macvtap")) {
+                r = table_add_many(table,
+                                   TABLE_EMPTY,
+                                   TABLE_STRING, "Mode:",
+                                   TABLE_STRING, macvlan_mode_to_string(info->macvlan_mode));
+                if (r < 0)
+                        return table_log_add_error(r);
+        } else if (streq_ptr(info->netdev_kind, "ipvlan")) {
+                _cleanup_free_ char *p = NULL, *s = NULL;
+
+                if (info->ipvlan_flags & IPVLAN_F_PRIVATE)
+                        p = strdup("private");
+                else if (info->ipvlan_flags & IPVLAN_F_VEPA)
+                        p = strdup("vepa");
+                else
+                        p = strdup("bridge");
+                if (!p)
+                        log_oom();
+
+                s = strjoin(ipvlan_mode_to_string(info->ipvlan_mode), " (", p, ")");
+                if (!s)
+                        return log_oom();
+
+                r = table_add_many(table,
+                                   TABLE_EMPTY,
+                                   TABLE_STRING, "Mode:",
+                                   TABLE_STRING, s);
+                if (r < 0)
+                        return table_log_add_error(r);
         }
 
         if (info->has_wlan_link_info) {
@@ -2302,15 +2400,7 @@ static int link_renew_one(sd_bus *bus, int index, const char *name) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         int r;
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.network1",
-                        "/org/freedesktop/network1",
-                        "org.freedesktop.network1.Manager",
-                        "RenewLink",
-                        &error,
-                        NULL,
-                        "i", index);
+        r = bus_call_method(bus, bus_network_mgr, "RenewLink", &error, NULL, "i", index);
         if (r < 0)
                 return log_error_errno(r, "Failed to renew dynamic configuration of interface %s: %s",
                                        name, bus_error_message(&error, r));
@@ -2344,15 +2434,7 @@ static int link_force_renew_one(sd_bus *bus, int index, const char *name) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         int r;
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.network1",
-                        "/org/freedesktop/network1",
-                        "org.freedesktop.network1.Manager",
-                        "ForceRenewLink",
-                        &error,
-                        NULL,
-                        "i", index);
+        r = bus_call_method(bus, bus_network_mgr, "ForceRenewLink", &error, NULL, "i", index);
         if (r < 0)
                 return log_error_errno(r, "Failed to force renew dynamic configuration of interface %s: %s",
                                        name, bus_error_message(&error, r));
@@ -2391,13 +2473,7 @@ static int verb_reload(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return log_error_errno(r, "Failed to connect system bus: %m");
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.network1",
-                        "/org/freedesktop/network1",
-                        "org.freedesktop.network1.Manager",
-                        "Reload",
-                        &error, NULL, NULL);
+        r = bus_call_method(bus, bus_network_mgr, "Reload", &error, NULL, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to reload network settings: %m");
 
@@ -2433,13 +2509,7 @@ static int verb_reconfigure(int argc, char *argv[], void *userdata) {
 
         SET_FOREACH(p, indexes, j) {
                 index = PTR_TO_INT(p);
-                r = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.network1",
-                                "/org/freedesktop/network1",
-                                "org.freedesktop.network1.Manager",
-                                "ReconfigureLink",
-                                &error, NULL, "i", index);
+                r = bus_call_method(bus, bus_network_mgr, "ReconfigureLink", &error, NULL, "i", index);
                 if (r < 0) {
                         char ifname[IF_NAMESIZE + 1];
 
index 0473aba6159eeba5e4a440507f19ef369e082d11..55191849d8c89e121762d33079fe0a9ec5227713 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include "dhcp-internal.h"
+#include "dhcp6-internal.h"
 #include "escape.h"
 #include "in-addr-util.h"
 #include "networkd-dhcp-common.h"
@@ -266,7 +267,69 @@ int config_parse_dhcp6_pd_hint(
         return 0;
 }
 
-int config_parse_dhcp6_mud_url(
+int config_parse_dhcp_user_class(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        char ***l = data;
+        int r;
+
+        assert(l);
+        assert(lvalue);
+        assert(rvalue);
+
+        if (isempty(rvalue)) {
+                *l = strv_free(*l);
+                return 0;
+        }
+
+        for (;;) {
+                _cleanup_free_ char *w = NULL;
+
+                r = extract_first_word(&rvalue, &w, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
+                if (r == -ENOMEM)
+                        return log_oom();
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to split user classes option, ignoring: %s", rvalue);
+                        break;
+                }
+                if (r == 0)
+                        break;
+
+                if (ltype == AF_INET) {
+                        if (strlen(w) > UINT8_MAX) {
+                                log_syntax(unit, LOG_ERR, filename, line, 0,
+                                           "%s length is not in the range 1-255, ignoring.", w);
+                                continue;
+                        }
+                } else {
+                        if (strlen(w) > UINT16_MAX) {
+                                log_syntax(unit, LOG_ERR, filename, line, 0,
+                                           "%s length is not in the range 1-65535, ignoring.", w);
+                                continue;
+                        }
+                }
+
+                r = strv_push(l, w);
+                if (r < 0)
+                        return log_oom();
+
+                w = NULL;
+        }
+
+        return 0;
+}
+
+int config_parse_dhcp_vendor_class(
                 const char *unit,
                 const char *filename,
                 unsigned line,
@@ -277,7 +340,59 @@ int config_parse_dhcp6_mud_url(
                 const char *rvalue,
                 void *data,
                 void *userdata) {
+        char ***l = data;
+        int r;
+
+        assert(l);
+        assert(lvalue);
+        assert(rvalue);
 
+        if (isempty(rvalue)) {
+                *l = strv_free(*l);
+                return 0;
+        }
+
+        for (;;) {
+                _cleanup_free_ char *w = NULL;
+
+                r = extract_first_word(&rvalue, &w, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
+                if (r == -ENOMEM)
+                        return log_oom();
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to split vendor classes option, ignoring: %s", rvalue);
+                        break;
+                }
+                if (r == 0)
+                        break;
+
+                if (strlen(w) > UINT8_MAX) {
+                        log_syntax(unit, LOG_ERR, filename, line, 0,
+                                   "%s length is not in the range 1-255, ignoring.", w);
+                        continue;
+                }
+
+                r = strv_push(l, w);
+                if (r < 0)
+                        return log_oom();
+
+                w = NULL;
+        }
+
+        return 0;
+}
+
+int config_parse_dhcp6_mud_url(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
         _cleanup_free_ char *unescaped = NULL;
         Network *network = data;
         int r;
@@ -298,7 +413,7 @@ int config_parse_dhcp6_mud_url(
                 return 0;
         }
 
-        if (!http_url_is_valid(unescaped) || strlen(unescaped) > 255) {
+        if (!http_url_is_valid(unescaped) || strlen(unescaped) > UINT8_MAX) {
                 log_syntax(unit, LOG_ERR, filename, line, 0,
                            "Failed to parse MUD URL '%s', ignoring: %m", rvalue);
 
@@ -320,13 +435,14 @@ int config_parse_dhcp_send_option(
                 void *data,
                 void *userdata) {
 
-        _cleanup_(sd_dhcp_option_unrefp) sd_dhcp_option *opt = NULL, *old = NULL;
+        _cleanup_(sd_dhcp_option_unrefp) sd_dhcp_option *opt4 = NULL, *old4 = NULL;
+        _cleanup_(sd_dhcp6_option_unrefp) sd_dhcp6_option *opt6 = NULL, *old6 = NULL;
         _cleanup_free_ char *word = NULL, *q = NULL;
         OrderedHashmap **options = data;
         union in_addr_union addr;
         DHCPOptionDataType type;
-        uint8_t u, uint8_data;
-        uint16_t uint16_data;
+        uint8_t u8, uint8_data;
+        uint16_t u16, uint16_data;
         uint32_t uint32_data;
         const void *udata;
         const char *p;
@@ -353,16 +469,30 @@ int config_parse_dhcp_send_option(
                 return 0;
         }
 
-        r = safe_atou8(word, &u);
-        if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r,
-                           "Invalid DHCP option, ignoring assignment: %s", rvalue);
-                return 0;
-        }
-        if (u < 1 || u >= 255) {
-                log_syntax(unit, LOG_ERR, filename, line, 0,
-                           "Invalid DHCP option, valid range is 1-254, ignoring assignment: %s", rvalue);
-                return 0;
+        if (ltype == AF_INET6) {
+                r = safe_atou16(word, &u16);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Invalid DHCP option, ignoring assignment: %s", rvalue);
+                         return 0;
+                }
+                if (u16 < 1 || u16 >= UINT16_MAX) {
+                        log_syntax(unit, LOG_ERR, filename, line, 0,
+                                   "Invalid DHCP option, valid range is 1-65535, ignoring assignment: %s", rvalue);
+                        return 0;
+                }
+        } else {
+                r = safe_atou8(word, &u8);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Invalid DHCP option, ignoring assignment: %s", rvalue);
+                         return 0;
+                }
+                if (u8 < 1 || u8 >= UINT8_MAX) {
+                        log_syntax(unit, LOG_ERR, filename, line, 0,
+                                   "Invalid DHCP option, valid range is 1-254, ignoring assignment: %s", rvalue);
+                        return 0;
+                }
         }
 
         word = mfree(word);
@@ -387,7 +517,7 @@ int config_parse_dhcp_send_option(
                 r = safe_atou8(p, &uint8_data);
                 if (r < 0) {
                         log_syntax(unit, LOG_ERR, filename, line, r,
-                                   "Failed to parse DHCPv4 uint8 data, ignoring assignment: %s", p);
+                                   "Failed to parse DHCP uint8 data, ignoring assignment: %s", p);
                         return 0;
                 }
 
@@ -399,7 +529,7 @@ int config_parse_dhcp_send_option(
                 r = safe_atou16(p, &uint16_data);
                 if (r < 0) {
                         log_syntax(unit, LOG_ERR, filename, line, r,
-                                   "Failed to parse DHCPv4 uint16 data, ignoring assignment: %s", p);
+                                   "Failed to parse DHCP uint16 data, ignoring assignment: %s", p);
                         return 0;
                 }
 
@@ -411,7 +541,7 @@ int config_parse_dhcp_send_option(
                 r = safe_atou32(p, &uint32_data);
                 if (r < 0) {
                         log_syntax(unit, LOG_ERR, filename, line, r,
-                                   "Failed to parse DHCPv4 uint32 data, ignoring assignment: %s", p);
+                                   "Failed to parse DHCP uint32 data, ignoring assignment: %s", p);
                         return 0;
                 }
 
@@ -424,7 +554,7 @@ int config_parse_dhcp_send_option(
                 r = in_addr_from_string(AF_INET, p, &addr);
                 if (r < 0) {
                         log_syntax(unit, LOG_ERR, filename, line, r,
-                                   "Failed to parse DHCPv4 ipv4address data, ignoring assignment: %s", p);
+                                   "Failed to parse DHCP ipv4address data, ignoring assignment: %s", p);
                         return 0;
                 }
 
@@ -432,11 +562,23 @@ int config_parse_dhcp_send_option(
                 sz = sizeof(addr.in.s_addr);
                 break;
         }
+        case DHCP_OPTION_DATA_IPV6ADDRESS: {
+                r = in_addr_from_string(AF_INET6, p, &addr);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to parse DHCP ipv6address data, ignoring assignment: %s", p);
+                        return 0;
+                }
+
+                udata = &addr.in6;
+                sz = sizeof(addr.in6.s6_addr);
+                break;
+        }
         case DHCP_OPTION_DATA_STRING:
                 sz = cunescape(p, UNESCAPE_ACCEPT_NUL, &q);
                 if (sz < 0) {
                         log_syntax(unit, LOG_ERR, filename, line, sz,
-                                   "Failed to decode DHCPv4 option data, ignoring assignment: %s", p);
+                                   "Failed to decode DHCP option data, ignoring assignment: %s", p);
                 }
 
                 udata = q;
@@ -445,27 +587,125 @@ int config_parse_dhcp_send_option(
                 return -EINVAL;
         }
 
-        r = sd_dhcp_option_new(u, udata, sz, &opt);
-        if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r,
-                           "Failed to store DHCPv4 option '%s', ignoring assignment: %m", rvalue);
-                return 0;
+        if (ltype == AF_INET6) {
+                r = sd_dhcp6_option_new(u16, udata, sz, &opt6);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue);
+                        return 0;
+                }
+
+                r = ordered_hashmap_ensure_allocated(options, &dhcp6_option_hash_ops);
+                if (r < 0)
+                        return log_oom();
+
+                /* Overwrite existing option */
+                old6 = ordered_hashmap_get(*options, UINT_TO_PTR(u16));
+                r = ordered_hashmap_replace(*options, UINT_TO_PTR(u16), opt6);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue);
+                        return 0;
+                }
+                TAKE_PTR(opt6);
+        } else {
+                r = sd_dhcp_option_new(u8, udata, sz, &opt4);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue);
+                        return 0;
+                }
+
+                r = ordered_hashmap_ensure_allocated(options, &dhcp_option_hash_ops);
+                if (r < 0)
+                        return log_oom();
+
+                /* Overwrite existing option */
+                old4 = ordered_hashmap_get(*options, UINT_TO_PTR(u8));
+                r = ordered_hashmap_replace(*options, UINT_TO_PTR(u8), opt4);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue);
+                        return 0;
+                }
+                TAKE_PTR(opt4);
         }
+        return 0;
+}
 
-        r = ordered_hashmap_ensure_allocated(options, &dhcp_option_hash_ops);
-        if (r < 0)
-                return log_oom();
+int config_parse_dhcp_request_options(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        Network *network = data;
+        const char *p;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if (isempty(rvalue)) {
+                if (ltype == AF_INET)
+                        network->dhcp_request_options = set_free(network->dhcp_request_options);
+                else
+                        network->dhcp6_request_options = set_free(network->dhcp6_request_options);
 
-        /* Overwrite existing option */
-        old = ordered_hashmap_remove(*options, UINT_TO_PTR(u));
-        r = ordered_hashmap_put(*options, UINT_TO_PTR(u), opt);
-        if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r,
-                           "Failed to store DHCPv4 option '%s', ignoring assignment: %m", rvalue);
                 return 0;
         }
 
-        TAKE_PTR(opt);
+        for (p = rvalue;;) {
+                _cleanup_free_ char *n = NULL;
+                uint32_t i;
+
+                r = extract_first_word(&p, &n, NULL, 0);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to parse DHCP request option, ignoring assignment: %s",
+                                   rvalue);
+                        return 0;
+                }
+                if (r == 0)
+                        return 0;
+
+                r = safe_atou32(n, &i);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "DHCP request option is invalid, ignoring assignment: %s", n);
+                        continue;
+                }
+
+                if (i < 1 || i >= UINT8_MAX) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "DHCP request option is invalid, valid range is 1-254, ignoring assignment: %s", n);
+                        continue;
+                }
+
+                if (ltype == AF_INET)
+                        r = set_ensure_allocated(&network->dhcp_request_options, NULL);
+                else
+                        r = set_ensure_allocated(&network->dhcp6_request_options, NULL);
+                if (r < 0)
+                        return log_oom();
+
+                if (ltype == AF_INET)
+                        r = set_put(network->dhcp_request_options, UINT32_TO_PTR(i));
+                else
+                        r = set_put(network->dhcp6_request_options, UINT32_TO_PTR(i));
+                if (r < 0)
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to store DHCP request option '%s', ignoring assignment: %m", n);
+        }
+
         return 0;
 }
 
@@ -486,6 +726,7 @@ static const char * const dhcp_option_data_type_table[_DHCP_OPTION_DATA_MAX] = {
         [DHCP_OPTION_DATA_UINT32]      = "uint32",
         [DHCP_OPTION_DATA_STRING]      = "string",
         [DHCP_OPTION_DATA_IPV4ADDRESS] = "ipv4address",
+        [DHCP_OPTION_DATA_IPV6ADDRESS] = "ipv6address",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(dhcp_option_data_type, DHCPOptionDataType);
index ca86016ef2a7209b649230e442bb2fc906dcd5d5..d837f89c25865e00719aaeb6520c12a0808d6501 100644 (file)
@@ -21,6 +21,7 @@ typedef enum DHCPOptionDataType {
         DHCP_OPTION_DATA_UINT32,
         DHCP_OPTION_DATA_STRING,
         DHCP_OPTION_DATA_IPV4ADDRESS,
+        DHCP_OPTION_DATA_IPV6ADDRESS,
         _DHCP_OPTION_DATA_MAX,
         _DHCP_OPTION_DATA_INVALID,
 } DHCPOptionDataType;
@@ -49,4 +50,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_iaid);
 CONFIG_PARSER_PROTOTYPE(config_parse_section_route_table);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_hint);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_mud_url);
+CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_user_class);
+CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_vendor_class);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_send_option);
+CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_request_options);
index c0df1fb2c4c381bef4cfcfce685150ee22ff5b5d..2e9cef590fffb7e81c058bdb7f0b140360603397 100644 (file)
@@ -2,14 +2,17 @@
 
 #include "sd-dhcp-server.h"
 
+#include "fd-util.h"
+#include "fileio.h"
 #include "networkd-dhcp-server.h"
 #include "networkd-link.h"
 #include "networkd-manager.h"
 #include "networkd-network.h"
 #include "parse-util.h"
-#include "strv.h"
+#include "socket-netlink.h"
 #include "string-table.h"
 #include "string-util.h"
+#include "strv.h"
 
 static Address* link_find_dhcp_server_address(Link *link) {
         Address *address;
@@ -174,6 +177,87 @@ static int link_push_uplink_to_dhcp_server(
         return sd_dhcp_server_set_servers(s, what, addresses, n_addresses);
 }
 
+static int dhcp4_server_parse_dns_server_string_and_warn(Link *l, const char *string, struct in_addr **addresses, size_t *n_allocated, size_t *n_addresses) {
+        for (;;) {
+                _cleanup_free_ char *word = NULL, *server_name = NULL;
+                union in_addr_union address;
+                int family, r, ifindex = 0;
+
+                r = extract_first_word(&string, &word, NULL, 0);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        break;
+
+                r = in_addr_ifindex_name_from_string_auto(word, &family, &address, &ifindex, &server_name);
+                if (r < 0) {
+                        log_warning_errno(r, "Failed to parse DNS server address '%s', ignoring: %m", word);
+                        continue;
+                }
+
+                /* Only look for IPv4 addresses */
+                if (family != AF_INET)
+                        continue;
+
+                /* Never propagate obviously borked data */
+                if (in4_addr_is_null(&address.in) || in4_addr_is_localhost(&address.in))
+                        continue;
+
+                if (!GREEDY_REALLOC(*addresses, *n_allocated, *n_addresses + 1))
+                        return log_oom();
+
+                (*addresses)[(*n_addresses)++] = address.in;
+        }
+
+        return 0;
+}
+
+static int dhcp4_server_set_dns_from_resolve_conf(Link *link) {
+        _cleanup_free_ struct in_addr *addresses = NULL;
+        size_t n_addresses = 0, n_allocated = 0;
+        _cleanup_fclose_ FILE *f = NULL;
+        int n = 0, r;
+
+        f = fopen(PRIVATE_UPLINK_RESOLV_CONF, "re");
+        if (!f) {
+                if (errno == ENOENT)
+                        return 0;
+
+                return log_warning_errno(errno, "Failed to open " PRIVATE_UPLINK_RESOLV_CONF ": %m");
+        }
+
+        for (;;) {
+                _cleanup_free_ char *line = NULL;
+                const char *a;
+                char *l;
+
+                r = read_line(f, LONG_LINE_MAX, &line);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to read " PRIVATE_UPLINK_RESOLV_CONF ": %m");
+                if (r == 0)
+                        break;
+
+                n++;
+
+                l = strstrip(line);
+                if (IN_SET(*l, '#', ';', 0))
+                        continue;
+
+                a = first_word(l, "nameserver");
+                if (!a)
+                        continue;
+
+                r = dhcp4_server_parse_dns_server_string_and_warn(link, a, &addresses, &n_allocated, &n_addresses);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to parse DNS server address '%s', ignoring.", a);
+        }
+
+        if (n_addresses <= 0)
+                return 0;
+
+        return sd_dhcp_server_set_dns(link->dhcp_server, addresses, n_addresses);
+}
+
 int dhcp4_server_configure(Link *link) {
         bool acquired_uplink = false;
         sd_dhcp_option *p;
@@ -267,8 +351,10 @@ int dhcp4_server_configure(Link *link) {
                                                        "Not emitting %s on link, couldn't find suitable uplink.",
                                                        dhcp_lease_info_to_string(n));
                                         r = 0;
-                                } else
+                                } else if (uplink->network)
                                         r = link_push_uplink_to_dhcp_server(uplink, n, link->dhcp_server);
+                                else if (n == SD_DHCP_LEASE_DNS_SERVERS)
+                                        r = dhcp4_server_set_dns_from_resolve_conf(link);
                         }
                         if (r < 0)
                                 log_link_warning_errno(link, r,
index ada14ecd18c8f46ac63e6425fb60261872011937..42e6b5aef2a9aad329cd19ca416f90ffd1ebf5d1 100644 (file)
@@ -1488,6 +1488,12 @@ int dhcp4_configure(Link *link) {
                         return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set ip service type: %m");
         }
 
+        if (link->network->dhcp_fallback_lease_lifetime > 0) {
+                r = sd_dhcp_client_set_fallback_lease_lifetime(link->dhcp_client, link->network->dhcp_fallback_lease_lifetime);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed set to lease lifetime: %m");
+        }
+
         if (link->network->dhcp_send_decline) {
                 r = configure_dhcpv4_duplicate_address_detection(link);
                 if (r < 0)
@@ -1605,7 +1611,7 @@ int config_parse_dhcp_black_listed_ip_address(
         return 0;
 }
 
-int config_parse_dhcp_user_class(
+int config_parse_dhcp_ip_service_type(
                 const char *unit,
                 const char *filename,
                 unsigned line,
@@ -1617,49 +1623,22 @@ int config_parse_dhcp_user_class(
                 void *data,
                 void *userdata) {
 
-        char ***l = data;
-        int r;
-
-        assert(l);
+        assert(filename);
         assert(lvalue);
         assert(rvalue);
 
-        if (isempty(rvalue)) {
-                *l = strv_free(*l);
-                return 0;
-        }
-
-        for (;;) {
-                _cleanup_free_ char *w = NULL;
-
-                r = extract_first_word(&rvalue, &w, NULL, 0);
-                if (r == -ENOMEM)
-                        return log_oom();
-                if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r,
-                                   "Failed to split user classes option, ignoring: %s", rvalue);
-                        break;
-                }
-                if (r == 0)
-                        break;
-
-                if (strlen(w) > 255) {
-                        log_syntax(unit, LOG_ERR, filename, line, 0,
-                                   "%s length is not in the range 1-255, ignoring.", w);
-                        continue;
-                }
-
-                r = strv_push(l, w);
-                if (r < 0)
-                        return log_oom();
-
-                w = NULL;
-        }
+        if (streq(rvalue, "CS4"))
+                *((int *)data) = IPTOS_CLASS_CS4;
+        else if (streq(rvalue, "CS6"))
+                *((int *)data) = IPTOS_CLASS_CS6;
+        else
+                log_syntax(unit, LOG_WARNING, filename, line, 0,
+                           "Failed to parse IPServiceType type '%s', ignoring.", rvalue);
 
         return 0;
 }
 
-int config_parse_dhcp_request_options(
+int config_parse_dhcp_mud_url(
                 const char *unit,
                 const char *filename,
                 unsigned line,
@@ -1671,89 +1650,37 @@ int config_parse_dhcp_request_options(
                 void *data,
                 void *userdata) {
 
+        _cleanup_free_ char *unescaped = NULL;
         Network *network = data;
-        const char *p;
         int r;
 
         assert(filename);
         assert(lvalue);
         assert(rvalue);
-        assert(data);
 
         if (isempty(rvalue)) {
-                network->dhcp_request_options = set_free(network->dhcp_request_options);
+                network->dhcp_mudurl = mfree(network->dhcp_mudurl);
                 return 0;
         }
 
-        for (p = rvalue;;) {
-                _cleanup_free_ char *n = NULL;
-                uint32_t i;
-
-                r = extract_first_word(&p, &n, NULL, 0);
-                if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r,
-                                   "Failed to parse DHCP request option, ignoring assignment: %s",
-                                   rvalue);
-                        return 0;
-                }
-                if (r == 0)
-                        return 0;
-
-                r = safe_atou32(n, &i);
-                if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r,
-                                   "DHCP request option is invalid, ignoring assignment: %s", n);
-                        continue;
-                }
-
-                if (i < 1 || i >= 255) {
-                        log_syntax(unit, LOG_ERR, filename, line, r,
-                                   "DHCP request option is invalid, valid range is 1-254, ignoring assignment: %s", n);
-                        continue;
-                }
-
-                r = set_ensure_allocated(&network->dhcp_request_options, NULL);
-                if (r < 0)
-                        return log_oom();
-
-                r = set_put(network->dhcp_request_options, UINT32_TO_PTR(i));
-                if (r < 0)
-                        log_syntax(unit, LOG_ERR, filename, line, r,
-                                   "Failed to store DHCP request option '%s', ignoring assignment: %m", n);
+        r = cunescape(rvalue, 0, &unescaped);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Failed to Failed to unescape MUD URL, ignoring: %s", rvalue);
+                return 0;
         }
 
-        return 0;
-}
-
-int config_parse_dhcp_ip_service_type(
-                const char *unit,
-                const char *filename,
-                unsigned line,
-                const char *section,
-                unsigned section_line,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
+        if (!http_url_is_valid(unescaped) || strlen(unescaped) > 255) {
+                log_syntax(unit, LOG_ERR, filename, line, 0,
+                           "Failed to parse MUD URL '%s', ignoring: %m", rvalue);
 
-        if (streq(rvalue, "CS4"))
-                *((int *)data) = IPTOS_CLASS_CS4;
-        else if (streq(rvalue, "CS6"))
-                *((int *)data) = IPTOS_CLASS_CS6;
-        else
-                log_syntax(unit, LOG_WARNING, filename, line, 0,
-                           "Failed to parse IPServiceType type '%s', ignoring.", rvalue);
+                return 0;
+        }
 
-        return 0;
+        return free_and_strdup_warn(&network->dhcp_mudurl, unescaped);
 }
 
-int config_parse_dhcp_mud_url(
-                const char *unit,
+int config_parse_dhcp_fallback_lease_lifetime(const char *unit,
                 const char *filename,
                 unsigned line,
                 const char *section,
@@ -1763,35 +1690,32 @@ int config_parse_dhcp_mud_url(
                 const char *rvalue,
                 void *data,
                 void *userdata) {
-
-        _cleanup_free_ char *unescaped = NULL;
-        Network *network = data;
-        int r;
+        Network *network = userdata;
+        unsigned k;
 
         assert(filename);
+        assert(section);
         assert(lvalue);
         assert(rvalue);
+        assert(data);
 
         if (isempty(rvalue)) {
-                network->dhcp_mudurl = mfree(network->dhcp_mudurl);
-                return 0;
-        }
-
-        r = cunescape(rvalue, 0, &unescaped);
-        if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r,
-                           "Failed to Failed to unescape MUD URL, ignoring: %s", rvalue);
+                network->dhcp_fallback_lease_lifetime = 0;
                 return 0;
         }
 
-        if (!http_url_is_valid(unescaped) || strlen(unescaped) > 255) {
+        /* We accept only "forever" or "infinity". */
+        if (STR_IN_SET(rvalue, "forever", "infinity"))
+                k = CACHE_INFO_INFINITY_LIFE_TIME;
+        else {
                 log_syntax(unit, LOG_ERR, filename, line, 0,
-                           "Failed to parse MUD URL '%s', ignoring: %m", rvalue);
-
+                           "Invalid LeaseLifetime= value, ignoring: %s", rvalue);
                 return 0;
         }
 
-        return free_and_strdup_warn(&network->dhcp_mudurl, unescaped);
+        network->dhcp_fallback_lease_lifetime = k;
+
+        return 0;
 }
 
 static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
index b0c30b598ce9ce8cc1962856c289462dbcf3b1e1..a6e24be78d73744dbccaa84b71ac5e10d1450b99 100644 (file)
@@ -25,7 +25,6 @@ int dhcp4_set_promote_secondaries(Link *link);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_client_identifier);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_black_listed_ip_address);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_max_attempts);
-CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_user_class);
-CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_request_options);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_ip_service_type);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_mud_url);
+CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_fallback_lease_lifetime);
index 3580498e3512cb0b8b53728b8420d9a0ac0943bf..29226b64bf8404593282cb2e5517b8ddc8368611 100644 (file)
@@ -620,7 +620,10 @@ static int dhcp6_set_hostname(sd_dhcp6_client *client, Link *link) {
 
 int dhcp6_configure(Link *link) {
         _cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
+        sd_dhcp6_option *send_option;
+        void *request_options;
         const DUID *duid;
+        Iterator i;
         int r;
 
         assert(link);
@@ -662,6 +665,14 @@ int dhcp6_configure(Link *link) {
         if (r < 0)
                 return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set DUID: %m");
 
+        ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp6_client_send_options, i) {
+                r = sd_dhcp6_client_add_option(client, send_option);
+                if (r == -EEXIST)
+                        continue;
+                if (r < 0)
+                        return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set option: %m");
+        }
+
         r = dhcp6_set_hostname(client, link);
         if (r < 0)
                 return r;
@@ -682,6 +693,31 @@ int dhcp6_configure(Link *link) {
                         return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set MUD URL: %m");
         }
 
+        SET_FOREACH(request_options, link->network->dhcp6_request_options, i) {
+                uint32_t option = PTR_TO_UINT32(request_options);
+
+                r = sd_dhcp6_client_set_request_option(client, option);
+                if (r == -EEXIST) {
+                        log_link_debug(link, "DHCP6 CLIENT: Failed to set request flag for '%u' already exists, ignoring.", option);
+                        continue;
+                }
+
+                if (r < 0)
+                        return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set request flag for '%u': %m", option);
+        }
+
+        if (link->network->dhcp6_user_class) {
+                r = sd_dhcp6_client_set_request_user_class(client, link->network->dhcp6_user_class);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set user class: %m");
+        }
+
+        if (link->network->dhcp6_vendor_class) {
+                r = sd_dhcp6_client_set_request_vendor_class(client, link->network->dhcp6_vendor_class);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set vendor class: %m");
+        }
+
         r = sd_dhcp6_client_set_callback(client, dhcp6_handler, link);
         if (r < 0)
                 return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set callback: %m");
index 62f84faee3ac169541b8d29f885ed0eaff281aa3..54d6bb2330d7e752b02741aad014e7a2f928aad7 100644 (file)
@@ -498,7 +498,7 @@ int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, v
                 return -ENOMEM;
 
         STRV_FOREACH(i, ntas) {
-                r = set_put_strdup(ns, *i);
+                r = set_put_strdup(&ns, *i);
                 if (r < 0)
                         return r;
         }
index e261473f6f2f2150093cbc119d758abca3109732..32fe86045d6172cdaae813b1eaf7aff2ad3e09b2 100644 (file)
@@ -1825,6 +1825,53 @@ int link_down(Link *link, link_netlink_message_handler_t callback) {
         return 0;
 }
 
+static int link_group_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+        int r;
+
+        assert(link);
+
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+                return 1;
+
+        r = sd_netlink_message_get_errno(m);
+        if (r < 0)
+                log_link_message_warning_errno(link, m, r, "Could not set group for the interface");
+
+        return 1;
+}
+
+static int link_set_group(Link *link) {
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
+        int r;
+
+        assert(link);
+        assert(link->network);
+        assert(link->manager);
+        assert(link->manager->rtnl);
+
+        if (link->network->group <= 0)
+                return 0;
+
+        log_link_debug(link, "Setting group");
+
+        r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
+
+        r = sd_netlink_message_append_u32(req, IFLA_GROUP, link->network->group);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not set link group: %m");
+
+        r = netlink_call_async(link->manager->rtnl, NULL, req, link_group_handler,
+                               link_netlink_destroy_callback, link);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
+
+        link_ref(link);
+
+        return 0;
+}
+
 static int link_handle_bound_to_list(Link *link) {
         Link *l;
         Iterator i;
@@ -2819,6 +2866,10 @@ static int link_configure(Link *link) {
         if (r < 0)
                 return r;
 
+        r = link_set_group(link);
+        if (r < 0)
+                return r;
+
         if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4)) {
                 r = ipv4ll_configure(link);
                 if (r < 0)
index 0631cc96a0bfa0a71ec0c97b58c477f922725ac5..fe8877797719516e7cef4ee895f6ae94b7adb15f 100644 (file)
@@ -12,6 +12,7 @@
 #include "networkd-network.h"
 #include "string-table.h"
 #include "string-util.h"
+#include "strv.h"
 #include "tmpfile-util.h"
 
 DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting.");
@@ -36,10 +37,10 @@ bool link_lldp_rx_enabled(Link *link) {
         if (!link->network)
                 return false;
 
-        /* LLDP should be handled on bridge slaves as those have a direct
-         * connection to their peers not on the bridge master. Linux doesn't
-         * even (by default) forward lldp packets to the bridge master.*/
-        if (streq_ptr("bridge", link->kind))
+        /* LLDP should be handled on bridge and bond slaves as those have a direct connection to their peers,
+         * not on the bridge/bond master. Linux doesn't even (by default) forward lldp packets to the bridge
+         * master.*/
+        if (link->kind && STR_IN_SET(link->kind, "bridge", "bond"))
                 return false;
 
         return link->network->lldp_mode != LLDP_MODE_NO;
index 1fbf9d0dd9161657cce39dfabcaca3c0e1452e4d..f2d4e6f2bbb15a20ddcf5afe01a1bba5c9035df7 100644 (file)
@@ -6,8 +6,8 @@
 #include <net/if_arp.h>
 
 #include "alloc-util.h"
-#include "escape.h"
 #include "env-file.h"
+#include "escape.h"
 #include "fd-util.h"
 #include "hostname-util.h"
 #include "missing_network.h"
@@ -18,6 +18,7 @@
 #include "random-util.h"
 #include "socket-util.h"
 #include "string-util.h"
+#include "strv.h"
 #include "unaligned.h"
 #include "web-util.h"
 
@@ -54,6 +55,9 @@ bool link_lldp_emit_enabled(Link *link) {
         if (!link->network)
                 return false;
 
+        if (link->kind && STR_IN_SET(link->kind, "bridge", "bond"))
+                return false;
+
         return link->network->lldp_emit != LLDP_EMIT_NO;
 }
 
index 3e9fb8c2179d2a76bb1f49b0da50e12237118476..f9b611e41949b2b9d6faea11d231492a9ed26dd9 100644 (file)
@@ -2233,7 +2233,7 @@ void manager_dirty(Manager *manager) {
 }
 
 static int set_hostname_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
-        Manager *manager = userdata;
+        _unused_ Manager *manager = userdata;
         const sd_bus_error *e;
 
         assert(m);
@@ -2279,7 +2279,7 @@ int manager_set_hostname(Manager *m, const char *hostname) {
 }
 
 static int set_timezone_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
-        Manager *manager = userdata;
+        _unused_ Manager *manager = userdata;
         const sd_bus_error *e;
 
         assert(m);
index e376adbdeeec354acb63ea8d65a9390c22467f81..3749ff6b8d994cdcf6e60917e723594fcc142a52 100644 (file)
@@ -46,6 +46,7 @@ Match.KernelVersion,                         config_parse_net_condition,
 Match.Architecture,                          config_parse_net_condition,                               CONDITION_ARCHITECTURE,        offsetof(Network, conditions)
 Link.MACAddress,                             config_parse_hwaddr,                                      0,                             offsetof(Network, mac)
 Link.MTUBytes,                               config_parse_mtu,                                         AF_UNSPEC,                     offsetof(Network, mtu)
+Link.Group,                                  config_parse_uint32,                                      0,                             offsetof(Network, group)
 Link.ARP,                                    config_parse_tristate,                                    0,                             offsetof(Network, arp)
 Link.Multicast,                              config_parse_tristate,                                    0,                             offsetof(Network, multicast)
 Link.AllMulticast,                           config_parse_tristate,                                    0,                             offsetof(Network, allmulticast)
@@ -165,7 +166,7 @@ DHCPv4.UseHostname,                          config_parse_bool,
 DHCPv4.UseDomains,                           config_parse_dhcp_use_domains,                            0,                             offsetof(Network, dhcp_use_domains)
 DHCPv4.UseRoutes,                            config_parse_bool,                                        0,                             offsetof(Network, dhcp_use_routes)
 DHCPv4.UseGateway,                           config_parse_tristate,                                    0,                             offsetof(Network, dhcp_use_gateway)
-DHCPv4.RequestOptions,                       config_parse_dhcp_request_options,                        0,                             0
+DHCPv4.RequestOptions,                       config_parse_dhcp_request_options,                        AF_INET,                       0
 DHCPv4.Anonymize,                            config_parse_bool,                                        0,                             offsetof(Network, dhcp_anonymize)
 DHCPv4.SendHostname,                         config_parse_bool,                                        0,                             offsetof(Network, dhcp_send_hostname)
 DHCPv4.Hostname,                             config_parse_hostname,                                    0,                             offsetof(Network, dhcp_hostname)
@@ -173,7 +174,7 @@ DHCPv4.RequestBroadcast,                     config_parse_bool,
 DHCPv4.VendorClassIdentifier,                config_parse_string,                                      0,                             offsetof(Network, dhcp_vendor_class_identifier)
 DHCPv4.MUDURL,                               config_parse_dhcp_mud_url,                                0,                             0
 DHCPv4.MaxAttempts,                          config_parse_dhcp_max_attempts,                           0,                             0
-DHCPv4.UserClass,                            config_parse_dhcp_user_class,                             0,                             offsetof(Network, dhcp_user_class)
+DHCPv4.UserClass,                            config_parse_dhcp_user_class,                             AF_INET,                       offsetof(Network, dhcp_user_class)
 DHCPv4.DUIDType,                             config_parse_duid_type,                                   0,                             offsetof(Network, duid)
 DHCPv4.DUIDRawData,                          config_parse_duid_rawdata,                                0,                             offsetof(Network, duid)
 DHCPv4.RouteMetric,                          config_parse_unsigned,                                    0,                             offsetof(Network, dhcp_route_metric)
@@ -185,16 +186,21 @@ DHCPv4.SendRelease,                          config_parse_bool,
 DHCPv4.SendDecline,                          config_parse_bool,                                        0,                             offsetof(Network, dhcp_send_decline)
 DHCPv4.BlackList,                            config_parse_dhcp_black_listed_ip_address,                0,                             0
 DHCPv4.IPServiceType,                        config_parse_dhcp_ip_service_type,                        0,                             offsetof(Network, ip_service_type)
-DHCPv4.SendOption,                           config_parse_dhcp_send_option,                            0,                             offsetof(Network, dhcp_client_send_options)
+DHCPv4.SendOption,                           config_parse_dhcp_send_option,                            AF_INET,                       offsetof(Network, dhcp_client_send_options)
 DHCPv4.SendVendorOption,                     config_parse_dhcp_send_option,                            0,                             offsetof(Network, dhcp_client_send_vendor_options)
 DHCPv4.RouteMTUBytes,                        config_parse_mtu,                                         AF_INET,                       offsetof(Network, dhcp_route_mtu)
+DHCPv4.FallbackLeaseLifetimeSec,             config_parse_dhcp_fallback_lease_lifetime,                0,                             0
 DHCPv6.UseDNS,                               config_parse_bool,                                        0,                             offsetof(Network, dhcp6_use_dns)
 DHCPv6.UseNTP,                               config_parse_bool,                                        0,                             offsetof(Network, dhcp6_use_ntp)
 DHCPv6.RapidCommit,                          config_parse_bool,                                        0,                             offsetof(Network, rapid_commit)
 DHCPv6.MUDURL,                               config_parse_dhcp6_mud_url,                               0,                             0
+DHCPv6.RequestOptions,                       config_parse_dhcp_request_options,                        AF_INET6,                      0
+DHCPv6.UserClass,                            config_parse_dhcp_user_class,                             AF_INET6,                      offsetof(Network, dhcp6_user_class)
+DHCPv6.VendorClass,                          config_parse_dhcp_vendor_class,                           0,                             offsetof(Network, dhcp6_vendor_class)
 DHCPv6.ForceDHCPv6PDOtherInformation,        config_parse_bool,                                        0,                             offsetof(Network, dhcp6_force_pd_other_information)
 DHCPv6.PrefixDelegationHint,                 config_parse_dhcp6_pd_hint,                               0,                             0
 DHCPv6.WithoutRA,                            config_parse_bool,                                        0,                             offsetof(Network, dhcp6_without_ra)
+DHCPv6.SendOption,                           config_parse_dhcp_send_option,                            AF_INET6,                      offsetof(Network, dhcp6_client_send_options)
 IPv6AcceptRA.UseAutonomousPrefix,            config_parse_bool,                                        0,                             offsetof(Network, ipv6_accept_ra_use_autonomous_prefix)
 IPv6AcceptRA.UseOnLinkPrefix,                config_parse_bool,                                        0,                             offsetof(Network, ipv6_accept_ra_use_onlink_prefix)
 IPv6AcceptRA.UseDNS,                         config_parse_bool,                                        0,                             offsetof(Network, ipv6_accept_ra_use_dns)
@@ -381,7 +387,7 @@ DHCP.Hostname,                               config_parse_hostname,
 DHCP.RequestBroadcast,                       config_parse_bool,                                        0,                             offsetof(Network, dhcp_broadcast)
 DHCP.CriticalConnection,                     config_parse_tristate,                                    0,                             offsetof(Network, dhcp_critical)
 DHCP.VendorClassIdentifier,                  config_parse_string,                                      0,                             offsetof(Network, dhcp_vendor_class_identifier)
-DHCP.UserClass,                              config_parse_dhcp_user_class,                             0,                             offsetof(Network, dhcp_user_class)
+DHCP.UserClass,                              config_parse_dhcp_user_class,                             AF_INET,                       offsetof(Network, dhcp_user_class)
 DHCP.DUIDType,                               config_parse_duid_type,                                   0,                             offsetof(Network, duid)
 DHCP.DUIDRawData,                            config_parse_duid_rawdata,                                0,                             offsetof(Network, duid)
 DHCP.RouteMetric,                            config_parse_unsigned,                                    0,                             offsetof(Network, dhcp_route_metric)
index d9646a21cba844626c6861ae7818ab1d9029ef17..cd57df6d3dbe81e141c2c2279d4dc707deff9213 100644 (file)
@@ -3,6 +3,7 @@
 #include <net/if.h>
 #include <netinet/in.h>
 #include <linux/netdevice.h>
+#include <unistd.h>
 
 #include "alloc-util.h"
 #include "conf-files.h"
@@ -172,7 +173,7 @@ int network_verify(Network *network) {
                                          network->filename);
 
         /* skip out early if configuration does not match the environment */
-        if (!condition_test_list(network->conditions, NULL, NULL, NULL))
+        if (!condition_test_list(network->conditions, environ, NULL, NULL, NULL))
                 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
                                        "%s: Conditions in the file do not match the system environment, skipping.",
                                        network->filename);
@@ -649,8 +650,11 @@ static Network *network_free(Network *network) {
         free(network->dhcp_hostname);
         set_free(network->dhcp_black_listed_ip);
         set_free(network->dhcp_request_options);
+        set_free(network->dhcp6_request_options);
         free(network->mac);
         free(network->dhcp6_mudurl);
+        strv_free(network->dhcp6_user_class);
+        strv_free(network->dhcp6_vendor_class);
 
         if (network->dhcp_acd)
                 sd_ipv4acd_unref(network->dhcp_acd);
index cbdeda96fc418bce82e1e86287f09bbffdef6c7c..6811658fcc238857d29e956d0efe0835ee160629 100644 (file)
@@ -97,6 +97,7 @@ struct Network {
         uint64_t dhcp_max_attempts;
         unsigned dhcp_route_metric;
         uint32_t dhcp_route_table;
+        uint32_t dhcp_fallback_lease_lifetime;
         uint32_t dhcp_route_mtu;
         uint16_t dhcp_client_port;
         int dhcp_critical;
@@ -132,7 +133,11 @@ struct Network {
         bool dhcp6_without_ra;
         uint8_t dhcp6_pd_length;
         char *dhcp6_mudurl;
+        char **dhcp6_user_class;
+        char **dhcp6_vendor_class;
         struct in6_addr dhcp6_pd_address;
+        OrderedHashmap *dhcp6_client_send_options;
+        Set *dhcp6_request_options;
 
         /* DHCP Server Support */
         bool dhcp_server;
@@ -246,6 +251,7 @@ struct Network {
 
         struct ether_addr *mac;
         uint32_t mtu;
+        uint32_t group;
         int arp;
         int multicast;
         int allmulticast;
index 5471e74592338c5cdc63791fbd90ae71090a080e..d9ad647a15a8ce62fd0bb8971843a1ac68335d79 100644 (file)
@@ -107,7 +107,7 @@ int kernel_route_expiration_supported(void) {
                         .type = CONDITION_KERNEL_VERSION,
                         .parameter = (char *) ">= 4.5"
                 };
-                r = condition_test(&c);
+                r = condition_test(&c, NULL);
                 if (r < 0)
                         return r;
 
index e23bec76807a910bdf17f814d241ee13a7cb8529..16009662838d07013256d7ae46603d1e5b5a952b 100644 (file)
@@ -253,4 +253,5 @@ int main(void) {
         test_network_get(manager, loopback);
 
         assert_se(manager_rtnl_enumerate_links(manager) >= 0);
+        return 0;
 }
index a76f3376951f8eabfbf204f94e3fa5dcd4893358..69d473401da661b1f48185abdc63976f90c8edc7 100644 (file)
@@ -18,6 +18,7 @@
 #include "string-util.h"
 #include "strv.h"
 #include "terminal-util.h"
+#include "time-util.h"
 #include "user-util.h"
 #include "util.h"
 
@@ -27,6 +28,7 @@ static const char *arg_status = NULL;
 static bool arg_booted = false;
 static uid_t arg_uid = UID_INVALID;
 static gid_t arg_gid = GID_INVALID;
+static bool arg_no_block = false;
 
 static int help(void) {
         _cleanup_free_ char *link = NULL;
@@ -45,6 +47,7 @@ static int help(void) {
                "     --uid=USER        Set user to send from\n"
                "     --status=TEXT     Set status text\n"
                "     --booted          Check if the system was booted up with systemd\n"
+               "     --no-block        Do not wait until operation finished\n"
                "\nSee the %s for details.\n"
                , program_invocation_short_name
                , ansi_highlight(), ansi_normal()
@@ -54,6 +57,26 @@ static int help(void) {
         return 0;
 }
 
+static pid_t manager_pid(void) {
+        const char *e;
+        pid_t pid;
+        int r;
+
+        /* If we run as a service managed by systemd --user the $MANAGERPID environment variable points to
+         * the service manager's PID. */
+        e = getenv("MANAGERPID");
+        if (!e)
+                return 0;
+
+        r = parse_pid(e, &pid);
+        if (r < 0) {
+                log_warning_errno(r, "$MANAGERPID is set to an invalid PID, ignoring: %s", e);
+                return 0;
+        }
+
+        return pid;
+}
+
 static int parse_argv(int argc, char *argv[]) {
 
         enum {
@@ -63,6 +86,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_STATUS,
                 ARG_BOOTED,
                 ARG_UID,
+                ARG_NO_BLOCK
         };
 
         static const struct option options[] = {
@@ -73,6 +97,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "status",    required_argument, NULL, ARG_STATUS    },
                 { "booted",    no_argument,       NULL, ARG_BOOTED    },
                 { "uid",       required_argument, NULL, ARG_UID       },
+                { "no-block",  no_argument,       NULL, ARG_NO_BLOCK  },
                 {}
         };
 
@@ -96,13 +121,24 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_PID:
+                        if (isempty(optarg) || streq(optarg, "auto")) {
+                                arg_pid = getppid();
 
-                        if (optarg) {
-                                if (parse_pid(optarg, &arg_pid) < 0)
-                                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                                               "Failed to parse PID %s.", optarg);
-                        } else
+                                if (arg_pid <= 1 ||
+                                    arg_pid == manager_pid()) /* Don't send from PID 1 or the service
+                                                               * manager's PID (which might be distinct from
+                                                               * 1, if we are a --user instance), that'd just
+                                                               * be confusing for the service manager */
+                                        arg_pid = getpid();
+                        } else if (streq(optarg, "parent"))
                                 arg_pid = getppid();
+                        else if (streq(optarg, "self"))
+                                arg_pid = getpid();
+                        else {
+                                r = parse_pid(optarg, &arg_pid);
+                                if (r < 0)
+                                        return log_error_errno(r, "Failed to parse PID %s.", optarg);
+                        }
 
                         break;
 
@@ -126,6 +162,10 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
                 }
 
+                case ARG_NO_BLOCK:
+                        arg_no_block = true;
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -151,6 +191,7 @@ static int run(int argc, char* argv[]) {
         _cleanup_strv_free_ char **final_env = NULL;
         char* our_env[4];
         unsigned i = 0;
+        pid_t source_pid;
         int r;
 
         log_show_color(true);
@@ -207,12 +248,33 @@ static int run(int argc, char* argv[]) {
             setreuid(arg_uid, (uid_t) -1) < 0)
                 return log_error_errno(errno, "Failed to change UID: %m");
 
-        r = sd_pid_notify(arg_pid ? arg_pid : getppid(), false, n);
+        if (arg_pid > 0)
+                source_pid = arg_pid;
+        else {
+                /* Pretend the message originates from our parent, given that we are typically called from a
+                 * shell script, i.e. we are not the main process of a service but only a child of it. */
+                source_pid = getppid();
+                if (source_pid <= 1 ||
+                    source_pid == manager_pid()) /* safety check: don't claim we'd send anything from PID 1
+                                                  * or the service manager itself */
+                        source_pid = 0;
+        }
+        r = sd_pid_notify(source_pid, false, n);
         if (r < 0)
                 return log_error_errno(r, "Failed to notify init system: %m");
         if (r == 0)
                 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
                                        "No status data could be sent: $NOTIFY_SOCKET was not set");
+
+        if (!arg_no_block) {
+                r = sd_notify_barrier(0, 5 * USEC_PER_SEC);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to invoke barrier: %m");
+                if (r == 0)
+                        return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                               "No status data could be sent: $NOTIFY_SOCKET was not set");
+        }
+
         return 0;
 }
 
index f5048d9473cb2c11c53b4077af2718911090ae7e..a16ee5c60a23491ace496cd79b53310c7fbd118f 100644 (file)
@@ -199,16 +199,12 @@ int create_subcgroup(pid_t pid, bool keep_unit, CGroupUnified unified_requested)
  * namespace.
  */
 static int get_process_controllers(Set **ret) {
-        _cleanup_set_free_free_ Set *controllers = NULL;
+        _cleanup_set_free_ Set *controllers = NULL;
         _cleanup_fclose_ FILE *f = NULL;
         int r;
 
         assert(ret);
 
-        controllers = set_new(&string_hash_ops);
-        if (!controllers)
-                return -ENOMEM;
-
         f = fopen("/proc/self/cgroup", "re");
         if (!f)
                 return errno == ENOENT ? -ESRCH : -errno;
@@ -237,7 +233,7 @@ static int get_process_controllers(Set **ret) {
                 if (STR_IN_SET(l, "", "name=systemd", "name=unified"))
                         continue;
 
-                r = set_put_strdup(controllers, l);
+                r = set_put_strdup(&controllers, l);
                 if (r < 0)
                         return r;
         }
@@ -303,7 +299,7 @@ static int mount_legacy_cgns_supported(
                 uid_t uid_range,
                 const char *selinux_apifs_context) {
 
-        _cleanup_set_free_free_ Set *controllers = NULL;
+        _cleanup_set_free_ Set *controllers = NULL;
         const char *cgroup_root = "/sys/fs/cgroup", *c;
         int r;
 
@@ -323,7 +319,7 @@ static int mount_legacy_cgns_supported(
                  * uid/gid as seen from e.g. /proc/1/mountinfo. So we simply
                  * pass uid 0 and not uid_shift to tmpfs_patch_options().
                  */
-                r = tmpfs_patch_options("mode=755", 0, selinux_apifs_context, &options);
+                r = tmpfs_patch_options("mode=755" TMPFS_LIMITS_SYS_FS_CGROUP, 0, selinux_apifs_context, &options);
                 if (r < 0)
                         return log_oom();
 
@@ -425,7 +421,7 @@ static int mount_legacy_cgns_unsupported(
         if (r == 0) {
                 _cleanup_free_ char *options = NULL;
 
-                r = tmpfs_patch_options("mode=755", uid_shift == 0 ? UID_INVALID : uid_shift, selinux_apifs_context, &options);
+                r = tmpfs_patch_options("mode=755" TMPFS_LIMITS_SYS_FS_CGROUP, uid_shift == 0 ? UID_INVALID : uid_shift, selinux_apifs_context, &options);
                 if (r < 0)
                         return log_oom();
 
index a862355a64598d32737dd8e99b0713ccdfa70a1d..33cc19a4251510f9db59d81a012221fb7cc27b67 100644 (file)
@@ -569,7 +569,7 @@ int mount_all(const char *dest,
         static const MountPoint mount_table[] = {
                 /* First we list inner child mounts (i.e. mounts applied *after* entering user namespacing) */
                 { "proc",            "/proc",           "proc",  NULL,        MS_NOSUID|MS_NOEXEC|MS_NODEV,
-                  MOUNT_FATAL|MOUNT_IN_USERNS },
+                  MOUNT_FATAL|MOUNT_IN_USERNS|MOUNT_MKDIR },
 
                 { "/proc/sys",       "/proc/sys",       NULL,    NULL,        MS_BIND,
                   MOUNT_FATAL|MOUNT_IN_USERNS|MOUNT_APPLY_APIVFS_RO },                          /* Bind mount first ... */
@@ -599,28 +599,28 @@ int mount_all(const char *dest,
                 PROC_READ_ONLY("/proc/scsi"),
 
                 { "mqueue",          "/dev/mqueue",     "mqueue", NULL,       MS_NOSUID|MS_NOEXEC|MS_NODEV,
-                  MOUNT_IN_USERNS },
+                  MOUNT_IN_USERNS|MOUNT_MKDIR },
 
                 /* Then we list outer child mounts (i.e. mounts applied *before* entering user namespacing) */
-                { "tmpfs",           "/tmp",            "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
-                  MOUNT_FATAL|MOUNT_APPLY_TMPFS_TMP },
-                { "tmpfs",           "/sys",            "tmpfs", "mode=555",  MS_NOSUID|MS_NOEXEC|MS_NODEV,
-                  MOUNT_FATAL|MOUNT_APPLY_APIVFS_NETNS },
-                { "sysfs",           "/sys",            "sysfs", NULL,        MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV,
-                  MOUNT_FATAL|MOUNT_APPLY_APIVFS_RO },    /* skipped if above was mounted */
-                { "sysfs",           "/sys",            "sysfs", NULL,        MS_NOSUID|MS_NOEXEC|MS_NODEV,
-                  MOUNT_FATAL },                          /* skipped if above was mounted */
-                { "tmpfs",           "/dev",            "tmpfs", "mode=755",  MS_NOSUID|MS_STRICTATIME,
-                  MOUNT_FATAL },
-                { "tmpfs",           "/dev/shm",        "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
-                  MOUNT_FATAL },
-                { "tmpfs",           "/run",            "tmpfs", "mode=755",  MS_NOSUID|MS_NODEV|MS_STRICTATIME,
-                  MOUNT_FATAL },
+                { "tmpfs",           "/tmp",            "tmpfs", "mode=1777" TMPFS_LIMITS_TMP,     MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+                  MOUNT_FATAL|MOUNT_APPLY_TMPFS_TMP|MOUNT_MKDIR },
+                { "tmpfs",           "/sys",            "tmpfs", "mode=555" TMPFS_LIMITS_SYS,      MS_NOSUID|MS_NOEXEC|MS_NODEV,
+                  MOUNT_FATAL|MOUNT_APPLY_APIVFS_NETNS|MOUNT_MKDIR },
+                { "sysfs",           "/sys",            "sysfs", NULL,                             MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV,
+                  MOUNT_FATAL|MOUNT_APPLY_APIVFS_RO|MOUNT_MKDIR },    /* skipped if above was mounted */
+                { "sysfs",           "/sys",            "sysfs", NULL,                             MS_NOSUID|MS_NOEXEC|MS_NODEV,
+                  MOUNT_FATAL|MOUNT_MKDIR },                          /* skipped if above was mounted */
+                { "tmpfs",           "/dev",            "tmpfs", "mode=755" TMPFS_LIMITS_DEV,      MS_NOSUID|MS_STRICTATIME,
+                  MOUNT_FATAL|MOUNT_MKDIR },
+                { "tmpfs",           "/dev/shm",        "tmpfs", "mode=1777" TMPFS_LIMITS_DEV_SHM, MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+                  MOUNT_FATAL|MOUNT_MKDIR },
+                { "tmpfs",           "/run",            "tmpfs", "mode=755" TMPFS_LIMITS_RUN,      MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+                  MOUNT_FATAL|MOUNT_MKDIR },
 
 #if HAVE_SELINUX
-                { "/sys/fs/selinux", "/sys/fs/selinux", NULL,    NULL,        MS_BIND,
+                { "/sys/fs/selinux", "/sys/fs/selinux", NULL,    NULL,                             MS_BIND,
                   0 },  /* Bind mount first */
-                { NULL,              "/sys/fs/selinux", NULL,    NULL,        MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
+                { NULL,              "/sys/fs/selinux", NULL,    NULL,                             MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
                   0 },  /* Then, make it r/o */
 #endif
         };
@@ -663,17 +663,19 @@ int mount_all(const char *dest,
                                 continue;
                 }
 
-                r = mkdir_userns_p(dest, where, 0755, (use_userns && !in_userns) ? uid_shift : UID_INVALID);
-                if (r < 0 && r != -EEXIST) {
-                        if (fatal && r != -EROFS)
-                                return log_error_errno(r, "Failed to create directory %s: %m", where);
+                if (FLAGS_SET(mount_table[k].mount_settings, MOUNT_MKDIR)) {
+                        r = mkdir_userns_p(dest, where, 0755, (use_userns && !in_userns) ? uid_shift : UID_INVALID);
+                        if (r < 0 && r != -EEXIST) {
+                                if (fatal && r != -EROFS)
+                                        return log_error_errno(r, "Failed to create directory %s: %m", where);
 
-                        log_debug_errno(r, "Failed to create directory %s: %m", where);
-                        /* If we failed mkdir() or chown() due to the root
-                         * directory being read only, attempt to mount this fs
-                         * anyway and let mount_verbose log any errors */
-                        if (r != -EROFS)
-                                continue;
+                                log_debug_errno(r, "Failed to create directory %s: %m", where);
+
+                                /* If we failed mkdir() or chown() due to the root directory being read only,
+                                 * attempt to mount this fs anyway and let mount_verbose log any errors */
+                                if (r != -EROFS)
+                                        continue;
+                        }
                 }
 
                 o = mount_table[k].options;
@@ -1021,7 +1023,7 @@ static int setup_volatile_state(const char *directory, uid_t uid_shift, const ch
         if (r < 0 && errno != EEXIST)
                 return log_error_errno(errno, "Failed to create %s: %m", directory);
 
-        options = "mode=755";
+        options = "mode=755" TMPFS_LIMITS_VOLATILE_STATE;
         r = tmpfs_patch_options(options, uid_shift == 0 ? UID_INVALID : uid_shift, selinux_apifs_context, &buf);
         if (r < 0)
                 return log_oom();
@@ -1066,7 +1068,7 @@ static int setup_volatile_yes(const char *directory, uid_t uid_shift, const char
         if (!mkdtemp(template))
                 return log_error_errno(errno, "Failed to create temporary directory: %m");
 
-        options = "mode=755";
+        options = "mode=755" TMPFS_LIMITS_ROOTFS;
         r = tmpfs_patch_options(options, uid_shift == 0 ? UID_INVALID : uid_shift, selinux_apifs_context, &buf);
         if (r < 0)
                 goto fail;
@@ -1133,7 +1135,7 @@ static int setup_volatile_overlay(const char *directory, uid_t uid_shift, const
         if (!mkdtemp(template))
                 return log_error_errno(errno, "Failed to create temporary directory: %m");
 
-        options = "mode=755";
+        options = "mode=755" TMPFS_LIMITS_ROOTFS;
         r = tmpfs_patch_options(options, uid_shift == 0 ? UID_INVALID : uid_shift, selinux_apifs_context, &buf);
         if (r < 0)
                 goto finish;
index 680ff350e5d33a12ccc8480247d8665be79654c7..e8bb90383987297d50a2121001f0e6972dc8d080 100644 (file)
@@ -16,6 +16,7 @@ typedef enum MountSettingsMask {
         MOUNT_APPLY_TMPFS_TMP    = 1 << 5, /* if set, /tmp will be mounted as tmpfs */
         MOUNT_ROOT_ONLY          = 1 << 6, /* if set, only root mounts are mounted */
         MOUNT_NON_ROOT_ONLY      = 1 << 7, /* if set, only non-root mounts are mounted */
+        MOUNT_MKDIR              = 1 << 8, /* if set, make directory to mount over first */
 } MountSettingsMask;
 
 typedef enum CustomMountType {
index 9b7ca5e3dd5fc97e2932a1b2aabc9c3414acff59..64773a3d9cf803a48863de17c094d2219eca3bee 100644 (file)
@@ -122,11 +122,9 @@ int register_machine(
         assert(bus);
 
         if (keep_unit) {
-                r = sd_bus_call_method(
+                r = bus_call_method(
                                 bus,
-                                "org.freedesktop.machine1",
-                                "/org/freedesktop/machine1",
-                                "org.freedesktop.machine1.Manager",
+                                bus_machine_mgr,
                                 "RegisterMachineWithNetwork",
                                 &error,
                                 NULL,
@@ -141,13 +139,7 @@ int register_machine(
         } else {
                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
 
-                r = sd_bus_message_new_method_call(
-                                bus,
-                                &m,
-                                "org.freedesktop.machine1",
-                                "/org/freedesktop/machine1",
-                                "org.freedesktop.machine1.Manager",
-                                "CreateMachineWithNetwork");
+                r = bus_message_new_method_call(bus, &m,  bus_machine_mgr, "CreateMachineWithNetwork");
                 if (r < 0)
                         return bus_log_create_error(r);
 
@@ -218,16 +210,7 @@ int unregister_machine(
 
         assert(bus);
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.machine1",
-                        "/org/freedesktop/machine1",
-                        "org.freedesktop.machine1.Manager",
-                        "UnregisterMachine",
-                        &error,
-                        NULL,
-                        "s",
-                        machine_name);
+        r = bus_call_method(bus, bus_machine_mgr, "UnregisterMachine", &error, NULL, "s", machine_name);
         if (r < 0)
                 log_debug("Failed to unregister machine: %s", bus_error_message(&error, r));
 
@@ -262,13 +245,7 @@ int allocate_scope(
         if (r < 0)
                 return log_error_errno(r, "Failed to mangle scope name: %m");
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &m,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "StartTransientUnit");
+        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "StartTransientUnit");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -354,26 +331,15 @@ int terminate_scope(
         if (r < 0)
                 return log_error_errno(r, "Failed to mangle scope name: %m");
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "AbandonScope",
-                        &error,
-                        NULL,
-                        "s",
-                        scope);
+        r = bus_call_method(bus, bus_systemd_mgr, "AbandonScope", &error, NULL, "s", scope);
         if (r < 0) {
                 log_debug_errno(r, "Failed to abandon scope '%s', ignoring: %s", scope, bus_error_message(&error, r));
                 sd_bus_error_free(&error);
         }
 
-        r = sd_bus_call_method(
+        r = bus_call_method(
                         bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
+                        bus_systemd_mgr,
                         "KillUnit",
                         &error,
                         NULL,
@@ -386,16 +352,7 @@ int terminate_scope(
                 sd_bus_error_free(&error);
         }
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "UnrefUnit",
-                        &error,
-                        NULL,
-                        "s",
-                        scope);
+        r = bus_call_method(bus, bus_systemd_mgr, "UnrefUnit", &error, NULL, "s", scope);
         if (r < 0)
                 log_debug_errno(r, "Failed to drop reference to scope '%s', ignoring: %s", scope, bus_error_message(&error, r));
 
index 8aa7b9d805adae93cb94b156a9a42533085aa3c9..8e8881749aa54f56cf21936c8767a80556b65f9b 100644 (file)
@@ -3486,6 +3486,16 @@ static int outer_child(
         if (r < 0)
                 return r;
 
+        r = mount_custom(
+                        directory,
+                        arg_custom_mounts,
+                        arg_n_custom_mounts,
+                        arg_uid_shift,
+                        arg_selinux_apifs_context,
+                        MOUNT_NON_ROOT_ONLY);
+        if (r < 0)
+                return r;
+
         r = setup_timezone(directory);
         if (r < 0)
                 return r;
@@ -3502,16 +3512,6 @@ static int outer_child(
         if (r < 0)
                 return r;
 
-        r = mount_custom(
-                        directory,
-                        arg_custom_mounts,
-                        arg_n_custom_mounts,
-                        arg_uid_shift,
-                        arg_selinux_apifs_context,
-                        MOUNT_NON_ROOT_ONLY);
-        if (r < 0)
-                return r;
-
         if (!arg_use_cgns) {
                 r = mount_cgroups(
                                 directory,
@@ -3687,19 +3687,15 @@ static int nspawn_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t r
                 .iov_base = buf,
                 .iov_len = sizeof(buf)-1,
         };
-        union {
-                struct cmsghdr cmsghdr;
-                uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
-                            CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)];
-        } control = {};
+        CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred)) +
+                         CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)) control;
         struct msghdr msghdr = {
                 .msg_iov = &iovec,
                 .msg_iovlen = 1,
                 .msg_control = &control,
                 .msg_controllen = sizeof(control),
         };
-        struct cmsghdr *cmsg;
-        struct ucred *ucred = NULL;
+        struct ucred *ucred;
         ssize_t n;
         pid_t inner_child_pid;
         _cleanup_strv_free_ char **tags = NULL;
@@ -3713,24 +3709,15 @@ static int nspawn_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t r
                 return 0;
         }
 
-        n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
-        if (n < 0) {
-                if (IN_SET(errno, EAGAIN, EINTR))
-                        return 0;
+        n = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
+        if (IN_SET(n, -EAGAIN, -EINTR))
+                return 0;
+        if (n < 0)
+                return log_warning_errno(n, "Couldn't read notification socket: %m");
 
-                return log_warning_errno(errno, "Couldn't read notification socket: %m");
-        }
         cmsg_close_all(&msghdr);
 
-        CMSG_FOREACH(cmsg, &msghdr) {
-                if (cmsg->cmsg_level == SOL_SOCKET &&
-                           cmsg->cmsg_type == SCM_CREDENTIALS &&
-                           cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
-
-                        ucred = (struct ucred*) CMSG_DATA(cmsg);
-                }
-        }
-
+        ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred);
         if (!ucred || ucred->pid != inner_child_pid) {
                 log_debug("Received notify message without valid credentials. Ignoring.");
                 return 0;
index 8c16b7f360c294704a802224b8b3c9a063bae6cd..9aa6debc164e945be224444f8238248e0a79c1e7 100644 (file)
@@ -77,7 +77,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
                         return NSS_STATUS_TRYAGAIN;
                 }
 
-                /* We respond to our local host name, our hostname suffixed with a single dot. */
+                /* We respond to our local hostname, our hostname suffixed with a single dot. */
                 if (!streq(name, hn) && !streq_ptr(startswith(name, hn), "."))
                         goto not_found;
 
index 364356da56222df8cd1f150fb04b87c6aba39f5b..ce51fa89380e7d07e0210bb173a95b5792f0d23b 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "alloc-util.h"
 #include "bus-common-errors.h"
+#include "bus-util.h"
 #include "env-util.h"
 #include "errno-util.h"
 #include "format-util.h"
@@ -128,14 +129,7 @@ enum nss_status _nss_mymachines_gethostbyname4_r(
         if (r < 0)
                 goto fail;
 
-        r = sd_bus_call_method(bus,
-                               "org.freedesktop.machine1",
-                               "/org/freedesktop/machine1",
-                               "org.freedesktop.machine1.Manager",
-                               "GetMachineAddresses",
-                               NULL,
-                               &reply,
-                               "s", name);
+        r = bus_call_method(bus, bus_machine_mgr, "GetMachineAddresses", NULL, &reply, "s", name);
         if (r < 0)
                 goto fail;
 
@@ -287,14 +281,7 @@ enum nss_status _nss_mymachines_gethostbyname3_r(
         if (r < 0)
                 goto fail;
 
-        r = sd_bus_call_method(bus,
-                               "org.freedesktop.machine1",
-                               "/org/freedesktop/machine1",
-                               "org.freedesktop.machine1.Manager",
-                               "GetMachineAddresses",
-                               NULL,
-                               &reply,
-                               "s", name);
+        r = bus_call_method(bus, bus_machine_mgr, "GetMachineAddresses", NULL, &reply, "s", name);
         if (r < 0)
                 goto fail;
 
@@ -464,15 +451,7 @@ enum nss_status _nss_mymachines_getpwnam_r(
         if (r < 0)
                 goto fail;
 
-        r = sd_bus_call_method(bus,
-                               "org.freedesktop.machine1",
-                               "/org/freedesktop/machine1",
-                               "org.freedesktop.machine1.Manager",
-                               "MapFromMachineUser",
-                               &error,
-                               &reply,
-                               "su",
-                               machine, (uint32_t) uid);
+        r = bus_call_method(bus, bus_machine_mgr, "MapFromMachineUser", &error, &reply, "su", machine, (uint32_t) uid);
         if (r < 0) {
                 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_USER_MAPPING))
                         return NSS_STATUS_NOTFOUND;
@@ -548,15 +527,7 @@ enum nss_status _nss_mymachines_getpwuid_r(
         if (r < 0)
                 goto fail;
 
-        r = sd_bus_call_method(bus,
-                               "org.freedesktop.machine1",
-                               "/org/freedesktop/machine1",
-                               "org.freedesktop.machine1.Manager",
-                               "MapToMachineUser",
-                               &error,
-                               &reply,
-                               "u",
-                               (uint32_t) uid);
+        r = bus_call_method(bus, bus_machine_mgr, "MapToMachineUser", &error, &reply, "u", (uint32_t) uid);
         if (r < 0) {
                 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_USER_MAPPING))
                         return NSS_STATUS_NOTFOUND;
@@ -647,15 +618,7 @@ enum nss_status _nss_mymachines_getgrnam_r(
         if (r < 0)
                 goto fail;
 
-        r = sd_bus_call_method(bus,
-                               "org.freedesktop.machine1",
-                               "/org/freedesktop/machine1",
-                               "org.freedesktop.machine1.Manager",
-                               "MapFromMachineGroup",
-                               &error,
-                               &reply,
-                               "su",
-                               machine, (uint32_t) gid);
+        r = bus_call_method(bus, bus_machine_mgr, "MapFromMachineGroup", &error, &reply, "su", machine, (uint32_t) gid);
         if (r < 0) {
                 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_GROUP_MAPPING))
                         return NSS_STATUS_NOTFOUND;
@@ -728,15 +691,7 @@ enum nss_status _nss_mymachines_getgrgid_r(
         if (r < 0)
                 goto fail;
 
-        r = sd_bus_call_method(bus,
-                               "org.freedesktop.machine1",
-                               "/org/freedesktop/machine1",
-                               "org.freedesktop.machine1.Manager",
-                               "MapToMachineGroup",
-                               &error,
-                               &reply,
-                               "u",
-                               (uint32_t) gid);
+        r = bus_call_method(bus, bus_machine_mgr, "MapToMachineGroup", &error, &reply, "u", (uint32_t) gid);
         if (r < 0) {
                 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_GROUP_MAPPING))
                         return NSS_STATUS_NOTFOUND;
index de46a8d4697c2d6bfc08ff63d37549620fa94585..0ee3ddd843fdb5742deb9e4fe165ff3c058334ed 100644 (file)
@@ -10,6 +10,7 @@
 #include "sd-bus.h"
 
 #include "bus-common-errors.h"
+#include "bus-util.h"
 #include "errno-util.h"
 #include "in-addr-util.h"
 #include "macro.h"
@@ -142,13 +143,7 @@ enum nss_status _nss_resolve_gethostbyname4_r(
         if (r < 0)
                 goto fail;
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &req,
-                        "org.freedesktop.resolve1",
-                        "/org/freedesktop/resolve1",
-                        "org.freedesktop.resolve1.Manager",
-                        "ResolveHostname");
+        r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveHostname");
         if (r < 0)
                 goto fail;
 
@@ -322,13 +317,7 @@ enum nss_status _nss_resolve_gethostbyname3_r(
         if (r < 0)
                 goto fail;
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &req,
-                        "org.freedesktop.resolve1",
-                        "/org/freedesktop/resolve1",
-                        "org.freedesktop.resolve1.Manager",
-                        "ResolveHostname");
+        r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveHostname");
         if (r < 0)
                 goto fail;
 
@@ -514,13 +503,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
         if (r < 0)
                 goto fail;
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &req,
-                        "org.freedesktop.resolve1",
-                        "/org/freedesktop/resolve1",
-                        "org.freedesktop.resolve1.Manager",
-                        "ResolveAddress");
+        r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveAddress");
         if (r < 0)
                 goto fail;
 
index 4d63d8a2f09726e94276e2d6d44b0db6419db749..6a2d9c885ed7b211f329a59790402c6a920dd6fa 100644 (file)
@@ -310,7 +310,12 @@ enum nss_status _nss_systemd_setpwent(int stayopen) {
         getpwent_data.iterator = userdb_iterator_free(getpwent_data.iterator);
         getpwent_data.by_membership = false;
 
-        r = userdb_all(nss_glue_userdb_flags(), &getpwent_data.iterator);
+        /* Don't synthesize root/nobody when iterating. Let nss-files take care of that. If the two records
+         * are missing there, then that's fine, after all getpwent() is known to be possibly incomplete
+         * (think: LDAP/NIS type situations), and our synthesizing of root/nobody is a robustness fallback
+         * only, which matters for getpwnam()/getpwuid() primarily, which are the main NSS entrypoints to the
+         * user database. */
+        r = userdb_all(nss_glue_userdb_flags() | USERDB_DONT_SYNTHESIZE, &getpwent_data.iterator);
         return r < 0 ? NSS_STATUS_UNAVAIL : NSS_STATUS_SUCCESS;
 }
 
@@ -329,7 +334,8 @@ enum nss_status _nss_systemd_setgrent(int stayopen) {
         getgrent_data.iterator = userdb_iterator_free(getgrent_data.iterator);
         getpwent_data.by_membership = false;
 
-        r = groupdb_all(nss_glue_userdb_flags(), &getgrent_data.iterator);
+        /* See _nss_systemd_setpwent() for an explanation why we use USERDB_DONT_SYNTHESIZE here */
+        r = groupdb_all(nss_glue_userdb_flags() | USERDB_DONT_SYNTHESIZE, &getgrent_data.iterator);
         return r < 0 ? NSS_STATUS_UNAVAIL : NSS_STATUS_SUCCESS;
 }
 
index d73d67c4e8a4d80e457af13794630c84af0e3970..97f50c90335bcd426ef4158b4fa5ad533e0bd495 100644 (file)
@@ -7,7 +7,9 @@
 #include <unistd.h>
 
 #include "alloc-util.h"
+#include "blockdev-util.h"
 #include "dissect-image.h"
+#include "fd-util.h"
 #include "main-func.h"
 #include "process-util.h"
 #include "signal-util.h"
@@ -42,6 +44,7 @@ static int makefs(const char *type, const char *device) {
 
 static int run(int argc, char *argv[]) {
         _cleanup_free_ char *device = NULL, *type = NULL, *detected = NULL;
+        _cleanup_close_ int lock_fd = -1;
         struct stat st;
         int r;
 
@@ -54,28 +57,31 @@ static int run(int argc, char *argv[]) {
         /* type and device must be copied because makefs calls safe_fork, which clears argv[] */
         type = strdup(argv[1]);
         if (!type)
-                return -ENOMEM;
+                return log_oom();
 
         device = strdup(argv[2]);
         if (!device)
-                return -ENOMEM;
+                return log_oom();
 
         if (stat(device, &st) < 0)
                 return log_error_errno(errno, "Failed to stat \"%s\": %m", device);
 
-        if (!S_ISBLK(st.st_mode))
+        if (S_ISBLK(st.st_mode)) {
+                /* Lock the device so that udev doesn't interfere with our work */
+
+                lock_fd = lock_whole_block_device(st.st_rdev, LOCK_EX);
+                if (lock_fd < 0)
+                        return log_error_errno(lock_fd, "Failed to lock whole block device of \"%s\": %m", device);
+        } else
                 log_info("%s is not a block device.", device);
 
         r = probe_filesystem(device, &detected);
+        if (r == -EUCLEAN)
+                return log_error_errno(r, "Ambiguous results of probing for file system on \"%s\", refusing to proceed.", device);
         if (r < 0)
-                return log_warning_errno(r,
-                                         r == -EUCLEAN ?
-                                         "Cannot reliably determine probe \"%s\", refusing to proceed." :
-                                         "Failed to probe \"%s\": %m",
-                                         device);
-
+                return log_error_errno(r, "Failed to probe \"%s\": %m", device);
         if (detected) {
-                log_info("%s is not empty (type %s), exiting", device, detected);
+                log_info("'%s' is not empty (contains file system of type %s), exiting.", device, detected);
                 return 0;
         }
 
index 3bbc8da3f188c19911e4cc313d2c52e0537ec79b..46e82eaf90a360c6d46e21a39c60c2d63c225472 100644 (file)
@@ -58,6 +58,7 @@ static enum {
         EMPTY_ALLOW,    /* allow empty disks, create partition table if necessary */
         EMPTY_REQUIRE,  /* require an empty disk, create a partition table */
         EMPTY_FORCE,    /* make disk empty, erase everything, create a partition table always */
+        EMPTY_CREATE,   /* create disk as loopback file, create a partition table always */
 } arg_empty = EMPTY_REFUSE;
 
 static bool arg_dry_run = true;
@@ -70,6 +71,7 @@ static int arg_factory_reset = -1;
 static sd_id128_t arg_seed = SD_ID128_NULL;
 static bool arg_randomize = false;
 static int arg_pretty = -1;
+static uint64_t arg_size = UINT64_MAX;
 
 STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_definitions, freep);
@@ -714,7 +716,7 @@ static int context_grow_partitions_on_free_area(Context *context, FreeArea *a) {
                         assert(p->new_size != UINT64_MAX);
                         m = p->new_size + span;
 
-                        xsz = partition_max_size(a->after);
+                        xsz = partition_max_size(p);
                         if (xsz != UINT64_MAX && m > xsz)
                                 m = xsz;
 
@@ -1166,7 +1168,11 @@ static int disk_acquire_uuid(Context *context, sd_id128_t *ret) {
         return 0;
 }
 
-static int context_load_partition_table(Context *context, const char *node) {
+static int context_load_partition_table(
+                Context *context,
+                const char *node,
+                int *backing_fd) {
+
         _cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
         _cleanup_(fdisk_unref_tablep) struct fdisk_table *t = NULL;
         uint64_t left_boundary = UINT64_MAX, first_lba, last_lba, nsectors;
@@ -1178,14 +1184,31 @@ static int context_load_partition_table(Context *context, const char *node) {
 
         assert(context);
         assert(node);
+        assert(backing_fd);
 
         c = fdisk_new_context();
         if (!c)
                 return log_oom();
 
-        r = fdisk_assign_device(c, node, arg_dry_run);
+        /* libfdisk doesn't have an API to operate on arbitrary fds, hence reopen the fd going via the
+         * /proc/self/fd/ magic path if we have an existing fd. Open the original file otherwise. */
+        if (*backing_fd < 0)
+                r = fdisk_assign_device(c, node, arg_dry_run);
+        else {
+                char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
+                xsprintf(procfs_path, "/proc/self/fd/%i", *backing_fd);
+
+                r = fdisk_assign_device(c, procfs_path, arg_dry_run);
+        }
         if (r < 0)
-                return log_error_errno(r, "Failed to open device: %m");
+                return log_error_errno(r, "Failed to open device '%s': %m", node);
+
+        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 = fcntl(fdisk_get_devfd(c), F_DUPFD_CLOEXEC, 3);
+                if (*backing_fd < 0)
+                        return log_error_errno(errno, "Failed to duplicate fdisk fd: %m");
+        }
 
         /* Tell udev not to interfere while we are processing the device */
         if (flock(fdisk_get_devfd(c), arg_dry_run ? LOCK_SH : LOCK_EX) < 0)
@@ -1225,6 +1248,7 @@ static int context_load_partition_table(Context *context, const char *node) {
                 break;
 
         case EMPTY_FORCE:
+        case EMPTY_CREATE:
                 /* Always reinitiaize the disk, don't consider what there was on the disk before */
                 from_scratch = true;
                 break;
@@ -1722,7 +1746,7 @@ static int context_dump_partition_bar(Context *context, const char *node) {
         bool z = false;
         size_t c, j = 0;
 
-        assert((c = columns()) >= 2);
+        assert_se((c = columns()) >= 2);
         c -= 2; /* We do not use the leftmost and rightmost character cell */
 
         bar = new0(Partition*, c);
@@ -1900,8 +1924,7 @@ static int context_discard_range(Context *context, uint64_t offset, uint64_t siz
         if (size <= 0)
                 return 0;
 
-        fd = fdisk_get_devfd(context->fdisk_context);
-        assert(fd >= 0);
+        assert_se((fd = fdisk_get_devfd(context->fdisk_context)) >= 0);
 
         if (fstat(fd, &st) < 0)
                 return -errno;
@@ -2210,7 +2233,6 @@ static int context_acquire_partition_uuids_and_labels(Context *context) {
 
         LIST_FOREACH(partitions, p, context->partitions) {
                 assert(sd_id128_is_null(p->new_uuid));
-                assert(!p->new_label);
 
                 /* Never touch foreign partitions */
                 if (PARTITION_IS_FOREIGN(p)) {
@@ -2233,6 +2255,9 @@ static int context_acquire_partition_uuids_and_labels(Context *context) {
                                 return r;
                 }
 
+                if (p->new_label) /* Explicitly set by user? */
+                        continue;
+
                 if (!isempty(p->current_label)) {
                         p->new_label = strdup(p->current_label); /* never change initialized labels */
                         if (!p->new_label)
@@ -2256,7 +2281,7 @@ static int device_kernel_partitions_supported(int fd) {
         if (fstat(fd, &st) < 0)
                 return log_error_errno(fd, "Failed to fstat() image file: %m");
         if (!S_ISBLK(st.st_mode))
-                return false;
+                return -ENOTBLK; /* we do not log in this one special case about errors */
 
         if (ioctl(fd, LOOP_GET_STATUS64, &info) < 0) {
 
@@ -2461,9 +2486,11 @@ static int context_write_partition_table(
                 return log_error_errno(r, "Failed to write partition table: %m");
 
         capable = device_kernel_partitions_supported(fdisk_get_devfd(context->fdisk_context));
-        if (capable < 0)
+        if (capable == -ENOTBLK)
+                log_debug("Not telling kernel to reread partition table, since we are not operating on a block device.");
+        else if (capable < 0)
                 return capable;
-        if (capable > 0) {
+        else if (capable > 0) {
                 log_info("Telling kernel to reread partition table.");
 
                 if (from_scratch)
@@ -2588,8 +2615,8 @@ static int help(void) {
                "  -h --help               Show this help\n"
                "     --version            Show package version\n"
                "     --dry-run=BOOL       Whether to run dry-run operation\n"
-               "     --empty=MODE         One of refuse, allow, require, force; controls how to\n"
-               "                          handle empty disks lacking partition table\n"
+               "     --empty=MODE         One of refuse, allow, require, force, create; controls\n"
+               "                          how to handle empty disks lacking partition tables\n"
                "     --discard=BOOL       Whether to discard backing blocks for new partitions\n"
                "     --pretty=BOOL        Whether to show pretty summary before executing operation\n"
                "     --factory-reset=BOOL Whether to remove data partitions before recreating\n"
@@ -2598,6 +2625,7 @@ static int help(void) {
                "     --root=PATH          Operate relative to root path\n"
                "     --definitions=DIR    Find partitions in specified directory\n"
                "     --seed=UUID          128bit seed UUID to derive all UUIDs from\n"
+               "     --size=BYTES         Grow loopback file to specified size\n"
                "\nSee the %s for details.\n"
                , program_invocation_short_name
                , ansi_highlight(), ansi_normal()
@@ -2620,6 +2648,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_SEED,
                 ARG_PRETTY,
                 ARG_DEFINITIONS,
+                ARG_SIZE,
         };
 
         static const struct option options[] = {
@@ -2634,10 +2663,11 @@ static int parse_argv(int argc, char *argv[]) {
                 { "seed",              required_argument, NULL, ARG_SEED              },
                 { "pretty",            required_argument, NULL, ARG_PRETTY            },
                 { "definitions",       required_argument, NULL, ARG_DEFINITIONS       },
+                { "size",              required_argument, NULL, ARG_SIZE              },
                 {}
         };
 
-        int c, r;
+        int c, r, dry_run = -1;
 
         assert(argc >= 0);
         assert(argv);
@@ -2657,7 +2687,7 @@ static int parse_argv(int argc, char *argv[]) {
                         if (r < 0)
                                 return log_error_errno(r, "Failed to parse --dry-run= parameter: %s", optarg);
 
-                        arg_dry_run = r;
+                        dry_run = r;
                         break;
 
                 case ARG_EMPTY:
@@ -2669,7 +2699,14 @@ static int parse_argv(int argc, char *argv[]) {
                                 arg_empty = EMPTY_REQUIRE;
                         else if (streq(optarg, "force"))
                                 arg_empty = EMPTY_FORCE;
-                        else
+                        else if (streq(optarg, "create")) {
+                                arg_empty = EMPTY_CREATE;
+
+                                if (dry_run < 0)
+                                        dry_run = false; /* Imply --dry-run=no if we create the loopback file
+                                                          * anew. After all we cannot really break anyone's
+                                                          * partition tables that way. */
+                        } else
                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                                        "Failed to parse --empty= parameter: %s", optarg);
                         break;
@@ -2730,6 +2767,27 @@ static int parse_argv(int argc, char *argv[]) {
                                 return r;
                         break;
 
+                case ARG_SIZE: {
+                        uint64_t parsed, rounded;
+
+                        r = parse_size(optarg, 1024, &parsed);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to parse --size= parameter: %s", optarg);
+
+                        rounded = round_up_size(parsed, 4096);
+                        if (rounded == 0)
+                                return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Specified image size too small, refusing.");
+                        if (rounded == UINT64_MAX)
+                                return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Specified image size too large, refusing.");
+
+                        if (rounded != parsed)
+                                log_warning("Specified size is not a multiple of 4096, rounding up automatically. (%" PRIu64 " → %" PRIu64 ")",
+                                            parsed, rounded);
+
+                        arg_size = rounded;
+                        break;
+                }
+
                 case '?':
                         return -EINVAL;
 
@@ -2741,14 +2799,27 @@ static int parse_argv(int argc, char *argv[]) {
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                        "Expected at most one argument, the path to the block device.");
 
-        if (arg_factory_reset > 0 && IN_SET(arg_empty, EMPTY_FORCE, EMPTY_REQUIRE))
+        if (arg_factory_reset > 0 && IN_SET(arg_empty, EMPTY_FORCE, EMPTY_REQUIRE, EMPTY_CREATE))
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "Combination of --factory-reset=yes and --empty=force/--empty=require is invalid.");
+                                       "Combination of --factory-reset=yes and --empty=force/--empty=require/--empty=create is invalid.");
 
         if (arg_can_factory_reset)
-                arg_dry_run = true;
+                arg_dry_run = true; /* When --can-factory-reset is specified we don't make changes, hence
+                                     * non-dry-run mode makes no sense. Thus, imply dry run mode so that we
+                                     * open things strictly read-only. */
+        else if (dry_run >= 0)
+                arg_dry_run = dry_run;
+
+        if (arg_empty == EMPTY_CREATE && arg_size == UINT64_MAX)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "If --empty=create is specified, --size= must be specified, too.");
 
         arg_node = argc > optind ? argv[optind] : NULL;
+
+        if (IN_SET(arg_empty, EMPTY_FORCE, EMPTY_REQUIRE, EMPTY_CREATE) && !arg_node)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "A path to a device node or loopback file must be specified when --empty=force, --empty=require or --empty=create are used.");
+
         return 1;
 }
 
@@ -2815,12 +2886,16 @@ static int remove_efi_variable_factory_reset(void) {
         return 0;
 }
 
-static int acquire_root_devno(const char *p, int mode, char **ret) {
+static int acquire_root_devno(const char *p, int mode, char **ret, int *ret_fd) {
         _cleanup_close_ int fd = -1;
         struct stat st;
-        dev_t devno;
+        dev_t devno, fd_devno = (mode_t) -1;
         int r;
 
+        assert(p);
+        assert(ret);
+        assert(ret_fd);
+
         fd = open(p, mode);
         if (fd < 0)
                 return -errno;
@@ -2836,23 +2911,23 @@ static int acquire_root_devno(const char *p, int mode, char **ret) {
                         return log_oom();
 
                 *ret = s;
+                *ret_fd = TAKE_FD(fd);
+
                 return 0;
         }
 
         if (S_ISBLK(st.st_mode))
-                devno = st.st_rdev;
+                fd_devno = devno = st.st_rdev;
         else if (S_ISDIR(st.st_mode)) {
 
                 devno = st.st_dev;
-
-                if (major(st.st_dev) == 0) {
+                if (major(devno) == 0) {
                         r = btrfs_get_block_device_fd(fd, &devno);
                         if (r == -ENOTTY) /* not btrfs */
                                 return -ENODEV;
                         if (r < 0)
                                 return r;
                 }
-
         } else
                 return -ENOTBLK;
 
@@ -2866,21 +2941,50 @@ static int acquire_root_devno(const char *p, int mode, char **ret) {
         if (r < 0)
                 log_debug_errno(r, "Failed to find whole disk block device for '%s', ignoring: %m", p);
 
-        return device_path_make_canonical(S_IFBLK, devno, ret);
+        r = device_path_make_canonical(S_IFBLK, devno, ret);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to determine canonical path for '%s': %m", p);
+
+        /* Only if we still lock at the same block device we can reuse the fd. Otherwise return an
+         * invalidated fd. */
+        *ret_fd = fd_devno != (mode_t) -1 && fd_devno == devno ? TAKE_FD(fd) : -1;
+        return 0;
 }
 
-static int find_root(char **ret) {
+static int find_root(char **ret, int *ret_fd) {
         const char *t;
         int r;
 
+        assert(ret);
+        assert(ret_fd);
+
         if (arg_node) {
-                r = acquire_root_devno(arg_node, O_RDONLY|O_CLOEXEC, ret);
+                if (arg_empty == EMPTY_CREATE) {
+                        _cleanup_close_ int fd = -1;
+                        _cleanup_free_ char *s = NULL;
+
+                        s = strdup(arg_node);
+                        if (!s)
+                                return log_oom();
+
+                        fd = open(arg_node, O_RDONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOFOLLOW, 0777);
+                        if (fd < 0)
+                                return log_error_errno(errno, "Failed to create '%s': %m", arg_node);
+
+                        *ret = TAKE_PTR(s);
+                        *ret_fd = TAKE_FD(fd);
+                        return 0;
+                }
+
+                r = acquire_root_devno(arg_node, O_RDONLY|O_CLOEXEC, ret, ret_fd);
                 if (r < 0)
                         return log_error_errno(r, "Failed to determine backing device of %s: %m", arg_node);
 
                 return 0;
         }
 
+        assert(IN_SET(arg_empty, EMPTY_REFUSE, EMPTY_ALLOW));
+
         /* Let's search for the root device. We look for two cases here: first in /, and then in /usr. The
          * latter we check for cases where / is a tmpfs and only /usr is an actual persistent block device
          * (think: volatile setups) */
@@ -2898,7 +3002,7 @@ static int find_root(char **ret) {
                 } else
                         p = t;
 
-                r = acquire_root_devno(p, O_RDONLY|O_DIRECTORY|O_CLOEXEC, ret);
+                r = acquire_root_devno(p, O_RDONLY|O_DIRECTORY|O_CLOEXEC, ret, ret_fd);
                 if (r < 0) {
                         if (r != -ENODEV)
                                 return log_error_errno(r, "Failed to determine backing device of %s: %m", p);
@@ -2909,9 +3013,83 @@ static int find_root(char **ret) {
         return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "Failed to discover root block device.");
 }
 
+static int resize_backing_fd(const char *node, int *fd) {
+        char buf1[FORMAT_BYTES_MAX], buf2[FORMAT_BYTES_MAX];
+        _cleanup_close_ int writable_fd = -1;
+        struct stat st;
+        int r;
+
+        assert(node);
+        assert(fd);
+
+        if (arg_size == UINT64_MAX) /* Nothing to do */
+                return 0;
+
+        if (*fd < 0) {
+                /* Open the file if we haven't opened it yet. Note that we open it read-only here, just to
+                 * keep a reference to the file we can pass around. */
+                *fd = open(node, O_RDONLY|O_CLOEXEC);
+                if (*fd < 0)
+                        return log_error_errno(errno, "Failed to open '%s' in order to adjust size: %m", node);
+        }
+
+        if (fstat(*fd, &st) < 0)
+                return log_error_errno(errno, "Failed to stat '%s': %m", node);
+
+        r = stat_verify_regular(&st);
+        if (r < 0)
+                return log_error_errno(r, "Specified path '%s' is not a regular file, cannot resize: %m", node);
+
+        assert_se(format_bytes(buf1, sizeof(buf1), st.st_size));
+        assert_se(format_bytes(buf2, sizeof(buf2), arg_size));
+
+        if ((uint64_t) st.st_size >= arg_size) {
+                log_info("File '%s' already is of requested size or larger, not growing. (%s >= %s)", node, buf1, buf2);
+                return 0;
+        }
+
+        /* The file descriptor is read-only. In order to grow the file we need to have a writable fd. We
+         * reopen the file for that temporarily. We keep the writable fd only open for this operation though,
+         * as fdisk can't accept it anyway. */
+
+        writable_fd = fd_reopen(*fd, O_WRONLY|O_CLOEXEC);
+        if (writable_fd < 0)
+                return log_error_errno(writable_fd, "Failed to reopen backing file '%s' writable: %m", node);
+
+        if (!arg_discard) {
+                if (fallocate(writable_fd, 0, 0, arg_size) < 0) {
+                        if (!ERRNO_IS_NOT_SUPPORTED(errno))
+                                return log_error_errno(errno, "Failed to grow '%s' from %s to %s by allocation: %m",
+                                                       node, buf1, buf2);
+
+                        /* Fallback to truncation, if fallocate() is not supported. */
+                        log_debug("Backing file system does not support fallocate(), falling back to ftruncate().");
+                } else {
+                        if (st.st_size == 0) /* Likely regular file just created by us */
+                                log_info("Allocated %s for '%s'.", buf2, node);
+                        else
+                                log_info("File '%s' grown from %s to %s by allocation.", node, buf1, buf2);
+
+                        return 1;
+                }
+        }
+
+        if (ftruncate(writable_fd, arg_size) < 0)
+                return log_error_errno(errno, "Failed to grow '%s' from %s to %s by truncation: %m",
+                                       node, buf1, buf2);
+
+        if (st.st_size == 0) /* Likely regular file just created by us */
+                log_info("Sized '%s' to %s.", node, buf2);
+        else
+                log_info("File '%s' grown from %s to %s by truncation.", node, buf1, buf2);
+
+        return 1;
+}
+
 static int run(int argc, char *argv[]) {
         _cleanup_(context_freep) Context* context = NULL;
         _cleanup_free_ char *node = NULL;
+        _cleanup_close_ int backing_fd = -1;
         bool from_scratch;
         int r;
 
@@ -2946,14 +3124,22 @@ static int run(int argc, char *argv[]) {
         if (r < 0)
                 return r;
 
-        if (context->n_partitions <= 0 && arg_empty != EMPTY_FORCE)
+        if (context->n_partitions <= 0 && arg_empty == EMPTY_REFUSE) {
+                log_info("Didn't find any partition definition files, nothing to do.");
                 return 0;
+        }
 
-        r = find_root(&node);
+        r = find_root(&node, &backing_fd);
         if (r < 0)
                 return r;
 
-        r = context_load_partition_table(context, node);
+        if (arg_size != UINT64_MAX) {
+                r = resize_backing_fd(node, &backing_fd);
+                if (r < 0)
+                        return r;
+        }
+
+        r = context_load_partition_table(context, node, &backing_fd);
         if (r == -EHWPOISON)
                 return 77; /* Special return value which means "Not GPT, so not doing anything". This isn't
                             * really an error when called at boot. */
@@ -2982,7 +3168,7 @@ static int run(int argc, char *argv[]) {
 
                 /* Reload the reduced partition table */
                 context_unload_partition_table(context);
-                r = context_load_partition_table(context, node);
+                r = context_load_partition_table(context, node, &backing_fd);
                 if (r < 0)
                         return r;
         }
index 7da6b1b027fea4a465571cf0400dbe2e5ff97380..58fcc797c43e72843710f369d371fee3446485ef 100755 (executable)
@@ -8,11 +8,9 @@ D=$(mktemp --directory)
 trap "rm -rf '$D'" EXIT INT QUIT PIPE
 mkdir -p $D/definitions
 
-truncate -s 1G $D/zzz
-
 SEED=e2a40bf9-73f1-4278-9160-49c031e7aef8
 
-$repart $D/zzz --empty=force --dry-run=no --seed=$SEED
+$repart $D/zzz --empty=create --size=1G --seed=$SEED
 
 sfdisk -d $D/zzz | grep -v -e 'sector-size' -e '^$' > $D/empty
 
@@ -90,9 +88,7 @@ $D/zzz4 : start=     1777624, size=      131072, type=0657FD6D-A4AB-43C4-84E5-09
 $D/zzz5 : start=     1908696, size=      188416, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=03477476-06AD-44E8-9EF4-BC2BD7771289, name="linux-generic"
 EOF
 
-truncate -s 2G $D/zzz
-
-$repart $D/zzz --dry-run=no --seed=$SEED --definitions=$D/definitions
+$repart $D/zzz --size=2G --dry-run=no --seed=$SEED --definitions=$D/definitions
 
 sfdisk -d $D/zzz | grep -v -e 'sector-size' -e '^$' >$D/populated3
 
index 58e4a6670d8b483df0517a50268564a638436f75..a6aaa14ab6a1c59ab602b4594ba24f3f783f1e78 100644 (file)
@@ -127,10 +127,7 @@ static int send_item(
                 const char *name,
                 int fd) {
 
-        union {
-                struct cmsghdr cmsghdr;
-                uint8_t buf[CMSG_SPACE(sizeof(int))];
-        } control = {};
+        CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int))) control = {};
         struct iovec iovec;
         struct msghdr mh = {
                 .msg_control = &control,
@@ -155,7 +152,6 @@ static int send_item(
         cmsg->cmsg_len = CMSG_LEN(sizeof(int));
         memcpy(CMSG_DATA(cmsg), &data_fd, sizeof(int));
 
-        mh.msg_controllen = CMSG_SPACE(sizeof(int));
         iovec = IOVEC_MAKE_STRING(name);
 
         if (sendmsg(socket_fd, &mh, MSG_NOSIGNAL) < 0)
@@ -169,10 +165,7 @@ static int recv_item(
                 char **ret_name,
                 int *ret_fd) {
 
-        union {
-                struct cmsghdr cmsghdr;
-                uint8_t buf[CMSG_SPACE(sizeof(int))];
-        } control = {};
+        CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int))) control;
         char buffer[PATH_MAX+2];
         struct iovec iov = IOVEC_INIT(buffer, sizeof(buffer)-1);
         struct msghdr mh = {
@@ -190,9 +183,9 @@ static int recv_item(
         assert(ret_name);
         assert(ret_fd);
 
-        n = recvmsg(socket_fd, &mh, MSG_CMSG_CLOEXEC);
+        n = recvmsg_safe(socket_fd, &mh, MSG_CMSG_CLOEXEC);
         if (n < 0)
-                return -errno;
+                return (int) n;
 
         CMSG_FOREACH(cmsg, &mh) {
                 if (cmsg->cmsg_level == SOL_SOCKET &&
@@ -1156,10 +1149,6 @@ int portable_detach(
                 return log_debug_errno(errno, "Failed to open '%s' directory: %m", where);
         }
 
-        unit_files = set_new(&string_hash_ops);
-        if (!unit_files)
-                return -ENOMEM;
-
         markers = set_new(&path_hash_ops);
         if (!markers)
                 return -ENOMEM;
@@ -1172,7 +1161,7 @@ int portable_detach(
                         continue;
 
                 /* Filter out duplicates */
-                if (set_get(unit_files, de->d_name))
+                if (set_contains(unit_files, de->d_name))
                         continue;
 
                 dirent_ensure_type(d, de);
@@ -1197,7 +1186,7 @@ int portable_detach(
                 if (r > 0)
                         return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, "Unit file '%s' is active, can't detach.", de->d_name);
 
-                r = set_put_strdup(unit_files, de->d_name);
+                r = set_put_strdup(&unit_files, de->d_name);
                 if (r < 0)
                         return log_debug_errno(r, "Failed to add unit name '%s' to set: %m", de->d_name);
 
@@ -1310,7 +1299,7 @@ static int portable_get_state_internal(
 
         _cleanup_(lookup_paths_free) LookupPaths paths = {};
         bool found_enabled = false, found_running = false;
-        _cleanup_set_free_free_ Set *unit_files = NULL;
+        _cleanup_set_free_ Set *unit_files = NULL;
         _cleanup_closedir_ DIR *d = NULL;
         const char *where;
         struct dirent *de;
@@ -1336,10 +1325,6 @@ static int portable_get_state_internal(
                 return log_debug_errno(errno, "Failed to open '%s' directory: %m", where);
         }
 
-        unit_files = set_new(&string_hash_ops);
-        if (!unit_files)
-                return -ENOMEM;
-
         FOREACH_DIRENT(de, d, return log_debug_errno(errno, "Failed to enumerate '%s' directory: %m", where)) {
                 UnitFileState state;
 
@@ -1347,7 +1332,7 @@ static int portable_get_state_internal(
                         continue;
 
                 /* Filter out duplicates */
-                if (set_get(unit_files, de->d_name))
+                if (set_contains(unit_files, de->d_name))
                         continue;
 
                 dirent_ensure_type(d, de);
@@ -1372,7 +1357,7 @@ static int portable_get_state_internal(
                 if (r > 0)
                         found_running = true;
 
-                r = set_put_strdup(unit_files, de->d_name);
+                r = set_put_strdup(&unit_files, de->d_name);
                 if (r < 0)
                         return log_debug_errno(r, "Failed to add unit name '%s' to set: %m", de->d_name);
         }
index bf5badd699c3b29979e53eeb8f319de56abc2dd9..1bde30e90f1ab7b2a1c7bbbe8cf2731b89085f71 100644 (file)
@@ -239,13 +239,7 @@ static int inspect_image(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return r;
 
-        r = sd_bus_message_new_method_call(
-                                bus,
-                                &m,
-                                "org.freedesktop.portable1",
-                                "/org/freedesktop/portable1",
-                                "org.freedesktop.portable1.Manager",
-                                "GetImageMetadata");
+        r = bus_message_new_method_call(bus, &m, bus_portable_mgr, "GetImageMetadata");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -554,13 +548,7 @@ static int maybe_stop_disable(sd_bus *bus, char *image, char *argv[]) {
         if (r < 0)
                 return log_error_errno(r, "Could not watch jobs: %m");
 
-        r = sd_bus_message_new_method_call(
-                                bus,
-                                &m,
-                                "org.freedesktop.portable1",
-                                "/org/freedesktop/portable1",
-                                "org.freedesktop.portable1.Manager",
-                                "GetImageMetadata");
+        r = bus_message_new_method_call(bus, &m, bus_portable_mgr, "GetImageMetadata");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -643,13 +631,7 @@ static int attach_image(int argc, char *argv[], void *userdata) {
 
         (void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
-        r = sd_bus_message_new_method_call(
-                                bus,
-                                &m,
-                                "org.freedesktop.portable1",
-                                "/org/freedesktop/portable1",
-                                "org.freedesktop.portable1.Manager",
-                                "AttachImage");
+        r = bus_message_new_method_call(bus, &m, bus_portable_mgr, "AttachImage");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -697,15 +679,7 @@ static int detach_image(int argc, char *argv[], void *userdata) {
 
         (void) maybe_stop_disable(bus, image, argv);
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.portable1",
-                        "/org/freedesktop/portable1",
-                        "org.freedesktop.portable1.Manager",
-                        "DetachImage",
-                        &error,
-                        &reply,
-                        "sb", image, arg_runtime);
+        r = bus_call_method(bus, bus_portable_mgr, "DetachImage", &error, &reply, "sb", image, arg_runtime);
         if (r < 0)
                 return log_error_errno(r, "Failed to detach image: %s", bus_error_message(&error, r));
 
@@ -726,15 +700,7 @@ static int list_images(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return r;
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.portable1",
-                        "/org/freedesktop/portable1",
-                        "org.freedesktop.portable1.Manager",
-                        "ListImages",
-                        &error,
-                        &reply,
-                        NULL);
+        r = bus_call_method(bus, bus_portable_mgr, "ListImages", &error, &reply, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to list images: %s", bus_error_message(&error, r));
 
@@ -811,13 +777,7 @@ static int remove_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 *m = NULL;
 
-                r = sd_bus_message_new_method_call(
-                                bus,
-                                &m,
-                                "org.freedesktop.portable1",
-                                "/org/freedesktop/portable1",
-                                "org.freedesktop.portable1.Manager",
-                                "RemoveImage");
+                r = bus_message_new_method_call(bus, &m, bus_portable_mgr, "RemoveImage");
                 if (r < 0)
                         return bus_log_create_error(r);
 
@@ -851,15 +811,7 @@ static int read_only_image(int argc, char *argv[], void *userdata) {
 
         (void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.portable1",
-                        "/org/freedesktop/portable1",
-                        "org.freedesktop.portable1.Manager",
-                        "MarkImageReadOnly",
-                        &error,
-                        NULL,
-                        "sb", argv[1], b);
+        r = bus_call_method(bus, bus_portable_mgr, "MarkImageReadOnly", &error, NULL, "sb", argv[1], b);
         if (r < 0)
                 return log_error_errno(r, "Could not mark image read-only: %s", bus_error_message(&error, r));
 
@@ -888,26 +840,10 @@ static int set_limit(int argc, char *argv[], void *userdata) {
 
         if (argc > 2)
                 /* With two arguments changes the quota limit of the specified image */
-                r = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.portable1",
-                                "/org/freedesktop/portable1",
-                                "org.freedesktop.portable1.Manager",
-                                "SetImageLimit",
-                                &error,
-                                NULL,
-                                "st", argv[1], limit);
+                r = bus_call_method(bus, bus_portable_mgr, "SetImageLimit", &error, NULL, "st", argv[1], limit);
         else
                 /* With one argument changes the pool quota limit */
-                r = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.portable1",
-                                "/org/freedesktop/portable1",
-                                "org.freedesktop.portable1.Manager",
-                                "SetPoolLimit",
-                                &error,
-                                NULL,
-                                "t", limit);
+                r = bus_call_method(bus, bus_portable_mgr, "SetPoolLimit", &error, NULL, "t", limit);
 
         if (r < 0)
                 return log_error_errno(r, "Could not set limit: %s", bus_error_message(&error, r));
@@ -931,15 +867,7 @@ static int is_image_attached(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return r;
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.portable1",
-                        "/org/freedesktop/portable1",
-                        "org.freedesktop.portable1.Manager",
-                        "GetImageState",
-                        &error,
-                        &reply,
-                        "s", image);
+        r = bus_call_method(bus, bus_portable_mgr, "GetImageState", &error, &reply, "s", image);
         if (r < 0)
                 return log_error_errno(r, "Failed to get image state: %s", bus_error_message(&error, r));
 
@@ -964,14 +892,7 @@ static int dump_profiles(void) {
         if (r < 0)
                 return r;
 
-        r = sd_bus_get_property_strv(
-                        bus,
-                        "org.freedesktop.portable1",
-                        "/org/freedesktop/portable1",
-                        "org.freedesktop.portable1.Manager",
-                        "Profiles",
-                        &error,
-                        &l);
+        r = bus_get_property_strv(bus, bus_portable_mgr, "Profiles", &error, &l);
         if (r < 0)
                 return log_error_errno(r, "Failed to acquire list of profiles: %s", bus_error_message(&error, r));
 
index c4d8d4e5d9a3bb309017553f7b6c813b22b6bfc8..92b67b6333d764ce474aeb05a7085fcfebd178ae 100644 (file)
@@ -64,8 +64,6 @@ systemd_resolved_sources = files('''
         resolved-etc-hosts.h
         resolved-etc-hosts.c
         resolved-dnstls.h
-        resolved-util.c
-        resolved-util.h
 '''.split())
 
 resolvectl_sources = files('''
@@ -230,10 +228,4 @@ tests += [
          [],
          [],
          'ENABLE_RESOLVE', 'manual'],
-
-        [['src/resolve/test-resolved-util.c',
-          'src/resolve/resolved-util.c',
-          'src/resolve/resolved-util.h'],
-         [],
-         []],
 ]
index 8abaeb5f1c67507f6bd829709deebcbd4f42a82e..d68b7ba7847078ea4afa52882ea71fee51d18556 100644 (file)
@@ -169,13 +169,7 @@ static int resolve_host(sd_bus *bus, const char *name) {
 
         log_debug("Resolving %s (family %s, interface %s).", name, af_to_name(arg_family) ?: "*", isempty(arg_ifname) ? "*" : arg_ifname);
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &req,
-                        "org.freedesktop.resolve1",
-                        "/org/freedesktop/resolve1",
-                        "org.freedesktop.resolve1.Manager",
-                        "ResolveHostname");
+        r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveHostname");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -286,13 +280,7 @@ static int resolve_address(sd_bus *bus, int family, const union in_addr_union *a
 
         log_debug("Resolving %s.", pretty);
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &req,
-                        "org.freedesktop.resolve1",
-                        "/org/freedesktop/resolve1",
-                        "org.freedesktop.resolve1.Manager",
-                        "ResolveAddress");
+        r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveAddress");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -421,13 +409,7 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_
 
         log_debug("Resolving %s %s %s (interface %s).", name, dns_class_to_string(class), dns_type_to_string(type), isempty(arg_ifname) ? "*" : arg_ifname);
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &req,
-                        "org.freedesktop.resolve1",
-                        "/org/freedesktop/resolve1",
-                        "org.freedesktop.resolve1.Manager",
-                        "ResolveRecord");
+        r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveRecord");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -689,13 +671,7 @@ static int resolve_service(sd_bus *bus, const char *name, const char *type, cons
         else
                 log_debug("Resolving service type %s (family %s, interface %s).", domain, af_to_name(arg_family) ?: "*", isempty(arg_ifname) ? "*" : arg_ifname);
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &req,
-                        "org.freedesktop.resolve1",
-                        "/org/freedesktop/resolve1",
-                        "org.freedesktop.resolve1.Manager",
-                        "ResolveService");
+        r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveService");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -994,14 +970,7 @@ static int show_statistics(int argc, char **argv, void *userdata) {
 
         assert(bus);
 
-        r = sd_bus_get_property_trivial(bus,
-                                        "org.freedesktop.resolve1",
-                                        "/org/freedesktop/resolve1",
-                                        "org.freedesktop.resolve1.Manager",
-                                        "DNSSECSupported",
-                                        &error,
-                                        'b',
-                                        &dnssec_supported);
+        r = bus_get_property_trivial(bus, bus_resolve_mgr, "DNSSECSupported", &error, 'b', &dnssec_supported);
         if (r < 0)
                 return log_error_errno(r, "Failed to get DNSSEC supported state: %s", bus_error_message(&error, r));
 
@@ -1010,14 +979,7 @@ static int show_statistics(int argc, char **argv, void *userdata) {
                yes_no(dnssec_supported),
                ansi_normal());
 
-        r = sd_bus_get_property(bus,
-                                "org.freedesktop.resolve1",
-                                "/org/freedesktop/resolve1",
-                                "org.freedesktop.resolve1.Manager",
-                                "TransactionStatistics",
-                                &error,
-                                &reply,
-                                "(tt)");
+        r = bus_get_property(bus, bus_resolve_mgr, "TransactionStatistics", &error, &reply, "(tt)");
         if (r < 0)
                 return log_error_errno(r, "Failed to get transaction statistics: %s", bus_error_message(&error, r));
 
@@ -1029,14 +991,7 @@ static int show_statistics(int argc, char **argv, void *userdata) {
 
         reply = sd_bus_message_unref(reply);
 
-        r = sd_bus_get_property(bus,
-                                "org.freedesktop.resolve1",
-                                "/org/freedesktop/resolve1",
-                                "org.freedesktop.resolve1.Manager",
-                                "CacheStatistics",
-                                &error,
-                                &reply,
-                                "(ttt)");
+        r = bus_get_property(bus, bus_resolve_mgr, "CacheStatistics", &error, &reply, "(ttt)");
         if (r < 0)
                 return log_error_errno(r, "Failed to get cache statistics: %s", bus_error_message(&error, r));
 
@@ -1049,14 +1004,7 @@ static int show_statistics(int argc, char **argv, void *userdata) {
 
         reply = sd_bus_message_unref(reply);
 
-        r = sd_bus_get_property(bus,
-                                "org.freedesktop.resolve1",
-                                "/org/freedesktop/resolve1",
-                                "org.freedesktop.resolve1.Manager",
-                                "DNSSECStatistics",
-                                &error,
-                                &reply,
-                                "(tttt)");
+        r = bus_get_property(bus, bus_resolve_mgr, "DNSSECStatistics", &error, &reply, "(tttt)");
         if (r < 0)
                 return log_error_errno(r, "Failed to get DNSSEC statistics: %s", bus_error_message(&error, r));
 
@@ -1124,14 +1072,7 @@ static int reset_statistics(int argc, char **argv, void *userdata) {
         sd_bus *bus = userdata;
         int r;
 
-        r = sd_bus_call_method(bus,
-                               "org.freedesktop.resolve1",
-                               "/org/freedesktop/resolve1",
-                               "org.freedesktop.resolve1.Manager",
-                               "ResetStatistics",
-                               &error,
-                               NULL,
-                               NULL);
+        r = bus_call_method(bus, bus_resolve_mgr, "ResetStatistics", &error, NULL, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to reset statistics: %s", bus_error_message(&error, r));
 
@@ -1143,14 +1084,7 @@ static int flush_caches(int argc, char **argv, void *userdata) {
         sd_bus *bus = userdata;
         int r;
 
-        r = sd_bus_call_method(bus,
-                               "org.freedesktop.resolve1",
-                               "/org/freedesktop/resolve1",
-                               "org.freedesktop.resolve1.Manager",
-                               "FlushCaches",
-                               &error,
-                               NULL,
-                               NULL);
+        r = bus_call_method(bus, bus_resolve_mgr, "FlushCaches", &error, NULL, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to flush caches: %s", bus_error_message(&error, r));
 
@@ -1162,14 +1096,7 @@ static int reset_server_features(int argc, char **argv, void *userdata) {
         sd_bus *bus = userdata;
         int r;
 
-        r = sd_bus_call_method(bus,
-                               "org.freedesktop.resolve1",
-                               "/org/freedesktop/resolve1",
-                               "org.freedesktop.resolve1.Manager",
-                               "ResetServerFeatures",
-                               &error,
-                               NULL,
-                               NULL);
+        r = bus_call_method(bus, bus_resolve_mgr, "ResetServerFeatures", &error, NULL, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to reset server features: %s", bus_error_message(&error, r));
 
@@ -1921,18 +1848,12 @@ static int verb_status(int argc, char **argv, void *userdata) {
         return r;
 }
 
-static int call_dns(sd_bus *bus, char **dns, const char *destination, const char *path, const char *interface, sd_bus_error *error) {
+static int call_dns(sd_bus *bus, char **dns, const BusLocator *locator, sd_bus_error *error) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
         char **p;
         int r;
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &req,
-                        destination,
-                        path,
-                        interface,
-                        "SetLinkDNS");
+        r = bus_message_new_method_call(bus, &req, locator, "SetLinkDNS");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -1997,19 +1918,11 @@ static int verb_dns(int argc, char **argv, void *userdata) {
         if (argc < 3)
                 return status_ifindex(bus, arg_ifindex, NULL, STATUS_DNS, NULL);
 
-        r = call_dns(bus, argv + 2,
-                     "org.freedesktop.resolve1",
-                     "/org/freedesktop/resolve1",
-                     "org.freedesktop.resolve1.Manager",
-                     &error);
+        r = call_dns(bus, argv + 2, bus_resolve_mgr, &error);
         if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
                 sd_bus_error_free(&error);
 
-                r = call_dns(bus, argv + 2,
-                             "org.freedesktop.network1",
-                             "/org/freedesktop/network1",
-                             "org.freedesktop.network1.Manager",
-                             &error);
+                r = call_dns(bus, argv + 2, bus_network_mgr, &error);
         }
         if (r < 0) {
                 if (arg_ifindex_permissive &&
@@ -2022,18 +1935,12 @@ static int verb_dns(int argc, char **argv, void *userdata) {
         return 0;
 }
 
-static int call_domain(sd_bus *bus, char **domain, const char *destination, const char *path, const char *interface, sd_bus_error *error) {
+static int call_domain(sd_bus *bus, char **domain, const BusLocator *locator, sd_bus_error *error) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
         char **p;
         int r;
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &req,
-                        destination,
-                        path,
-                        interface,
-                        "SetLinkDomains");
+        r = bus_message_new_method_call(bus, &req, locator, "SetLinkDomains");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -2092,19 +1999,11 @@ static int verb_domain(int argc, char **argv, void *userdata) {
         if (argc < 3)
                 return status_ifindex(bus, arg_ifindex, NULL, STATUS_DOMAIN, NULL);
 
-        r = call_domain(bus, argv + 2,
-                        "org.freedesktop.resolve1",
-                        "/org/freedesktop/resolve1",
-                        "org.freedesktop.resolve1.Manager",
-                        &error);
+        r = call_domain(bus, argv + 2, bus_resolve_mgr, &error);
         if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
                 sd_bus_error_free(&error);
 
-                r = call_domain(bus, argv + 2,
-                                "org.freedesktop.network1",
-                                "/org/freedesktop/network1",
-                                "org.freedesktop.network1.Manager",
-                                &error);
+                r = call_domain(bus, argv + 2, bus_network_mgr, &error);
         }
         if (r < 0) {
                 if (arg_ifindex_permissive &&
@@ -2140,27 +2039,11 @@ static int verb_default_route(int argc, char **argv, void *userdata) {
         if (b < 0)
                 return log_error_errno(b, "Failed to parse boolean argument: %s", argv[2]);
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.resolve1",
-                        "/org/freedesktop/resolve1",
-                        "org.freedesktop.resolve1.Manager",
-                        "SetLinkDefaultRoute",
-                        &error,
-                        NULL,
-                        "ib", arg_ifindex, b);
+        r = bus_call_method(bus, bus_resolve_mgr, "SetLinkDefaultRoute", &error, NULL, "ib", arg_ifindex, b);
         if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
                 sd_bus_error_free(&error);
 
-                r = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.network1",
-                                "/org/freedesktop/network1",
-                                "org.freedesktop.network1.Manager",
-                                "SetLinkDefaultRoute",
-                                &error,
-                                NULL,
-                                "ib", arg_ifindex, b);
+                r = bus_call_method(bus, bus_network_mgr, "SetLinkDefaultRoute", &error, NULL, "ib", arg_ifindex, b);
         }
         if (r < 0) {
                 if (arg_ifindex_permissive &&
@@ -2192,27 +2075,11 @@ static int verb_llmnr(int argc, char **argv, void *userdata) {
         if (argc < 3)
                 return status_ifindex(bus, arg_ifindex, NULL, STATUS_LLMNR, NULL);
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.resolve1",
-                        "/org/freedesktop/resolve1",
-                        "org.freedesktop.resolve1.Manager",
-                        "SetLinkLLMNR",
-                        &error,
-                        NULL,
-                        "is", arg_ifindex, argv[2]);
+        r = bus_call_method(bus, bus_resolve_mgr, "SetLinkLLMNR", &error, NULL, "is", arg_ifindex, argv[2]);
         if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
                 sd_bus_error_free(&error);
 
-                r = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.network1",
-                                "/org/freedesktop/network1",
-                                "org.freedesktop.network1.Manager",
-                                "SetLinkLLMNR",
-                                &error,
-                                NULL,
-                                "is", arg_ifindex, argv[2]);
+                r = bus_call_method(bus, bus_network_mgr, "SetLinkLLMNR", &error, NULL, "is", arg_ifindex, argv[2]);
         }
         if (r < 0) {
                 if (arg_ifindex_permissive &&
@@ -2244,23 +2111,13 @@ static int verb_mdns(int argc, char **argv, void *userdata) {
         if (argc < 3)
                 return status_ifindex(bus, arg_ifindex, NULL, STATUS_MDNS, NULL);
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.resolve1",
-                        "/org/freedesktop/resolve1",
-                        "org.freedesktop.resolve1.Manager",
-                        "SetLinkMulticastDNS",
-                        &error,
-                        NULL,
-                        "is", arg_ifindex, argv[2]);
+        r = bus_call_method(bus, bus_resolve_mgr, "SetLinkMulticastDNS", &error, NULL, "is", arg_ifindex, argv[2]);
         if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
                 sd_bus_error_free(&error);
 
-                r = sd_bus_call_method(
+                r = bus_call_method(
                                 bus,
-                                "org.freedesktop.network1",
-                                "/org/freedesktop/network1",
-                                "org.freedesktop.network1.Manager",
+                                bus_network_mgr,
                                 "SetLinkMulticastDNS",
                                 &error,
                                 NULL,
@@ -2296,23 +2153,13 @@ static int verb_dns_over_tls(int argc, char **argv, void *userdata) {
         if (argc < 3)
                 return status_ifindex(bus, arg_ifindex, NULL, STATUS_PRIVATE, NULL);
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.resolve1",
-                        "/org/freedesktop/resolve1",
-                        "org.freedesktop.resolve1.Manager",
-                        "SetLinkDNSOverTLS",
-                        &error,
-                        NULL,
-                        "is", arg_ifindex, argv[2]);
+        r = bus_call_method(bus, bus_resolve_mgr, "SetLinkDNSOverTLS", &error, NULL, "is", arg_ifindex, argv[2]);
         if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
                 sd_bus_error_free(&error);
 
-                r = sd_bus_call_method(
+                r = bus_call_method(
                                 bus,
-                                "org.freedesktop.network1",
-                                "/org/freedesktop/network1",
-                                "org.freedesktop.network1.Manager",
+                                bus_network_mgr,
                                 "SetLinkDNSOverTLS",
                                 &error,
                                 NULL,
@@ -2348,27 +2195,11 @@ static int verb_dnssec(int argc, char **argv, void *userdata) {
         if (argc < 3)
                 return status_ifindex(bus, arg_ifindex, NULL, STATUS_DNSSEC, NULL);
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.resolve1",
-                        "/org/freedesktop/resolve1",
-                        "org.freedesktop.resolve1.Manager",
-                        "SetLinkDNSSEC",
-                        &error,
-                        NULL,
-                        "is", arg_ifindex, argv[2]);
+        r = bus_call_method(bus, bus_resolve_mgr, "SetLinkDNSSEC", &error, NULL, "is", arg_ifindex, argv[2]);
         if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
                 sd_bus_error_free(&error);
 
-                r = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.network1",
-                                "/org/freedesktop/network1",
-                                "org.freedesktop.network1.Manager",
-                                "SetLinkDNSSEC",
-                                &error,
-                                NULL,
-                                "is", arg_ifindex, argv[2]);
+                r = bus_call_method(bus, bus_network_mgr, "SetLinkDNSSEC", &error, NULL, "is", arg_ifindex, argv[2]);
         }
         if (r < 0) {
                 if (arg_ifindex_permissive &&
@@ -2381,17 +2212,11 @@ static int verb_dnssec(int argc, char **argv, void *userdata) {
         return 0;
 }
 
-static int call_nta(sd_bus *bus, char **nta, const char *destination, const char *path, const char *interface, sd_bus_error *error) {
+static int call_nta(sd_bus *bus, char **nta, const BusLocator *locator,  sd_bus_error *error) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
         int r;
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &req,
-                        destination,
-                        path,
-                        interface,
-                        "SetLinkDNSSECNegativeTrustAnchors");
+        r = bus_message_new_method_call(bus, &req, locator, "SetLinkDNSSECNegativeTrustAnchors");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -2442,19 +2267,11 @@ static int verb_nta(int argc, char **argv, void *userdata) {
                         }
                 }
 
-        r = call_nta(bus, clear ? NULL : argv + 2,
-                     "org.freedesktop.resolve1",
-                     "/org/freedesktop/resolve1",
-                     "org.freedesktop.resolve1.Manager",
-                     &error);
+        r = call_nta(bus, clear ? NULL : argv + 2, bus_resolve_mgr, &error);
         if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
                 sd_bus_error_free(&error);
 
-                r = call_nta(bus, clear ? NULL : argv + 2,
-                             "org.freedesktop.network1",
-                             "/org/freedesktop/network1",
-                             "org.freedesktop.network1.Manager",
-                             &error);
+                r = call_nta(bus, clear ? NULL : argv + 2, bus_network_mgr, &error);
         }
         if (r < 0) {
                 if (arg_ifindex_permissive &&
@@ -2483,27 +2300,11 @@ static int verb_revert_link(int argc, char **argv, void *userdata) {
         if (arg_ifindex <= 0)
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Interface argument required.");
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.resolve1",
-                        "/org/freedesktop/resolve1",
-                        "org.freedesktop.resolve1.Manager",
-                        "RevertLink",
-                        &error,
-                        NULL,
-                "i", arg_ifindex);
+        r = bus_call_method(bus, bus_resolve_mgr, "RevertLink", &error, NULL, "i", arg_ifindex);
         if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
                 sd_bus_error_free(&error);
 
-                r = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.network1",
-                                "/org/freedesktop/network1",
-                                "org.freedesktop.network1.Manager",
-                                "RevertLinkDNS",
-                                &error,
-                                NULL,
-                                "i", arg_ifindex);
+                r = bus_call_method(bus, bus_network_mgr, "RevertLinkDNS", &error, NULL, "i", arg_ifindex);
         }
         if (r < 0) {
                 if (arg_ifindex_permissive &&
index f56166b94cdb999bb09ee4fa461137c794f85103..38d2483c24f54ea3726d97296c6a6ff0abca6e5c 100644 (file)
@@ -1116,7 +1116,7 @@ static void bus_method_resolve_service_complete(DnsQuery *q) {
 
         if (has_root_domain && found <= 0) {
                 /* If there's exactly one SRV RR and it uses
-                 * the root domain as host name, then the
+                 * the root domain as hostname, then the
                  * service is explicitly not offered on the
                  * domain. Report this as a recognizable
                  * error. See RFC 2782, Section "Usage
@@ -1855,166 +1855,129 @@ static const sd_bus_vtable resolve_vtable[] = {
         SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", bus_property_get_ntas, 0, 0),
         SD_BUS_PROPERTY("DNSStubListener", "s", bus_property_get_dns_stub_listener_mode, offsetof(Manager, dns_stub_listener_mode), 0),
 
-        SD_BUS_METHOD_WITH_NAMES("ResolveHostname",
-                                 "isit",
-                                 SD_BUS_PARAM(ifindex)
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(family)
-                                 SD_BUS_PARAM(flags),
-                                 "a(iiay)st",
-                                 SD_BUS_PARAM(addresses)
-                                 SD_BUS_PARAM(canonical)
-                                 SD_BUS_PARAM(flags),
-                                 bus_method_resolve_hostname,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("ResolveAddress",
-                                 "iiayt",
-                                 SD_BUS_PARAM(ifindex)
-                                 SD_BUS_PARAM(family)
-                                 SD_BUS_PARAM(address)
-                                 SD_BUS_PARAM(flags),
-                                 "a(is)t",
-                                 SD_BUS_PARAM(names)
-                                 SD_BUS_PARAM(flags),
-                                 bus_method_resolve_address,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("ResolveRecord",
-                                 "isqqt",
-                                 SD_BUS_PARAM(ifindex)
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(class)
-                                 SD_BUS_PARAM(type)
-                                 SD_BUS_PARAM(flags),
-                                 "a(iqqay)t",
-                                 SD_BUS_PARAM(records)
-                                 SD_BUS_PARAM(flags),
-                                 bus_method_resolve_record,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("ResolveService",
-                                 "isssit",
-                                 SD_BUS_PARAM(ifindex)
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(type)
-                                 SD_BUS_PARAM(domain)
-                                 SD_BUS_PARAM(family)
-                                 SD_BUS_PARAM(flags),
-                                 "a(qqqsa(iiay)s)aayssst",
-                                 SD_BUS_PARAM(srv_data)
-                                 SD_BUS_PARAM(txt_data)
-                                 SD_BUS_PARAM(canonical_name)
-                                 SD_BUS_PARAM(canonical_type)
-                                 SD_BUS_PARAM(canonical_domain)
-                                 SD_BUS_PARAM(flags),
-                                 bus_method_resolve_service,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("GetLink",
-                                 "i",
-                                 SD_BUS_PARAM(ifindex),
-                                 "o",
-                                 SD_BUS_PARAM(path),
-                                 bus_method_get_link,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetLinkDNS",
-                                 "ia(iay)",
-                                 SD_BUS_PARAM(ifindex)
-                                 SD_BUS_PARAM(addresses),
-                                 NULL,,
-                                 bus_method_set_link_dns_servers,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetLinkDomains",
-                                 "ia(sb)",
-                                 SD_BUS_PARAM(ifindex)
-                                 SD_BUS_PARAM(domains),
-                                 NULL,,
-                                 bus_method_set_link_domains,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetLinkDefaultRoute",
-                                 "ib",
-                                 SD_BUS_PARAM(ifindex)
-                                 SD_BUS_PARAM(enable),
-                                 NULL,,
-                                 bus_method_set_link_default_route,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetLinkLLMNR",
-                                 "is",
-                                 SD_BUS_PARAM(ifindex)
-                                 SD_BUS_PARAM(mode),
-                                 NULL,,
-                                 bus_method_set_link_llmnr,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetLinkMulticastDNS",
-                                 "is",
-                                 SD_BUS_PARAM(ifindex)
-                                 SD_BUS_PARAM(mode),
-                                 NULL,,
-                                 bus_method_set_link_mdns,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetLinkDNSOverTLS",
-                                 "is",
-                                 SD_BUS_PARAM(ifindex)
-                                 SD_BUS_PARAM(mode),
-                                 NULL,,
-                                 bus_method_set_link_dns_over_tls,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetLinkDNSSEC",
-                                 "is",
-                                 SD_BUS_PARAM(ifindex)
-                                 SD_BUS_PARAM(mode),
-                                 NULL,,
-                                 bus_method_set_link_dnssec,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetLinkDNSSECNegativeTrustAnchors",
-                                 "ias",
-                                 SD_BUS_PARAM(ifindex)
-                                 SD_BUS_PARAM(names),
-                                 NULL,,
-                                 bus_method_set_link_dnssec_negative_trust_anchors,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("RevertLink",
-                                 "i",
-                                 SD_BUS_PARAM(ifindex),
-                                 NULL,,
-                                 bus_method_revert_link,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("RegisterService",
-                                 "sssqqqaa{say}",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(name_template)
-                                 SD_BUS_PARAM(type)
-                                 SD_BUS_PARAM(service_port)
-                                 SD_BUS_PARAM(service_priority)
-                                 SD_BUS_PARAM(serwise_weight)
-                                 SD_BUS_PARAM(txt_datas),
-                                 "o",
-                                 SD_BUS_PARAM(service_path),
-                                 bus_method_register_service,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("UnregisterService",
-                                 "o",
-                                 SD_BUS_PARAM(service_path),
-                                 NULL,,
-                                 bus_method_unregister_service,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-
-        SD_BUS_METHOD("ResetStatistics",
-                      NULL,
-                      NULL,
-                      bus_method_reset_statistics,
-                      SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("FlushCaches",
-                      NULL,
-                      NULL,
-                      bus_method_flush_caches,
-                      SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("ResetServerFeatures",
-                      NULL,
-                      NULL,
-                      bus_method_reset_server_features,
-                      SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ResolveHostname",
+                                SD_BUS_ARGS("i", ifindex, "s", name, "i", family, "t", flags),
+                                SD_BUS_RESULT("a(iiay)", addresses, "s", canonical, "t", flags),
+                                bus_method_resolve_hostname,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ResolveAddress",
+                                SD_BUS_ARGS("i",  ifindex, "i", family, "ay", address, "t", flags),
+                                SD_BUS_RESULT("a(is)", names, "t", flags),
+                                bus_method_resolve_address,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ResolveRecord",
+                                SD_BUS_ARGS("i", ifindex, "s", name, "q", class, "q", type, "t", flags),
+                                SD_BUS_RESULT("a(iqqay)", records, "t", flags),
+                                bus_method_resolve_record,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ResolveService",
+                                SD_BUS_ARGS("i", ifindex,
+                                            "s", name,
+                                            "s", type,
+                                            "s", domain,
+                                            "i", family,
+                                            "t", flags),
+                                SD_BUS_RESULT("a(qqqsa(iiay)s)", srv_data,
+                                              "aay", txt_data,
+                                              "s", canonical_name,
+                                              "s", canonical_type,
+                                              "s", canonical_domain,
+                                              "t", flags),
+                                bus_method_resolve_service,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetLink",
+                                SD_BUS_ARGS("i", ifindex),
+                                SD_BUS_RESULT("o", path),
+                                bus_method_get_link,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetLinkDNS",
+                                SD_BUS_ARGS("i", ifindex, "a(iay)", addresses),
+                                SD_BUS_NO_RESULT,
+                                bus_method_set_link_dns_servers,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetLinkDomains",
+                                SD_BUS_ARGS("i", ifindex, "a(sb)", domains),
+                                SD_BUS_NO_RESULT,
+                                bus_method_set_link_domains,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetLinkDefaultRoute",
+                                SD_BUS_ARGS("i", ifindex, "b", enable),
+                                SD_BUS_NO_RESULT,
+                                bus_method_set_link_default_route,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetLinkLLMNR",
+                                SD_BUS_ARGS("i", ifindex, "s", mode),
+                                SD_BUS_NO_RESULT,
+                                bus_method_set_link_llmnr,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetLinkMulticastDNS",
+                                SD_BUS_ARGS("i", ifindex, "s", mode),
+                                SD_BUS_NO_RESULT,
+                                bus_method_set_link_mdns,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetLinkDNSOverTLS",
+                                SD_BUS_ARGS("i", ifindex, "s", mode),
+                                SD_BUS_NO_RESULT,
+                                bus_method_set_link_dns_over_tls,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetLinkDNSSEC",
+                                SD_BUS_ARGS("i", ifindex, "s", mode),
+                                SD_BUS_NO_RESULT,
+                                bus_method_set_link_dnssec,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetLinkDNSSECNegativeTrustAnchors",
+                                SD_BUS_ARGS("i", ifindex, "as", names),
+                                SD_BUS_NO_RESULT,
+                                bus_method_set_link_dnssec_negative_trust_anchors,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("RevertLink",
+                                SD_BUS_ARGS("i", ifindex),
+                                SD_BUS_NO_RESULT,
+                                bus_method_revert_link,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("RegisterService",
+                                SD_BUS_ARGS("s", name,
+                                            "s", name_template,
+                                            "s", type,
+                                            "q", service_port,
+                                            "q", service_priority,
+                                            "q", service_weight,
+                                            "aa{say}", txt_datas),
+                                SD_BUS_RESULT("o", service_path),
+                                bus_method_register_service,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("UnregisterService",
+                                SD_BUS_ARGS("o", service_path),
+                                SD_BUS_NO_RESULT,
+                                bus_method_unregister_service,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ResetStatistics",
+                                SD_BUS_NO_ARGS,
+                                SD_BUS_NO_RESULT,
+                                bus_method_reset_statistics,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("FlushCaches",
+                                SD_BUS_NO_ARGS,
+                                SD_BUS_NO_RESULT,
+                                bus_method_flush_caches,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ResetServerFeatures",
+                                SD_BUS_NO_ARGS,
+                                SD_BUS_NO_RESULT,
+                                bus_method_reset_server_features,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
 
         SD_BUS_VTABLE_END,
 };
 
+const BusObjectImplementation manager_object = {
+        "/org/freedesktop/resolve1",
+        "org.freedesktop.resolve1.Manager",
+        .vtables = BUS_VTABLES(resolve_vtable),
+        .children = BUS_IMPLEMENTATIONS(&link_object,
+                                        &dnssd_object),
+};
+
 static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
         Manager *m = userdata;
         int b, r;
@@ -2049,25 +2012,9 @@ int manager_connect_bus(Manager *m) {
         if (r < 0)
                 return log_error_errno(r, "Failed to connect to system bus: %m");
 
-        r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", resolve_vtable, m);
-        if (r < 0)
-                return log_error_errno(r, "Failed to register object: %m");
-
-        r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/resolve1/link", "org.freedesktop.resolve1.Link", link_vtable, link_object_find, m);
-        if (r < 0)
-                return log_error_errno(r, "Failed to register link objects: %m");
-
-        r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/resolve1/link", link_node_enumerator, m);
+        r = bus_add_implementation(m->bus, &manager_object, m);
         if (r < 0)
-                return log_error_errno(r, "Failed to register link enumerator: %m");
-
-        r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/resolve1/dnssd", "org.freedesktop.resolve1.DnssdService", dnssd_vtable, dnssd_object_find, m);
-        if (r < 0)
-                return log_error_errno(r, "Failed to register dnssd objects: %m");
-
-        r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/resolve1/dnssd", dnssd_node_enumerator, m);
-        if (r < 0)
-                return log_error_errno(r, "Failed to register dnssd enumerator: %m");
+                return r;
 
         r = bus_log_control_api_register(m->bus);
         if (r < 0)
index a499f76ad573ecce82d9475dba97152eb6a9fd8d..e69171ca709baec5e4032c366403e92d7c475b4c 100644 (file)
@@ -1,8 +1,11 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include "bus-util.h"
 #include "resolved-manager.h"
 
+extern const BusObjectImplementation manager_object;
+
 int manager_connect_bus(Manager *m);
 int _manager_send_changed(Manager *manager, const char *property, ...) _sentinel_;
 #define manager_send_changed(manager, ...) _manager_send_changed(manager, __VA_ARGS__, NULL)
index ca5b8e7918391c782eb2a3fd31c675f9943b3910..e915343c01216051e85e8bf5692d7c5c14e1e34b 100644 (file)
@@ -8,7 +8,10 @@
 #include "parse-util.h"
 #include "resolved-conf.h"
 #include "resolved-dnssd.h"
-#include "resolved-util.h"
+#include "resolved-manager.h"
+#include "resolved-dns-search-domain.h"
+#include "dns-domain.h"
+#include "socket-netlink.h"
 #include "specifier.h"
 #include "string-table.h"
 #include "string-util.h"
@@ -218,10 +221,15 @@ int config_parse_search_domains(
 
 int config_parse_dnssd_service_name(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) {
         static const Specifier specifier_table[] = {
+                { 'm', specifier_machine_id,      NULL },
                 { 'b', specifier_boot_id,         NULL },
                 { 'H', specifier_host_name,       NULL },
-                { 'm', specifier_machine_id,      NULL },
                 { 'v', specifier_kernel_release,  NULL },
+                { 'a', specifier_architecture,    NULL },
+                { 'o', specifier_os_id,           NULL },
+                { 'w', specifier_os_version_id,   NULL },
+                { 'B', specifier_os_build_id,     NULL },
+                { 'W', specifier_os_variant_id,   NULL },
                 {}
         };
         DnssdService *s = userdata;
index 4713df587ba0ecc8ba4163b20ffa268b7d6c4c4b..ac3937cfaeec8e6053b062af12fa19dd61923a19 100644 (file)
@@ -14,7 +14,6 @@ enum DnsStubListenerMode {
         _DNS_STUB_LISTENER_MODE_INVALID = -1
 };
 
-#include "resolved-manager.h"
 #include "resolved-dns-server.h"
 
 int manager_parse_config_file(Manager *m);
index 5ee946bc7502be2ec10146d16281369a7a3af62d..fc7ccf553e9adb0580a134aea481bba9e9b4ec07 100644 (file)
@@ -10,8 +10,8 @@ typedef struct DnsQuery DnsQuery;
 
 #include "resolved-dns-answer.h"
 #include "resolved-dns-question.h"
-#include "resolved-dns-stream.h"
 #include "resolved-dns-search-domain.h"
+#include "resolved-dns-transaction.h"
 
 struct DnsQueryCandidate {
         DnsQuery *query;
index f4b45c4f20822a51e60a36fc4d26c913166bd832..974692be5b170380050082dab3ec05f72a147148 100644 (file)
@@ -2,18 +2,19 @@
 #pragma once
 
 #include "list.h"
+#include "ratelimit.h"
 
+typedef struct DnsQueryCandidate DnsQueryCandidate;
 typedef struct DnsScope DnsScope;
 
 #include "resolved-dns-cache.h"
 #include "resolved-dns-dnssec.h"
 #include "resolved-dns-packet.h"
-#include "resolved-dns-query.h"
+
 #include "resolved-dns-search-domain.h"
 #include "resolved-dns-server.h"
 #include "resolved-dns-stream.h"
 #include "resolved-dns-zone.h"
-#include "resolved-link.h"
 
 typedef enum DnsScopeMatch {
         DNS_SCOPE_NO,
index 21c2442c516b7698a765bf6aec6f67fcefc6826e..425a46334948c7531cc37877c69f06c52fe7135a 100644 (file)
@@ -3,6 +3,8 @@
 #include "alloc-util.h"
 #include "dns-domain.h"
 #include "resolved-dns-search-domain.h"
+#include "resolved-link.h"
+#include "resolved-manager.h"
 
 int dns_search_domain_new(
                 Manager *m,
index d0c2914d367920742a2bb80369fedd1cb01f0989..df0b2f14049928e072de232462ba295fe74a2879 100644 (file)
@@ -1,18 +1,18 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include "list.h"
 #include "macro.h"
 
 typedef struct DnsSearchDomain DnsSearchDomain;
+typedef struct Link Link;
+typedef struct Manager Manager;
 
 typedef enum DnsSearchDomainType {
         DNS_SEARCH_DOMAIN_SYSTEM,
         DNS_SEARCH_DOMAIN_LINK,
 } DnsSearchDomainType;
 
-#include "resolved-link.h"
-#include "resolved-manager.h"
-
 struct DnsSearchDomain {
         Manager *manager;
 
index 4b0599ab9cf3df9e1f3bb839b0e304df44b0397c..106b002bc6dc498b601e8edc7f94c2c5de71f5f9 100644 (file)
@@ -6,6 +6,7 @@
 #include "resolved-bus.h"
 #include "resolved-dns-server.h"
 #include "resolved-dns-stub.h"
+#include "resolved-manager.h"
 #include "resolved-resolv-conf.h"
 #include "siphash24.h"
 #include "string-table.h"
index 889c80a2054bdaf488eb0632c8af0f6014796e46..792f966121b0eef5a1412108a52b9ae0dee78851 100644 (file)
@@ -2,8 +2,18 @@
 #pragma once
 
 #include "in-addr-util.h"
+#include "list.h"
+#include "resolve-util.h"
+#include "time-util.h"
 
+typedef struct DnsScope DnsScope;
 typedef struct DnsServer DnsServer;
+typedef struct DnsStream DnsStream;
+typedef struct DnsPacket DnsPacket;
+typedef struct Link Link;
+typedef struct Manager Manager;
+
+#include "resolved-dnstls.h"
 
 typedef enum DnsServerType {
         DNS_SERVER_SYSTEM,
@@ -35,10 +45,6 @@ typedef enum DnsServerFeatureLevel {
 const char* dns_server_feature_level_to_string(int i) _const_;
 int dns_server_feature_level_from_string(const char *s) _pure_;
 
-#include "resolved-dnstls.h"
-#include "resolved-link.h"
-#include "resolved-manager.h"
-
 struct DnsServer {
         Manager *manager;
 
index 2a106949976ea307ff34eb935eceaeb193e32375..bbaffc165ac3b9eb26818095f1e8c24427400129 100644 (file)
@@ -8,6 +8,7 @@
 #include "io-util.h"
 #include "missing_network.h"
 #include "resolved-dns-stream.h"
+#include "resolved-manager.h"
 
 #define DNS_STREAM_TIMEOUT_USEC (10 * USEC_PER_SEC)
 #define DNS_STREAMS_MAX 128
@@ -86,11 +87,8 @@ static int dns_stream_complete(DnsStream *s, int error) {
 }
 
 static int dns_stream_identify(DnsStream *s) {
-        union {
-                struct cmsghdr header; /* For alignment */
-                uint8_t buffer[CMSG_SPACE(MAXSIZE(struct in_pktinfo, struct in6_pktinfo))
-                               + EXTRA_CMSG_SPACE /* kernel appears to require extra space */];
-        } control;
+        CMSG_BUFFER_TYPE(CMSG_SPACE(MAXSIZE(struct in_pktinfo, struct in6_pktinfo))
+                         + EXTRA_CMSG_SPACE /* kernel appears to require extra space */) control;
         struct msghdr mh = {};
         struct cmsghdr *cmsg;
         socklen_t sl;
index 1013f6e45e6a0dc0cdff39ceae9ef6e70462024f..9fd8f5a342f2e16108cecc6a77154b99121743de 100644 (file)
@@ -1,9 +1,18 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include "sd-event.h"
+
+#include "ordered-set.h"
 #include "socket-util.h"
 
+typedef struct DnsServer DnsServer;
 typedef struct DnsStream DnsStream;
+typedef struct DnsTransaction DnsTransaction;
+typedef struct Manager Manager;
+
+#include "resolved-dns-packet.h"
+#include "resolved-dnstls.h"
 
 typedef enum DnsStreamType {
         DNS_STREAM_LOOKUP,        /* Outgoing connection to a classic DNS server */
@@ -14,11 +23,6 @@ typedef enum DnsStreamType {
         _DNS_STREAM_TYPE_INVALID = -1,
 } DnsStreamType;
 
-#include "resolved-dns-packet.h"
-#include "resolved-dns-transaction.h"
-#include "resolved-dnstls.h"
-#include "resolved-manager.h"
-
 #define DNS_STREAM_WRITE_TLS_DATA 1
 
 /* Streams are used by three subsystems:
index bdfcbc1acc3a791cdca98a1a156ee423789851d5..b1d4348409fc41aab1fa41e4b756acbf195078fb 100644 (file)
@@ -1,10 +1,18 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include "sd-event.h"
+
 typedef struct DnsTransaction DnsTransaction;
 typedef enum DnsTransactionState DnsTransactionState;
 typedef enum DnsTransactionSource DnsTransactionSource;
 
+#include "resolved-dns-answer.h"
+#include "resolved-dns-dnssec.h"
+#include "resolved-dns-packet.h"
+#include "resolved-dns-question.h"
+#include "resolved-dns-server.h"
+
 enum DnsTransactionState {
         DNS_TRANSACTION_NULL,
         DNS_TRANSACTION_PENDING,
@@ -37,13 +45,6 @@ enum DnsTransactionSource {
         _DNS_TRANSACTION_SOURCE_INVALID = -1
 };
 
-#include "resolved-dns-answer.h"
-#include "resolved-dns-packet.h"
-#include "resolved-dns-question.h"
-#include "resolved-dns-scope.h"
-#include "resolved-dns-server.h"
-#include "resolved-dns-stream.h"
-
 struct DnsTransaction {
         DnsScope *scope;
 
index 92842bcf89d43f8646b768f1b3333a8b88db4780..843f4c0f45fb6b6d6f8f5aa44137dbbe1c1eb4e3 100644 (file)
@@ -184,11 +184,10 @@ static int dns_trust_anchor_add_builtin_negative(DnsTrustAnchor *d) {
          * unsigned. */
 
         NULSTR_FOREACH(name, private_domains) {
-
                 if (dns_trust_anchor_knows_domain_positive(d, name))
                         continue;
 
-                r = set_put_strdup(d->negative_by_name, name);
+                r = set_put_strdup(&d->negative_by_name, name);
                 if (r < 0)
                         return r;
         }
index d5cc2767d7d7905154bacd902ee793e57076a983..0ef4c892f7066f9d9d64771935074866dc20299a 100644 (file)
@@ -6,6 +6,7 @@
 #include "resolved-dns-packet.h"
 #include "resolved-dns-zone.h"
 #include "resolved-dnssd.h"
+#include "resolved-manager.h"
 #include "string-util.h"
 
 /* Never allow more than 1K entries */
index f7dcb3bfa56f8fb4afc035e9ab165d3211129b21..33efb8ef06c6cc5833d2801d35dc10a04edf0dba 100644 (file)
@@ -6,6 +6,7 @@
 #include "resolved-dnssd-bus.h"
 #include "resolved-dnssd.h"
 #include "resolved-link.h"
+#include "resolved-manager.h"
 #include "strv.h"
 #include "user-util.h"
 
@@ -62,16 +63,7 @@ int bus_dnssd_method_unregister(sd_bus_message *message, void *userdata, sd_bus_
         return sd_bus_reply_method_return(message, NULL);
 }
 
-const sd_bus_vtable dnssd_vtable[] = {
-        SD_BUS_VTABLE_START(0),
-
-        SD_BUS_METHOD("Unregister", NULL, NULL, bus_dnssd_method_unregister, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_SIGNAL("Conflicted", NULL, 0),
-
-        SD_BUS_VTABLE_END
-};
-
-int dnssd_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
+static int dnssd_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
         _cleanup_free_ char *name = NULL;
         Manager *m = userdata;
         DnssdService *service;
@@ -95,7 +87,7 @@ int dnssd_object_find(sd_bus *bus, const char *path, const char *interface, void
         return 1;
 }
 
-int dnssd_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
+static int dnssd_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
         _cleanup_strv_free_ char **l = NULL;
         Manager *m = userdata;
         DnssdService *service;
@@ -127,3 +119,19 @@ int dnssd_node_enumerator(sd_bus *bus, const char *path, void *userdata, char **
 
         return 1;
 }
+
+static const sd_bus_vtable dnssd_vtable[] = {
+        SD_BUS_VTABLE_START(0),
+
+        SD_BUS_METHOD("Unregister", NULL, NULL, bus_dnssd_method_unregister, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_SIGNAL("Conflicted", NULL, 0),
+
+        SD_BUS_VTABLE_END
+};
+
+const BusObjectImplementation dnssd_object = {
+        "/org/freedesktop/resolve1/dnssd",
+        "org.freedesktop.resolve1.DnssdService",
+        .fallback_vtables = BUS_FALLBACK_VTABLES({dnssd_vtable, dnssd_object_find}),
+        .node_enumerator = dnssd_node_enumerator,
+};
index 9ee2ce17ec8c1eedf0d3671ffab46aaf24205230..8cd75642a7bda91163f953268a41130319758011 100644 (file)
@@ -2,9 +2,8 @@
 
 #include "sd-bus.h"
 
-extern const sd_bus_vtable dnssd_vtable[];
+#include "bus-util.h"
 
-int dnssd_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error);
-int dnssd_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error);
+extern const BusObjectImplementation dnssd_object;
 
 int bus_dnssd_method_unregister(sd_bus_message *message, void *userdata, sd_bus_error *error);
index 0e6fa1d0c96069365dedd1da0be3e741f35456eb..bc886fd0e0bd6b42b85ebe0bde0ce87862063de0 100644 (file)
@@ -153,10 +153,15 @@ static int specifier_dnssd_host_name(char specifier, const void *data, const voi
 
 int dnssd_render_instance_name(DnssdService *s, char **ret_name) {
         static const Specifier specifier_table[] = {
+                { 'm', specifier_machine_id,      NULL },
                 { 'b', specifier_boot_id,         NULL },
                 { 'H', specifier_dnssd_host_name, NULL },
-                { 'm', specifier_machine_id,      NULL },
                 { 'v', specifier_kernel_release,  NULL },
+                { 'a', specifier_architecture,    NULL },
+                { 'o', specifier_os_id,           NULL },
+                { 'w', specifier_os_version_id,   NULL },
+                { 'B', specifier_os_build_id,     NULL },
+                { 'W', specifier_os_variant_id,   NULL },
                 {}
         };
         _cleanup_free_ char *name = NULL;
index ef90a7d5ae941723b19a630dadf6f7c04a39ae94..6b7db7ef8c4a1f99a2114f5d24ba3d839008b244 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "resolved-dns-stream.h"
 #include "resolved-dnstls.h"
+#include "resolved-manager.h"
 
 #define TLS_PROTOCOL_PRIORITY "NORMAL:-VERS-ALL:+VERS-TLS1.3:+VERS-TLS1.2"
 DEFINE_TRIVIAL_CLEANUP_FUNC(gnutls_session_t, gnutls_deinit);
@@ -27,7 +28,7 @@ static ssize_t dnstls_stream_writev(gnutls_transport_ptr_t p, const giovec_t *io
 }
 
 int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) {
-        _cleanup_(gnutls_deinitp) gnutls_session_t gs;
+        _cleanup_(gnutls_deinitp) gnutls_session_t gs = NULL;
         int r;
 
         assert(stream);
index 7763cbcb5acb31add7153b05a78f57cf3e4020bf..f95738649df7115ce02af3af612335fc602db05e 100644 (file)
@@ -11,6 +11,7 @@
 #include "io-util.h"
 #include "resolved-dns-stream.h"
 #include "resolved-dnstls.h"
+#include "resolved-manager.h"
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(SSL*, SSL_free);
 DEFINE_TRIVIAL_CLEANUP_FUNC(BIO*, BIO_free);
index 1b9121171e98d55f3fa6c04786170857943e5097..6199335b7091682f3b5f8cb8bd5c580ff03fb4c3 100644 (file)
@@ -3,9 +3,14 @@
 
 #if ENABLE_DNS_OVER_TLS
 
+#include <stdint.h>
+
+typedef struct DnsServer DnsServer;
+typedef struct DnsStream DnsStream;
 typedef struct DnsTlsManagerData DnsTlsManagerData;
 typedef struct DnsTlsServerData DnsTlsServerData;
 typedef struct DnsTlsStreamData DnsTlsStreamData;
+typedef struct Manager Manager;
 
 #if DNS_OVER_TLS_USE_GNUTLS
 #include "resolved-dnstls-gnutls.h"
@@ -15,10 +20,6 @@ typedef struct DnsTlsStreamData DnsTlsStreamData;
 #error Unknown dependency for supporting DNS-over-TLS
 #endif
 
-#include "resolved-dns-stream.h"
-#include "resolved-dns-transaction.h"
-#include "resolved-manager.h"
-
 #define DNSTLS_STREAM_CLOSED 1
 
 int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server);
index c2839d425ad256e6eac44fbeb8e7b16a74e2fe6b..2cb06c098da929f1b3ad4c63395226d22fd39fee 100644 (file)
@@ -100,7 +100,7 @@ static int parse_line(EtcHosts *hosts, unsigned nr, const char *line) {
 
                 r = extract_first_word(&line, &name, NULL, EXTRACT_RELAX);
                 if (r < 0)
-                        return log_error_errno(r, "/etc/hosts:%u: couldn't extract host name: %m", nr);
+                        return log_error_errno(r, "/etc/hosts:%u: couldn't extract hostname: %m", nr);
                 if (r == 0)
                         break;
 
@@ -162,7 +162,7 @@ static int parse_line(EtcHosts *hosts, unsigned nr, const char *line) {
         }
 
         if (!found)
-                log_warning("/etc/hosts:%u: line is missing any host names", nr);
+                log_warning("/etc/hosts:%u: line is missing any hostnames", nr);
 
         return 0;
 }
index 049fe9ebddafaa3aee42db68fe35ba7b50ddd758..4a451ccc4c7f9c36aa584b9b171345bde160315d 100644 (file)
@@ -5,6 +5,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
 #include <stddef.h>
 #include "conf-parser.h"
 #include "resolved-conf.h"
+#include "resolved-manager.h"
 %}
 struct ConfigPerfItem;
 %null_strings
@@ -26,4 +27,4 @@ Resolve.DNSSEC,          config_parse_dnssec_mode,            0,
 Resolve.DNSOverTLS,      config_parse_dns_over_tls_mode,      0,                   offsetof(Manager, dns_over_tls_mode)
 Resolve.Cache,           config_parse_dns_cache_mode,         DNS_CACHE_MODE_YES,  offsetof(Manager, enable_cache)
 Resolve.DNSStubListener, config_parse_dns_stub_listener_mode, 0,                   offsetof(Manager, dns_stub_listener_mode)
-Resolve.ReadEtcHosts,    config_parse_bool,                   0,                   offsetof(Manager, read_etc_hosts)
\ No newline at end of file
+Resolve.ReadEtcHosts,    config_parse_bool,                   0,                   offsetof(Manager, read_etc_hosts)
index a2d61f398d405dc29d1bbbfa690530c8a7af0e53..a2ca5cb8f608dd881a0db5f5ece40e7f3b1fab18 100644 (file)
@@ -629,7 +629,7 @@ int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, v
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
                                                  "Invalid negative trust anchor domain: %s", *i);
 
-                r = set_put_strdup(ns, *i);
+                r = set_put_strdup(&ns, *i);
                 if (r < 0)
                         return r;
         }
@@ -682,76 +682,7 @@ int bus_link_method_revert(sd_bus_message *message, void *userdata, sd_bus_error
         return sd_bus_reply_method_return(message, NULL);
 }
 
-const sd_bus_vtable link_vtable[] = {
-        SD_BUS_VTABLE_START(0),
-
-        SD_BUS_PROPERTY("ScopesMask", "t", property_get_scopes_mask, 0, 0),
-        SD_BUS_PROPERTY("DNS", "a(iay)", property_get_dns, 0, 0),
-        SD_BUS_PROPERTY("CurrentDNSServer", "(iay)", property_get_current_dns_server, offsetof(Link, current_dns_server), 0),
-        SD_BUS_PROPERTY("Domains", "a(sb)", property_get_domains, 0, 0),
-        SD_BUS_PROPERTY("DefaultRoute", "b", property_get_default_route, 0, 0),
-        SD_BUS_PROPERTY("LLMNR", "s", bus_property_get_resolve_support, offsetof(Link, llmnr_support), 0),
-        SD_BUS_PROPERTY("MulticastDNS", "s", bus_property_get_resolve_support, offsetof(Link, mdns_support), 0),
-        SD_BUS_PROPERTY("DNSOverTLS", "s", property_get_dns_over_tls_mode, 0, 0),
-        SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode, 0, 0),
-        SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", property_get_ntas, 0, 0),
-        SD_BUS_PROPERTY("DNSSECSupported", "b", property_get_dnssec_supported, 0, 0),
-
-        SD_BUS_METHOD_WITH_NAMES("SetDNS",
-                                 "a(iay)",
-                                 SD_BUS_PARAM(addresses),
-                                 NULL,,
-                                 bus_link_method_set_dns_servers,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetDomains",
-                                 "a(sb)",
-                                 SD_BUS_PARAM(domains),
-                                 NULL,,
-                                 bus_link_method_set_domains,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetDefaultRoute",
-                                 "b",
-                                 SD_BUS_PARAM(enable),
-                                 NULL,,
-                                 bus_link_method_set_default_route,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetLLMNR",
-                                 "s",
-                                 SD_BUS_PARAM(mode),
-                                 NULL,,
-                                 bus_link_method_set_llmnr,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetMulticastDNS",
-                                 "s",
-                                 SD_BUS_PARAM(mode),
-                                 NULL,,
-                                 bus_link_method_set_mdns,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetDNSOverTLS",
-                                 "s",
-                                 SD_BUS_PARAM(mode),
-                                 NULL,,
-                                 bus_link_method_set_dns_over_tls,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetDNSSEC",
-                                 "s",
-                                 SD_BUS_PARAM(mode),
-                                 NULL,,
-                                 bus_link_method_set_dnssec,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetDNSSECNegativeTrustAnchors",
-                                 "as",
-                                 SD_BUS_PARAM(names),
-                                 NULL,,
-                                 bus_link_method_set_dnssec_negative_trust_anchors,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-
-        SD_BUS_METHOD("Revert", NULL, NULL, bus_link_method_revert, SD_BUS_VTABLE_UNPRIVILEGED),
-
-        SD_BUS_VTABLE_END
-};
-
-int link_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
+static int link_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
         _cleanup_free_ char *e = NULL;
         Manager *m = userdata;
         Link *link;
@@ -794,7 +725,7 @@ char *link_bus_path(const Link *link) {
         return p;
 }
 
-int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
+static int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
         _cleanup_strv_free_ char **l = NULL;
         Manager *m = userdata;
         Link *link;
@@ -825,3 +756,74 @@ int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***
 
         return 1;
 }
+
+static const sd_bus_vtable link_vtable[] = {
+        SD_BUS_VTABLE_START(0),
+
+        SD_BUS_PROPERTY("ScopesMask", "t", property_get_scopes_mask, 0, 0),
+        SD_BUS_PROPERTY("DNS", "a(iay)", property_get_dns, 0, 0),
+        SD_BUS_PROPERTY("CurrentDNSServer", "(iay)", property_get_current_dns_server, offsetof(Link, current_dns_server), 0),
+        SD_BUS_PROPERTY("Domains", "a(sb)", property_get_domains, 0, 0),
+        SD_BUS_PROPERTY("DefaultRoute", "b", property_get_default_route, 0, 0),
+        SD_BUS_PROPERTY("LLMNR", "s", bus_property_get_resolve_support, offsetof(Link, llmnr_support), 0),
+        SD_BUS_PROPERTY("MulticastDNS", "s", bus_property_get_resolve_support, offsetof(Link, mdns_support), 0),
+        SD_BUS_PROPERTY("DNSOverTLS", "s", property_get_dns_over_tls_mode, 0, 0),
+        SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode, 0, 0),
+        SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", property_get_ntas, 0, 0),
+        SD_BUS_PROPERTY("DNSSECSupported", "b", property_get_dnssec_supported, 0, 0),
+
+        SD_BUS_METHOD_WITH_ARGS("SetDNS",
+                                SD_BUS_ARGS("a(iay)", addresses),
+                                SD_BUS_NO_RESULT,
+                                bus_link_method_set_dns_servers,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetDomains",
+                                SD_BUS_ARGS("a(sb)", domains),
+                                SD_BUS_NO_RESULT,
+                                bus_link_method_set_domains,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetDefaultRoute",
+                                SD_BUS_ARGS("b", enable),
+                                SD_BUS_NO_RESULT,
+                                bus_link_method_set_default_route,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetLLMNR",
+                                SD_BUS_ARGS("s", mode),
+                                SD_BUS_NO_RESULT,
+                                bus_link_method_set_llmnr,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetMulticastDNS",
+                                SD_BUS_ARGS("s", mode),
+                                SD_BUS_NO_RESULT,
+                                bus_link_method_set_mdns,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetDNSOverTLS",
+                                SD_BUS_ARGS("s", mode),
+                                SD_BUS_NO_RESULT,
+                                bus_link_method_set_dns_over_tls,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetDNSSEC",
+                                SD_BUS_ARGS("s", mode),
+                                SD_BUS_NO_RESULT,
+                                bus_link_method_set_dnssec,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetDNSSECNegativeTrustAnchors",
+                                SD_BUS_ARGS("as", names),
+                                SD_BUS_NO_RESULT,
+                                bus_link_method_set_dnssec_negative_trust_anchors,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("Revert",
+                                SD_BUS_NO_ARGS,
+                                SD_BUS_NO_RESULT,
+                                bus_link_method_revert,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+
+        SD_BUS_VTABLE_END
+};
+
+const BusObjectImplementation link_object = {
+        "/org/freedesktop/resolve1/link",
+        "org.freedesktop.resolve1.Link",
+        .fallback_vtables = BUS_FALLBACK_VTABLES({link_vtable, link_object_find}),
+        .node_enumerator = link_node_enumerator,
+};
index 74068a4777110b11de319ce349a09a28718a7ccf..c24996002437f106b02dde776c1ac05afe25ec94 100644 (file)
@@ -3,13 +3,12 @@
 
 #include "sd-bus.h"
 
+#include "bus-util.h"
 #include "resolved-link.h"
 
-extern const sd_bus_vtable link_vtable[];
+extern const BusObjectImplementation link_object;
 
-int link_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error);
 char *link_bus_path(const Link *link);
-int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error);
 
 int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error);
index f19fc2f3aa12d480188faedea3048c5ff8b7b2b0..5eb184a10f38e48919d5dfc0754180a7f958953c 100644 (file)
@@ -493,7 +493,7 @@ static int link_update_dnssec_negative_trust_anchors(Link *l) {
         if (!ns)
                 return -ENOMEM;
 
-        r = set_put_strdupv(ns, ntas);
+        r = set_put_strdupv(&ns, ntas);
         if (r < 0)
                 return r;
 
index 4b545a553688160503d3423b1bd55e00646c8236..44d489ce4792435fbe61f2e862ca82ffeb21b041 100644 (file)
@@ -1,6 +1,8 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include "sd-netlink.h"
+
 #include "in-addr-util.h"
 #include "ratelimit.h"
 #include "resolve-util.h"
@@ -12,7 +14,6 @@ typedef struct LinkAddress LinkAddress;
 #include "resolved-dns-scope.h"
 #include "resolved-dns-search-domain.h"
 #include "resolved-dns-server.h"
-#include "resolved-manager.h"
 
 #define LINK_SEARCH_DOMAINS_MAX 256
 #define LINK_DNS_SERVERS_MAX 256
index 94590e3038673ef03a798edd5fbff7c9a625451f..1da590b68acc418056c3fdc229e273b14b785f50 100644 (file)
@@ -341,7 +341,7 @@ static int determine_hostname(char **full_hostname, char **llmnr_hostname, char
         p = h;
         r = dns_label_unescape(&p, label, sizeof label, 0);
         if (r < 0)
-                return log_error_errno(r, "Failed to unescape host name: %m");
+                return log_error_errno(r, "Failed to unescape hostname: %m");
         if (r == 0)
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                        "Couldn't find a single label in hostname.");
@@ -371,7 +371,7 @@ static int determine_hostname(char **full_hostname, char **llmnr_hostname, char
 
         r = dns_label_escape_new(decoded, r, &n);
         if (r < 0)
-                return log_error_errno(r, "Failed to escape host name: %m");
+                return log_error_errno(r, "Failed to escape hostname: %m");
 
         if (is_localhost(n))
                 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
@@ -411,7 +411,7 @@ static int make_fallback_hostnames(char **full_hostname, char **llmnr_hostname,
         p = fallback_hostname();
         r = dns_label_unescape(&p, label, sizeof label, 0);
         if (r < 0)
-                return log_error_errno(r, "Failed to unescape fallback host name: %m");
+                return log_error_errno(r, "Failed to unescape fallback hostname: %m");
 
         assert(r > 0); /* The fallback hostname must have at least one label */
 
@@ -741,12 +741,9 @@ Manager *manager_free(Manager *m) {
 
 int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
         _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
-        union {
-                struct cmsghdr header; /* For alignment */
-                uint8_t buffer[CMSG_SPACE(MAXSIZE(struct in_pktinfo, struct in6_pktinfo))
-                               + CMSG_SPACE(int) /* ttl/hoplimit */
-                               + EXTRA_CMSG_SPACE /* kernel appears to require extra buffer space */];
-        } control;
+        CMSG_BUFFER_TYPE(CMSG_SPACE(MAXSIZE(struct in_pktinfo, struct in6_pktinfo))
+                         + CMSG_SPACE(int) /* ttl/hoplimit */
+                         + EXTRA_CMSG_SPACE /* kernel appears to require extra buffer space */) control;
         union sockaddr_union sa;
         struct iovec iov;
         struct msghdr mh = {
@@ -775,17 +772,14 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
 
         iov = IOVEC_MAKE(DNS_PACKET_DATA(p), p->allocated);
 
-        l = recvmsg(fd, &mh, 0);
-        if (l < 0) {
-                if (IN_SET(errno, EAGAIN, EINTR))
-                        return 0;
-
-                return -errno;
-        }
+        l = recvmsg_safe(fd, &mh, 0);
+        if (IN_SET(l, -EAGAIN, -EINTR))
+                return 0;
+        if (l < 0)
+                return l;
         if (l == 0)
                 return 0;
 
-        assert(!(mh.msg_flags & MSG_CTRUNC));
         assert(!(mh.msg_flags & MSG_TRUNC));
 
         p->size = (size_t) l;
@@ -933,10 +927,8 @@ static int manager_ipv4_send(
                 uint16_t port,
                 const struct in_addr *source,
                 DnsPacket *p) {
-        union {
-                struct cmsghdr header; /* For alignment */
-                uint8_t buffer[CMSG_SPACE(sizeof(struct in_pktinfo))];
-        } control = {};
+
+        CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct in_pktinfo))) control = {};
         union sockaddr_union sa;
         struct iovec iov;
         struct msghdr mh = {
@@ -965,10 +957,10 @@ static int manager_ipv4_send(
                 struct in_pktinfo *pi;
 
                 mh.msg_control = &control;
-                mh.msg_controllen = CMSG_LEN(sizeof(struct in_pktinfo));
+                mh.msg_controllen = sizeof(control);
 
                 cmsg = CMSG_FIRSTHDR(&mh);
-                cmsg->cmsg_len = mh.msg_controllen;
+                cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
                 cmsg->cmsg_level = IPPROTO_IP;
                 cmsg->cmsg_type = IP_PKTINFO;
 
@@ -991,10 +983,7 @@ static int manager_ipv6_send(
                 const struct in6_addr *source,
                 DnsPacket *p) {
 
-        union {
-                struct cmsghdr header; /* For alignment */
-                uint8_t buffer[CMSG_SPACE(sizeof(struct in6_pktinfo))];
-        } control = {};
+        CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct in6_pktinfo))) control = {};
         union sockaddr_union sa;
         struct iovec iov;
         struct msghdr mh = {
@@ -1024,10 +1013,10 @@ static int manager_ipv6_send(
                 struct in6_pktinfo *pi;
 
                 mh.msg_control = &control;
-                mh.msg_controllen = CMSG_LEN(sizeof(struct in6_pktinfo));
+                mh.msg_controllen = sizeof(control);
 
                 cmsg = CMSG_FIRSTHDR(&mh);
-                cmsg->cmsg_len = mh.msg_controllen;
+                cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
                 cmsg->cmsg_level = IPPROTO_IPV6;
                 cmsg->cmsg_type = IPV6_PKTINFO;
 
index 446f258b49ba63dd99de01944e6caf31dedde2fa..cbaef5e49c65f986b6530774c419df1ef094249f 100644 (file)
@@ -1,6 +1,8 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include <sys/stat.h>
+
 #include "sd-event.h"
 #include "sd-netlink.h"
 #include "sd-network.h"
@@ -15,10 +17,8 @@ typedef struct Manager Manager;
 #include "resolved-conf.h"
 #include "resolved-dns-query.h"
 #include "resolved-dns-search-domain.h"
-#include "resolved-dns-server.h"
 #include "resolved-dns-stream.h"
 #include "resolved-dns-trust-anchor.h"
-#include "resolved-dnstls.h"
 #include "resolved-link.h"
 
 #define MANAGER_SEARCH_DOMAINS_MAX 256
@@ -73,7 +73,7 @@ struct Manager {
         bool need_builtin_fallbacks:1;
 
         bool read_resolv_conf:1;
-        usec_t resolv_conf_mtime;
+        struct stat resolv_conf_stat;
 
         DnsTrustAnchor trust_anchor;
 
@@ -167,6 +167,7 @@ void manager_verify_all(Manager *m);
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
 
+/* For some reason we need some extra cmsg space on some kernels/archs. One of those days we ned to figure out why */
 #define EXTRA_CMSG_SPACE 1024
 
 int manager_is_own_hostname(Manager *m, const char *name);
index c06213f4867fd2bed64e5a60436c926daea03ce7..97aee7abc816ba756e83bad37212c9bac92f02a4 100644 (file)
@@ -14,6 +14,7 @@
 #include "resolved-conf.h"
 #include "resolved-dns-server.h"
 #include "resolved-resolv-conf.h"
+#include "stat-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "tmpfile-util-label.h"
@@ -93,7 +94,7 @@ int manager_read_resolv_conf(Manager *m) {
         }
 
         /* Have we already seen the file? */
-        if (timespec_load(&st.st_mtim) == m->resolv_conf_mtime)
+        if (stat_inode_unmodified(&st, &m->resolv_conf_stat))
                 return 0;
 
         if (file_is_our_own(&st))
@@ -159,7 +160,7 @@ int manager_read_resolv_conf(Manager *m) {
                 log_syntax(NULL, LOG_DEBUG, "/etc/resolv.conf", n, 0, "Ignoring resolv.conf line: %s", l);
         }
 
-        m->resolv_conf_mtime = timespec_load(&st.st_mtim);
+        m->resolv_conf_stat = st;
 
         /* Flush out all servers and search domains that are still
          * marked. Those are then ones that didn't appear in the new
diff --git a/src/resolve/resolved-util.c b/src/resolve/resolved-util.c
deleted file mode 100644 (file)
index ac8df63..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
-
-#include "alloc-util.h"
-#include "macro.h"
-#include "resolved-util.h"
-#include "socket-netlink.h"
-
-int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name) {
-        _cleanup_free_ char *buf = NULL, *name = NULL;
-        const char *m;
-        int r;
-
-        assert(s);
-
-        m = strchr(s, '#');
-        if (m) {
-                name = strdup(m+1);
-                if (!name)
-                        return -ENOMEM;
-
-                buf = strndup(s, m - s);
-                if (!buf)
-                        return -ENOMEM;
-
-                s = buf;
-        }
-
-        r = in_addr_ifindex_from_string_auto(s, family, ret, ifindex);
-        if (r < 0)
-                return r;
-
-        if (server_name)
-                *server_name = TAKE_PTR(name);
-
-        return r;
-}
diff --git a/src/resolve/resolved-util.h b/src/resolve/resolved-util.h
deleted file mode 100644 (file)
index 10ebbc0..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
-#pragma once
-
-#include "in-addr-util.h"
-
-int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name);
index 27848cccae7bc3e854489301a92cdd3c069e79e3..50989a6b0a33ff63f76ea36e0b0925606a010187 100644 (file)
@@ -7,14 +7,17 @@
 #include "sd-daemon.h"
 #include "sd-event.h"
 
+#include "bus-log-control-api.h"
 #include "capability-util.h"
 #include "daemon-util.h"
 #include "main-func.h"
 #include "mkdir.h"
+#include "resolved-bus.h"
 #include "resolved-conf.h"
 #include "resolved-manager.h"
 #include "resolved-resolv-conf.h"
 #include "selinux-util.h"
+#include "service-util.h"
 #include "signal-util.h"
 #include "user-util.h"
 
@@ -25,8 +28,13 @@ static int run(int argc, char *argv[]) {
 
         log_setup_service();
 
-        if (argc != 1)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments.");
+        r = service_parse_argv("systemd-resolved.service",
+                               "Provide name resolution with caching using DNS, mDNS, LLMNR.",
+                               BUS_IMPLEMENTATIONS(&manager_object,
+                                                   &log_control_object),
+                               argc, argv);
+        if (r <= 0)
+                return r;
 
         umask(0022);
 
diff --git a/src/resolve/test-resolved-util.c b/src/resolve/test-resolved-util.c
deleted file mode 100644 (file)
index 35bd73c..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
-
-#include "log.h"
-#include "resolved-util.h"
-#include "string-util.h"
-#include "tests.h"
-
-
-static void test_in_addr_ifindex_name_from_string_auto_one(const char *a, const char *expected) {
-        int family, ifindex;
-        union in_addr_union ua;
-        _cleanup_free_ char *server_name = NULL;
-
-        assert_se(in_addr_ifindex_name_from_string_auto(a, &family, &ua, &ifindex, &server_name) >= 0);
-        assert_se(streq_ptr(server_name, expected));
-}
-
-static void test_in_addr_ifindex_name_from_string_auto(void) {
-        log_info("/* %s */", __func__);
-
-        test_in_addr_ifindex_name_from_string_auto_one("192.168.0.1", NULL);
-        test_in_addr_ifindex_name_from_string_auto_one("192.168.0.1#test.com", "test.com");
-        test_in_addr_ifindex_name_from_string_auto_one("fe80::18%19", NULL);
-        test_in_addr_ifindex_name_from_string_auto_one("fe80::18%19#another.test.com", "another.test.com");
-}
-
-int main(int argc, char **argv) {
-        test_setup_logging(LOG_DEBUG);
-
-        test_in_addr_ifindex_name_from_string_auto();
-        return 0;
-}
index ea49d5dab558720ac07438ba3ec14b56f8ee5f29..8761dc5d07f89dc2709c280a09c3bd9f039b6f54 100644 (file)
@@ -1166,13 +1166,7 @@ static int start_transient_service(
                         return r;
         }
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &m,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "StartTransientUnit");
+        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "StartTransientUnit");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -1420,13 +1414,7 @@ static int start_transient_scope(sd_bus *bus) {
                         return r;
         }
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &m,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "StartTransientUnit");
+        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "StartTransientUnit");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -1610,13 +1598,7 @@ static int start_transient_trigger(
                         return log_error_errno(r, "Failed to change unit suffix: %m");
         }
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &m,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "StartTransientUnit");
+        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "StartTransientUnit");
         if (r < 0)
                 return bus_log_create_error(r);
 
index d565ebd43e655108b03930c4ac6b4a31a4cd993c..38c464c912a53e4f2c76ed7b37ce169d4f95930b 100644 (file)
@@ -23,7 +23,7 @@ struct acpi_table_header {
         uint32_t oem_revision;
         char asl_compiler_id[4];
         uint32_t asl_compiler_revision;
-};
+} _packed_;
 
 enum {
         ACPI_FPDT_TYPE_BOOT =   0,
@@ -36,12 +36,12 @@ struct acpi_fpdt_header {
         uint8_t revision;
         uint8_t reserved[4];
         uint64_t ptr;
-};
+} _packed_;
 
 struct acpi_fpdt_boot_header {
         char signature[4];
         uint32_t length;
-};
+} _packed_;
 
 enum {
         ACPI_FPDT_S3PERF_RESUME_REC =   0,
@@ -59,7 +59,7 @@ struct acpi_fpdt_boot {
         uint64_t startup_start;
         uint64_t exit_services_entry;
         uint64_t exit_services_exit;
-};
+} _packed;
 
 int acpi_get_boot_usec(usec_t *loader_start, usec_t *loader_exit) {
         _cleanup_free_ char *buf = NULL;
index 9b74d909b1c62a21150b0bd4f1e8832185d3114a..4c5781a11ad5830ac4c81760ce5225e0bc777b47 100644 (file)
@@ -859,14 +859,10 @@ int ask_password_agent(
         pollfd[FD_INOTIFY].events = POLLIN;
 
         for (;;) {
+                CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
                 char passphrase[LINE_MAX+1];
-                struct msghdr msghdr;
                 struct iovec iovec;
                 struct ucred *ucred;
-                union {
-                        struct cmsghdr cmsghdr;
-                        uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
-                } control;
                 ssize_t n;
                 int k;
                 usec_t t;
@@ -918,19 +914,18 @@ int ask_password_agent(
 
                 iovec = IOVEC_MAKE(passphrase, sizeof(passphrase));
 
-                zero(control);
-                zero(msghdr);
-                msghdr.msg_iov = &iovec;
-                msghdr.msg_iovlen = 1;
-                msghdr.msg_control = &control;
-                msghdr.msg_controllen = sizeof(control);
+                struct msghdr msghdr = {
+                        .msg_iov = &iovec,
+                        .msg_iovlen = 1,
+                        .msg_control = &control,
+                        .msg_controllen = sizeof(control),
+                };
 
-                n = recvmsg(socket_fd, &msghdr, 0);
+                n = recvmsg_safe(socket_fd, &msghdr, 0);
+                if (IN_SET(n, -EAGAIN, -EINTR))
+                        continue;
                 if (n < 0) {
-                        if (IN_SET(errno, EAGAIN, EINTR))
-                                continue;
-
-                        r = -errno;
+                        r = (int) n;
                         goto finish;
                 }
 
@@ -941,15 +936,12 @@ int ask_password_agent(
                         continue;
                 }
 
-                if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) ||
-                    control.cmsghdr.cmsg_level != SOL_SOCKET ||
-                    control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
-                    control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
+                ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred);
+                if (!ucred) {
                         log_debug("Received message without credentials. Ignoring.");
                         continue;
                 }
 
-                ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
                 if (ucred->uid != 0) {
                         log_debug("Got request from unprivileged user. Ignoring.");
                         continue;
diff --git a/src/shared/binfmt-util.c b/src/shared/binfmt-util.c
new file mode 100644 (file)
index 0000000..0229726
--- /dev/null
@@ -0,0 +1,33 @@
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/vfs.h>
+
+#include "binfmt-util.h"
+#include "fileio.h"
+#include "missing_magic.h"
+#include "stat-util.h"
+
+int disable_binfmt(void) {
+        int r;
+
+        /* Flush out all rules. This is important during shutdown to cover for rules using "F", since those
+         * might pin a file and thus block us from unmounting stuff cleanly.
+         *
+         * We are a bit careful here, since binfmt_misc might still be an autofs which we don't want to
+         * trigger. */
+
+        r = path_is_fs_type("/proc/sys/fs/binfmt_misc", BINFMTFS_MAGIC);
+        if (r == 0 || r == -ENOENT) {
+                log_debug("binfmt_misc is not mounted, not detaching entries.");
+                return 0;
+        }
+        if (r < 0)
+                return log_warning_errno(r, "Failed to determine whether binfmt_misc is mounted: %m");
+
+        r = write_string_file("/proc/sys/fs/binfmt_misc/status", "-1", WRITE_STRING_FILE_DISABLE_BUFFER);
+        if (r < 0)
+                return log_warning_errno(r, "Failed to unregister binfmt_misc entries: %m");
+
+        log_debug("Unregistered all remaining binfmt_misc entries.");
+        return 0;
+}
diff --git a/src/shared/binfmt-util.h b/src/shared/binfmt-util.h
new file mode 100644 (file)
index 0000000..70feaad
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int disable_binfmt(void);
diff --git a/src/shared/bond-util.c b/src/shared/bond-util.c
new file mode 100644 (file)
index 0000000..2296ecd
--- /dev/null
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bond-util.h"
+#include "string-table.h"
+
+static const char* const bond_mode_table[_NETDEV_BOND_MODE_MAX] = {
+        [NETDEV_BOND_MODE_BALANCE_RR] = "balance-rr",
+        [NETDEV_BOND_MODE_ACTIVE_BACKUP] = "active-backup",
+        [NETDEV_BOND_MODE_BALANCE_XOR] = "balance-xor",
+        [NETDEV_BOND_MODE_BROADCAST] = "broadcast",
+        [NETDEV_BOND_MODE_802_3AD] = "802.3ad",
+        [NETDEV_BOND_MODE_BALANCE_TLB] = "balance-tlb",
+        [NETDEV_BOND_MODE_BALANCE_ALB] = "balance-alb",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_mode, BondMode);
+
+static const char* const bond_xmit_hash_policy_table[_NETDEV_BOND_XMIT_HASH_POLICY_MAX] = {
+        [NETDEV_BOND_XMIT_HASH_POLICY_LAYER2] = "layer2",
+        [NETDEV_BOND_XMIT_HASH_POLICY_LAYER34] = "layer3+4",
+        [NETDEV_BOND_XMIT_HASH_POLICY_LAYER23] = "layer2+3",
+        [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23] = "encap2+3",
+        [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34] = "encap3+4",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_xmit_hash_policy, BondXmitHashPolicy);
+
+static const char* const bond_lacp_rate_table[_NETDEV_BOND_LACP_RATE_MAX] = {
+        [NETDEV_BOND_LACP_RATE_SLOW] = "slow",
+        [NETDEV_BOND_LACP_RATE_FAST] = "fast",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_lacp_rate, BondLacpRate);
+
+static const char* const bond_ad_select_table[_NETDEV_BOND_AD_SELECT_MAX] = {
+        [NETDEV_BOND_AD_SELECT_STABLE] = "stable",
+        [NETDEV_BOND_AD_SELECT_BANDWIDTH] = "bandwidth",
+        [NETDEV_BOND_AD_SELECT_COUNT] = "count",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_ad_select, BondAdSelect);
+
+static const char* const bond_fail_over_mac_table[_NETDEV_BOND_FAIL_OVER_MAC_MAX] = {
+        [NETDEV_BOND_FAIL_OVER_MAC_NONE] = "none",
+        [NETDEV_BOND_FAIL_OVER_MAC_ACTIVE] = "active",
+        [NETDEV_BOND_FAIL_OVER_MAC_FOLLOW] = "follow",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_fail_over_mac, BondFailOverMac);
+
+static const char *const bond_arp_validate_table[_NETDEV_BOND_ARP_VALIDATE_MAX] = {
+        [NETDEV_BOND_ARP_VALIDATE_NONE] = "none",
+        [NETDEV_BOND_ARP_VALIDATE_ACTIVE]= "active",
+        [NETDEV_BOND_ARP_VALIDATE_BACKUP]= "backup",
+        [NETDEV_BOND_ARP_VALIDATE_ALL]= "all",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_arp_validate, BondArpValidate);
+
+static const char *const bond_arp_all_targets_table[_NETDEV_BOND_ARP_ALL_TARGETS_MAX] = {
+        [NETDEV_BOND_ARP_ALL_TARGETS_ANY] = "any",
+        [NETDEV_BOND_ARP_ALL_TARGETS_ALL] = "all",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_arp_all_targets, BondArpAllTargets);
+
+static const char *const bond_primary_reselect_table[_NETDEV_BOND_PRIMARY_RESELECT_MAX] = {
+        [NETDEV_BOND_PRIMARY_RESELECT_ALWAYS] = "always",
+        [NETDEV_BOND_PRIMARY_RESELECT_BETTER]= "better",
+        [NETDEV_BOND_PRIMARY_RESELECT_FAILURE]= "failure",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_primary_reselect, BondPrimaryReselect);
diff --git a/src/shared/bond-util.h b/src/shared/bond-util.h
new file mode 100644 (file)
index 0000000..66f86e7
--- /dev/null
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <netinet/in.h>
+#include <linux/if_bonding.h>
+
+#include "macro.h"
+
+/*
+ * Maximum number of targets supported by the kernel for a single
+ * bond netdev.
+ */
+#define NETDEV_BOND_ARP_TARGETS_MAX 16
+
+typedef enum BondMode {
+        NETDEV_BOND_MODE_BALANCE_RR    = BOND_MODE_ROUNDROBIN,
+        NETDEV_BOND_MODE_ACTIVE_BACKUP = BOND_MODE_ACTIVEBACKUP,
+        NETDEV_BOND_MODE_BALANCE_XOR   = BOND_MODE_XOR,
+        NETDEV_BOND_MODE_BROADCAST     = BOND_MODE_BROADCAST,
+        NETDEV_BOND_MODE_802_3AD       = BOND_MODE_8023AD,
+        NETDEV_BOND_MODE_BALANCE_TLB   = BOND_MODE_TLB,
+        NETDEV_BOND_MODE_BALANCE_ALB   = BOND_MODE_ALB,
+        _NETDEV_BOND_MODE_MAX,
+        _NETDEV_BOND_MODE_INVALID      = -1
+} BondMode;
+
+typedef enum BondXmitHashPolicy {
+        NETDEV_BOND_XMIT_HASH_POLICY_LAYER2   = BOND_XMIT_POLICY_LAYER2,
+        NETDEV_BOND_XMIT_HASH_POLICY_LAYER34  = BOND_XMIT_POLICY_LAYER34,
+        NETDEV_BOND_XMIT_HASH_POLICY_LAYER23  = BOND_XMIT_POLICY_LAYER23,
+        NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23  = BOND_XMIT_POLICY_ENCAP23,
+        NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34  = BOND_XMIT_POLICY_ENCAP34,
+        _NETDEV_BOND_XMIT_HASH_POLICY_MAX,
+        _NETDEV_BOND_XMIT_HASH_POLICY_INVALID = -1
+} BondXmitHashPolicy;
+
+typedef enum BondLacpRate {
+        NETDEV_BOND_LACP_RATE_SLOW,
+        NETDEV_BOND_LACP_RATE_FAST,
+        _NETDEV_BOND_LACP_RATE_MAX,
+        _NETDEV_BOND_LACP_RATE_INVALID = -1,
+} BondLacpRate;
+
+typedef enum BondAdSelect {
+        NETDEV_BOND_AD_SELECT_STABLE,
+        NETDEV_BOND_AD_SELECT_BANDWIDTH,
+        NETDEV_BOND_AD_SELECT_COUNT,
+        _NETDEV_BOND_AD_SELECT_MAX,
+        _NETDEV_BOND_AD_SELECT_INVALID = -1,
+} BondAdSelect;
+
+typedef enum BondFailOverMac {
+        NETDEV_BOND_FAIL_OVER_MAC_NONE,
+        NETDEV_BOND_FAIL_OVER_MAC_ACTIVE,
+        NETDEV_BOND_FAIL_OVER_MAC_FOLLOW,
+        _NETDEV_BOND_FAIL_OVER_MAC_MAX,
+        _NETDEV_BOND_FAIL_OVER_MAC_INVALID = -1,
+} BondFailOverMac;
+
+typedef enum BondArpValidate {
+        NETDEV_BOND_ARP_VALIDATE_NONE,
+        NETDEV_BOND_ARP_VALIDATE_ACTIVE,
+        NETDEV_BOND_ARP_VALIDATE_BACKUP,
+        NETDEV_BOND_ARP_VALIDATE_ALL,
+        _NETDEV_BOND_ARP_VALIDATE_MAX,
+        _NETDEV_BOND_ARP_VALIDATE_INVALID = -1,
+} BondArpValidate;
+
+typedef enum BondArpAllTargets {
+        NETDEV_BOND_ARP_ALL_TARGETS_ANY,
+        NETDEV_BOND_ARP_ALL_TARGETS_ALL,
+        _NETDEV_BOND_ARP_ALL_TARGETS_MAX,
+        _NETDEV_BOND_ARP_ALL_TARGETS_INVALID = -1,
+} BondArpAllTargets;
+
+typedef enum BondPrimaryReselect {
+        NETDEV_BOND_PRIMARY_RESELECT_ALWAYS,
+        NETDEV_BOND_PRIMARY_RESELECT_BETTER,
+        NETDEV_BOND_PRIMARY_RESELECT_FAILURE,
+        _NETDEV_BOND_PRIMARY_RESELECT_MAX,
+        _NETDEV_BOND_PRIMARY_RESELECT_INVALID = -1,
+} BondPrimaryReselect;
+
+const char *bond_mode_to_string(BondMode d) _const_;
+BondMode bond_mode_from_string(const char *d) _pure_;
+
+const char *bond_xmit_hash_policy_to_string(BondXmitHashPolicy d) _const_;
+BondXmitHashPolicy bond_xmit_hash_policy_from_string(const char *d) _pure_;
+
+const char *bond_lacp_rate_to_string(BondLacpRate d) _const_;
+BondLacpRate bond_lacp_rate_from_string(const char *d) _pure_;
+
+const char *bond_fail_over_mac_to_string(BondFailOverMac d) _const_;
+BondFailOverMac bond_fail_over_mac_from_string(const char *d) _pure_;
+
+const char *bond_ad_select_to_string(BondAdSelect d) _const_;
+BondAdSelect bond_ad_select_from_string(const char *d) _pure_;
+
+const char *bond_arp_validate_to_string(BondArpValidate d) _const_;
+BondArpValidate bond_arp_validate_from_string(const char *d) _pure_;
+
+const char *bond_arp_all_targets_to_string(BondArpAllTargets d) _const_;
+BondArpAllTargets bond_arp_all_targets_from_string(const char *d) _pure_;
+
+const char *bond_primary_reselect_to_string(BondPrimaryReselect d) _const_;
+BondPrimaryReselect bond_primary_reselect_from_string(const char *d) _pure_;
diff --git a/src/shared/bus-locator.c b/src/shared/bus-locator.c
new file mode 100644 (file)
index 0000000..a79699d
--- /dev/null
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bus-locator.h"
+
+const BusLocator* const bus_home_mgr = &(BusLocator){
+        .destination = "org.freedesktop.home1",
+        .path = "/org/freedesktop/home1",
+        .interface = "org.freedesktop.home1.Manager",
+};
+
+const BusLocator* const bus_import_mgr = &(BusLocator){
+        .destination ="org.freedesktop.import1",
+        .path = "/org/freedesktop/import1",
+        .interface = "org.freedesktop.import1.Manager"
+};
+
+const BusLocator* const bus_locale = &(BusLocator){
+        .destination = "org.freedesktop.locale1",
+        .path = "/org/freedesktop/locale1",
+        .interface = "org.freedesktop.locale1"
+};
+
+const BusLocator* const bus_login_mgr = &(BusLocator){
+        .destination = "org.freedesktop.login1",
+        .path = "/org/freedesktop/login1",
+        .interface = "org.freedesktop.login1.Manager"
+};
+
+const BusLocator* const bus_machine_mgr = &(BusLocator){
+        .destination ="org.freedesktop.machine1",
+        .path = "/org/freedesktop/machine1",
+        .interface = "org.freedesktop.machine1.Manager"
+};
+
+const BusLocator* const bus_network_mgr = &(BusLocator){
+        .destination = "org.freedesktop.network1",
+        .path = "/org/freedesktop/network1",
+        .interface = "org.freedesktop.network1.Manager"
+};
+
+const BusLocator* const bus_portable_mgr = &(BusLocator){
+        .destination = "org.freedesktop.portable1",
+        .path = "/org/freedesktop/portable1",
+        .interface = "org.freedesktop.portable1.Manager"
+};
+
+const BusLocator* const bus_resolve_mgr = &(BusLocator){
+        .destination = "org.freedesktop.resolve1",
+        .path = "/org/freedesktop/resolve1",
+        .interface = "org.freedesktop.resolve1.Manager"
+};
+
+const BusLocator* const bus_systemd_mgr = &(BusLocator){
+        .destination = "org.freedesktop.systemd1",
+        .path = "/org/freedesktop/systemd1",
+        .interface = "org.freedesktop.systemd1.Manager"
+};
+
+const BusLocator* const bus_timedate = &(BusLocator){
+        .destination = "org.freedesktop.timedate1",
+        .path = "/org/freedesktop/timedate1",
+        .interface = "org.freedesktop.timedate1"
+};
diff --git a/src/shared/bus-locator.h b/src/shared/bus-locator.h
new file mode 100644 (file)
index 0000000..91a9aaf
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+typedef struct BusLocator {
+        const char    *destination;
+        const char    *path;
+        const char    *interface;
+} BusLocator;
+
+extern const BusLocator* const bus_home_mgr;
+extern const BusLocator* const bus_import_mgr;
+extern const BusLocator* const bus_locale;
+extern const BusLocator* const bus_login_mgr;
+extern const BusLocator* const bus_machine_mgr;
+extern const BusLocator* const bus_network_mgr;
+extern const BusLocator* const bus_portable_mgr;
+extern const BusLocator* const bus_resolve_mgr;
+extern const BusLocator* const bus_systemd_mgr;
+extern const BusLocator* const bus_timedate;
index ffc52c77745e6b434be8df55776cd423f3959abe..a1d0d1729151d8a9ef72330dc8d049014f0c93c4 100644 (file)
@@ -107,17 +107,8 @@ static const sd_bus_vtable log_control_vtable[] = {
         SD_BUS_VTABLE_END,
 };
 
-int bus_log_control_api_register(sd_bus *bus) {
-        int r;
-
-        r = sd_bus_add_object_vtable(
-                        bus,
-                        NULL,
-                        "/org/freedesktop/LogControl1",
-                        "org.freedesktop.LogControl1",
-                        log_control_vtable, NULL);
-        if (r < 0)
-                return log_error_errno(r, "Failed to register service API object: %m");
-
-        return 0;
-}
+const BusObjectImplementation log_control_object = {
+        "/org/freedesktop/LogControl1",
+        "org.freedesktop.LogControl1",
+        .vtables = BUS_VTABLES(log_control_vtable),
+};
index a6fb2757c5f89d4b76a5b9159601eda1c958928d..b1d00b38bcfcdd1d08e7b1cde7cd83200bca2f67 100644 (file)
@@ -2,7 +2,12 @@
 
 #include "sd-bus.h"
 
-int bus_log_control_api_register(sd_bus *bus);
+#include "bus-util.h"
+
+extern const BusObjectImplementation log_control_object;
+static inline int bus_log_control_api_register(sd_bus *bus) {
+        return bus_add_implementation(bus, &log_control_object, NULL);
+}
 
 int bus_property_get_log_level(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
 int bus_property_set_log_level(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, void *userdata, sd_bus_error *error);
index 463a0ddb716086bb83eff8d235c127b33f7fb6f9..3be75e6b4d291459334abf640be0328a8e4a7edc 100644 (file)
@@ -1436,7 +1436,8 @@ static int bus_append_mount_property(sd_bus_message *m, const char *field, const
 
         if (STR_IN_SET(field, "SloppyOptions",
                               "LazyUnmount",
-                              "ForceUnmount"))
+                              "ForceUnmount",
+                              "ReadwriteOnly"))
                 return bus_append_parse_boolean(m, field, eq);
 
         return 0;
index 81683e5afed1eabbf2fb142fb25321c858e665e7..c7611a6e851db1db5293463169e67689f0ba7388 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "alloc-util.h"
 #include "bus-internal.h"
+#include "bus-introspect.h"
 #include "bus-label.h"
 #include "bus-message.h"
 #include "bus-util.h"
@@ -1549,3 +1550,167 @@ int bus_message_new_method_call(
 
         return sd_bus_message_new_method_call(bus, m, locator->destination, locator->path, locator->interface, member);
 }
+
+int bus_add_implementation(sd_bus *bus, const BusObjectImplementation *impl, void *userdata) {
+        int r;
+
+        log_debug("Registering bus object implementation for path=%s iface=%s", impl->path, impl->interface);
+
+        for (const sd_bus_vtable **p = impl->vtables; p && *p; p++) {
+                r = sd_bus_add_object_vtable(bus, NULL,
+                                             impl->path,
+                                             impl->interface,
+                                             *p,
+                                             userdata);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to register bus path %s with interface %s: %m",
+                                               impl->path,
+                                               impl->interface);
+        }
+
+        for (const BusObjectVtablePair *p = impl->fallback_vtables; p && p->vtable; p++) {
+                r = sd_bus_add_fallback_vtable(bus, NULL,
+                                               impl->path,
+                                               impl->interface,
+                                               p->vtable,
+                                               p->object_find,
+                                               userdata);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to register bus path %s with interface %s: %m",
+                                               impl->path,
+                                               impl->interface);
+        }
+
+        if (impl->node_enumerator) {
+                r = sd_bus_add_node_enumerator(bus, NULL,
+                                               impl->path,
+                                               impl->node_enumerator,
+                                               userdata);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to add node enumerator for %s: %m",
+                                               impl->path);
+        }
+
+        for (size_t i = 0; impl->children && impl->children[i]; i++) {
+                r = bus_add_implementation(bus, impl->children[i], userdata);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+static const BusObjectImplementation* find_implementation(
+                const char *pattern,
+                const BusObjectImplementation* const* bus_objects) {
+
+        for (size_t i = 0; bus_objects && bus_objects[i]; i++) {
+                const BusObjectImplementation *impl = bus_objects[i];
+
+                if (STR_IN_SET(pattern, impl->path, impl->interface))
+                        return impl;
+
+                impl = find_implementation(pattern, impl->children);
+                if (impl)
+                        return impl;
+        }
+
+        return NULL;
+}
+
+static int bus_introspect_implementation(
+                struct introspect *intro,
+                const BusObjectImplementation *impl) {
+        int r;
+
+        for (const sd_bus_vtable **p = impl->vtables; p && *p; p++) {
+                r = introspect_write_interface(intro, impl->interface, *p);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to write introspection data: %m");
+        }
+
+        for (const BusObjectVtablePair *p = impl->fallback_vtables; p && p->vtable; p++) {
+                r = introspect_write_interface(intro, impl->interface, p->vtable);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to write introspection data: %m");
+        }
+
+        return 0;
+}
+
+static void list_paths(
+                FILE *out,
+                const BusObjectImplementation* const* bus_objects) {
+
+        for (size_t i = 0; bus_objects[i]; i++) {
+                fprintf(out, "%s\t%s\n", bus_objects[i]->path, bus_objects[i]->interface);
+                if (bus_objects[i]->children)
+                        list_paths(out, bus_objects[i]->children);
+        }
+}
+
+int bus_introspect_implementations(
+                FILE *out,
+                const char *pattern,
+                const BusObjectImplementation* const* bus_objects) {
+
+        const BusObjectImplementation *impl, *main_impl = NULL;
+        _cleanup_free_ char *s = NULL;
+        int r;
+
+        if (streq(pattern, "list")) {
+                list_paths(out, bus_objects);
+                return 0;
+        }
+
+        struct introspect intro = {};
+        bool is_interface = interface_name_is_valid(pattern);
+
+        impl = find_implementation(pattern, bus_objects);
+        if (!impl)
+                return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
+                                       "%s %s not found",
+                                       is_interface ? "Interface" : "Object path",
+                                       pattern);
+
+        /* We use trusted=false here to get all the @org.freedesktop.systemd1.Privileged annotations. */
+        r = introspect_begin(&intro, false);
+        if (r < 0)
+                return log_error_errno(r, "Failed to write introspection data: %m");
+
+        r = introspect_write_default_interfaces(&intro, impl->manager);
+        if (r < 0)
+                return log_error_errno(r, "Failed to write introspection data: %m");
+
+        /* Check if there is a non-fallback path that applies to the given interface, also
+         * print it. This is useful in the case of units: o.fd.systemd1.Service is declared
+         * as a fallback vtable for o/fd/systemd1/unit, and we also want to print
+         * o.fd.systemd1.Unit, which is the non-fallback implementation. */
+        if (impl->fallback_vtables && is_interface)
+                main_impl = find_implementation(impl->path, bus_objects);
+
+        if (main_impl)
+                bus_introspect_implementation(&intro, main_impl);
+
+        if (impl != main_impl)
+                bus_introspect_implementation(&intro, impl);
+
+        _cleanup_set_free_ Set *nodes = NULL;
+
+        for (size_t i = 0; impl->children && impl->children[i]; i++) {
+                r = set_put_strdup(&nodes, impl->children[i]->path);
+                if (r < 0)
+                        return log_oom();
+        }
+
+        r = introspect_write_child_nodes(&intro, nodes, impl->path);
+        if (r < 0)
+                return r;
+
+        r = introspect_finish(&intro, &s);
+        if (r < 0)
+                return log_error_errno(r, "Failed to write introspection data: %m");
+
+        fputs(s, out);
+        return 0;
+}
index fd1820ca7e60fceb992b15a1ae3e3df0f5b64221..ef14217e9374278ca9a74b026b5766af1c8d688e 100644 (file)
@@ -9,6 +9,7 @@
 #include "sd-bus.h"
 #include "sd-event.h"
 
+#include "bus-locator.h"
 #include "macro.h"
 #include "set.h"
 #include "string-util.h"
@@ -22,11 +23,26 @@ typedef enum BusTransport {
         _BUS_TRANSPORT_INVALID = -1
 } BusTransport;
 
-typedef struct BusLocator {
-        const char    *destination;
-        const char    *path;
-        const char    *interface;
-} BusLocator;
+typedef struct BusObjectImplementation BusObjectImplementation;
+
+typedef struct BusObjectVtablePair {
+        const sd_bus_vtable *vtable;
+        sd_bus_object_find_t object_find;
+} BusObjectVtablePair;
+
+struct BusObjectImplementation {
+        const char *path;
+        const char *interface;
+        const sd_bus_vtable **vtables;
+        const BusObjectVtablePair *fallback_vtables;
+        sd_bus_node_enumerator_t node_enumerator;
+        bool manager;
+        const BusObjectImplementation **children;
+};
+
+#define BUS_VTABLES(...) ((const sd_bus_vtable* []){ __VA_ARGS__, NULL })
+#define BUS_FALLBACK_VTABLES(...) ((const BusObjectVtablePair[]) { __VA_ARGS__, {} })
+#define BUS_IMPLEMENTATIONS(...) ((const BusObjectImplementation* []) { __VA_ARGS__, NULL })
 
 typedef int (*bus_property_set_t) (sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata);
 
@@ -199,3 +215,9 @@ int bus_set_property(sd_bus *bus, const BusLocator *locator, const char *member,
 int bus_match_signal(sd_bus *bus, sd_bus_slot **ret, const BusLocator *locator, const char *member, sd_bus_message_handler_t callback, void *userdata);
 int bus_match_signal_async(sd_bus *bus, sd_bus_slot **ret, const BusLocator *locator, const char *member, sd_bus_message_handler_t callback, sd_bus_message_handler_t install_callback, void *userdata);
 int bus_message_new_method_call(sd_bus *bus, sd_bus_message **m, const BusLocator *locator, const char *member);
+
+int bus_add_implementation(sd_bus *bus, const BusObjectImplementation *impl, void *userdata);
+int bus_introspect_implementations(
+                FILE *out,
+                const char *pattern,
+                const BusObjectImplementation* const* bus_objects);
index 4e6b862d5efef71219552d6eaf1bcf262ee21e96..eb33ba23400d11d639d713c9c7f82c5ce102eeb3 100644 (file)
@@ -65,7 +65,7 @@ void bus_wait_for_jobs_free(BusWaitForJobs *d) {
         if (!d)
                 return;
 
-        set_free_free(d->jobs);
+        set_free(d->jobs);
 
         sd_bus_slot_unref(d->slot_disconnected);
         sd_bus_slot_unref(d->slot_job_removed);
@@ -315,15 +315,9 @@ int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_ar
 }
 
 int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) {
-        int r;
-
         assert(d);
 
-        r = set_ensure_allocated(&d->jobs, &string_hash_ops);
-        if (r < 0)
-                return r;
-
-        return set_put_strdup(d->jobs, path);
+        return set_put_strdup(&d->jobs, path);
 }
 
 int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet) {
index 78b2a604038c6bd94e77473d022c92f5c9758af4..3ee3c0ccba659586b746f02f24a8dc6b98573688 100644 (file)
@@ -80,6 +80,15 @@ static WaitForItem *wait_for_item_free(WaitForItem *item) {
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(WaitForItem*, wait_for_item_free);
 
+static void call_unit_callback_and_wait(BusWaitForUnits *d, WaitForItem *item, bool good) {
+        d->current = item;
+
+        if (item->unit_callback)
+                item->unit_callback(d, item->bus_path, good, item->userdata);
+
+        wait_for_item_free(item);
+}
+
 static void bus_wait_for_units_clear(BusWaitForUnits *d) {
         WaitForItem *item;
 
@@ -88,12 +97,8 @@ static void bus_wait_for_units_clear(BusWaitForUnits *d) {
         d->slot_disconnected = sd_bus_slot_unref(d->slot_disconnected);
         d->bus = sd_bus_unref(d->bus);
 
-        while ((item = hashmap_first(d->items))) {
-                d->current = item;
-
-                item->unit_callback(d, item->bus_path, false, item->userdata);
-                wait_for_item_free(item);
-        }
+        while ((item = hashmap_first(d->items)))
+                call_unit_callback_and_wait(d, item, false);
 
         d->items = hashmap_free(d->items);
 }
@@ -212,13 +217,7 @@ static void wait_for_item_check_ready(WaitForItem *item) {
                         return;
         }
 
-        if (item->unit_callback) {
-                d->current = item;
-                item->unit_callback(d, item->bus_path, true, item->userdata);
-        }
-
-        wait_for_item_free(item);
-
+        call_unit_callback_and_wait(d, item, true);
         bus_wait_for_units_check_ready(d);
 }
 
@@ -303,10 +302,7 @@ static int on_get_all_properties(sd_bus_message *m, void *userdata, sd_bus_error
                 log_debug_errno(sd_bus_error_get_errno(error), "GetAll() failed for %s: %s",
                                 item->bus_path, error->message);
 
-                d->current = item;
-                item->unit_callback(d, item->bus_path, false, item->userdata);
-                wait_for_item_free(item);
-
+                call_unit_callback_and_wait(d, item, false);
                 bus_wait_for_units_check_ready(d);
                 return 0;
         }
index 217ab3fbaf47eea8a862126edac9b21b6abef8b0..db6a103c42a74ed382359a1e32fba5795efcb63c 100644 (file)
@@ -17,6 +17,7 @@
 #include "process-util.h"
 #include "sort-util.h"
 #include "string-util.h"
+#include "strv.h"
 #include "time-util.h"
 
 #define BITS_WEEKDAYS 127
@@ -29,6 +30,9 @@
  * linked compenents anyway. */
 #define CALENDARSPEC_COMPONENTS_MAX 240
 
+/* Let's make sure that the microsecond component is safe to be stored in an 'int' */
+assert_cc(INT_MAX >= USEC_PER_SEC);
+
 static void chain_free(CalendarComponent *c) {
         CalendarComponent *n;
 
@@ -87,6 +91,16 @@ static void normalize_chain(CalendarComponent **c) {
                 if (i->stop > i->start && i->repeat > 0)
                         i->stop -= (i->stop - i->start) % i->repeat;
 
+                /* If a repeat value is specified, but it cannot even be triggered once, let's suppress
+                 * it.
+                 *
+                 * Similar, if the stop value is the same as the start value, then let's just make this a
+                 * non-repeating chain element */
+                if ((i->stop > i->start && i->repeat > 0 && i->start + i->repeat > i->stop) ||
+                    i->start == i->stop) {
+                        i->repeat = 0;
+                        i->stop = -1;
+                }
         }
 
         if (n <= 1)
@@ -161,7 +175,7 @@ int calendar_spec_normalize(CalendarSpec *c) {
         return 0;
 }
 
-_pure_ static bool chain_valid(CalendarComponent *c, int from, int to, bool end_of_month) {
+static bool chain_valid(CalendarComponent *c, int from, int to, bool end_of_month) {
         assert(to >= from);
 
         if (!c)
@@ -365,14 +379,13 @@ int calendar_spec_to_string(const CalendarSpec *c, char **p) {
         }
 
         r = fflush_and_check(f);
+        fclose(f);
+
         if (r < 0) {
                 free(buf);
-                fclose(f);
                 return r;
         }
 
-        fclose(f);
-
         *p = buf;
         return 0;
 }
@@ -642,6 +655,16 @@ static int prepend_component(const char **p, bool usec, unsigned nesting, Calend
 
                 if (repeat == 0)
                         return -ERANGE;
+        } else {
+                /* If no repeat value is specified for the µs component, then let's explicitly refuse ranges
+                 * below 1s because our default repeat granularity is beyond that. */
+
+                /* Overflow check */
+                if (start > INT_MAX - repeat)
+                        return -ERANGE;
+
+                if (usec && stop >= 0 && start + repeat > stop)
+                        return -EINVAL;
         }
 
         if (!IN_SET(*e, 0, ' ', ',', '-', '~', ':'))
@@ -961,9 +984,10 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
                 if (r < 0)
                         return r;
 
-        } else if (strcaseeq(p, "annually") ||
-                   strcaseeq(p, "yearly") ||
-                   strcaseeq(p, "anually") /* backwards compatibility */ ) {
+        } else if (STRCASE_IN_SET(p,
+                                  "annually",
+                                  "yearly",
+                                  "anually") /* backwards compatibility */ ) {
 
                 r = const_chain(1, &c->month);
                 if (r < 0)
@@ -1022,10 +1046,11 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
                 if (r < 0)
                         return r;
 
-        } else if (strcaseeq(p, "biannually") ||
-                   strcaseeq(p, "bi-annually") ||
-                   strcaseeq(p, "semiannually") ||
-                   strcaseeq(p, "semi-annually")) {
+        } else if (STRCASE_IN_SET(p,
+                                  "biannually",
+                                  "bi-annually",
+                                  "semiannually",
+                                  "semi-annually")) {
 
                 r = const_chain(1, &c->month);
                 if (r < 0)
index 3bf8a39e1a5afd615f885f078fea06f4b437c732..0a5d95b4b1299d36a56d6297a37612081725ed98 100644 (file)
@@ -19,9 +19,9 @@ typedef struct CalendarComponent {
 
 typedef struct CalendarSpec {
         int weekdays_bits;
-        bool end_of_month;
-        bool utc;
-        int dst;
+        bool end_of_month:1;
+        bool utc:1;
+        signed int dst:2;
         char *timezone;
 
         CalendarComponent *year;
index 9f4c7fe3380f7639644dfc541d7c61840cd99505..bf3b5fa1622800a26edfedaf75720bb03d61600c 100644 (file)
@@ -25,6 +25,7 @@
 #include "extract-word.h"
 #include "fd-util.h"
 #include "fileio.h"
+#include "fs-util.h"
 #include "glob-util.h"
 #include "hostname-util.h"
 #include "ima-util.h"
@@ -72,11 +73,11 @@ Condition* condition_new(ConditionType type, const char *parameter, bool trigger
         return c;
 }
 
-void condition_free(Condition *c) {
+Condition* condition_free(Condition *c) {
         assert(c);
 
         free(c->parameter);
-        free(c);
+        return mfree(c);
 }
 
 Condition* condition_free_list_type(Condition *head, ConditionType type) {
@@ -92,7 +93,7 @@ Condition* condition_free_list_type(Condition *head, ConditionType type) {
         return head;
 }
 
-static int condition_test_kernel_command_line(Condition *c) {
+static int condition_test_kernel_command_line(Condition *c, char **env) {
         _cleanup_free_ char *line = NULL;
         const char *p;
         bool equal;
@@ -201,7 +202,7 @@ static bool test_order(int k, OrderOperator p) {
         }
 }
 
-static int condition_test_kernel_version(Condition *c) {
+static int condition_test_kernel_version(Condition *c, char **env) {
         OrderOperator order;
         struct utsname u;
         const char *p;
@@ -259,7 +260,7 @@ static int condition_test_kernel_version(Condition *c) {
         return true;
 }
 
-static int condition_test_memory(Condition *c) {
+static int condition_test_memory(Condition *c, char **env) {
         OrderOperator order;
         uint64_t m, k;
         const char *p;
@@ -283,7 +284,7 @@ static int condition_test_memory(Condition *c) {
         return test_order(CMP(m, k), order);
 }
 
-static int condition_test_cpus(Condition *c) {
+static int condition_test_cpus(Condition *c, char **env) {
         OrderOperator order;
         const char *p;
         unsigned k;
@@ -309,7 +310,7 @@ static int condition_test_cpus(Condition *c) {
         return test_order(CMP((unsigned) n, k), order);
 }
 
-static int condition_test_user(Condition *c) {
+static int condition_test_user(Condition *c, char **env) {
         uid_t id;
         int r;
         _cleanup_free_ char *username = NULL;
@@ -344,7 +345,7 @@ static int condition_test_user(Condition *c) {
         return id == getuid() || id == geteuid();
 }
 
-static int condition_test_control_group_controller(Condition *c) {
+static int condition_test_control_group_controller(Condition *c, char **env) {
         int r;
         CGroupMask system_mask, wanted_mask = 0;
 
@@ -368,7 +369,7 @@ static int condition_test_control_group_controller(Condition *c) {
         return FLAGS_SET(system_mask, wanted_mask);
 }
 
-static int condition_test_group(Condition *c) {
+static int condition_test_group(Condition *c, char **env) {
         gid_t id;
         int r;
 
@@ -387,7 +388,7 @@ static int condition_test_group(Condition *c) {
         return in_group(c->parameter) > 0;
 }
 
-static int condition_test_virtualization(Condition *c) {
+static int condition_test_virtualization(Condition *c, char **env) {
         int b, v;
 
         assert(c);
@@ -417,7 +418,7 @@ static int condition_test_virtualization(Condition *c) {
         return v != VIRTUALIZATION_NONE && streq(c->parameter, virtualization_to_string(v));
 }
 
-static int condition_test_architecture(Condition *c) {
+static int condition_test_architecture(Condition *c, char **env) {
         int a, b;
 
         assert(c);
@@ -439,7 +440,7 @@ static int condition_test_architecture(Condition *c) {
         return a == b;
 }
 
-static int condition_test_host(Condition *c) {
+static int condition_test_host(Condition *c, char **env) {
         _cleanup_free_ char *h = NULL;
         sd_id128_t x, y;
         int r;
@@ -464,7 +465,7 @@ static int condition_test_host(Condition *c) {
         return fnmatch(c->parameter, h, FNM_CASEFOLD) == 0;
 }
 
-static int condition_test_ac_power(Condition *c) {
+static int condition_test_ac_power(Condition *c, char **env) {
         int r;
 
         assert(c);
@@ -478,7 +479,7 @@ static int condition_test_ac_power(Condition *c) {
         return (on_ac_power() != 0) == !!r;
 }
 
-static int condition_test_security(Condition *c) {
+static int condition_test_security(Condition *c, char **env) {
         assert(c);
         assert(c->parameter);
         assert(c->type == CONDITION_SECURITY);
@@ -501,7 +502,7 @@ static int condition_test_security(Condition *c) {
         return false;
 }
 
-static int condition_test_capability(Condition *c) {
+static int condition_test_capability(Condition *c, char **env) {
         unsigned long long capabilities = (unsigned long long) -1;
         _cleanup_fclose_ FILE *f = NULL;
         int value, r;
@@ -544,31 +545,48 @@ static int condition_test_capability(Condition *c) {
         return !!(capabilities & (1ULL << value));
 }
 
-static int condition_test_needs_update(Condition *c) {
-        const char *p;
+static int condition_test_needs_update(Condition *c, char **env) {
         struct stat usr, other;
+        const char *p;
+        bool b;
+        int r;
 
         assert(c);
         assert(c->parameter);
         assert(c->type == CONDITION_NEEDS_UPDATE);
 
+        r = proc_cmdline_get_bool("systemd.condition-needs-update", &b);
+        if (r < 0)
+                log_debug_errno(r, "Failed to parse systemd.condition-needs-update= kernel command line argument, ignoring: %m");
+        if (r > 0)
+                return b;
+
+        if (!path_is_absolute(c->parameter)) {
+                log_debug("Specified condition parameter '%s' is not absolute, assuming an update is needed.", c->parameter);
+                return true;
+        }
+
         /* If the file system is read-only we shouldn't suggest an update */
-        if (path_is_read_only_fs(c->parameter) > 0)
+        r = path_is_read_only_fs(c->parameter);
+        if (r < 0)
+                log_debug_errno(r, "Failed to determine if '%s' is read-only, ignoring: %m", c->parameter);
+        if (r > 0)
                 return false;
 
-        /* Any other failure means we should allow the condition to be true,
-         * so that we rather invoke too many update tools than too
-         * few. */
-
-        if (!path_is_absolute(c->parameter))
-                return true;
+        /* Any other failure means we should allow the condition to be true, so that we rather invoke too
+         * many update tools than too few. */
 
         p = strjoina(c->parameter, "/.updated");
-        if (lstat(p, &other) < 0)
+        if (lstat(p, &other) < 0) {
+                if (errno != ENOENT)
+                        log_debug_errno(errno, "Failed to stat() '%s', assuming an update is needed: %m", p);
                 return true;
+        }
 
-        if (lstat("/usr/", &usr) < 0)
+        if (lstat("/usr/", &usr) < 0) {
+                log_debug_errno(errno, "Failed to stat() /usr/, assuming an update is needed: %m");
                 return true;
+        }
 
         /*
          * First, compare seconds as they are always accurate...
@@ -584,47 +602,84 @@ static int condition_test_needs_update(Condition *c) {
          * AND the target file's nanoseconds == 0
          * (otherwise the filesystem supports nsec timestamps, see stat(2)).
          */
-        if (usr.st_mtim.tv_nsec > 0 && other.st_mtim.tv_nsec == 0) {
-                _cleanup_free_ char *timestamp_str = NULL;
-                uint64_t timestamp;
-                int r;
+        if (usr.st_mtim.tv_nsec == 0 || other.st_mtim.tv_nsec > 0)
+                return usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec;
 
-                r = parse_env_file(NULL, p, "TIMESTAMP_NSEC", &timestamp_str);
-                if (r < 0) {
-                        log_error_errno(r, "Failed to parse timestamp file '%s', using mtime: %m", p);
-                        return true;
-                } else if (r == 0) {
-                        log_debug("No data in timestamp file '%s', using mtime", p);
-                        return true;
-                }
-
-                r = safe_atou64(timestamp_str, &timestamp);
-                if (r < 0) {
-                        log_error_errno(r, "Failed to parse timestamp value '%s' in file '%s', using mtime: %m", timestamp_str, p);
-                        return true;
-                }
+        _cleanup_free_ char *timestamp_str = NULL;
+        r = parse_env_file(NULL, p, "TIMESTAMP_NSEC", &timestamp_str);
+        if (r < 0) {
+                log_debug_errno(r, "Failed to parse timestamp file '%s', using mtime: %m", p);
+                return true;
+        } else if (r == 0) {
+                log_debug("No data in timestamp file '%s', using mtime.", p);
+                return true;
+        }
 
-                timespec_store(&other.st_mtim, timestamp);
+        uint64_t timestamp;
+        r = safe_atou64(timestamp_str, &timestamp);
+        if (r < 0) {
+                log_debug_errno(r, "Failed to parse timestamp value '%s' in file '%s', using mtime: %m", timestamp_str, p);
+                return true;
         }
 
-        return usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec;
+        return timespec_load_nsec(&usr.st_mtim) > timestamp;
 }
 
-static int condition_test_first_boot(Condition *c) {
-        int r;
+static int condition_test_first_boot(Condition *c, char **env) {
+        int r, q;
+        bool b;
 
         assert(c);
         assert(c->parameter);
         assert(c->type == CONDITION_FIRST_BOOT);
 
+        r = proc_cmdline_get_bool("systemd.condition-first-boot", &b);
+        if (r < 0)
+                log_debug_errno(r, "Failed to parse systemd.condition-first-boot= kernel command line argument, ignoring: %m");
+        if (r > 0)
+                return b == !!r;
+
         r = parse_boolean(c->parameter);
         if (r < 0)
                 return r;
 
-        return (access("/run/systemd/first-boot", F_OK) >= 0) == !!r;
+        q = access("/run/systemd/first-boot", F_OK);
+        if (q < 0 && errno != ENOENT)
+                log_debug_errno(errno, "Failed to check if /run/systemd/first-boot exists, ignoring: %m");
+
+        return (q >= 0) == !!r;
+}
+
+static int condition_test_environment(Condition *c, char **env) {
+        bool equal;
+        char **i;
+
+        assert(c);
+        assert(c->parameter);
+        assert(c->type == CONDITION_ENVIRONMENT);
+
+        equal = strchr(c->parameter, '=');
+
+        STRV_FOREACH(i, env) {
+                bool found;
+
+                if (equal)
+                        found = streq(c->parameter, *i);
+                else {
+                        const char *f;
+
+                        f = startswith(*i, c->parameter);
+                        found = f && IN_SET(*f, 0, '=');
+                }
+
+                if (found)
+                        return true;
+        }
+
+        return false;
 }
 
-static int condition_test_path_exists(Condition *c) {
+static int condition_test_path_exists(Condition *c, char **env) {
         assert(c);
         assert(c->parameter);
         assert(c->type == CONDITION_PATH_EXISTS);
@@ -632,7 +687,7 @@ static int condition_test_path_exists(Condition *c) {
         return access(c->parameter, F_OK) >= 0;
 }
 
-static int condition_test_path_exists_glob(Condition *c) {
+static int condition_test_path_exists_glob(Condition *c, char **env) {
         assert(c);
         assert(c->parameter);
         assert(c->type == CONDITION_PATH_EXISTS_GLOB);
@@ -640,7 +695,7 @@ static int condition_test_path_exists_glob(Condition *c) {
         return glob_exists(c->parameter) > 0;
 }
 
-static int condition_test_path_is_directory(Condition *c) {
+static int condition_test_path_is_directory(Condition *c, char **env) {
         assert(c);
         assert(c->parameter);
         assert(c->type == CONDITION_PATH_IS_DIRECTORY);
@@ -648,7 +703,7 @@ static int condition_test_path_is_directory(Condition *c) {
         return is_dir(c->parameter, true) > 0;
 }
 
-static int condition_test_path_is_symbolic_link(Condition *c) {
+static int condition_test_path_is_symbolic_link(Condition *c, char **env) {
         assert(c);
         assert(c->parameter);
         assert(c->type == CONDITION_PATH_IS_SYMBOLIC_LINK);
@@ -656,7 +711,7 @@ static int condition_test_path_is_symbolic_link(Condition *c) {
         return is_symlink(c->parameter) > 0;
 }
 
-static int condition_test_path_is_mount_point(Condition *c) {
+static int condition_test_path_is_mount_point(Condition *c, char **env) {
         assert(c);
         assert(c->parameter);
         assert(c->type == CONDITION_PATH_IS_MOUNT_POINT);
@@ -664,7 +719,7 @@ static int condition_test_path_is_mount_point(Condition *c) {
         return path_is_mount_point(c->parameter, NULL, AT_SYMLINK_FOLLOW) > 0;
 }
 
-static int condition_test_path_is_read_write(Condition *c) {
+static int condition_test_path_is_read_write(Condition *c, char **env) {
         assert(c);
         assert(c->parameter);
         assert(c->type == CONDITION_PATH_IS_READ_WRITE);
@@ -672,7 +727,21 @@ static int condition_test_path_is_read_write(Condition *c) {
         return path_is_read_only_fs(c->parameter) <= 0;
 }
 
-static int condition_test_directory_not_empty(Condition *c) {
+static int condition_test_path_is_encrypted(Condition *c, char **env) {
+        int r;
+
+        assert(c);
+        assert(c->parameter);
+        assert(c->type == CONDITION_PATH_IS_ENCRYPTED);
+
+        r = path_is_encrypted(c->parameter);
+        if (r < 0 && r != -ENOENT)
+                log_debug_errno(r, "Failed to determine if '%s' is encrypted: %m", c->parameter);
+
+        return r > 0;
+}
+
+static int condition_test_directory_not_empty(Condition *c, char **env) {
         int r;
 
         assert(c);
@@ -683,7 +752,7 @@ static int condition_test_directory_not_empty(Condition *c) {
         return r <= 0 && r != -ENOENT;
 }
 
-static int condition_test_file_not_empty(Condition *c) {
+static int condition_test_file_not_empty(Condition *c, char **env) {
         struct stat st;
 
         assert(c);
@@ -695,7 +764,7 @@ static int condition_test_file_not_empty(Condition *c) {
                 st.st_size > 0);
 }
 
-static int condition_test_file_is_executable(Condition *c) {
+static int condition_test_file_is_executable(Condition *c, char **env) {
         struct stat st;
 
         assert(c);
@@ -707,7 +776,7 @@ static int condition_test_file_is_executable(Condition *c) {
                 (st.st_mode & 0111));
 }
 
-static int condition_test_null(Condition *c) {
+static int condition_test_null(Condition *c, char **env) {
         assert(c);
         assert(c->type == CONDITION_NULL);
 
@@ -716,15 +785,16 @@ static int condition_test_null(Condition *c) {
         return true;
 }
 
-int condition_test(Condition *c) {
+int condition_test(Condition *c, char **env) {
 
-        static int (*const condition_tests[_CONDITION_TYPE_MAX])(Condition *c) = {
+        static int (*const condition_tests[_CONDITION_TYPE_MAX])(Condition *c, char **env) = {
                 [CONDITION_PATH_EXISTS]              = condition_test_path_exists,
                 [CONDITION_PATH_EXISTS_GLOB]         = condition_test_path_exists_glob,
                 [CONDITION_PATH_IS_DIRECTORY]        = condition_test_path_is_directory,
                 [CONDITION_PATH_IS_SYMBOLIC_LINK]    = condition_test_path_is_symbolic_link,
                 [CONDITION_PATH_IS_MOUNT_POINT]      = condition_test_path_is_mount_point,
                 [CONDITION_PATH_IS_READ_WRITE]       = condition_test_path_is_read_write,
+                [CONDITION_PATH_IS_ENCRYPTED]        = condition_test_path_is_encrypted,
                 [CONDITION_DIRECTORY_NOT_EMPTY]      = condition_test_directory_not_empty,
                 [CONDITION_FILE_NOT_EMPTY]           = condition_test_file_not_empty,
                 [CONDITION_FILE_IS_EXECUTABLE]       = condition_test_file_is_executable,
@@ -744,6 +814,7 @@ int condition_test(Condition *c) {
                 [CONDITION_NULL]                     = condition_test_null,
                 [CONDITION_CPUS]                     = condition_test_cpus,
                 [CONDITION_MEMORY]                   = condition_test_memory,
+                [CONDITION_ENVIRONMENT]              = condition_test_environment,
         };
 
         int r, b;
@@ -752,7 +823,7 @@ int condition_test(Condition *c) {
         assert(c->type >= 0);
         assert(c->type < _CONDITION_TYPE_MAX);
 
-        r = condition_tests[c->type](c);
+        r = condition_tests[c->type](c, env);
         if (r < 0) {
                 c->result = CONDITION_ERROR;
                 return r;
@@ -763,7 +834,13 @@ int condition_test(Condition *c) {
         return b;
 }
 
-bool condition_test_list(Condition *first, const char *(*to_string)(ConditionType t), condition_test_logger_t logger, void *userdata) {
+bool condition_test_list(
+                Condition *first,
+                char **env,
+                condition_to_string_t to_string,
+                condition_test_logger_t logger,
+                void *userdata) {
+
         Condition *c;
         int triggered = -1;
 
@@ -779,7 +856,7 @@ bool condition_test_list(Condition *first, const char *(*to_string)(ConditionTyp
         LIST_FOREACH(conditions, c, first) {
                 int r;
 
-                r = condition_test(c);
+                r = condition_test(c, env);
 
                 if (logger) {
                         const char *p = c->type == CONDITION_NULL ? "true" : c->parameter;
@@ -812,9 +889,10 @@ bool condition_test_list(Condition *first, const char *(*to_string)(ConditionTyp
         return triggered != 0;
 }
 
-void condition_dump(Condition *c, FILE *f, const char *prefix, const char *(*to_string)(ConditionType t)) {
+void condition_dump(Condition *c, FILE *f, const char *prefix, condition_to_string_t to_string) {
         assert(c);
         assert(f);
+        assert(to_string);
 
         prefix = strempty(prefix);
 
@@ -828,7 +906,7 @@ void condition_dump(Condition *c, FILE *f, const char *prefix, const char *(*to_
                 condition_result_to_string(c->result));
 }
 
-void condition_dump_list(Condition *first, FILE *f, const char *prefix, const char *(*to_string)(ConditionType t)) {
+void condition_dump_list(Condition *first, FILE *f, const char *prefix, condition_to_string_t to_string) {
         Condition *c;
 
         LIST_FOREACH(conditions, c, first)
@@ -852,6 +930,7 @@ static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
         [CONDITION_PATH_IS_SYMBOLIC_LINK] = "ConditionPathIsSymbolicLink",
         [CONDITION_PATH_IS_MOUNT_POINT] = "ConditionPathIsMountPoint",
         [CONDITION_PATH_IS_READ_WRITE] = "ConditionPathIsReadWrite",
+        [CONDITION_PATH_IS_ENCRYPTED] = "ConditionPathIsEncrypted",
         [CONDITION_DIRECTORY_NOT_EMPTY] = "ConditionDirectoryNotEmpty",
         [CONDITION_FILE_NOT_EMPTY] = "ConditionFileNotEmpty",
         [CONDITION_FILE_IS_EXECUTABLE] = "ConditionFileIsExecutable",
@@ -861,6 +940,7 @@ static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
         [CONDITION_NULL] = "ConditionNull",
         [CONDITION_CPUS] = "ConditionCPUs",
         [CONDITION_MEMORY] = "ConditionMemory",
+        [CONDITION_ENVIRONMENT] = "ConditionEnvironment",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(condition_type, ConditionType);
@@ -882,6 +962,7 @@ static const char* const assert_type_table[_CONDITION_TYPE_MAX] = {
         [CONDITION_PATH_IS_SYMBOLIC_LINK] = "AssertPathIsSymbolicLink",
         [CONDITION_PATH_IS_MOUNT_POINT] = "AssertPathIsMountPoint",
         [CONDITION_PATH_IS_READ_WRITE] = "AssertPathIsReadWrite",
+        [CONDITION_PATH_IS_ENCRYPTED] = "AssertPathIsEncrypted",
         [CONDITION_DIRECTORY_NOT_EMPTY] = "AssertDirectoryNotEmpty",
         [CONDITION_FILE_NOT_EMPTY] = "AssertFileNotEmpty",
         [CONDITION_FILE_IS_EXECUTABLE] = "AssertFileIsExecutable",
@@ -891,6 +972,7 @@ static const char* const assert_type_table[_CONDITION_TYPE_MAX] = {
         [CONDITION_NULL] = "AssertNull",
         [CONDITION_CPUS] = "AssertCPUs",
         [CONDITION_MEMORY] = "AssertMemory",
+        [CONDITION_ENVIRONMENT] = "AssertEnvironment",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(assert_type, ConditionType);
index 84322e74259a0cf1e2a80db64fd74af559383e8e..fea74d228d8d0210433c438f524fb1b50829293e 100644 (file)
@@ -18,6 +18,7 @@ typedef enum ConditionType {
         CONDITION_AC_POWER,
         CONDITION_MEMORY,
         CONDITION_CPUS,
+        CONDITION_ENVIRONMENT,
 
         CONDITION_NEEDS_UPDATE,
         CONDITION_FIRST_BOOT,
@@ -28,6 +29,7 @@ typedef enum ConditionType {
         CONDITION_PATH_IS_SYMBOLIC_LINK,
         CONDITION_PATH_IS_MOUNT_POINT,
         CONDITION_PATH_IS_READ_WRITE,
+        CONDITION_PATH_IS_ENCRYPTED,
         CONDITION_DIRECTORY_NOT_EMPTY,
         CONDITION_FILE_NOT_EMPTY,
         CONDITION_FILE_IS_EXECUTABLE,
@@ -66,18 +68,20 @@ typedef struct Condition {
 } Condition;
 
 Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate);
-void condition_free(Condition *c);
+Condition* condition_free(Condition *c);
 Condition* condition_free_list_type(Condition *first, ConditionType type);
 static inline Condition* condition_free_list(Condition *first) {
         return condition_free_list_type(first, _CONDITION_TYPE_INVALID);
 }
 
-int condition_test(Condition *c);
+int condition_test(Condition *c, char **env);
+
 typedef int (*condition_test_logger_t)(void *userdata, int level, int error, const char *file, int line, const char *func, const char *format, ...) _printf_(7, 8);
-bool condition_test_list(Condition *first, const char *(*to_string)(ConditionType t), condition_test_logger_t logger, void *userdata);
+typedef const char* (*condition_to_string_t)(ConditionType t) _const_;
+bool condition_test_list(Condition *first, char **env, condition_to_string_t to_string, condition_test_logger_t logger, void *userdata);
 
-void condition_dump(Condition *c, FILE *f, const char *prefix, const char *(*to_string)(ConditionType t));
-void condition_dump_list(Condition *c, FILE *f, const char *prefix, const char *(*to_string)(ConditionType t));
+void condition_dump(Condition *c, FILE *f, const char *prefix, condition_to_string_t to_string);
+void condition_dump_list(Condition *c, FILE *f, const char *prefix, condition_to_string_t to_string);
 
 const char* condition_type_to_string(ConditionType t) _const_;
 ConditionType condition_type_from_string(const char *s) _pure_;
@@ -96,6 +100,7 @@ static inline bool condition_takes_path(ConditionType t) {
                       CONDITION_PATH_IS_SYMBOLIC_LINK,
                       CONDITION_PATH_IS_MOUNT_POINT,
                       CONDITION_PATH_IS_READ_WRITE,
+                      CONDITION_PATH_IS_ENCRYPTED,
                       CONDITION_DIRECTORY_NOT_EMPTY,
                       CONDITION_FILE_NOT_EMPTY,
                       CONDITION_FILE_IS_EXECUTABLE,
index 3ba33606fbcdfaaa3676404a6f33bd7428d5d351..23cb3b65b67678c84727a1c680d1a194d70ae72e 100644 (file)
@@ -1187,3 +1187,35 @@ int config_parse_permille(const char* unit,
 
         return 0;
 }
+
+int config_parse_vlanprotocol(const char* unit,
+                              const char *filename,
+                              unsigned line,
+                              const char *section,
+                              unsigned section_line,
+                              const char *lvalue,
+                              int ltype,
+                              const char *rvalue,
+                              void *data,
+                              void *userdata) {
+        int *vlan_protocol = data;
+        assert(filename);
+        assert(lvalue);
+
+        if (isempty(rvalue)) {
+                *vlan_protocol = -1;
+                return 0;
+        }
+
+        if (STR_IN_SET(rvalue, "802.1ad", "802.1AD"))
+                *vlan_protocol = ETH_P_8021AD;
+        else if (STR_IN_SET(rvalue, "802.1q", "802.1Q"))
+                *vlan_protocol = ETH_P_8021Q;
+        else {
+                log_syntax(unit, LOG_ERR, filename, line, 0,
+                           "Failed to parse VLAN protocol value, ignoring: %s", rvalue);
+                return 0;
+        }
+
+        return 0;
+}
index 2f3cb4217d01ebda574db82f7de8cdf3450c3933..59e74590cabff84870530ee816a5c1817b03c180 100644 (file)
@@ -142,6 +142,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_ifnames);
 CONFIG_PARSER_PROTOTYPE(config_parse_ip_port);
 CONFIG_PARSER_PROTOTYPE(config_parse_mtu);
 CONFIG_PARSER_PROTOTYPE(config_parse_rlimit);
+CONFIG_PARSER_PROTOTYPE(config_parse_vlanprotocol);
 
 typedef enum Disabled {
         DISABLED_CONFIGURATION,
index 23ad6b06cfa9f06ef307fc1798ff9c21d41765fd..8decac94b2238fd74011a57a66ae1357aa4c77f9 100644 (file)
@@ -75,10 +75,9 @@ int probe_filesystem(const char *node, char **ret_fstype) {
                 log_debug("No type detected on partition %s", node);
                 goto not_found;
         }
-        if (r == -2) {
-                log_debug("Results ambiguous for partition %s", node);
-                return -EUCLEAN;
-        }
+        if (r == -2)
+                return log_debug_errno(SYNTHETIC_ERRNO(EUCLEAN),
+                                       "Results ambiguous for partition %s", node);
         if (r != 0)
                 return errno_or_else(EIO);
 
index fe29af24d079fa675a804d115a27a97d1e2e2643..3bb12f92257983071463aeb6c97a447c6fd92a9c 100644 (file)
@@ -209,7 +209,7 @@ int ethtool_get_link_info(int *ethtool_fd, const char *ifname,
 
                 speed = ethtool_cmd_speed(&ecmd);
                 *ret_speed = speed == (uint32_t) SPEED_UNKNOWN ?
-                        SIZE_MAX : (size_t) speed * 1000 * 1000;
+                        UINT64_MAX : (uint64_t) speed * 1000 * 1000;
         }
 
         if (ret_duplex)
@@ -256,8 +256,13 @@ int ethtool_get_permanent_macaddr(int *ethtool_fd, const char *ifname, struct et
         if (epaddr.addr.size != 6)
                 return -EOPNOTSUPP;
 
+#pragma GCC diagnostic push
+#if HAVE_ZERO_LENGTH_BOUNDS
+#  pragma GCC diagnostic ignored "-Wzero-length-bounds"
+#endif
         for (size_t i = 0; i < epaddr.addr.size; i++)
                 ret->ether_addr_octet[i] = epaddr.addr.data[i];
+#pragma GCC diagnostic pop
 
         return 0;
 }
@@ -431,18 +436,24 @@ int ethtool_set_nic_buffer_size(int *ethtool_fd, const char *ifname, netdev_ring
         if (r < 0)
                 return -errno;
 
-        if (ring->rx_pending_set) {
-                if (ecmd.rx_pending != ring->rx_pending) {
-                        ecmd.rx_pending = ring->rx_pending;
-                        need_update = true;
-                }
+        if (ring->rx_pending_set && ecmd.rx_pending != ring->rx_pending) {
+                ecmd.rx_pending = ring->rx_pending;
+                need_update = true;
         }
 
-        if (ring->tx_pending_set) {
-                   if (ecmd.tx_pending != ring->tx_pending) {
-                           ecmd.tx_pending = ring->tx_pending;
-                           need_update = true;
-                }
+        if (ring->rx_mini_pending_set && ecmd.rx_mini_pending != ring->rx_mini_pending) {
+                ecmd.rx_mini_pending = ring->rx_mini_pending;
+                need_update = true;
+        }
+
+        if (ring->rx_jumbo_pending_set && ecmd.rx_jumbo_pending != ring->rx_jumbo_pending) {
+                ecmd.rx_jumbo_pending = ring->rx_jumbo_pending;
+                need_update = true;
+        }
+
+        if (ring->tx_pending_set && ecmd.tx_pending != ring->tx_pending) {
+                ecmd.tx_pending = ring->tx_pending;
+                need_update = true;
         }
 
         if (need_update) {
@@ -479,7 +490,12 @@ static int get_stringset(int ethtool_fd, struct ifreq *ifr, int stringset_id, st
         if (!buffer.info.sset_mask)
                 return -EINVAL;
 
+#pragma GCC diagnostic push
+#if HAVE_ZERO_LENGTH_BOUNDS
+#  pragma GCC diagnostic ignored "-Wzero-length-bounds"
+#endif
         len = buffer.info.data[0];
+#pragma GCC diagnostic pop
 
         strings = malloc0(sizeof(struct ethtool_gstrings) + len * ETH_GSTRING_LEN);
         if (!strings)
@@ -1036,6 +1052,12 @@ int config_parse_nic_buffer_size(const char *unit,
         if (streq(lvalue, "RxBufferSize")) {
                 ring->rx_pending = k;
                 ring->rx_pending_set = true;
+        } else if (streq(lvalue, "RxMiniBufferSize")) {
+                ring->rx_mini_pending = k;
+                ring->rx_mini_pending_set = true;
+        } else if (streq(lvalue, "RxJumboBufferSize")) {
+                ring->rx_jumbo_pending = k;
+                ring->rx_jumbo_pending_set = true;
         } else if (streq(lvalue, "TxBufferSize")) {
                 ring->tx_pending = k;
                 ring->tx_pending_set = true;
index 55c41f5bc751ef082e7ed32c1a50100947cf1139..47302417089874025badb0723cd47baa4cdde676 100644 (file)
@@ -84,9 +84,13 @@ typedef struct netdev_channels {
 
 typedef struct netdev_ring_param {
         uint32_t rx_pending;
+        uint32_t rx_mini_pending;
+        uint32_t rx_jumbo_pending;
         uint32_t tx_pending;
 
         bool rx_pending_set;
+        bool rx_mini_pending_set;
+        bool rx_jumbo_pending_set;
         bool tx_pending_set;
 } netdev_ring_param;
 
index fd51abf05d0d83d3268d46eeb2991f2a6008e045..87ef5c3f00c98172ea7d85ab3e4a3d4c086aaab3 100644 (file)
@@ -73,6 +73,7 @@ typedef struct TableData {
         bool uppercase;             /* Uppercase string on display */
 
         const char *color;          /* ANSI color string to use for this cell. When written to terminal should not move cursor. Will automatically be reset after the cell */
+        const char *rgap_color;     /* The ANSI color to use for the gap right of this cell. Usually used to underline entire rows in a gapless fashion */
         char *url;                  /* A URL to use for a clickable hyperlink */
         char *formatted;            /* A cached textual representation of the cell data, before ellipsation/alignment */
 
@@ -334,7 +335,7 @@ static bool table_data_matches(
                 return false;
 
         /* If a color/url/uppercase flag is set, refuse to merge */
-        if (d->color)
+        if (d->color || d->rgap_color)
                 return false;
         if (d->url)
                 return false;
@@ -542,6 +543,7 @@ static int table_dedup_cell(Table *t, TableCell *cell) {
                 return -ENOMEM;
 
         nd->color = od->color;
+        nd->rgap_color = od->rgap_color;
         nd->url = TAKE_PTR(curl);
         nd->uppercase = od->uppercase;
 
@@ -671,6 +673,20 @@ int table_set_color(Table *t, TableCell *cell, const char *color) {
         return 0;
 }
 
+int table_set_rgap_color(Table *t, TableCell *cell, const char *color) {
+        int r;
+
+        assert(t);
+        assert(cell);
+
+        r = table_dedup_cell(t, cell);
+        if (r < 0)
+                return r;
+
+        table_get_data(t, cell)->rgap_color = empty_to_null(color);
+        return 0;
+}
+
 int table_set_url(Table *t, TableCell *cell, const char *url) {
         _cleanup_free_ char *copy = NULL;
         int r;
@@ -744,6 +760,7 @@ int table_update(Table *t, TableCell *cell, TableDataType type, const void *data
                 return -ENOMEM;
 
         nd->color = od->color;
+        nd->rgap_color = od->rgap_color;
         nd->url = TAKE_PTR(curl);
         nd->uppercase = od->uppercase;
 
@@ -952,6 +969,25 @@ int table_add_many_internal(Table *t, TableDataType first_type, ...) {
                         break;
                 }
 
+                case TABLE_SET_RGAP_COLOR: {
+                        const char *c = va_arg(ap, const char*);
+                        r = table_set_rgap_color(t, last_cell, c);
+                        break;
+                }
+
+                case TABLE_SET_BOTH_COLORS: {
+                        const char *c = va_arg(ap, const char*);
+
+                        r = table_set_color(t, last_cell, c);
+                        if (r < 0) {
+                                va_end(ap);
+                                return r;
+                        }
+
+                        r = table_set_rgap_color(t, last_cell, c);
+                        break;
+                }
+
                 case TABLE_SET_URL: {
                         const char *u = va_arg(ap, const char*);
                         r = table_set_url(t, last_cell, u);
@@ -1241,7 +1277,7 @@ static int table_data_compare(const size_t *a, const size_t *b, Table *t) {
         return CMP(*a, *b);
 }
 
-static const char *table_data_format(Table *t, TableData *d) {
+static const char *table_data_format(Table *t, TableData *d, bool avoid_uppercasing) {
         assert(d);
 
         if (d->formatted)
@@ -1253,7 +1289,7 @@ static const char *table_data_format(Table *t, TableData *d) {
 
         case TABLE_STRING:
         case TABLE_PATH:
-                if (d->uppercase) {
+                if (d->uppercase && !avoid_uppercasing) {
                         char *p, *q;
 
                         d->formatted = new(char, strlen(d->string) + 1);
@@ -1272,6 +1308,9 @@ static const char *table_data_format(Table *t, TableData *d) {
         case TABLE_STRV: {
                 char *p;
 
+                if (strv_isempty(d->strv))
+                        return strempty(t->empty_string);
+
                 p = strv_join(d->strv, "\n");
                 if (!p)
                         return NULL;
@@ -1602,7 +1641,7 @@ static int table_data_requested_width_height(
         const char *t;
         int r;
 
-        t = table_data_format(table, d);
+        t = table_data_format(table, d, false);
         if (!t)
                 return -ENOMEM;
 
@@ -1694,6 +1733,20 @@ static char *align_string_mem(const char *str, const char *url, size_t new_lengt
         return ret;
 }
 
+static bool table_data_isempty(TableData *d) {
+        assert(d);
+
+        if (d->type == TABLE_EMPTY)
+                return true;
+
+        /* Let's also consider an empty strv as truly empty. */
+        if (d->type == TABLE_STRV)
+                return strv_isempty(d->strv);
+
+        /* Note that an empty string we do not consider empty here! */
+        return false;
+}
+
 static const char* table_data_color(TableData *d) {
         assert(d);
 
@@ -1701,12 +1754,21 @@ static const char* table_data_color(TableData *d) {
                 return d->color;
 
         /* Let's implicitly color all "empty" cells in grey, in case an "empty_string" is set that is not empty */
-        if (d->type == TABLE_EMPTY)
+        if (table_data_isempty(d))
                 return ansi_grey();
 
         return NULL;
 }
 
+static const char* table_data_rgap_color(TableData *d) {
+        assert(d);
+
+        if (d->rgap_color)
+                return d->rgap_color;
+
+        return NULL;
+}
+
 int table_print(Table *t, FILE *f) {
         size_t n_rows, *minimum_width, *maximum_width, display_columns, *requested_width,
                 i, j, table_minimum_width, table_maximum_width, table_requested_width, table_effective_width,
@@ -1784,7 +1846,7 @@ int table_print(Table *t, FILE *f) {
                                  * ellipsis. Hence, let's figure out the last line, and account for its
                                  * length plus ellipsis. */
 
-                                field = table_data_format(t, d);
+                                field = table_data_format(t, d, false);
                                 if (!field)
                                         return -ENOMEM;
 
@@ -1958,18 +2020,19 @@ int table_print(Table *t, FILE *f) {
                         row = t->data + i * t->n_columns;
 
                 do {
+                        const char *gap_color = NULL;
                         more_sublines = false;
 
                         for (j = 0; j < display_columns; j++) {
                                 _cleanup_free_ char *buffer = NULL, *extracted = NULL;
                                 bool lines_truncated = false;
-                                const char *field;
+                                const char *field, *color = NULL;
                                 TableData *d;
                                 size_t l;
 
                                 assert_se(d = row[t->display_map ? t->display_map[j] : j]);
 
-                                field = table_data_format(t, d);
+                                field = table_data_format(t, d, false);
                                 if (!field)
                                         return -ENOMEM;
 
@@ -2042,23 +2105,35 @@ int table_print(Table *t, FILE *f) {
                                         field = buffer;
                                 }
 
-                                if (row == t->data) /* underline header line fully, including the column separator */
-                                        fputs(ansi_underline(), f);
+                                if (colors_enabled()) {
+                                        if (gap_color)
+                                                fputs(gap_color, f);
+                                        else if (row == t->data) /* underline header line fully, including the column separator */
+                                                fputs(ansi_underline(), f);
+                                }
 
                                 if (j > 0)
-                                        fputc(' ', f); /* column separator */
+                                        fputc(' ', f); /* column separator left of cell */
+
+                                if (colors_enabled()) {
+                                        color = table_data_color(d);
 
-                                if (table_data_color(d) && colors_enabled()) {
-                                        if (row == t->data) /* first undo header underliner */
+                                        /* Undo gap color */
+                                        if (gap_color || (color && row == t->data))
                                                 fputs(ANSI_NORMAL, f);
 
-                                        fputs(table_data_color(d), f);
+                                        if (color)
+                                                fputs(color, f);
+                                        else if (gap_color && row == t->data) /* underline header line cell */
+                                                fputs(ansi_underline(), f);
                                 }
 
                                 fputs(field, f);
 
-                                if (colors_enabled() && (table_data_color(d) || row == t->data))
+                                if (colors_enabled() && (color || row == t->data))
                                         fputs(ANSI_NORMAL, f);
+
+                                gap_color = table_data_rgap_color(d);
                         }
 
                         fputc('\n', f);
@@ -2194,7 +2269,7 @@ static int table_data_to_json(TableData *d, JsonVariant **ret) {
 
         case TABLE_SIZE:
         case TABLE_BPS:
-                if (d->size == (size_t) -1)
+                if (d->size == (uint64_t) -1)
                         return json_variant_new_null(ret);
 
                 return json_variant_new_unsigned(ret, d->size);
@@ -2256,6 +2331,24 @@ static int table_data_to_json(TableData *d, JsonVariant **ret) {
         }
 }
 
+static char* string_to_json_field_name(const char *f) {
+        char *c, *x;
+
+        /* Tries to make a string more suitable as JSON field name. There are no strict rules defined what a
+         * field name can be hence this is a bit vague and black magic. Right now we only convert spaces to
+         * underscores and leave everything as is. */
+
+        c = strdup(f);
+        if (!c)
+                return NULL;
+
+        for (x = c; *x; x++)
+                if (isspace(*x))
+                        *x = '_';
+
+        return c;
+}
+
 int table_to_json(Table *t, JsonVariant **ret) {
         JsonVariant **rows = NULL, **elements = NULL;
         _cleanup_free_ size_t *sorted = NULL;
@@ -2298,11 +2391,27 @@ int table_to_json(Table *t, JsonVariant **ret) {
         }
 
         for (j = 0; j < display_columns; j++) {
+                _cleanup_free_ char *mangled = NULL;
+                const char *formatted;
                 TableData *d;
 
                 assert_se(d = t->data[t->display_map ? t->display_map[j] : j]);
 
-                r = table_data_to_json(d, elements + j*2);
+                /* Field names must be strings, hence format whatever we got here as a string first */
+                formatted = table_data_format(t, d, true);
+                if (!formatted) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                /* Arbitrary strings suck as field names, try to mangle them into something more suitable hence */
+                mangled = string_to_json_field_name(formatted);
+                if (!mangled) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                r = json_variant_new_string(elements + j*2, mangled);
                 if (r < 0)
                         goto finish;
         }
index 62f1ed740d90296afe0c2f5aa3423632232aae52..20b4ebd39b584400e129799722e095e0524a3c07 100644 (file)
@@ -47,6 +47,8 @@ typedef enum TableDataType {
         TABLE_SET_ALIGN_PERCENT,
         TABLE_SET_ELLIPSIZE_PERCENT,
         TABLE_SET_COLOR,
+        TABLE_SET_RGAP_COLOR,
+        TABLE_SET_BOTH_COLORS,
         TABLE_SET_URL,
         TABLE_SET_UPPERCASE,
 
@@ -89,6 +91,7 @@ int table_set_weight(Table *t, TableCell *cell, unsigned weight);
 int table_set_align_percent(Table *t, TableCell *cell, unsigned percent);
 int table_set_ellipsize_percent(Table *t, TableCell *cell, unsigned percent);
 int table_set_color(Table *t, TableCell *cell, const char *color);
+int table_set_rgap_color(Table *t, TableCell *cell, const char *color);
 int table_set_url(Table *t, TableCell *cell, const char *url);
 int table_set_uppercase(Table *t, TableCell *cell, bool b);
 
index 86a57e6b2ce8c2f9f304da38dc88d2cce94bf6e7..b19127be09a73facb69ddadd74844e3a8b0f0154 100644 (file)
@@ -35,6 +35,30 @@ int fstab_has_fstype(const char *fstype) {
         return false;
 }
 
+bool fstab_is_extrinsic(const char *mount, const char *opts) {
+
+        /* Don't bother with the OS data itself */
+        if (PATH_IN_SET(mount,
+                        "/",
+                        "/usr",
+                        "/etc"))
+                return true;
+
+        if (PATH_STARTSWITH_SET(mount,
+                                "/run/initramfs",    /* This should stay around from before we boot until after we shutdown */
+                                "/proc",             /* All of this is API VFS */
+                                "/sys",              /* … dito … */
+                                "/dev"))             /* … dito … */
+                return true;
+
+        /* If this is an initrd mount, and we are not in the initrd, then leave
+         * this around forever, too. */
+        if (opts && fstab_test_option(opts, "x-initrd.mount\0") && !in_initrd())
+                return true;
+
+        return false;
+}
+
 int fstab_is_mount_point(const char *mount) {
         _cleanup_endmntent_ FILE *f = NULL;
         struct mntent *m;
index f575ed0bb2996962e10d14b5d28fc5004e740a18..a73575e95c88b095873f4461de3dab4f4560329d 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "macro.h"
 
+bool fstab_is_extrinsic(const char *mount, const char *opts);
 int fstab_is_mount_point(const char *mount);
 int fstab_has_fstype(const char *fstype);
 
index acdd0096f1419391bae148a8a041928b4a8cd822..04d2f86a4a3e32dc1843b285a33bb619244a3be7 100644 (file)
@@ -260,6 +260,9 @@ int generator_write_device_deps(
         _cleanup_free_ char *node = NULL, *unit = NULL;
         int r;
 
+        if (fstab_is_extrinsic(where, opts))
+                return 0;
+
         if (!fstab_test_option(opts, "_netdev\0"))
                 return 0;
 
index 2061384afe30d0e589d9121c3ba4de7a9f55dc5f..9267d52b96e993f0a9501808a35a3fbf58ec07db 100644 (file)
@@ -115,7 +115,7 @@ int install_full_printf(const UnitFileInstallInfo *i, const char *format, char *
          * %U the UID of the running user
          * %u the username of running user
          * %m the machine ID of the running system
-         * %H the host name of the running system
+         * %H the hostname of the running system
          * %b the boot ID of the running system
          * %v `uname -r` of the running system
          */
@@ -133,9 +133,14 @@ int install_full_printf(const UnitFileInstallInfo *i, const char *format, char *
                 { 'u', specifier_user_name,           NULL },
 
                 { 'm', specifier_machine_id,          NULL },
-                { 'H', specifier_host_name,           NULL },
                 { 'b', specifier_boot_id,             NULL },
+                { 'H', specifier_host_name,           NULL },
                 { 'v', specifier_kernel_release,      NULL },
+                { 'a', specifier_architecture,        NULL },
+                { 'o', specifier_os_id,               NULL },
+                { 'w', specifier_os_version_id,       NULL },
+                { 'B', specifier_os_build_id,         NULL },
+                { 'W', specifier_os_variant_id,       NULL },
                 {}
         };
 
index 236f279ffb199c0e2803ffad0f5055cca3259cd2..21ad5aab36a6bc0485efd26f601bf521c911e13c 100644 (file)
@@ -55,16 +55,11 @@ typedef enum {
         PRESET_DISABLE,
 } PresetAction;
 
-typedef struct {
+struct UnitFilePresetRule {
         char *pattern;
         PresetAction action;
         char **instances;
-} PresetRule;
-
-typedef struct {
-        PresetRule *rules;
-        size_t n_rules;
-} Presets;
+};
 
 static bool unit_file_install_info_has_rules(const UnitFileInstallInfo *i) {
         assert(i);
@@ -80,7 +75,7 @@ static bool unit_file_install_info_has_also(const UnitFileInstallInfo *i) {
         return !strv_isempty(i->also);
 }
 
-static void presets_freep(Presets *p) {
+void unit_file_presets_freep(UnitFilePresets *p) {
         size_t i;
 
         if (!p)
@@ -1018,10 +1013,14 @@ static int install_info_add(
         int r;
 
         assert(c);
-        assert(name || path);
 
-        if (!name)
+        if (!name) {
+                /* 'name' and 'path' must not both be null. Check here 'path' using assert_se() to
+                 * workaround a bug in gcc that generates a -Wnonnull warning when calling basename(),
+                 * but this cannot be possible in any code path (See #6119). */
+                assert_se(path);
                 name = basename(path);
+        }
 
         if (!unit_name_is_valid(name, UNIT_NAME_ANY))
                 return -EINVAL;
@@ -1231,7 +1230,7 @@ static int unit_file_load(
                         return -EINVAL;
                 if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE|UNIT_NAME_INSTANCE) && !unit_type_may_template(type))
                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                               "Unit type %s cannot be templated.", unit_type_to_string(type));
+                                               "%s: unit type %s cannot be templated, ignoring.", path, unit_type_to_string(type));
 
                 if (!(flags & SEARCH_LOAD)) {
                         r = lstat(path, &st);
@@ -2772,6 +2771,12 @@ int unit_file_lookup_state(
                 break;
 
         case UNIT_FILE_TYPE_REGULAR:
+                /* Check if the name we were querying is actually an alias */
+                if (!streq(name, basename(i->path)) && !unit_name_is_valid(i->name, UNIT_NAME_INSTANCE)) {
+                        state = UNIT_FILE_ALIAS;
+                        break;
+                }
+
                 r = path_is_generator(paths, i->path);
                 if (r < 0)
                         return r;
@@ -2913,8 +2918,8 @@ static int presets_find_config(UnitFileScope scope, const char *root_dir, char *
         return conf_files_list_strv(files, ".preset", root_dir, 0, dirs);
 }
 
-static int read_presets(UnitFileScope scope, const char *root_dir, Presets *presets) {
-        _cleanup_(presets_freep) Presets ps = {};
+static int read_presets(UnitFileScope scope, const char *root_dir, UnitFilePresets *presets) {
+        _cleanup_(unit_file_presets_freep) UnitFilePresets ps = {};
         size_t n_allocated = 0;
         _cleanup_strv_free_ char **files = NULL;
         char **p;
@@ -2942,7 +2947,7 @@ static int read_presets(UnitFileScope scope, const char *root_dir, Presets *pres
 
                 for (;;) {
                         _cleanup_free_ char *line = NULL;
-                        PresetRule rule = {};
+                        UnitFilePresetRule rule = {};
                         const char *parameter;
                         char *l;
 
@@ -2972,7 +2977,7 @@ static int read_presets(UnitFileScope scope, const char *root_dir, Presets *pres
                                         continue;
                                 }
 
-                                rule = (PresetRule) {
+                                rule = (UnitFilePresetRule) {
                                         .pattern = unit_name,
                                         .action = PRESET_ENABLE,
                                         .instances = instances,
@@ -2987,7 +2992,7 @@ static int read_presets(UnitFileScope scope, const char *root_dir, Presets *pres
                                 if (!pattern)
                                         return -ENOMEM;
 
-                                rule = (PresetRule) {
+                                rule = (UnitFilePresetRule) {
                                         .pattern = pattern,
                                         .action = PRESET_DISABLE,
                                 };
@@ -3005,14 +3010,15 @@ static int read_presets(UnitFileScope scope, const char *root_dir, Presets *pres
                 }
         }
 
+        ps.initialized = true;
         *presets = ps;
-        ps = (Presets){};
+        ps = (UnitFilePresets){};
 
         return 0;
 }
 
 static int pattern_match_multiple_instances(
-                        const PresetRule rule,
+                        const UnitFilePresetRule rule,
                         const char *unit_name,
                         char ***ret) {
 
@@ -3066,17 +3072,17 @@ static int pattern_match_multiple_instances(
         return 0;
 }
 
-static int query_presets(const char *name, const Presets presets, char ***instance_name_list) {
+static int query_presets(const char *name, const UnitFilePresets *presets, char ***instance_name_list) {
         PresetAction action = PRESET_UNKNOWN;
         size_t i;
         char **s;
         if (!unit_name_is_valid(name, UNIT_NAME_ANY))
                 return -EINVAL;
 
-        for (i = 0; i < presets.n_rules; i++)
-                if (pattern_match_multiple_instances(presets.rules[i], name, instance_name_list) > 0 ||
-                    fnmatch(presets.rules[i].pattern, name, FNM_NOESCAPE) == 0) {
-                        action = presets.rules[i].action;
+        for (i = 0; i < presets->n_rules; i++)
+                if (pattern_match_multiple_instances(presets->rules[i], name, instance_name_list) > 0 ||
+                    fnmatch(presets->rules[i].pattern, name, FNM_NOESCAPE) == 0) {
+                        action = presets->rules[i].action;
                         break;
                 }
 
@@ -3099,15 +3105,19 @@ static int query_presets(const char *name, const Presets presets, char ***instan
         }
 }
 
-int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) {
-        _cleanup_(presets_freep) Presets presets = {};
+int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name, UnitFilePresets *cached) {
+        _cleanup_(unit_file_presets_freep) UnitFilePresets tmp = {};
         int r;
 
-        r = read_presets(scope, root_dir, &presets);
-        if (r < 0)
-                return r;
+        if (!cached)
+                cached = &tmp;
+        if (!cached->initialized) {
+                r = read_presets(scope, root_dir, cached);
+                if (r < 0)
+                        return r;
+        }
 
-        return query_presets(name, presets, NULL);
+        return query_presets(name, cached, NULL);
 }
 
 static int execute_preset(
@@ -3162,7 +3172,7 @@ static int preset_prepare_one(
                 InstallContext *minus,
                 LookupPaths *paths,
                 const char *name,
-                Presets presets,
+                const UnitFilePresets *presets,
                 UnitFileChange **changes,
                 size_t *n_changes) {
 
@@ -3221,7 +3231,7 @@ int unit_file_preset(
 
         _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
         _cleanup_(lookup_paths_free) LookupPaths paths = {};
-        _cleanup_(presets_freep) Presets presets = {};
+        _cleanup_(unit_file_presets_freep) UnitFilePresets presets = {};
         const char *config_path;
         char **i;
         int r;
@@ -3243,7 +3253,7 @@ int unit_file_preset(
                 return r;
 
         STRV_FOREACH(i, files) {
-                r = preset_prepare_one(scope, &plus, &minus, &paths, *i, presets, changes, n_changes);
+                r = preset_prepare_one(scope, &plus, &minus, &paths, *i, &presets, changes, n_changes);
                 if (r < 0)
                         return r;
         }
@@ -3261,7 +3271,7 @@ int unit_file_preset_all(
 
         _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
         _cleanup_(lookup_paths_free) LookupPaths paths = {};
-        _cleanup_(presets_freep) Presets presets = {};
+        _cleanup_(unit_file_presets_freep) UnitFilePresets presets = {};
         const char *config_path = NULL;
         char **i;
         int r;
@@ -3305,7 +3315,7 @@ int unit_file_preset_all(
                                 continue;
 
                         /* we don't pass changes[] in, because we want to handle errors on our own */
-                        r = preset_prepare_one(scope, &plus, &minus, &paths, de->d_name, presets, NULL, 0);
+                        r = preset_prepare_one(scope, &plus, &minus, &paths, de->d_name, &presets, NULL, 0);
                         if (r == -ERFKILL)
                                 r = unit_file_changes_add(changes, n_changes,
                                                           UNIT_FILE_IS_MASKED, de->d_name, NULL);
@@ -3344,7 +3354,7 @@ int unit_file_get_list(
                 char **patterns) {
 
         _cleanup_(lookup_paths_free) LookupPaths paths = {};
-        char **i;
+        char **dirname;
         int r;
 
         assert(scope >= 0);
@@ -3355,16 +3365,16 @@ int unit_file_get_list(
         if (r < 0)
                 return r;
 
-        STRV_FOREACH(i, paths.search_path) {
+        STRV_FOREACH(dirname, paths.search_path) {
                 _cleanup_closedir_ DIR *d = NULL;
                 struct dirent *de;
 
-                d = opendir(*i);
+                d = opendir(*dirname);
                 if (!d) {
                         if (errno == ENOENT)
                                 continue;
                         if (IN_SET(errno, ENOTDIR, EACCES)) {
-                                log_debug_errno(errno, "Failed to open \"%s\": %m", *i);
+                                log_debug_errno(errno, "Failed to open \"%s\": %m", *dirname);
                                 continue;
                         }
 
@@ -3392,7 +3402,7 @@ int unit_file_get_list(
                         if (!f)
                                 return -ENOMEM;
 
-                        f->path = path_make_absolute(de->d_name, *i);
+                        f->path = path_make_absolute(de->d_name, *dirname);
                         if (!f->path)
                                 return -ENOMEM;
 
@@ -3416,34 +3426,35 @@ int unit_file_get_list(
 }
 
 static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
-        [UNIT_FILE_ENABLED] = "enabled",
+        [UNIT_FILE_ENABLED]         = "enabled",
         [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
-        [UNIT_FILE_LINKED] = "linked",
-        [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
-        [UNIT_FILE_MASKED] = "masked",
-        [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
-        [UNIT_FILE_STATIC] = "static",
-        [UNIT_FILE_DISABLED] = "disabled",
-        [UNIT_FILE_INDIRECT] = "indirect",
-        [UNIT_FILE_GENERATED] = "generated",
-        [UNIT_FILE_TRANSIENT] = "transient",
-        [UNIT_FILE_BAD] = "bad",
+        [UNIT_FILE_LINKED]          = "linked",
+        [UNIT_FILE_LINKED_RUNTIME]  = "linked-runtime",
+        [UNIT_FILE_ALIAS]           = "alias",
+        [UNIT_FILE_MASKED]          = "masked",
+        [UNIT_FILE_MASKED_RUNTIME]  = "masked-runtime",
+        [UNIT_FILE_STATIC]          = "static",
+        [UNIT_FILE_DISABLED]        = "disabled",
+        [UNIT_FILE_INDIRECT]        = "indirect",
+        [UNIT_FILE_GENERATED]       = "generated",
+        [UNIT_FILE_TRANSIENT]       = "transient",
+        [UNIT_FILE_BAD]             = "bad",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
 
 static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
-        [UNIT_FILE_SYMLINK] = "symlink",
-        [UNIT_FILE_UNLINK] = "unlink",
-        [UNIT_FILE_IS_MASKED] = "masked",
+        [UNIT_FILE_SYMLINK]     = "symlink",
+        [UNIT_FILE_UNLINK]      = "unlink",
+        [UNIT_FILE_IS_MASKED]   = "masked",
         [UNIT_FILE_IS_DANGLING] = "dangling",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);
 
 static const char* const unit_file_preset_mode_table[_UNIT_FILE_PRESET_MAX] = {
-        [UNIT_FILE_PRESET_FULL] = "full",
-        [UNIT_FILE_PRESET_ENABLE_ONLY] = "enable-only",
+        [UNIT_FILE_PRESET_FULL]         = "full",
+        [UNIT_FILE_PRESET_ENABLE_ONLY]  = "enable-only",
         [UNIT_FILE_PRESET_DISABLE_ONLY] = "disable-only",
 };
 
index 54d22a45d3476f428efdaa49eea41d674c117478..5ff8bec16539bab90d5a540efed7bc6dc0adcc02 100644 (file)
@@ -189,7 +189,16 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang
 
 int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char **ret_dst);
 
-int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name);
+typedef struct UnitFilePresetRule UnitFilePresetRule;
+
+typedef struct {
+        UnitFilePresetRule *rules;
+        size_t n_rules;
+        bool initialized;
+} UnitFilePresets;
+
+void unit_file_presets_freep(UnitFilePresets *p);
+int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name, UnitFilePresets *cached);
 
 const char *unit_file_state_to_string(UnitFileState s) _const_;
 UnitFileState unit_file_state_from_string(const char *s) _pure_;
diff --git a/src/shared/ipvlan-util.c b/src/shared/ipvlan-util.c
new file mode 100644 (file)
index 0000000..da6be76
--- /dev/null
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <net/if.h>
+
+#include "ipvlan-util.h"
+#include "string-table.h"
+
+static const char* const ipvlan_mode_table[_NETDEV_IPVLAN_MODE_MAX] = {
+        [NETDEV_IPVLAN_MODE_L2] = "L2",
+        [NETDEV_IPVLAN_MODE_L3] = "L3",
+        [NETDEV_IPVLAN_MODE_L3S] = "L3S",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(ipvlan_mode, IPVlanMode);
+
+static const char* const ipvlan_flags_table[_NETDEV_IPVLAN_FLAGS_MAX] = {
+        [NETDEV_IPVLAN_FLAGS_BRIGDE] = "bridge",
+        [NETDEV_IPVLAN_FLAGS_PRIVATE] = "private",
+        [NETDEV_IPVLAN_FLAGS_VEPA] = "vepa",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(ipvlan_flags, IPVlanFlags);
diff --git a/src/shared/ipvlan-util.h b/src/shared/ipvlan-util.h
new file mode 100644 (file)
index 0000000..dda659d
--- /dev/null
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <netinet/in.h>
+#include <linux/if_link.h>
+
+#include "macro.h"
+
+typedef enum IPVlanMode {
+        NETDEV_IPVLAN_MODE_L2 = IPVLAN_MODE_L2,
+        NETDEV_IPVLAN_MODE_L3 = IPVLAN_MODE_L3,
+        NETDEV_IPVLAN_MODE_L3S = IPVLAN_MODE_L3S,
+        _NETDEV_IPVLAN_MODE_MAX,
+        _NETDEV_IPVLAN_MODE_INVALID = -1
+} IPVlanMode;
+
+typedef enum IPVlanFlags {
+        NETDEV_IPVLAN_FLAGS_BRIGDE,
+        NETDEV_IPVLAN_FLAGS_PRIVATE = IPVLAN_F_PRIVATE,
+        NETDEV_IPVLAN_FLAGS_VEPA = IPVLAN_F_VEPA,
+        _NETDEV_IPVLAN_FLAGS_MAX,
+        _NETDEV_IPVLAN_FLAGS_INVALID = -1
+} IPVlanFlags;
+
+const char *ipvlan_mode_to_string(IPVlanMode d) _const_;
+IPVlanMode ipvlan_mode_from_string(const char *d) _pure_;
+
+const char *ipvlan_flags_to_string(IPVlanFlags d) _const_;
+IPVlanFlags ipvlan_flags_from_string(const char *d) _pure_;
index 132dda14fc8bbca8d2bd178d3c7b233e241c459c..330ad456eea4d516925d81e8de833e5977f26545 100644 (file)
@@ -1396,6 +1396,19 @@ void json_variant_sensitive(JsonVariant *v) {
         v->sensitive = true;
 }
 
+bool json_variant_is_sensitive(JsonVariant *v) {
+        v = json_variant_formalize(v);
+        if (!json_variant_is_regular(v))
+                return false;
+
+        return v->sensitive;
+}
+
+static void json_variant_propagate_sensitive(JsonVariant *from, JsonVariant *to) {
+        if (json_variant_is_sensitive(from))
+                json_variant_sensitive(to);
+}
+
 int json_variant_get_source(JsonVariant *v, const char **ret_source, unsigned *ret_line, unsigned *ret_column) {
         assert_return(v, -EINVAL);
 
@@ -1829,6 +1842,8 @@ int json_variant_filter(JsonVariant **v, char **to_remove) {
         if (r < 0)
                 return r;
 
+        json_variant_propagate_sensitive(*v, w);
+
         json_variant_unref(*v);
         *v = TAKE_PTR(w);
 
@@ -1898,6 +1913,8 @@ int json_variant_set_field(JsonVariant **v, const char *field, JsonVariant *valu
         if (r < 0)
                 return r;
 
+        json_variant_propagate_sensitive(*v, w);
+
         json_variant_unref(*v);
         *v = TAKE_PTR(w);
 
@@ -2005,6 +2022,9 @@ int json_variant_merge(JsonVariant **v, JsonVariant *m) {
         if (r < 0)
                 return r;
 
+        json_variant_propagate_sensitive(*v, w);
+        json_variant_propagate_sensitive(m, w);
+
         json_variant_unref(*v);
         *v = TAKE_PTR(w);
 
@@ -2044,10 +2064,11 @@ int json_variant_append_array(JsonVariant **v, JsonVariant *element) {
 
                 r = json_variant_new_array(&nv, array, i + 1);
         }
-
         if (r < 0)
                 return r;
 
+        json_variant_propagate_sensitive(*v, nv);
+
         json_variant_unref(*v);
         *v = TAKE_PTR(nv);
 
@@ -2193,6 +2214,8 @@ static int json_variant_copy(JsonVariant **nv, JsonVariant *v) {
 
         memcpy_safe(&c->value, source, k);
 
+        json_variant_propagate_sensitive(v, c);
+
         *nv = c;
         return 0;
 }
@@ -4178,6 +4201,9 @@ int json_variant_sort(JsonVariant **v) {
         r = json_variant_new_object(&n, a, m);
         if (r < 0)
                 return r;
+
+        json_variant_propagate_sensitive(*v, n);
+
         if (!n->sorted) /* Check if this worked. This will fail if there are multiple identical keys used. */
                 return -ENOTUNIQ;
 
@@ -4226,6 +4252,9 @@ int json_variant_normalize(JsonVariant **v) {
         }
         if (r < 0)
                 goto finish;
+
+        json_variant_propagate_sensitive(*v, n);
+
         if (!n->normalized) { /* Let's see if normalization worked. It will fail if there are multiple
                                * identical keys used in the same object anywhere, or if there are floating
                                * point numbers used (see below) */
index a4e5b6f507bae7af81c858baa858e4dbe93ef5c8..ceb01a2028a461838bddfceb7f6424eb48d7edb9 100644 (file)
@@ -135,6 +135,7 @@ JsonVariant *json_variant_by_key_full(JsonVariant *v, const char *key, JsonVaria
 bool json_variant_equal(JsonVariant *a, JsonVariant *b);
 
 void json_variant_sensitive(JsonVariant *v);
+bool json_variant_is_sensitive(JsonVariant *v);
 
 struct json_variant_foreach_state {
         JsonVariant *variant;
index 2bfd0b60c26b1198eb1802ec91ab8c52123a5b1e..f7fe3b3220d5e36e866353ae2aad52ca2c1f176d 100644 (file)
@@ -121,8 +121,8 @@ static int parse_fieldv(const void *data, size_t length, const ParseFieldVec *fi
         return 0;
 }
 
-static int field_set_test(Set *fields, const char *name, size_t n) {
-        char *s = NULL;
+static int field_set_test(const Set *fields, const char *name, size_t n) {
+        char *s;
 
         if (!fields)
                 return 1;
@@ -131,7 +131,7 @@ static int field_set_test(Set *fields, const char *name, size_t n) {
         if (!s)
                 return log_oom();
 
-        return set_get(fields, s) ? 1 : 0;
+        return set_contains(fields, s);
 }
 
 static bool shall_print(const char *p, size_t l, OutputFlags flags) {
@@ -369,7 +369,7 @@ static int output_short(
                 OutputMode mode,
                 unsigned n_columns,
                 OutputFlags flags,
-                Set *output_fields,
+                const Set *output_fields,
                 const size_t highlight[2]) {
 
         int r;
@@ -533,7 +533,7 @@ static int output_verbose(
                 OutputMode mode,
                 unsigned n_columns,
                 OutputFlags flags,
-                Set *output_fields,
+                const Set *output_fields,
                 const size_t highlight[2]) {
 
         const void *data;
@@ -652,7 +652,7 @@ static int output_export(
                 OutputMode mode,
                 unsigned n_columns,
                 OutputFlags flags,
-                Set *output_fields,
+                const Set *output_fields,
                 const size_t highlight[2]) {
 
         sd_id128_t boot_id;
@@ -849,7 +849,7 @@ static int update_json_data(
 static int update_json_data_split(
                 Hashmap *h,
                 OutputFlags flags,
-                Set *output_fields,
+                const Set *output_fields,
                 const void *data,
                 size_t size) {
 
@@ -870,7 +870,7 @@ static int update_json_data_split(
                 return 0;
 
         name = strndupa(data, eq - (const char*) data);
-        if (output_fields && !set_get(output_fields, name))
+        if (output_fields && !set_contains(output_fields, name))
                 return 0;
 
         return update_json_data(h, flags, name, eq + 1, size - (eq - (const char*) data) - 1);
@@ -882,7 +882,7 @@ static int output_json(
                 OutputMode mode,
                 unsigned n_columns,
                 OutputFlags flags,
-                Set *output_fields,
+                const Set *output_fields,
                 const size_t highlight[2]) {
 
         char sid[SD_ID128_STRING_MAX], usecbuf[DECIMAL_STR_MAX(usec_t)];
@@ -1016,57 +1016,83 @@ finish:
         return r;
 }
 
-static int output_cat(
+static int output_cat_field(
                 FILE *f,
                 sd_journal *j,
-                OutputMode mode,
-                unsigned n_columns,
                 OutputFlags flags,
-                Set *output_fields,
+                const char *field,
                 const size_t highlight[2]) {
 
+        const char *highlight_on, *highlight_off;
         const void *data;
-        size_t l;
+        size_t l, fl;
         int r;
-        const char *highlight_on = "", *highlight_off = "";
-
-        assert(j);
-        assert(f);
 
-        if (flags & OUTPUT_COLOR) {
+        if (FLAGS_SET(flags, OUTPUT_COLOR)) {
                 highlight_on = ANSI_HIGHLIGHT_RED;
                 highlight_off = ANSI_NORMAL;
-        }
-
-        sd_journal_set_data_threshold(j, 0);
+        } else
+                highlight_on = highlight_off = "";
 
-        r = sd_journal_get_data(j, "MESSAGE", &data, &l);
+        r = sd_journal_get_data(j, field, &data, &l);
         if (r == -EBADMSG) {
                 log_debug_errno(r, "Skipping message we can't read: %m");
                 return 0;
         }
-        if (r < 0) {
-                /* An entry without MESSAGE=? */
-                if (r == -ENOENT)
-                        return 0;
-
+        if (r == -ENOENT) /* An entry without the requested field */
+                return 0;
+        if (r < 0)
                 return log_error_errno(r, "Failed to get data: %m");
-        }
 
-        assert(l >= 8);
+        fl = strlen(field);
+        assert(l >= fl + 1);
+        assert(((char*) data)[fl] == '=');
+
+        data = (const uint8_t*) data + fl + 1;
+        l -= fl + 1;
 
-        if (highlight && (flags & OUTPUT_COLOR)) {
+        if (highlight && FLAGS_SET(flags, OUTPUT_COLOR)) {
                 assert(highlight[0] <= highlight[1]);
-                assert(highlight[1] <= l - 8);
+                assert(highlight[1] <= l);
 
-                fwrite((const char*) data + 8, 1, highlight[0], f);
+                fwrite((const char*) data, 1, highlight[0], f);
                 fwrite(highlight_on, 1, strlen(highlight_on), f);
-                fwrite((const char*) data + 8 + highlight[0], 1, highlight[1] - highlight[0], f);
+                fwrite((const char*) data + highlight[0], 1, highlight[1] - highlight[0], f);
                 fwrite(highlight_off, 1, strlen(highlight_off), f);
-                fwrite((const char*) data + 8 + highlight[1], 1, l - 8 - highlight[1], f);
+                fwrite((const char*) data + highlight[1], 1, l - highlight[1], f);
         } else
-                fwrite((const char*) data + 8, 1, l - 8, f);
+                fwrite((const char*) data, 1, l, f);
+
         fputc('\n', f);
+        return 0;
+}
+
+static int output_cat(
+                FILE *f,
+                sd_journal *j,
+                OutputMode mode,
+                unsigned n_columns,
+                OutputFlags flags,
+                const Set *output_fields,
+                const size_t highlight[2]) {
+
+        const char *field;
+        Iterator iterator;
+        int r;
+
+        assert(j);
+        assert(f);
+
+        (void) sd_journal_set_data_threshold(j, 0);
+
+        if (set_isempty(output_fields))
+                return output_cat_field(f, j, flags, "MESSAGE", highlight);
+
+        SET_FOREACH(field, output_fields, iterator) {
+                r = output_cat_field(f, j, flags, field, streq(field, "MESSAGE") ? highlight : NULL);
+                if (r < 0)
+                        return r;
+        }
 
         return 0;
 }
@@ -1077,7 +1103,7 @@ static int (*output_funcs[_OUTPUT_MODE_MAX])(
                 OutputMode mode,
                 unsigned n_columns,
                 OutputFlags flags,
-                Set *output_fields,
+                const Set *output_fields,
                 const size_t highlight[2]) = {
 
         [OUTPUT_SHORT]             = output_short,
@@ -1107,30 +1133,25 @@ int show_journal_entry(
                 const size_t highlight[2],
                 bool *ellipsized) {
 
-        int ret;
-        _cleanup_set_free_free_ Set *fields = NULL;
+        _cleanup_set_free_ Set *fields = NULL;
+        int r;
+
         assert(mode >= 0);
         assert(mode < _OUTPUT_MODE_MAX);
 
         if (n_columns <= 0)
                 n_columns = columns();
 
-        if (output_fields) {
-                fields = set_new(&string_hash_ops);
-                if (!fields)
-                        return log_oom();
-
-                ret = set_put_strdupv(fields, output_fields);
-                if (ret < 0)
-                        return ret;
-        }
+        r = set_put_strdupv(&fields, output_fields);
+        if (r < 0)
+                return r;
 
-        ret = output_funcs[mode](f, j, mode, n_columns, flags, fields, highlight);
+        r = output_funcs[mode](f, j, mode, n_columns, flags, fields, highlight);
 
-        if (ellipsized && ret > 0)
+        if (ellipsized && r > 0)
                 *ellipsized = true;
 
-        return ret;
+        return r;
 }
 
 static int maybe_print_begin_newline(FILE *f, OutputFlags *flags) {
diff --git a/src/shared/macvlan-util.c b/src/shared/macvlan-util.c
new file mode 100644 (file)
index 0000000..90382ac
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "conf-parser.h"
+#include "macvlan-util.h"
+#include "string-table.h"
+
+static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = {
+        [NETDEV_MACVLAN_MODE_PRIVATE] = "private",
+        [NETDEV_MACVLAN_MODE_VEPA] = "vepa",
+        [NETDEV_MACVLAN_MODE_BRIDGE] = "bridge",
+        [NETDEV_MACVLAN_MODE_PASSTHRU] = "passthru",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(macvlan_mode, MacVlanMode);
diff --git a/src/shared/macvlan-util.h b/src/shared/macvlan-util.h
new file mode 100644 (file)
index 0000000..24f864a
--- /dev/null
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <linux/if_link.h>
+
+typedef enum MacVlanMode {
+        NETDEV_MACVLAN_MODE_PRIVATE = MACVLAN_MODE_PRIVATE,
+        NETDEV_MACVLAN_MODE_VEPA = MACVLAN_MODE_VEPA,
+        NETDEV_MACVLAN_MODE_BRIDGE = MACVLAN_MODE_BRIDGE,
+        NETDEV_MACVLAN_MODE_PASSTHRU = MACVLAN_MODE_PASSTHRU,
+        _NETDEV_MACVLAN_MODE_MAX,
+        _NETDEV_MACVLAN_MODE_INVALID = -1
+} MacVlanMode;
+
+const char *macvlan_mode_to_string(MacVlanMode d) _const_;
+MacVlanMode macvlan_mode_from_string(const char *d) _pure_;
index 483148492c876fbc477c26e12a1147e1477d7128..e3aee57ac816e7ae9e96c1ec1d4fcb32e52606d6 100644 (file)
@@ -12,9 +12,13 @@ shared_sources = files('''
         barrier.h
         base-filesystem.c
         base-filesystem.h
+        binfmt-util.c
+        binfmt-util.h
         bitmap.c
         bitmap.h
         blkid-util.h
+        bond-util.c
+        bond-util.h
         boot-timestamps.c
         boot-timestamps.h
         bootspec.c
@@ -23,6 +27,8 @@ shared_sources = files('''
         bpf-program.h
         bridge-util.c
         bridge-util.h
+        bus-locator.c
+        bus-locator.h
         bus-log-control-api.c
         bus-log-control-api.h
         bus-polkit.c
@@ -114,6 +120,8 @@ shared_sources = files('''
         install-printf.h
         install.c
         install.h
+        ipvlan-util.c
+        ipvlan-util.h
         ip-protocol-list.c
         ip-protocol-list.h
         journal-importer.c
@@ -145,6 +153,8 @@ shared_sources = files('''
         machine-image.h
         machine-pool.c
         machine-pool.h
+        macvlan-util.c
+        macvlan-util.h
         main-func.h
         module-util.h
         mount-util.c
@@ -182,6 +192,8 @@ shared_sources = files('''
         securebits-util.h
         serialize.c
         serialize.h
+        service-util.c
+        service-util.h
         sleep-config.c
         sleep-config.h
         socket-netlink.c
@@ -327,6 +339,7 @@ libshared_deps = [threads,
                   librt,
                   libseccomp,
                   libselinux,
+                  libzstd,
                   libxz]
 
 libshared_sym_path = '@0@/libshared.sym'.format(meson.current_source_dir())
index ae6ff9108a84172d8c8dbd2b8950c845bb1ad392..f3ee656c0f179374262638f06882f9770132c1f2 100644 (file)
@@ -239,7 +239,7 @@ int bind_remount_recursive_with_mountinfo(
                         }
 
                         if (!set_contains(done, path)) {
-                                r = set_put_strdup(todo, path);
+                                r = set_put_strdup(&todo, path);
                                 if (r < 0)
                                         return r;
                         }
@@ -266,7 +266,7 @@ int bind_remount_recursive_with_mountinfo(
 
                         log_debug("Made top-level directory %s a mount point.", prefix);
 
-                        r = set_put_strdup(done, simplified);
+                        r = set_put_strdup(&done, simplified);
                         if (r < 0)
                                 return r;
                 }
index 06fddacf16d03b60350abcc1cfefa1aa3528d658..c7c89b3345cb3b74f80ac92234ea798cede5d2fc 100644 (file)
@@ -6,6 +6,26 @@
 
 #include "macro.h"
 
+/* 4MB for contents of regular files, 64k inodes for directories, symbolic links and device specials,
+   using large storage array systems as a baseline */
+#define TMPFS_LIMITS_DEV             ",size=4m,nr_inodes=64k"
+/* Very little, if any use expected */
+#define TMPFS_LIMITS_EMPTY_OR_ALMOST ",size=4m,nr_inodes=1k"
+#define TMPFS_LIMITS_SYS             TMPFS_LIMITS_EMPTY_OR_ALMOST
+#define TMPFS_LIMITS_SYS_FS_CGROUP   TMPFS_LIMITS_EMPTY_OR_ALMOST
+/* On an extremely small device with only 256MB of RAM, 20% of RAM for /run should be enough for re-exec of
+   PID1 because 16MB of free space is required. */
+#define TMPFS_LIMITS_RUN             ",size=20%,nr_inodes=800k"
+/* 10% of RAM (using 16GB of RAM as a baseline) translates to 400k inodes (assuming 4k each) and 25%
+   translates to 1M inodes */
+#define TMPFS_LIMITS_TMP             ",size=10%,nr_inodes=400k"
+#define TMPFS_LIMITS_DEV_SHM         TMPFS_LIMITS_TMP
+#define TMPFS_LIMITS_TEMPORARY_FS    TMPFS_LIMITS_TMP
+/* More space for volatile root and /var */
+#define TMPFS_LIMITS_VAR             ",size=25%,nr_inodes=1m"
+#define TMPFS_LIMITS_ROOTFS          TMPFS_LIMITS_VAR
+#define TMPFS_LIMITS_VOLATILE_STATE  TMPFS_LIMITS_VAR
+
 int repeat_unmount(const char *path, int flags);
 int umount_recursive(const char *target, int flags);
 int bind_remount_recursive(const char *prefix, unsigned long new_flags, unsigned long flags_mask, char **blacklist);
index 5ed26a6c9237a8eededb428a62df047673fa12d6..24a17a2ffef8873aae63155a1ba43c0cd7a1a22f 100644 (file)
@@ -15,7 +15,6 @@
 
 int resize_fs(int fd, uint64_t sz, uint64_t *ret_size) {
         struct statfs sfs;
-        int r;
 
         assert(fd >= 0);
 
@@ -54,8 +53,7 @@ int resize_fs(int fd, uint64_t sz, uint64_t *ret_size) {
 
                 sz -= sz % sfs.f_bsize;
 
-                r = snprintf(args.name, sizeof(args.name), "%" PRIu64, sz);
-                assert((size_t) r < sizeof(args.name));
+                xsprintf(args.name, "%" PRIu64, sz);
 
                 if (ioctl(fd, BTRFS_IOC_RESIZE, &args) < 0)
                         return -errno;
index eeca17f3412c5ea267726487ec7bd870ee55c566..320b1767c566a950c7a102fb7e0946d02cf368e8 100644 (file)
@@ -384,6 +384,7 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
                 .value =
                 "lookup_dcookie\0"
                 "perf_event_open\0"
+                "pidfd_getfd\0"
                 "ptrace\0"
                 "rtas\0"
 #ifdef __NR_s390_runtime_instr
@@ -449,6 +450,7 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
                 "oldstat\0"
                 "open\0"
                 "openat\0"
+                "openat2\0"
                 "readlink\0"
                 "readlinkat\0"
                 "removexattr\0"
@@ -1741,7 +1743,7 @@ int seccomp_restrict_archs(Set *archs) {
 }
 
 int parse_syscall_archs(char **l, Set **archs) {
-        _cleanup_set_free_ Set *_archs;
+        _cleanup_set_free_ Set *_archs = NULL;
         char **s;
         int r;
 
diff --git a/src/shared/service-util.c b/src/shared/service-util.c
new file mode 100644 (file)
index 0000000..c9b684f
--- /dev/null
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <getopt.h>
+#include <stdio.h>
+
+#include "alloc-util.h"
+#include "pretty-print.h"
+#include "service-util.h"
+#include "terminal-util.h"
+#include "util.h"
+
+static int help(const char *program_path, const char *service, const char *description, bool bus_introspect) {
+        _cleanup_free_ char *link = NULL;
+        int r;
+
+        r = terminal_urlify_man(service, "8", &link);
+        if (r < 0)
+                return log_oom();
+
+        printf("%s [OPTIONS...]\n\n"
+               "%s%s%s\n\n"
+               "This program takes no positional arguments.\n\n"
+               "%sOptions%s:\n"
+               "  -h --help                 Show this help\n"
+               "     --version              Show package version\n"
+               "     --bus-introspect=PATH  Write D-Bus XML introspection data\n"
+               "\nSee the %s for details.\n"
+               , program_path
+               , ansi_highlight(), description, ansi_normal()
+               , ansi_underline(), ansi_normal()
+               , link
+        );
+
+        return 0; /* No further action */
+}
+
+int service_parse_argv(
+                const char *service,
+                const char *description,
+                const BusObjectImplementation* const* bus_objects,
+                int argc, char *argv[]) {
+
+        enum {
+                ARG_VERSION = 0x100,
+                ARG_BUS_INTROSPECT,
+        };
+
+        static const struct option options[] = {
+                { "help",           no_argument,       NULL, 'h'                },
+                { "version",        no_argument,       NULL, ARG_VERSION        },
+                { "bus-introspect", required_argument, NULL, ARG_BUS_INTROSPECT },
+                {}
+        };
+
+        int c;
+
+        assert(argc >= 0);
+        assert(argv);
+
+        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
+                switch(c) {
+
+                case 'h':
+                        return help(argv[0], service, description, bus_objects);
+
+                case ARG_VERSION:
+                        return version();
+
+                case ARG_BUS_INTROSPECT:
+                        return bus_introspect_implementations(
+                                        stdout,
+                                        optarg,
+                                        bus_objects);
+
+                case '?':
+                        return -EINVAL;
+
+                default:
+                        assert_not_reached("Unknown option code.");
+                }
+
+        if (optind < argc)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "This program takes no arguments.");
+
+        return 1; /* Further action */
+}
diff --git a/src/shared/service-util.h b/src/shared/service-util.h
new file mode 100644 (file)
index 0000000..76bff61
--- /dev/null
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include "bus-util.h"
+
+int service_parse_argv(
+                const char *service,
+                const char *description,
+                const BusObjectImplementation* const* bus_objects,
+                int argc, char *argv[]);
index 5177137b995d0744e6d4e6b37670a45041cb1773..16b0e6a5c3c609313819d1e3e20465094dddbc57 100644 (file)
@@ -243,8 +243,9 @@ int socket_address_parse_netlink(SocketAddress *a, const char *s) {
         assert(a);
         assert(s);
 
-        zero(*a);
-        a->type = SOCK_RAW;
+        *a = (SocketAddress) {
+                .type = SOCK_RAW,
+        };
 
         r = extract_first_word(&s, &word, NULL, 0);
         if (r < 0)
@@ -361,3 +362,33 @@ int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_u
 
         return r;
 }
+
+int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name) {
+        _cleanup_free_ char *buf = NULL, *name = NULL;
+        const char *m;
+        int r;
+
+        assert(s);
+
+        m = strchr(s, '#');
+        if (m) {
+                name = strdup(m+1);
+                if (!name)
+                        return -ENOMEM;
+
+                buf = strndup(s, m - s);
+                if (!buf)
+                        return -ENOMEM;
+
+                s = buf;
+        }
+
+        r = in_addr_ifindex_from_string_auto(s, family, ret, ifindex);
+        if (r < 0)
+                return r;
+
+        if (server_name)
+                *server_name = TAKE_PTR(name);
+
+        return r;
+}
index fa58409d6182f77c937cf52f149d2574d969faa7..35c35db52d1999ff7e8aa5f470a52e28d0f59c5c 100644 (file)
@@ -21,3 +21,4 @@ bool socket_address_is(const SocketAddress *a, const char *s, int type);
 bool socket_address_is_netlink(const SocketAddress *a, const char *s);
 
 int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex);
+int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name);
index b036ff67ddbdf3690a2f4a8961416fba8b84c49e..112cf6f8fb524dae0a7e10590145604694d92134 100644 (file)
@@ -9,10 +9,12 @@
 #include "sd-id128.h"
 
 #include "alloc-util.h"
+#include "architecture.h"
 #include "format-util.h"
 #include "fs-util.h"
 #include "hostname-util.h"
 #include "macro.h"
+#include "os-util.h"
 #include "specifier.h"
 #include "string-util.h"
 #include "strv.h"
@@ -158,6 +160,17 @@ int specifier_host_name(char specifier, const void *data, const void *userdata,
         return 0;
 }
 
+int specifier_short_host_name(char specifier, const void *data, const void *userdata, char **ret) {
+        char *n;
+
+        n = gethostname_short_malloc();
+        if (!n)
+                return -ENOMEM;
+
+        *ret = n;
+        return 0;
+}
+
 int specifier_kernel_release(char specifier, const void *data, const void *userdata, char **ret) {
         struct utsname uts;
         char *n;
@@ -175,6 +188,52 @@ int specifier_kernel_release(char specifier, const void *data, const void *userd
         return 0;
 }
 
+int specifier_architecture(char specifier, const void *data, const void *userdata, char **ret) {
+        char *t;
+
+        t = strdup(architecture_to_string(uname_architecture()));
+        if (!t)
+                return -ENOMEM;
+
+        *ret = t;
+        return 0;
+}
+
+static int specifier_os_release_common(const char *field, char **ret) {
+        char *t = NULL;
+        int r;
+
+        r = parse_os_release(NULL, field, &t, NULL);
+        if (r < 0)
+                return r;
+        if (!t) {
+                /* fields in /etc/os-release might quite possibly be missing, even if everything is entirely
+                 * valid otherwise. Let's hence return "" in that case. */
+                t = strdup("");
+                if (!t)
+                        return -ENOMEM;
+        }
+
+        *ret = t;
+        return 0;
+}
+
+int specifier_os_id(char specifier, const void *data, const void *userdata, char **ret) {
+        return specifier_os_release_common("ID", ret);
+}
+
+int specifier_os_version_id(char specifier, const void *data, const void *userdata, char **ret) {
+        return specifier_os_release_common("VERSION_ID", ret);
+}
+
+int specifier_os_build_id(char specifier, const void *data, const void *userdata, char **ret) {
+        return specifier_os_release_common("BUILD_ID", ret);
+}
+
+int specifier_os_variant_id(char specifier, const void *data, const void *userdata, char **ret) {
+        return specifier_os_release_common("VARIANT_ID", ret);
+}
+
 int specifier_group_name(char specifier, const void *data, const void *userdata, char **ret) {
         char *t;
 
index d0221ef714a794def0f846c91af12d78e1479b4e..50c6cbd6ab466644dcf59f58a9f6c92be9a1ec9d 100644 (file)
@@ -18,7 +18,13 @@ int specifier_string(char specifier, const void *data, const void *userdata, cha
 int specifier_machine_id(char specifier, const void *data, const void *userdata, char **ret);
 int specifier_boot_id(char specifier, const void *data, const void *userdata, char **ret);
 int specifier_host_name(char specifier, const void *data, const void *userdata, char **ret);
+int specifier_short_host_name(char specifier, const void *data, const void *userdata, char **ret);
 int specifier_kernel_release(char specifier, const void *data, const void *userdata, char **ret);
+int specifier_architecture(char specifier, const void *data, const void *userdata, char **ret);
+int specifier_os_id(char specifier, const void *data, const void *userdata, char **ret);
+int specifier_os_version_id(char specifier, const void *data, const void *userdata, char **ret);
+int specifier_os_build_id(char specifier, const void *data, const void *userdata, char **ret);
+int specifier_os_variant_id(char specifier, const void *data, const void *userdata, char **ret);
 
 int specifier_group_name(char specifier, const void *data, const void *userdata, char **ret);
 int specifier_group_id(char specifier, const void *data, const void *userdata, char **ret);
index 7ad0ecc8fdca4f340d6b38bb339e81cd57e541a2..4fe2489c55a6785f265b9a034429c785a5fd9394 100644 (file)
@@ -320,7 +320,7 @@ int unit_file_build_name_map(
                                 /* We don't explicitly check for alias loops here. unit_ids_map_get() which
                                  * limits the number of hops should be used to access the map. */
 
-                                _cleanup_free_ char *target = NULL, *target_abs = NULL;
+                                _cleanup_free_ char *target = NULL;
 
                                 r = readlinkat_malloc(dirfd(d), de->d_name, &target);
                                 if (r < 0) {
@@ -329,8 +329,9 @@ int unit_file_build_name_map(
                                         continue;
                                 }
 
-                                if (!path_is_absolute(target)) {
-                                        target_abs = path_join(*dir, target);
+                                const bool is_abs = path_is_absolute(target);
+                                if (lp->root_dir || !is_abs) {
+                                        char *target_abs = path_join(is_abs ? lp->root_dir : *dir, target);
                                         if (!target_abs)
                                                 return log_oom();
 
@@ -462,7 +463,7 @@ int unit_file_find_fragment(
 
         /* The unit always has its own name if it's not a template. */
         if (IN_SET(name_type, UNIT_NAME_PLAIN, UNIT_NAME_INSTANCE)) {
-                r = set_put_strdup(names, unit_name);
+                r = set_put_strdup(&names, unit_name);
                 if (r < 0)
                         return r;
         }
@@ -492,7 +493,7 @@ int unit_file_find_fragment(
                                 if (!streq(unit_name, *t))
                                         log_debug("%s: %s has alias %s", __func__, unit_name, *t);
 
-                                r = set_put_strdup(names, *t);
+                                r = set_put_strdup(&names, *t);
                         }
                         if (r < 0)
                                 return r;
index a44ba5b05182030f54b4e5e904581df1320a4011..9d402e792af5ac8fe4d6a1cb6b1f880806d051af 100644 (file)
@@ -16,6 +16,7 @@ enum UnitFileState {
         UNIT_FILE_ENABLED_RUNTIME,
         UNIT_FILE_LINKED,
         UNIT_FILE_LINKED_RUNTIME,
+        UNIT_FILE_ALIAS,
         UNIT_FILE_MASKED,
         UNIT_FILE_MASKED_RUNTIME,
         UNIT_FILE_STATIC,
index e5eff50840115eeecdeb4cadcbb06d47c87eddef..de04859a2f10db9829236e9e5f12660603ecf2fb 100644 (file)
@@ -279,7 +279,7 @@ void user_record_show(UserRecord *hr, bool show_full_group_info) {
                 printf(" Access Mode: 0%03oo\n", user_record_access_mode(hr));
 
         if (storage == USER_LUKS) {
-                printf("LUKS Discard: %s\n", yes_no(user_record_luks_discard(hr)));
+                printf("LUKS Discard: online=%s offline=%s\n", yes_no(user_record_luks_discard(hr)), yes_no(user_record_luks_offline_discard(hr)));
 
                 if (!sd_id128_is_null(hr->luks_uuid))
                         printf("   LUKS UUID: " SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(hr->luks_uuid));
@@ -340,12 +340,48 @@ void user_record_show(UserRecord *hr, bool show_full_group_info) {
 
         if (hr->disk_usage != UINT64_MAX) {
                 char buf[FORMAT_BYTES_MAX];
-                printf("  Disk Usage: %s\n", format_bytes(buf, sizeof(buf), hr->disk_usage));
+
+                if (hr->disk_size != UINT64_MAX) {
+                        unsigned permille;
+
+                        permille = (unsigned) DIV_ROUND_UP(hr->disk_usage * 1000U, hr->disk_size); /* Round up! */
+                        printf("  Disk Usage: %s (= %u.%01u%%)\n",
+                               format_bytes(buf, sizeof(buf), hr->disk_usage),
+                               permille / 10, permille % 10);
+                } else
+                        printf("  Disk Usage: %s\n", format_bytes(buf, sizeof(buf), hr->disk_usage));
         }
 
         if (hr->disk_free != UINT64_MAX) {
                 char buf[FORMAT_BYTES_MAX];
-                printf("   Disk Free: %s\n", format_bytes(buf, sizeof(buf), hr->disk_free));
+
+                if (hr->disk_size != UINT64_MAX) {
+                        const char *color_on, *color_off;
+                        unsigned permille;
+
+                        permille = (unsigned) ((hr->disk_free * 1000U) / hr->disk_size); /* Round down! */
+
+                        /* Color the output red or yellow if we are below 10% resp. 25% free. Because 10% and
+                         * 25% can be a lot of space still, let's additionally make some absolute
+                         * restrictions: 1G and 2G */
+                        if (permille <= 100U &&
+                            hr->disk_free < 1024U*1024U*1024U /* 1G */) {
+                                color_on = ansi_highlight_red();
+                                color_off = ansi_normal();
+                        } else if (permille <= 250U &&
+                                   hr->disk_free < 2U*1024U*1024U*1024U /* 2G */) {
+                                color_on = ansi_highlight_yellow();
+                                color_off = ansi_normal();
+                        } else
+                                color_on = color_off = "";
+
+                        printf("   Disk Free: %s%s (= %u.%01u%%)%s\n",
+                               color_on,
+                               format_bytes(buf, sizeof(buf), hr->disk_free),
+                               permille / 10, permille % 10,
+                               color_off);
+                } else
+                        printf("   Disk Free: %s\n", format_bytes(buf, sizeof(buf), hr->disk_free));
         }
 
         if (hr->disk_floor != UINT64_MAX) {
index 7832aca8dc8447694ca1c781087bf6dadc73ec73..83d86f69e761ab0a22a2366a0b20476a3a489072 100644 (file)
@@ -52,6 +52,7 @@ UserRecord* user_record_new(void) {
                 .nodev = true,
                 .nosuid = true,
                 .luks_discard = -1,
+                .luks_offline_discard = -1,
                 .luks_volume_key_size = UINT64_MAX,
                 .luks_pbkdf_time_cost_usec = UINT64_MAX,
                 .luks_pbkdf_memory_cost = UINT64_MAX,
@@ -944,6 +945,7 @@ static int dispatch_per_machine(const char *name, JsonVariant *variant, JsonDisp
                 { "luksUuid",                   JSON_VARIANT_STRING,        json_dispatch_id128,               offsetof(UserRecord, luks_uuid),                     0         },
                 { "fileSystemUuid",             JSON_VARIANT_STRING,        json_dispatch_id128,               offsetof(UserRecord, file_system_uuid),              0         },
                 { "luksDiscard",                _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate,            offsetof(UserRecord, luks_discard),                  0,        },
+                { "luksOfflineDiscard",         _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate,            offsetof(UserRecord, luks_offline_discard),          0,        },
                 { "luksCipher",                 JSON_VARIANT_STRING,        json_dispatch_string,              offsetof(UserRecord, luks_cipher),                   JSON_SAFE },
                 { "luksCipherMode",             JSON_VARIANT_STRING,        json_dispatch_string,              offsetof(UserRecord, luks_cipher_mode),              JSON_SAFE },
                 { "luksVolumeKeySize",          JSON_VARIANT_UNSIGNED,      json_dispatch_uint64,              offsetof(UserRecord, luks_volume_key_size),          0         },
@@ -1057,7 +1059,34 @@ static int dispatch_status(const char *name, JsonVariant *variant, JsonDispatchF
         return json_dispatch(m, status_dispatch_table, NULL, flags, userdata);
 }
 
+int user_record_build_image_path(UserStorage storage, const char *user_name_and_realm, char **ret) {
+        const char *suffix;
+        char *z;
+
+        assert(storage >= 0);
+        assert(user_name_and_realm);
+        assert(ret);
+
+        if (storage == USER_LUKS)
+                suffix = ".home";
+        else if (IN_SET(storage, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT))
+                suffix = ".homedir";
+        else {
+                *ret = NULL;
+                return 0;
+        }
+
+        z = strjoin("/home/", user_name_and_realm, suffix);
+        if (!z)
+                return -ENOMEM;
+
+        *ret = z;
+        return 1;
+}
+
 static int user_record_augment(UserRecord *h, JsonDispatchFlags json_flags) {
+        int r;
+
         assert(h);
 
         if (!FLAGS_SET(h->mask, USER_RECORD_REGULAR))
@@ -1082,22 +1111,9 @@ static int user_record_augment(UserRecord *h, JsonDispatchFlags json_flags) {
         }
 
         if (!h->image_path && !h->image_path_auto) {
-                const char *suffix;
-                UserStorage storage;
-
-                storage = user_record_storage(h);
-                if (storage == USER_LUKS)
-                        suffix = ".home";
-                else if (IN_SET(storage, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT))
-                        suffix = ".homedir";
-                else
-                        suffix = NULL;
-
-                if (suffix) {
-                        h->image_path_auto = strjoin("/home/", user_record_user_name_and_realm(h), suffix);
-                        if (!h->image_path_auto)
-                                return json_log_oom(h->json, json_flags);
-                }
+                r = user_record_build_image_path(user_record_storage(h), user_record_user_name_and_realm(h), &h->image_path_auto);
+                if (r < 0)
+                        return json_log(h->json, json_flags, r, "Failed to determine default image path: %m");
         }
 
         return 0;
@@ -1276,6 +1292,7 @@ int user_record_load(UserRecord *h, JsonVariant *v, UserRecordLoadFlags load_fla
                 { "luksUuid",                   JSON_VARIANT_STRING,        json_dispatch_id128,               offsetof(UserRecord, luks_uuid),                     0         },
                 { "fileSystemUuid",             JSON_VARIANT_STRING,        json_dispatch_id128,               offsetof(UserRecord, file_system_uuid),              0         },
                 { "luksDiscard",                _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate,            offsetof(UserRecord, luks_discard),                  0         },
+                { "luksOfflineDiscard",         _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate,            offsetof(UserRecord, luks_offline_discard),          0         },
                 { "luksCipher",                 JSON_VARIANT_STRING,        json_dispatch_string,              offsetof(UserRecord, luks_cipher),                   JSON_SAFE },
                 { "luksCipherMode",             JSON_VARIANT_STRING,        json_dispatch_string,              offsetof(UserRecord, luks_cipher_mode),              JSON_SAFE },
                 { "luksVolumeKeySize",          JSON_VARIANT_UNSIGNED,      json_dispatch_uint64,              offsetof(UserRecord, luks_volume_key_size),          0         },
@@ -1500,6 +1517,27 @@ bool user_record_luks_discard(UserRecord *h) {
         return path_startswith(ip, "/dev/");
 }
 
+bool user_record_luks_offline_discard(UserRecord *h) {
+        const char *ip;
+
+        assert(h);
+
+        if (h->luks_offline_discard >= 0)
+                return h->luks_offline_discard;
+
+        /* Discard while we are logged out should generally be a good idea, except when operating directly on
+         * physical media, where we should just bind it to the online discard mode. */
+
+        ip = user_record_image_path(h);
+        if (!ip)
+                return false;
+
+        if (path_startswith(ip, "/dev/"))
+                return user_record_luks_discard(h);
+
+        return true;
+}
+
 const char *user_record_luks_cipher(UserRecord *h) {
         assert(h);
 
index 5bac30476710373a39a183e92f42886964f9501d..9fd10610d926acce14ab26edb184fcdd0c2a68ab 100644 (file)
@@ -261,6 +261,7 @@ typedef struct UserRecord {
         sd_id128_t file_system_uuid;
 
         int luks_discard;
+        int luks_offline_discard;
         char *luks_cipher;
         char *luks_cipher_mode;
         uint64_t luks_volume_key_size;
@@ -332,6 +333,7 @@ const char *user_record_cifs_user_name(UserRecord *h);
 const char *user_record_shell(UserRecord *h);
 const char *user_record_real_name(UserRecord *h);
 bool user_record_luks_discard(UserRecord *h);
+bool user_record_luks_offline_discard(UserRecord *h);
 const char *user_record_luks_cipher(UserRecord *h);
 const char *user_record_luks_cipher_mode(UserRecord *h);
 uint64_t user_record_luks_volume_key_size(UserRecord *h);
@@ -347,6 +349,8 @@ usec_t user_record_ratelimit_interval_usec(UserRecord *h);
 uint64_t user_record_ratelimit_burst(UserRecord *h);
 bool user_record_can_authenticate(UserRecord *h);
 
+int user_record_build_image_path(UserStorage storage, const char *user_name_and_realm, char **ret);
+
 bool user_record_equal(UserRecord *a, UserRecord *b);
 bool user_record_compatible(UserRecord *a, UserRecord *b);
 int user_record_compare_last_change(UserRecord *a, UserRecord *b);
index 1d23ed48a2b87635b232dca04ed86264ee740a59..d2744b6918f4c2ba86b5fe4f4419ff6532635256 100644 (file)
@@ -45,10 +45,19 @@ bool running_in_chroot_or_offline(void) {
         return r > 0;
 }
 
+const Verb* verbs_find_verb(const char *name, const Verb verbs[]) {
+        for (size_t i = 0; verbs[i].dispatch; i++)
+                if (streq_ptr(name, verbs[i].verb) ||
+                    (!name && FLAGS_SET(verbs[i].flags, VERB_DEFAULT)))
+                        return &verbs[i];
+
+        /* At the end of the list? */
+        return NULL;
+}
+
 int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata) {
         const Verb *verb;
         const char *name;
-        unsigned i;
         int left;
 
         assert(verbs);
@@ -62,31 +71,16 @@ int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata) {
         optind = 0;
         name = argv[0];
 
-        for (i = 0;; i++) {
-                bool found;
-
-                /* At the end of the list? */
-                if (!verbs[i].dispatch) {
-                        if (name)
-                                log_error("Unknown operation %s.", name);
-                        else
-                                log_error("Requires operation parameter.");
-                        return -EINVAL;
-                }
-
+        verb = verbs_find_verb(name, verbs);
+        if (!verb) {
                 if (name)
-                        found = streq(name, verbs[i].verb);
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "Unknown command verb %s.", name);
                 else
-                        found = verbs[i].flags & VERB_DEFAULT;
-
-                if (found) {
-                        verb = &verbs[i];
-                        break;
-                }
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "Command verb required.");
         }
 
-        assert(verb);
-
         if (!name)
                 left = 1;
 
@@ -101,10 +95,7 @@ int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata) {
                                        "Too many arguments.");
 
         if ((verb->flags & VERB_ONLINE_ONLY) && running_in_chroot_or_offline()) {
-                if (name)
-                        log_info("Running in chroot, ignoring request: %s", name);
-                else
-                        log_info("Running in chroot, ignoring request.");
+                log_info("Running in chroot, ignoring command '%s'", name ?: verb->verb);
                 return 0;
         }
 
index c5fe6cc7c58b75c5065d96734b139ae2c76a4b2c..b6a1afcdee630de970a1acf205633a629e8427f4 100644 (file)
@@ -6,8 +6,8 @@
 #define VERB_ANY ((unsigned) -1)
 
 typedef enum VerbFlags {
-        VERB_DEFAULT      = 1 << 0,
-        VERB_ONLINE_ONLY  = 1 << 1,
+        VERB_DEFAULT      = 1 << 0,  /* The verb to run if no verb is specified */
+        VERB_ONLINE_ONLY  = 1 << 1,  /* Just do nothing when running in chroot or offline */
 } VerbFlags;
 
 typedef struct {
@@ -19,4 +19,5 @@ typedef struct {
 
 bool running_in_chroot_or_offline(void);
 
+const Verb* verbs_find_verb(const char *name, const Verb verbs[]);
 int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata);
index f2ad23d05570e82e9e96b3bc2fea158184a960bb..06c9710c6e329ad7837a72519656bf169709396e 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "alloc-util.h"
 #include "async.h"
+#include "binfmt-util.h"
 #include "cgroup-setup.h"
 #include "cgroup-util.h"
 #include "def.h"
@@ -386,6 +387,7 @@ int main(int argc, char *argv[]) {
                 sync_with_progress();
 
         disable_coredumps();
+        disable_binfmt();
 
         log_info("Sending SIGTERM to remaining processes...");
         broadcast_signal(SIGTERM, true, true, arg_timeout);
@@ -523,7 +525,7 @@ int main(int argc, char *argv[]) {
         }
 
         if (need_umount || need_swapoff || need_loop_detach || need_dm_detach)
-                log_error("Failed to finalize %s%s%s%s ignoring",
+                log_error("Failed to finalize%s%s%s%s ignoring.",
                           need_umount ? " file systems," : "",
                           need_swapoff ? " swap devices," : "",
                           need_loop_detach ? " loop devices," : "",
index 2ee6fc2f0a6aa0fcf4fbf2539cc4ba475875262b..7b548c50768d5a4e50b12477d3ccf30ffb4ebd9c 100644 (file)
 
 static unsigned arg_connections_max = 256;
 static const char *arg_remote_host = NULL;
+static usec_t arg_exit_idle_time = USEC_INFINITY;
 
 typedef struct Context {
         sd_event *event;
         sd_resolve *resolve;
+        sd_event_source *idle_time;
 
         Set *listen;
         Set *connections;
@@ -75,6 +77,51 @@ static void connection_free(Connection *c) {
         free(c);
 }
 
+static int idle_time_cb(sd_event_source *s, uint64_t usec, void *userdata) {
+        Context *c = userdata;
+        int r;
+
+        if (!set_isempty(c->connections)) {
+                log_warning("Idle timer fired even though there are connections, ignoring");
+                return 0;
+        }
+
+        r = sd_event_exit(c->event, 0);
+        if (r < 0) {
+                log_warning_errno(r, "Error while stopping event loop, ignoring: %m");
+                return 0;
+        }
+        return 0;
+}
+
+static int connection_release(Connection *c) {
+        int r;
+        Context *context = c->context;
+        usec_t idle_instant;
+
+        connection_free(c);
+
+        if (arg_exit_idle_time < USEC_INFINITY && set_isempty(context->connections)) {
+                idle_instant = usec_add(now(CLOCK_MONOTONIC), arg_exit_idle_time);
+                if (context->idle_time) {
+                        r = sd_event_source_set_time(context->idle_time, idle_instant);
+                        if (r < 0)
+                                return log_error_errno(r, "Error while setting idle time: %m");
+
+                        r = sd_event_source_set_enabled(context->idle_time, SD_EVENT_ONESHOT);
+                        if (r < 0)
+                                return log_error_errno(r, "Error while enabling idle time: %m");
+                } else {
+                        r = sd_event_add_time(context->event, &context->idle_time, CLOCK_MONOTONIC,
+                                              idle_instant, 0, idle_time_cb, context);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to create idle timer: %m");
+                }
+        }
+
+        return 0;
+}
+
 static void context_clear(Context *context) {
         assert(context);
 
@@ -83,6 +130,7 @@ static void context_clear(Context *context) {
 
         sd_event_unref(context->event);
         sd_resolve_unref(context->resolve);
+        sd_event_source_unref(context->idle_time);
 }
 
 static int connection_create_pipes(Connection *c, int buffer[static 2], size_t *sz) {
@@ -206,7 +254,7 @@ static int traffic_cb(sd_event_source *s, int fd, uint32_t revents, void *userda
         return 1;
 
 quit:
-        connection_free(c);
+        connection_release(c);
         return 0; /* ignore errors, continue serving */
 }
 
@@ -269,7 +317,7 @@ static int connection_complete(Connection *c) {
         return 0;
 
 fail:
-        connection_free(c);
+        connection_release(c);
         return 0; /* ignore errors, continue serving */
 }
 
@@ -299,7 +347,7 @@ static int connect_cb(sd_event_source *s, int fd, uint32_t revents, void *userda
         return connection_complete(c);
 
 fail:
-        connection_free(c);
+        connection_release(c);
         return 0; /* ignore errors, continue serving */
 }
 
@@ -343,7 +391,7 @@ static int connection_start(Connection *c, struct sockaddr *sa, socklen_t salen)
         return 0;
 
 fail:
-        connection_free(c);
+        connection_release(c);
         return 0; /* ignore errors, continue serving */
 }
 
@@ -361,7 +409,7 @@ static int resolve_handler(sd_resolve_query *q, int ret, const struct addrinfo *
         return connection_start(c, ai->ai_addr, ai->ai_addrlen);
 
 fail:
-        connection_free(c);
+        connection_release(c);
         return 0; /* ignore errors, continue serving */
 }
 
@@ -409,7 +457,7 @@ static int resolve_remote(Connection *c) {
         return 0;
 
 fail:
-        connection_free(c);
+        connection_release(c);
         return 0; /* ignore errors, continue serving */
 }
 
@@ -426,6 +474,12 @@ static int add_connection_socket(Context *context, int fd) {
                 return 0;
         }
 
+        if (context->idle_time) {
+                r = sd_event_source_set_enabled(context->idle_time, SD_EVENT_OFF);
+                if (r < 0)
+                        log_warning_errno(r, "Unable to disable idle timer, continuing: %m");
+        }
+
         r = set_ensure_allocated(&context->connections, NULL);
         if (r < 0) {
                 log_oom();
@@ -535,9 +589,13 @@ static int add_listen_socket(Context *context, int fd) {
 
 static int help(void) {
         _cleanup_free_ char *link = NULL;
+        _cleanup_free_ char *time_link = NULL;
         int r;
 
         r = terminal_urlify_man("systemd-socket-proxyd", "8", &link);
+        if (r < 0)
+                return log_oom();
+        r = terminal_urlify_man("systemd.time", "7", &time_link);
         if (r < 0)
                 return log_oom();
 
@@ -545,11 +603,14 @@ static int help(void) {
                "%1$s [SOCKET]\n\n"
                "Bidirectionally proxy local sockets to another (possibly remote) socket.\n\n"
                "  -c --connections-max=  Set the maximum number of connections to be accepted\n"
+               "     --exit-idle-time=   Exit when without a connection for this duration. See\n"
+               "                         the %3$s for time span format\n"
                "  -h --help              Show this help\n"
                "     --version           Show package version\n"
                "\nSee the %2$s for details.\n"
                , program_invocation_short_name
                , link
+               , time_link
         );
 
         return 0;
@@ -559,11 +620,13 @@ static int parse_argv(int argc, char *argv[]) {
 
         enum {
                 ARG_VERSION = 0x100,
+                ARG_EXIT_IDLE,
                 ARG_IGNORE_ENV
         };
 
         static const struct option options[] = {
                 { "connections-max", required_argument, NULL, 'c'           },
+                { "exit-idle-time",  required_argument, NULL, ARG_EXIT_IDLE },
                 { "help",            no_argument,       NULL, 'h'           },
                 { "version",         no_argument,       NULL, ARG_VERSION   },
                 {}
@@ -597,6 +660,12 @@ static int parse_argv(int argc, char *argv[]) {
 
                         break;
 
+                case ARG_EXIT_IDLE:
+                        r = parse_sec(optarg, &arg_exit_idle_time);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to parse --exit-idle-time= argument: %s", optarg);
+                        break;
+
                 case '?':
                         return -EINVAL;
 
index 0cdb740d21891c552ebeaa226f108cd3cd14b695..5274cd24b38704f22d0e2de18d113d2e557f8c54 100644 (file)
@@ -138,9 +138,9 @@ static int apply_all(OrderedHashmap *sysctl_options) {
                         if (!pattern)
                                 return log_oom();
 
-                        k = glob_extend(&paths, pattern);
+                        k = glob_extend(&paths, pattern, GLOB_NOCHECK);
                         if (k < 0) {
-                                if (option->ignore_failure || ERRNO_IS_PRIVILEGE(r))
+                                if (option->ignore_failure || ERRNO_IS_PRIVILEGE(k))
                                         log_debug_errno(k, "Failed to resolve glob '%s', ignoring: %m",
                                                         option->key);
                                 else {
index 64e23f0734e0b12dc2be855dcb6a691dfaba67ed..460e7f69b9ae3e34a26f1500e314bd1cf219151e 100644 (file)
@@ -390,6 +390,21 @@ static bool output_show_unit(const UnitInfo *u, char **patterns) {
         return true;
 }
 
+static int output_table(Table *table) {
+        int r;
+
+        assert(table);
+
+        if (OUTPUT_MODE_IS_JSON(arg_output))
+                r = table_print_json(table, NULL, output_mode_to_json_format_flags(arg_output) | JSON_FORMAT_COLOR_AUTO);
+        else
+                r = table_print(table, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to show table: %m");
+
+        return 0;
+}
+
 static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
         _cleanup_(table_unrefp) Table *table = NULL;
         const UnitInfo *u;
@@ -410,7 +425,9 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
         if (arg_full)
                 table_set_width(table, 0);
 
-        for (u = unit_infos; u < unit_infos + c; u++) {
+        (void) table_set_empty_string(table, "-");
+
+        for (u = unit_infos; unit_infos && u < unit_infos + c; u++) {
                 _cleanup_free_ char *j = NULL;
                 const char *on_underline = "", *on_loaded = "", *on_active = "";
                 const char *on_circle = "", *id;
@@ -423,14 +440,15 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
                 }
 
                 if (STR_IN_SET(u->load_state, "error", "not-found", "bad-setting", "masked") && !arg_plain) {
-                        on_circle = ansi_highlight_yellow();
+                        on_circle = underline ? ansi_highlight_yellow_underline() : ansi_highlight_yellow();
                         circle = true;
                         on_loaded = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
                 } else if (streq(u->active_state, "failed") && !arg_plain) {
-                        on_circle = ansi_highlight_red();
+                        on_circle = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
                         circle = true;
                         on_active = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
                 } else {
+                        on_circle = on_underline;
                         on_active = on_underline;
                         on_loaded = on_underline;
                 }
@@ -446,19 +464,19 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
 
                 r = table_add_many(table,
                                    TABLE_STRING, circle ? special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE) : " ",
-                                   TABLE_SET_COLOR, on_circle,
+                                   TABLE_SET_BOTH_COLORS, on_circle,
                                    TABLE_STRING, id,
-                                   TABLE_SET_COLOR, on_active,
+                                   TABLE_SET_BOTH_COLORS, on_active,
                                    TABLE_STRING, u->load_state,
-                                   TABLE_SET_COLOR, on_loaded,
+                                   TABLE_SET_BOTH_COLORS, on_loaded,
                                    TABLE_STRING, u->active_state,
-                                   TABLE_SET_COLOR, on_active,
+                                   TABLE_SET_BOTH_COLORS, on_active,
                                    TABLE_STRING, u->sub_state,
-                                   TABLE_SET_COLOR, on_active,
+                                   TABLE_SET_BOTH_COLORS, on_active,
                                    TABLE_STRING, u->job_id ? u->job_type: "",
-                                   TABLE_SET_COLOR, u->job_id ? on_underline : "",
+                                   TABLE_SET_BOTH_COLORS, u->job_id ? on_underline : "",
                                    TABLE_STRING, u->description,
-                                   TABLE_SET_COLOR, on_underline);
+                                   TABLE_SET_BOTH_COLORS, on_underline);
                 if (r < 0)
                         return table_log_add_error(r);
 
@@ -473,9 +491,9 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
                         return log_error_errno(r, "Failed to hide column: %m");
         }
 
-        r = table_print(table, NULL);
+        r = output_table(table);
         if (r < 0)
-                return log_error_errno(r, "Failed to print the table: %m");
+                return r;
 
         if (!arg_no_legend) {
                 const char *on, *off;
@@ -529,13 +547,7 @@ static int get_unit_list(
         assert(unit_infos);
         assert(_reply);
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &m,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "ListUnitsByPatterns");
+        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "ListUnitsByPatterns");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -556,13 +568,7 @@ static int get_unit_list(
                 m = sd_bus_message_unref(m);
                 sd_bus_error_free(&error);
 
-                r = sd_bus_message_new_method_call(
-                                bus,
-                                &m,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
-                                "ListUnitsFiltered");
+                r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "ListUnitsFiltered");
                 if (r < 0)
                         return bus_log_create_error(r);
 
@@ -991,7 +997,7 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
         const char *on, *off;
         int r;
 
-        table = table_new("listen", "type", "units", "activates");
+        table = table_new("listen", "type", "unit", "activates");
         if (!table)
                 return log_oom();
 
@@ -1006,9 +1012,11 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
         if (arg_full)
                 table_set_width(table, 0);
 
+        (void) table_set_empty_string(table, "-");
+
         if (cs) {
                 for (s = socket_infos; s < socket_infos + cs; s++) {
-                        _cleanup_free_ char *j = NULL, *activates = NULL;
+                        _cleanup_free_ char *j = NULL;
                         const char *path;
 
                         if (s->machine) {
@@ -1019,17 +1027,25 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
                         } else
                                 path = s->path;
 
-                        activates = strv_join(s->triggered, ", ");
-                        if (!activates)
-                                return log_oom();
-
                         r = table_add_many(table,
                                            TABLE_STRING, path,
                                            TABLE_STRING, s->type,
-                                           TABLE_STRING, s->id,
-                                           TABLE_STRING, activates);
+                                           TABLE_STRING, s->id);
                         if (r < 0)
                                 return table_log_add_error(r);
+
+                        if (strv_isempty(s->triggered))
+                                r = table_add_cell(table, NULL, TABLE_EMPTY, NULL);
+                        else if (strv_length(s->triggered) == 1)
+                                r = table_add_cell(table, NULL, TABLE_STRING, s->triggered[0]);
+                        else
+                                /* This should never happen, currently our socket units can only trigger a
+                                 * single unit. But let's handle this anyway, who knows what the future
+                                 * brings? */
+                                r = table_add_cell(table, NULL, TABLE_STRV, s->triggered);
+                        if (r < 0)
+                                return table_log_add_error(r);
+
                 }
 
                 on = ansi_highlight();
@@ -1039,9 +1055,9 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
                 off = ansi_normal();
         }
 
-        r = table_print(table, NULL);
+        r = output_table(table);
         if (r < 0)
-                return log_error_errno(r, "Failed to print the table: %m");
+                return r;
 
         if (!arg_no_legend) {
                 printf("\n%s%u sockets listed.%s\n", on, cs, off);
@@ -1250,6 +1266,8 @@ static int output_timers_list(struct timer_info *timer_infos, unsigned n) {
         if (arg_full)
                 table_set_width(table, 0);
 
+        (void) table_set_empty_string(table, "-");
+
         if (n > 0) {
                 for (t = timer_infos; t < timer_infos + n; t++) {
                         _cleanup_free_ char *j = NULL, *activates = NULL;
@@ -1285,9 +1303,9 @@ static int output_timers_list(struct timer_info *timer_infos, unsigned n) {
                 off = ansi_normal();
         }
 
-        r = table_print(table, NULL);
+        r = output_table(table);
         if (r < 0)
-                return log_error_errno(r, "Failed to print the table: %m");
+                return r;
 
         if (!arg_no_legend) {
                 printf("\n%s%u timers listed.%s\n", on, n, off);
@@ -1441,9 +1459,18 @@ static bool output_show_unit_file(const UnitFileList *u, char **states, char **p
         return true;
 }
 
+static bool show_preset_for_state(UnitFileState state) {
+        /* Don't show preset state in those unit file states, it'll only confuse users. */
+        return !IN_SET(state,
+                       UNIT_FILE_ALIAS,
+                       UNIT_FILE_STATIC,
+                       UNIT_FILE_GENERATED,
+                       UNIT_FILE_TRANSIENT);
+}
+
 static int output_unit_file_list(const UnitFileList *units, unsigned c) {
         _cleanup_(table_unrefp) Table *table = NULL;
-        const UnitFileList *u;
+        _cleanup_(unit_file_presets_freep) UnitFilePresets presets = {};
         int r;
 
         table = table_new("unit file", "state", "vendor preset");
@@ -1454,9 +1481,10 @@ static int output_unit_file_list(const UnitFileList *units, unsigned c) {
         if (arg_full)
                 table_set_width(table, 0);
 
-        for (u = units; u < units + c; u++) {
+        (void) table_set_empty_string(table, "-");
+
+        for (const UnitFileList *u = units; u < units + c; u++) {
                 const char *on_underline = NULL, *on_unit_color = NULL, *id;
-                const char *on_preset_color = NULL, *unit_preset_str;
                 bool underline;
 
                 underline = u + 1 < units + c &&
@@ -1471,39 +1499,52 @@ static int output_unit_file_list(const UnitFileList *units, unsigned c) {
                            UNIT_FILE_DISABLED,
                            UNIT_FILE_BAD))
                         on_unit_color = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
-                else if (u->state == UNIT_FILE_ENABLED)
+                else if (IN_SET(u->state,
+                                UNIT_FILE_ENABLED,
+                                UNIT_FILE_ALIAS))
                         on_unit_color = underline ? ansi_highlight_green_underline() : ansi_highlight_green();
                 else
                         on_unit_color = on_underline;
 
                 id = basename(u->path);
 
-                r = unit_file_query_preset(arg_scope, NULL, id);
-                if (r < 0) {
-                        unit_preset_str = "n/a";
-                        on_preset_color = underline ? on_underline : ansi_normal();
-                } else if (r == 0) {
-                        unit_preset_str = "disabled";
-                        on_preset_color = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
-                } else {
-                        unit_preset_str = "enabled";
-                        on_preset_color = underline ? ansi_highlight_green_underline() : ansi_highlight_green();
-                }
-
                 r = table_add_many(table,
                                    TABLE_STRING, id,
-                                   TABLE_SET_COLOR, strempty(on_underline),
+                                   TABLE_SET_BOTH_COLORS, strempty(on_underline),
                                    TABLE_STRING, unit_file_state_to_string(u->state),
-                                   TABLE_SET_COLOR, strempty(on_unit_color),
-                                   TABLE_STRING, unit_preset_str,
-                                   TABLE_SET_COLOR, strempty(on_preset_color));
+                                   TABLE_SET_BOTH_COLORS, strempty(on_unit_color));
+                if (r < 0)
+                        return table_log_add_error(r);
+
+                if (show_preset_for_state(u->state)) {
+                        const char *unit_preset_str, *on_preset_color;
+
+                        r = unit_file_query_preset(arg_scope, arg_root, id, &presets);
+                        if (r < 0) {
+                                unit_preset_str = "n/a";
+                                on_preset_color = underline ? on_underline : ansi_normal();
+                        } else if (r == 0) {
+                                unit_preset_str = "disabled";
+                                on_preset_color = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
+                        } else {
+                                unit_preset_str = "enabled";
+                                on_preset_color = underline ? ansi_highlight_green_underline() : ansi_highlight_green();
+                        }
+
+                        r = table_add_many(table,
+                                           TABLE_STRING, unit_preset_str,
+                                           TABLE_SET_BOTH_COLORS, strempty(on_preset_color));
+                } else
+                        r = table_add_many(table,
+                                           TABLE_EMPTY,
+                                           TABLE_SET_BOTH_COLORS, underline ? ansi_grey_underline() : ansi_grey());
                 if (r < 0)
                         return table_log_add_error(r);
         }
 
-        r = table_print(table, NULL);
+        r = output_table(table);
         if (r < 0)
-                return log_error_errno(r, "Failed to print the table: %m");
+                return r;
 
         if (!arg_no_legend)
                 printf("\n%u unit files listed.\n", c);
@@ -1567,13 +1608,7 @@ static int list_unit_files(int argc, char *argv[], void *userdata) {
                 if (r < 0)
                         return r;
 
-                r = sd_bus_message_new_method_call(
-                                bus,
-                                &m,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
-                                "ListUnitFilesByPatterns");
+                r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "ListUnitFilesByPatterns");
                 if (r < 0)
                         return bus_log_create_error(r);
 
@@ -1605,13 +1640,7 @@ static int list_unit_files(int argc, char *argv[], void *userdata) {
                         m = sd_bus_message_unref(m);
                         sd_bus_error_free(&error);
 
-                        r = sd_bus_message_new_method_call(
-                                        bus,
-                                        &m,
-                                        "org.freedesktop.systemd1",
-                                        "/org/freedesktop/systemd1",
-                                        "org.freedesktop.systemd1.Manager",
-                                        "ListUnitFiles");
+                        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "ListUnitFiles");
                         if (r < 0)
                                 return bus_log_create_error(r);
 
@@ -1996,6 +2025,8 @@ static int output_machines_list(struct machine_info *machine_infos, unsigned n)
         if (arg_full)
                 table_set_width(table, 0);
 
+        (void) table_set_empty_string(table, "-");
+
         for (m = machine_infos; m < machine_infos + n; m++) {
                 _cleanup_free_ char *mname = NULL;
                 const char *on_state = "", *on_failed = "";
@@ -2033,9 +2064,9 @@ static int output_machines_list(struct machine_info *machine_infos, unsigned n)
                         return table_log_add_error(r);
         }
 
-        r = table_print(table, NULL);
+        r = output_table(table);
         if (r < 0)
-                return log_error_errno(r, "Failed to print the table: %m");
+                return r;
 
         if (!arg_no_legend) {
                 printf("\n");
@@ -2123,15 +2154,7 @@ static int determine_default(char **ret_name) {
                 if (r < 0)
                         return r;
 
-                r = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
-                                "GetDefaultTarget",
-                                &error,
-                                &reply,
-                                NULL);
+                r = bus_call_method(bus, bus_systemd_mgr, "GetDefaultTarget", &error, &reply, NULL);
                 if (r < 0)
                         return log_error_errno(r, "Failed to get default target: %s", bus_error_message(&error, r));
 
@@ -2190,15 +2213,7 @@ static int set_default(int argc, char *argv[], void *userdata) {
                 if (r < 0)
                         return r;
 
-                r = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
-                                "SetDefaultTarget",
-                                &error,
-                                &reply,
-                                "sb", unit, 1);
+                r = bus_call_method(bus, bus_systemd_mgr, "SetDefaultTarget", &error, &reply, "sb", unit, 1);
                 if (r < 0)
                         return log_error_errno(r, "Failed to set default target: %s", bus_error_message(&error, r));
 
@@ -2241,15 +2256,7 @@ static int output_waiting_jobs(sd_bus *bus, Table *table, uint32_t id, const cha
 
         assert(bus);
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        method,
-                        &error,
-                        &reply,
-                        "u", id);
+        r = bus_call_method(bus, bus_systemd_mgr, method, &error, &reply, "u", id);
         if (r < 0)
                 return log_debug_errno(r, "Failed to get waiting jobs for job %" PRIu32, id);
 
@@ -2316,13 +2323,14 @@ static int output_jobs_list(sd_bus *bus, const struct job_info* jobs, unsigned n
         if (arg_full)
                 table_set_width(table, 0);
 
+        (void) table_set_empty_string(table, "-");
+
         for (j = jobs; j < jobs + n; j++) {
                 if (streq(j->state, "running"))
                         on = ansi_highlight();
                 else
                         on =  "";
 
-
                 r = table_add_many(table,
                                    TABLE_UINT, j->id,
                                    TABLE_STRING, j->name,
@@ -2373,15 +2381,7 @@ static int list_jobs(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return r;
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "ListJobs",
-                        &error,
-                        &reply,
-                        NULL);
+        r = bus_call_method(bus, bus_systemd_mgr, "ListJobs", &error, &reply, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to list jobs: %s", bus_error_message(&error, r));
 
@@ -2437,15 +2437,7 @@ static int cancel_job(int argc, char *argv[], void *userdata) {
                 if (q < 0)
                         return log_error_errno(q, "Failed to parse job id \"%s\": %m", *name);
 
-                q = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
-                                "CancelJob",
-                                &error,
-                                NULL,
-                                "u", id);
+                q = bus_call_method(bus, bus_systemd_mgr, "CancelJob", &error, NULL, "u", id);
                 if (q < 0) {
                         log_error_errno(q, "Failed to cancel job %"PRIu32": %s", id, bus_error_message(&error, q));
                         if (r == 0)
@@ -2467,15 +2459,7 @@ static int need_daemon_reload(sd_bus *bus, const char *unit) {
         /* We don't use unit_dbus_path_from_name() directly since we
          * don't want to load the unit if it isn't loaded. */
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "GetUnit",
-                        NULL,
-                        &reply,
-                        "s", unit);
+        r = bus_call_method(bus, bus_systemd_mgr, "GetUnit", NULL, &reply, "s", unit);
         if (r < 0)
                 return r;
 
@@ -2899,11 +2883,9 @@ static int start_unit_one(
                 _cleanup_(sd_bus_error_free) sd_bus_error enqueue_error = SD_BUS_ERROR_NULL;
 
                 /* Use the new, fancy EnqueueUnitJob() API if the user wants us to print the transaction */
-                r = sd_bus_call_method(
+                r = bus_call_method(
                                 bus,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
+                                bus_systemd_mgr,
                                 "EnqueueUnitJob",
                                 &enqueue_error,
                                 &reply,
@@ -2949,15 +2931,7 @@ static int start_unit_one(
         }
 
         if (!done) {
-                r = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
-                                method,
-                                error,
-                                &reply,
-                                "ss", name, mode);
+                r = bus_call_method(bus, bus_systemd_mgr, method, error, &reply, "ss", name, mode);
                 if (r < 0)
                         goto fail;
 
@@ -3146,15 +3120,7 @@ static int start_unit(int argc, char *argv[], void *userdata) {
         }
 
         if (arg_wait) {
-                r = sd_bus_call_method_async(
-                                bus,
-                                NULL,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
-                                "Subscribe",
-                                NULL, NULL,
-                                NULL);
+                r = bus_call_method_async(bus, NULL, bus_systemd_mgr, "Subscribe", NULL, NULL, NULL);
                 if (r < 0)
                         return log_error_errno(r, "Failed to enable subscription: %m");
 
@@ -3221,18 +3187,7 @@ static int logind_set_wall_message(void) {
         if (arg_dry_run)
                 return 0;
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.login1",
-                        "/org/freedesktop/login1",
-                        "org.freedesktop.login1.Manager",
-                        "SetWallMessage",
-                        &error,
-                        NULL,
-                        "sb",
-                        m,
-                        !arg_no_wall);
-
+        r = bus_call_method(bus, bus_login_mgr, "SetWallMessage", &error, NULL, "sb", m, !arg_no_wall);
         if (r < 0)
                 return log_warning_errno(r, "Failed to set wall message, ignoring: %s", bus_error_message(&error, r));
         return 0;
@@ -3274,15 +3229,7 @@ static int logind_reboot(enum action a) {
         if (arg_dry_run)
                 return 0;
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.login1",
-                        "/org/freedesktop/login1",
-                        "org.freedesktop.login1.Manager",
-                        actions[a].method,
-                        &error,
-                        NULL,
-                        "b", arg_ask_password);
+        r = bus_call_method(bus, bus_login_mgr, actions[a].method, &error, NULL, "b", arg_ask_password);
         if (r < 0)
                 return log_error_errno(r, "Failed to %s via logind: %s", actions[a].description, bus_error_message(&error, r));
 
@@ -3322,15 +3269,7 @@ static int logind_check_inhibitors(enum action a) {
         if (r < 0)
                 return r;
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.login1",
-                        "/org/freedesktop/login1",
-                        "org.freedesktop.login1.Manager",
-                        "ListInhibitors",
-                        NULL,
-                        &reply,
-                        NULL);
+        r = bus_call_method(bus, bus_login_mgr, "ListInhibitors", NULL, &reply, NULL);
         if (r < 0)
                 /* If logind is not around, then there are no inhibitors... */
                 return 0;
@@ -3425,15 +3364,7 @@ static int prepare_firmware_setup(void) {
         if (r < 0)
                 return r;
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.login1",
-                        "/org/freedesktop/login1",
-                        "org.freedesktop.login1.Manager",
-                        "SetRebootToFirmwareSetup",
-                        &error,
-                        NULL,
-                        "b", true);
+        r = bus_call_method(bus, bus_login_mgr, "SetRebootToFirmwareSetup", &error, NULL, "b", true);
         if (r < 0)
                 return log_error_errno(r, "Cannot indicate to EFI to boot into setup mode: %s", bus_error_message(&error, r));
 
@@ -3458,15 +3389,7 @@ static int prepare_boot_loader_menu(void) {
         if (r < 0)
                 return r;
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.login1",
-                        "/org/freedesktop/login1",
-                        "org.freedesktop.login1.Manager",
-                        "SetRebootToBootLoaderMenu",
-                        &error,
-                        NULL,
-                        "t", arg_boot_loader_menu);
+        r = bus_call_method(bus, bus_login_mgr, "SetRebootToBootLoaderMenu", &error, NULL, "t", arg_boot_loader_menu);
         if (r < 0)
                 return log_error_errno(r, "Cannot indicate to boot loader to enter boot loader entry menu: %s", bus_error_message(&error, r));
 
@@ -3491,15 +3414,7 @@ static int prepare_boot_loader_entry(void) {
         if (r < 0)
                 return r;
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.login1",
-                        "/org/freedesktop/login1",
-                        "org.freedesktop.login1.Manager",
-                        "SetRebootToBootLoaderEntry",
-                        &error,
-                        NULL,
-                        "s", arg_boot_loader_entry);
+        r = bus_call_method(bus, bus_login_mgr, "SetRebootToBootLoaderEntry", &error, NULL, "s", arg_boot_loader_entry);
         if (r < 0)
                 return log_error_errno(r, "Cannot set boot into loader entry '%s': %s", arg_boot_loader_entry, bus_error_message(&error, r));
 
@@ -3602,15 +3517,7 @@ static int set_exit_code(uint8_t code) {
         if (r < 0)
                 return r;
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "SetExitCode",
-                        &error,
-                        NULL,
-                        "y", code);
+        r = bus_call_method(bus, bus_systemd_mgr, "SetExitCode", &error, NULL, "y", code);
         if (r < 0)
                 return log_error_errno(r, "Failed to set exit code: %s", bus_error_message(&error, r));
 
@@ -3815,11 +3722,9 @@ static int kill_unit(int argc, char *argv[], void *userdata) {
         STRV_FOREACH(name, names) {
                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
 
-                q = sd_bus_call_method(
+                q = bus_call_method(
                                 bus,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
+                                bus_systemd_mgr,
                                 "KillUnit",
                                 &error,
                                 NULL,
@@ -3834,11 +3739,12 @@ static int kill_unit(int argc, char *argv[], void *userdata) {
         return r;
 }
 
-static int clean_unit(int argc, char *argv[], void *userdata) {
+static int clean_or_freeze_unit(int argc, char *argv[], void *userdata) {
         _cleanup_(bus_wait_for_units_freep) BusWaitForUnits *w = NULL;
         _cleanup_strv_free_ char **names = NULL;
         int r, ret = EXIT_SUCCESS;
         char **name;
+        const char *method;
         sd_bus *bus;
 
         r = acquire_bus(BUS_FULL, &bus);
@@ -3863,21 +3769,22 @@ static int clean_unit(int argc, char *argv[], void *userdata) {
                         return log_error_errno(r, "Failed to allocate unit waiter: %m");
         }
 
+        if (streq(argv[0], "clean"))
+                method = "CleanUnit";
+        else if (streq(argv[0], "freeze"))
+                method = "FreezeUnit";
+        else if (streq(argv[0], "thaw"))
+                method = "ThawUnit";
+        else
+                assert_not_reached("Unhandled method");
+
         STRV_FOREACH(name, names) {
                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
 
                 if (w) {
                         /* If we shall wait for the cleaning to complete, let's add a ref on the unit first */
-                        r = sd_bus_call_method(
-                                        bus,
-                                        "org.freedesktop.systemd1",
-                                        "/org/freedesktop/systemd1",
-                                        "org.freedesktop.systemd1.Manager",
-                                        "RefUnit",
-                                        &error,
-                                        NULL,
-                                        "s", *name);
+                        r = bus_call_method(bus, bus_systemd_mgr, "RefUnit", &error, NULL, "s", *name);
                         if (r < 0) {
                                 log_error_errno(r, "Failed to add reference to unit %s: %s", *name, bus_error_message(&error, r));
                                 if (ret == EXIT_SUCCESS)
@@ -3886,13 +3793,7 @@ static int clean_unit(int argc, char *argv[], void *userdata) {
                         }
                 }
 
-                r = sd_bus_message_new_method_call(
-                                bus,
-                                &m,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
-                                "CleanUnit");
+                r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, method);
                 if (r < 0)
                         return bus_log_create_error(r);
 
@@ -3900,13 +3801,15 @@ static int clean_unit(int argc, char *argv[], void *userdata) {
                 if (r < 0)
                         return bus_log_create_error(r);
 
-                r = sd_bus_message_append_strv(m, arg_clean_what);
-                if (r < 0)
-                        return bus_log_create_error(r);
+                if (streq(method, "CleanUnit")) {
+                        r = sd_bus_message_append_strv(m, arg_clean_what);
+                        if (r < 0)
+                                return bus_log_create_error(r);
+                }
 
                 r = sd_bus_call(bus, m, 0, &error, NULL);
                 if (r < 0) {
-                        log_error_errno(r, "Failed to clean unit %s: %s", *name, bus_error_message(&error, r));
+                        log_error_errno(r, "Failed to %s unit %s: %s", argv[0], *name, bus_error_message(&error, r));
                         if (ret == EXIT_SUCCESS) {
                                 ret = r;
                                 continue;
@@ -4046,6 +3949,7 @@ typedef struct UnitStatusInfo {
         const char *id;
         const char *load_state;
         const char *active_state;
+        const char *freezer_state;
         const char *sub_state;
         const char *unit_file_state;
         const char *unit_file_preset;
@@ -4182,7 +4086,7 @@ static void print_status_info(
                 bool *ellipsized) {
 
         char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], since2[FORMAT_TIMESTAMP_MAX];
-        const char *s1, *s2, *active_on, *active_off, *on, *off, *ss;
+        const char *s1, *s2, *active_on, *active_off, *on, *off, *ss, *fs;
         _cleanup_free_ char *formatted_path = NULL;
         ExecStatusInfo *p;
         usec_t timestamp;
@@ -4220,14 +4124,18 @@ static void print_status_info(
         if (!isempty(i->load_error))
                 printf("     Loaded: %s%s%s (Reason: %s)\n",
                        on, strna(i->load_state), off, i->load_error);
-        else if (path && !isempty(i->unit_file_state) && !isempty(i->unit_file_preset) &&
-                 !STR_IN_SET(i->unit_file_state, "generated", "transient"))
-                printf("     Loaded: %s%s%s (%s; %s; vendor preset: %s)\n",
-                       on, strna(i->load_state), off, path, i->unit_file_state, i->unit_file_preset);
-        else if (path && !isempty(i->unit_file_state))
-                printf("     Loaded: %s%s%s (%s; %s)\n",
-                       on, strna(i->load_state), off, path, i->unit_file_state);
-        else if (path)
+        else if (path && !isempty(i->unit_file_state)) {
+                bool show_preset = !isempty(i->unit_file_preset) &&
+                        show_preset_for_state(unit_file_state_from_string(i->unit_file_state));
+
+                printf("     Loaded: %s%s%s (%s; %s%s%s)\n",
+                       on, strna(i->load_state), off,
+                       path,
+                       i->unit_file_state,
+                       show_preset ? "; vendor preset: " : "",
+                       show_preset ? i->unit_file_preset : "");
+
+        } else if (path)
                 printf("     Loaded: %s%s%s (%s)\n",
                        on, strna(i->load_state), off, path);
         else
@@ -4282,6 +4190,10 @@ static void print_status_info(
                 printf("     Active: %s%s%s",
                        active_on, strna(i->active_state), active_off);
 
+        fs = !isempty(i->freezer_state) && !streq(i->freezer_state, "running") ? i->freezer_state : NULL;
+        if (fs)
+                printf(" %s(%s)%s", ansi_highlight_yellow(), fs, ansi_normal());
+
         if (!isempty(i->result) && !streq(i->result, "success"))
                 printf(" (Result: %s)", i->result);
 
@@ -5539,12 +5451,14 @@ static int show_one(
         static const struct bus_properties_map property_map[] = {
                 { "LoadState",                      "s",               NULL,           offsetof(UnitStatusInfo, load_state)                        },
                 { "ActiveState",                    "s",               NULL,           offsetof(UnitStatusInfo, active_state)                      },
+                { "FreezerState",                   "s",               NULL,           offsetof(UnitStatusInfo, freezer_state)                     },
                 { "Documentation",                  "as",              NULL,           offsetof(UnitStatusInfo, documentation)                     },
                 {}
         }, status_map[] = {
                 { "Id",                             "s",               NULL,           offsetof(UnitStatusInfo, id)                                },
                 { "LoadState",                      "s",               NULL,           offsetof(UnitStatusInfo, load_state)                        },
                 { "ActiveState",                    "s",               NULL,           offsetof(UnitStatusInfo, active_state)                      },
+                { "FreezerState",                   "s",               NULL,           offsetof(UnitStatusInfo, freezer_state)                     },
                 { "SubState",                       "s",               NULL,           offsetof(UnitStatusInfo, sub_state)                         },
                 { "UnitFileState",                  "s",               NULL,           offsetof(UnitStatusInfo, unit_file_state)                   },
                 { "UnitFilePreset",                 "s",               NULL,           offsetof(UnitStatusInfo, unit_file_preset)                  },
@@ -5717,15 +5631,7 @@ static int get_unit_dbus_path_by_pid(
         char *u;
         int r;
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "GetUnitByPID",
-                        &error,
-                        &reply,
-                        "u", pid);
+        r = bus_call_method(bus, bus_systemd_mgr, "GetUnitByPID", &error, &reply, "u", pid);
         if (r < 0)
                 return log_error_errno(r, "Failed to get unit for PID %"PRIu32": %s", pid, bus_error_message(&error, r));
 
@@ -5860,7 +5766,8 @@ static int show(int argc, char *argv[], void *userdata) {
 
         if (show_mode == SYSTEMCTL_SHOW_HELP && argc <= 1)
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "This command expects one or more unit names. Did you mean --help?");
+                                       "'help' command expects one or more unit names.\n"
+                                       "(Alternatively, help for systemctl itself may be shown with --help)");
 
         r = acquire_bus(BUS_MANAGER, &bus);
         if (r < 0)
@@ -6053,13 +5960,7 @@ static int set_property(int argc, char *argv[], void *userdata) {
 
         polkit_agent_open_maybe();
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &m,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "SetUnitProperties");
+        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "SetUnitProperties");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -6126,13 +6027,7 @@ static int daemon_reload(int argc, char *argv[], void *userdata) {
                 assert_not_reached("Unexpected action");
         }
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &m,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        method);
+        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, method);
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -6180,15 +6075,7 @@ static int trivial_method(int argc, char *argv[], void *userdata) {
                 streq(argv[0], "exit")          ? "Exit" :
                              /* poweroff */       "PowerOff";
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        method,
-                        &error,
-                        NULL,
-                        NULL);
+        r = bus_call_method(bus, bus_systemd_mgr, method, &error, NULL, NULL);
         if (r < 0 && arg_action == ACTION_SYSTEMCTL)
                 return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
 
@@ -6220,15 +6107,7 @@ static int reset_failed(int argc, char *argv[], void *userdata) {
         STRV_FOREACH(name, names) {
                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
 
-                q = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
-                                "ResetFailedUnit",
-                                &error,
-                                NULL,
-                                "s", *name);
+                q = bus_call_method(bus, bus_systemd_mgr, "ResetFailedUnit", &error, NULL, "s", *name);
                 if (q < 0) {
                         log_error_errno(q, "Failed to reset failed state of unit %s: %s", *name, bus_error_message(&error, q));
                         if (r == 0)
@@ -6269,15 +6148,7 @@ static int show_environment(int argc, char *argv[], void *userdata) {
 
         (void) pager_open(arg_pager_flags);
 
-        r = sd_bus_get_property(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "Environment",
-                        &error,
-                        &reply,
-                        "as");
+        r = bus_get_property(bus, bus_systemd_mgr, "Environment", &error, &reply, "as");
         if (r < 0)
                 return log_error_errno(r, "Failed to get environment: %s", bus_error_message(&error, r));
 
@@ -6358,15 +6229,7 @@ static int switch_root(int argc, char *argv[], void *userdata) {
 
         log_debug("Switching root - root: %s; init: %s", root, strna(init));
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "SwitchRoot",
-                        &error,
-                        NULL,
-                        "ss", root, init);
+        r = bus_call_method(bus, bus_systemd_mgr, "SwitchRoot", &error, NULL, "ss", root, init);
         if (r < 0) {
                 (void) default_signals(SIGTERM, -1);
 
@@ -6388,14 +6251,7 @@ static int log_level(int argc, char *argv[], void *userdata) {
         if (argc == 1) {
                 _cleanup_free_ char *level = NULL;
 
-                r = sd_bus_get_property_string(
-                                bus,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
-                                "LogLevel",
-                                &error,
-                                &level);
+                r = bus_get_property_string(bus, bus_systemd_mgr, "LogLevel", &error, &level);
                 if (r < 0)
                         return log_error_errno(r, "Failed to get log level: %s", bus_error_message(&error, r));
 
@@ -6404,15 +6260,7 @@ static int log_level(int argc, char *argv[], void *userdata) {
         } else {
                 assert(argc == 2);
 
-                r = sd_bus_set_property(
-                                bus,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
-                                "LogLevel",
-                                &error,
-                                "s",
-                                argv[1]);
+                r = bus_set_property(bus, bus_systemd_mgr, "LogLevel", &error, "s", argv[1]);
                 if (r < 0)
                         return log_error_errno(r, "Failed to set log level: %s", bus_error_message(&error, r));
         }
@@ -6432,14 +6280,7 @@ static int log_target(int argc, char *argv[], void *userdata) {
         if (argc == 1) {
                 _cleanup_free_ char *target = NULL;
 
-                r = sd_bus_get_property_string(
-                                bus,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
-                                "LogTarget",
-                                &error,
-                                &target);
+                r = bus_get_property_string(bus, bus_systemd_mgr, "LogTarget", &error, &target);
                 if (r < 0)
                         return log_error_errno(r, "Failed to get log target: %s", bus_error_message(&error, r));
 
@@ -6448,15 +6289,7 @@ static int log_target(int argc, char *argv[], void *userdata) {
         } else {
                 assert(argc == 2);
 
-                r = sd_bus_set_property(
-                                bus,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
-                                "LogTarget",
-                                &error,
-                                "s",
-                                argv[1]);
+                r = bus_set_property(bus, bus_systemd_mgr, "LogTarget", &error, "s", argv[1]);
                 if (r < 0)
                         return log_error_errno(r, "Failed to set log target: %s", bus_error_message(&error, r));
         }
@@ -6477,15 +6310,7 @@ static int service_watchdogs(int argc, char *argv[], void *userdata) {
 
         if (argc == 1) {
                 /* get ServiceWatchdogs */
-                r = sd_bus_get_property_trivial(
-                                bus,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
-                                "ServiceWatchdogs",
-                                &error,
-                                'b',
-                                &b);
+                r = bus_get_property_trivial(bus, bus_systemd_mgr, "ServiceWatchdogs", &error, 'b', &b);
                 if (r < 0)
                         return log_error_errno(r, "Failed to get service-watchdog state: %s", bus_error_message(&error, r));
 
@@ -6499,15 +6324,7 @@ static int service_watchdogs(int argc, char *argv[], void *userdata) {
                 if (b < 0)
                         return log_error_errno(b, "Failed to parse service-watchdogs argument: %m");
 
-                r = sd_bus_set_property(
-                                bus,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
-                                "ServiceWatchdogs",
-                                &error,
-                                "b",
-                                b);
+                r = bus_set_property(bus, bus_systemd_mgr, "ServiceWatchdogs", &error, "b", b);
                 if (r < 0)
                         return log_error_errno(r, "Failed to set service-watchdog state: %s", bus_error_message(&error, r));
         }
@@ -6535,13 +6352,7 @@ static int set_environment(int argc, char *argv[], void *userdata) {
                 ? "SetEnvironment"
                 : "UnsetEnvironment";
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &m,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        method);
+        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, method);
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -6568,13 +6379,7 @@ static int import_environment(int argc, char *argv[], void *userdata) {
 
         polkit_agent_open_maybe();
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &m,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "SetEnvironment");
+        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "SetEnvironment");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -7013,13 +6818,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
                 } else
                         assert_not_reached("Unknown verb");
 
-                r = sd_bus_message_new_method_call(
-                                bus,
-                                &m,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
-                                method);
+                r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, method);
                 if (r < 0)
                         return bus_log_create_error(r);
 
@@ -7155,13 +6954,7 @@ static int add_dependency(int argc, char *argv[], void *userdata) {
 
                 polkit_agent_open_maybe();
 
-                r = sd_bus_message_new_method_call(
-                                bus,
-                                &m,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
-                                "AddDependencyUnitFiles");
+                r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "AddDependencyUnitFiles");
                 if (r < 0)
                         return bus_log_create_error(r);
 
@@ -7217,11 +7010,9 @@ static int preset_all(int argc, char *argv[], void *userdata) {
 
                 polkit_agent_open_maybe();
 
-                r = sd_bus_call_method(
+                r = bus_call_method(
                                 bus,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
+                                bus_systemd_mgr,
                                 "PresetAllUnitFiles",
                                 &error,
                                 &reply,
@@ -7278,15 +7069,7 @@ static int show_installation_targets(sd_bus *bus, const char *name) {
         const char *link;
         int r;
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "GetUnitFileLinks",
-                        &error,
-                        &reply,
-                        "sb", name, arg_runtime);
+        r = bus_call_method(bus, bus_systemd_mgr, "GetUnitFileLinks", &error, &reply, "sb", name, arg_runtime);
         if (r < 0)
                 return log_error_errno(r, "Failed to get unit file links for %s: %s", name, bus_error_message(&error, r));
 
@@ -7335,6 +7118,7 @@ static int unit_is_enabled(int argc, char *argv[], void *userdata) {
                                    UNIT_FILE_ENABLED,
                                    UNIT_FILE_ENABLED_RUNTIME,
                                    UNIT_FILE_STATIC,
+                                   UNIT_FILE_ALIAS,
                                    UNIT_FILE_INDIRECT,
                                    UNIT_FILE_GENERATED))
                                 enabled = true;
@@ -7362,15 +7146,7 @@ static int unit_is_enabled(int argc, char *argv[], void *userdata) {
                         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
                         const char *s;
 
-                        r = sd_bus_call_method(
-                                        bus,
-                                        "org.freedesktop.systemd1",
-                                        "/org/freedesktop/systemd1",
-                                        "org.freedesktop.systemd1.Manager",
-                                        "GetUnitFileState",
-                                        &error,
-                                        &reply,
-                                        "s", *name);
+                        r = bus_call_method(bus, bus_systemd_mgr, "GetUnitFileState", &error, &reply, "s", *name);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r));
 
@@ -7401,14 +7177,7 @@ static int match_startup_finished(sd_bus_message *m, void *userdata, sd_bus_erro
 
         assert(state);
 
-        r = sd_bus_get_property_string(
-                        sd_bus_message_get_bus(m),
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "SystemState",
-                        NULL,
-                        state);
+        r = bus_get_property_string(sd_bus_message_get_bus(m), bus_systemd_mgr, "SystemState", NULL, state);
 
         sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), r);
         return 0;
@@ -7437,12 +7206,10 @@ static int is_system_running(int argc, char *argv[], void *userdata) {
                 if (r >= 0)
                         r = sd_bus_attach_event(bus, event, 0);
                 if (r >= 0)
-                        r = sd_bus_match_signal_async(
+                        r = bus_match_signal_async(
                                         bus,
                                         &slot_startup_finished,
-                                        "org.freedesktop.systemd1",
-                                        "/org/freedesktop/systemd1",
-                                        "org.freedesktop.systemd1.Manager",
+                                        bus_systemd_mgr,
                                         "StartupFinished",
                                         match_startup_finished, NULL, &state);
                 if (r < 0) {
@@ -7451,14 +7218,7 @@ static int is_system_running(int argc, char *argv[], void *userdata) {
                 }
         }
 
-        r = sd_bus_get_property_string(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "SystemState",
-                        &error,
-                        &state);
+        r = bus_get_property_string(bus, bus_systemd_mgr, "SystemState", &error, &state);
         if (r < 0) {
                 log_warning_errno(r, "Failed to query system state: %s", bus_error_message(&error, r));
 
@@ -7887,6 +7647,8 @@ static int systemctl_help(void) {
                "  kill UNIT...                        Send signal to processes of a unit\n"
                "  clean UNIT...                       Clean runtime, cache, state, logs or\n"
                "                                      configuration of unit\n"
+               "  freeze PATTERN...                   Freeze execution of unit processes\n"
+               "  thaw PATTERN...                     Resume execution of a frozen unit\n"
                "  is-active PATTERN...                Check whether units are active\n"
                "  is-failed PATTERN...                Check whether units are failed\n"
                "  status [PATTERN...|PID...]          Show runtime status of one or more units\n"
@@ -8214,14 +7976,7 @@ static int help_boot_loader_entry(void) {
         if (r < 0)
                 return r;
 
-        r = sd_bus_get_property_strv(
-                        bus,
-                        "org.freedesktop.login1",
-                        "/org/freedesktop/login1",
-                        "org.freedesktop.login1.Manager",
-                        "BootLoaderEntries",
-                        &error,
-                        &l);
+        r = bus_get_property_strv(bus, bus_login_mgr, "BootLoaderEntries", &error, &l);
         if (r < 0)
                 return log_error_errno(r, "Failed to enumerate boot loader entries: %s", bus_error_message(&error, r));
 
@@ -8582,6 +8337,11 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                                        "Unknown output '%s'.",
                                                        optarg);
+
+                        if (OUTPUT_MODE_IS_JSON(arg_output)) {
+                                arg_no_legend = true;
+                                arg_plain = true;
+                        }
                         break;
 
                 case 'i':
@@ -9160,7 +8920,9 @@ static int systemctl_main(int argc, char *argv[]) {
                 { "condrestart",           2,        VERB_ANY, VERB_ONLINE_ONLY, start_unit              }, /* For compatibility with RH */
                 { "isolate",               2,        2,        VERB_ONLINE_ONLY, start_unit              },
                 { "kill",                  2,        VERB_ANY, VERB_ONLINE_ONLY, kill_unit               },
-                { "clean",                 2,        VERB_ANY, VERB_ONLINE_ONLY, clean_unit              },
+                { "clean",                 2,        VERB_ANY, VERB_ONLINE_ONLY, clean_or_freeze_unit    },
+                { "freeze",                2,        VERB_ANY, VERB_ONLINE_ONLY, clean_or_freeze_unit    },
+                { "thaw",                  2,        VERB_ANY, VERB_ONLINE_ONLY, clean_or_freeze_unit    },
                 { "is-active",             2,        VERB_ANY, VERB_ONLINE_ONLY, check_unit_active       },
                 { "check",                 2,        VERB_ANY, VERB_ONLINE_ONLY, check_unit_active       }, /* deprecated alias of is-active */
                 { "is-failed",             2,        VERB_ANY, VERB_ONLINE_ONLY, check_unit_failed       },
@@ -9170,9 +8932,9 @@ static int systemctl_main(int argc, char *argv[]) {
                 { "help",                  VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, show                    },
                 { "daemon-reload",         VERB_ANY, 1,        VERB_ONLINE_ONLY, daemon_reload           },
                 { "daemon-reexec",         VERB_ANY, 1,        VERB_ONLINE_ONLY, daemon_reload           },
-                { "log-level",             VERB_ANY, 2,        0,                log_level               },
-                { "log-target",            VERB_ANY, 2,        0,                log_target              },
-                { "service-watchdogs",     VERB_ANY, 2,        0,                service_watchdogs       },
+                { "log-level",             VERB_ANY, 2,        VERB_ONLINE_ONLY, log_level               },
+                { "log-target",            VERB_ANY, 2,        VERB_ONLINE_ONLY, log_target              },
+                { "service-watchdogs",     VERB_ANY, 2,        VERB_ONLINE_ONLY, service_watchdogs       },
                 { "show-environment",      VERB_ANY, 1,        VERB_ONLINE_ONLY, show_environment        },
                 { "set-environment",       2,        VERB_ANY, VERB_ONLINE_ONLY, set_environment         },
                 { "unset-environment",     2,        VERB_ANY, VERB_ONLINE_ONLY, set_environment         },
@@ -9212,6 +8974,12 @@ static int systemctl_main(int argc, char *argv[]) {
                 {}
         };
 
+        const Verb *verb = verbs_find_verb(argv[optind], verbs);
+        if (verb && (verb->flags & VERB_ONLINE_ONLY) && arg_root)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Verb '%s' cannot be used with --root=.",
+                                       argv[optind] ?: verb->verb);
+
         return dispatch_verb(argc, argv, verbs, NULL);
 }
 
@@ -9320,17 +9088,7 @@ static int logind_schedule_shutdown(void) {
 
         (void) logind_set_wall_message();
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.login1",
-                        "/org/freedesktop/login1",
-                        "org.freedesktop.login1.Manager",
-                        "ScheduleShutdown",
-                        &error,
-                        NULL,
-                        "st",
-                        action,
-                        arg_when);
+        r = bus_call_method(bus, bus_login_mgr, "ScheduleShutdown", &error, NULL, "st", action, arg_when);
         if (r < 0)
                 return log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s", bus_error_message(&error, r));
 
@@ -9432,14 +9190,7 @@ static int logind_cancel_shutdown(void) {
 
         (void) logind_set_wall_message();
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.login1",
-                        "/org/freedesktop/login1",
-                        "org.freedesktop.login1.Manager",
-                        "CancelScheduledShutdown",
-                        &error,
-                        NULL, NULL);
+        r = bus_call_method(bus, bus_login_mgr, "CancelScheduledShutdown", &error, NULL, NULL);
         if (r < 0)
                 return log_warning_errno(r, "Failed to talk to logind, shutdown hasn't been cancelled: %s", bus_error_message(&error, r));
 
index 95b5914236a478b6eeb7028b4c2002dc4c71b65d..b10a3e04bc3490cb7d50987126433f1fb095138c 100644 (file)
@@ -44,6 +44,7 @@ enum {
         SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION  = 1ULL << 6,
         SD_BUS_VTABLE_PROPERTY_EXPLICIT            = 1ULL << 7,
         SD_BUS_VTABLE_SENSITIVE                    = 1ULL << 8, /* covers both directions: method call + reply */
+        SD_BUS_VTABLE_ABSOLUTE_OFFSET              = 1ULL << 9,
         _SD_BUS_VTABLE_CAPABILITY_MASK             = 0xFFFFULL << 40
 };
 
@@ -187,6 +188,124 @@ struct sd_bus_vtable {
                 .x = { { 0 } },                                         \
         }
 
+#define _SD_ECHO(X) X
+#define _SD_CONCAT(X) #X "\0"
+
+#define _SD_VARARGS_FOREACH_EVEN_01(FN, X, ...)
+#define _SD_VARARGS_FOREACH_EVEN_02(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_01(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_03(FN, X, ...)       _SD_VARARGS_FOREACH_EVEN_02(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_04(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_03(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_05(FN, X, ...)       _SD_VARARGS_FOREACH_EVEN_04(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_06(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_05(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_07(FN, X, ...)       _SD_VARARGS_FOREACH_EVEN_06(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_08(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_07(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_09(FN, X, ...)       _SD_VARARGS_FOREACH_EVEN_08(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_10(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_09(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_11(FN, X, ...)       _SD_VARARGS_FOREACH_EVEN_10(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_12(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_11(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_13(FN, X, ...)       _SD_VARARGS_FOREACH_EVEN_12(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_14(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_13(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_15(FN, X, ...)       _SD_VARARGS_FOREACH_EVEN_14(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_16(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_15(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_17(FN, X, ...)       _SD_VARARGS_FOREACH_EVEN_16(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_18(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_17(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_19(FN, X, ...)       _SD_VARARGS_FOREACH_EVEN_18(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_20(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_19(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_21(FN, X, ...)       _SD_VARARGS_FOREACH_EVEN_20(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_22(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_21(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_23(FN, X, ...)       _SD_VARARGS_FOREACH_EVEN_22(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_24(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_23(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_25(FN, X, ...)       _SD_VARARGS_FOREACH_EVEN_24(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_26(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_25(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_27(FN, X, ...)       _SD_VARARGS_FOREACH_EVEN_26(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_28(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_27(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_29(FN, X, ...)       _SD_VARARGS_FOREACH_EVEN_28(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_30(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_29(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_31(FN, X, ...)       _SD_VARARGS_FOREACH_EVEN_30(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_32(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_31(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_33(FN, X, ...)       _SD_VARARGS_FOREACH_EVEN_32(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_34(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_33(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_35(FN, X, ...)       _SD_VARARGS_FOREACH_EVEN_34(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_36(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_35(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_37(FN, X, ...)       _SD_VARARGS_FOREACH_EVEN_36(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_38(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_37(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_39(FN, X, ...)       _SD_VARARGS_FOREACH_EVEN_38(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_40(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_39(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_41(FN, X, ...)       _SD_VARARGS_FOREACH_EVEN_40(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_42(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_41(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_43(FN, X, ...)       _SD_VARARGS_FOREACH_EVEN_42(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_44(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_43(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_45(FN, X, ...)       _SD_VARARGS_FOREACH_EVEN_44(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_46(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_45(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_47(FN, X, ...)       _SD_VARARGS_FOREACH_EVEN_46(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_48(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_47(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_49(FN, X, ...)       _SD_VARARGS_FOREACH_EVEN_48(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_50(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_49(FN, __VA_ARGS__)
+
+#define _SD_VARARGS_FOREACH_EVEN_SEQ(_01, _02, _03, _04, _05, _06, _07, _08, _09, _10, \
+                                     _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \
+                                     _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \
+                                     _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \
+                                     _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \
+                                     NAME, ...) NAME
+
+#define _SD_VARARGS_FOREACH_EVEN(FN, ...)                                                      \
+        _SD_VARARGS_FOREACH_EVEN_SEQ(__VA_ARGS__,                                              \
+                                     _SD_VARARGS_FOREACH_EVEN_50, _SD_VARARGS_FOREACH_EVEN_49, \
+                                     _SD_VARARGS_FOREACH_EVEN_48, _SD_VARARGS_FOREACH_EVEN_47, \
+                                     _SD_VARARGS_FOREACH_EVEN_46, _SD_VARARGS_FOREACH_EVEN_45, \
+                                     _SD_VARARGS_FOREACH_EVEN_44, _SD_VARARGS_FOREACH_EVEN_43, \
+                                     _SD_VARARGS_FOREACH_EVEN_42, _SD_VARARGS_FOREACH_EVEN_41, \
+                                     _SD_VARARGS_FOREACH_EVEN_40, _SD_VARARGS_FOREACH_EVEN_39, \
+                                     _SD_VARARGS_FOREACH_EVEN_38, _SD_VARARGS_FOREACH_EVEN_37, \
+                                     _SD_VARARGS_FOREACH_EVEN_36, _SD_VARARGS_FOREACH_EVEN_35, \
+                                     _SD_VARARGS_FOREACH_EVEN_34, _SD_VARARGS_FOREACH_EVEN_33, \
+                                     _SD_VARARGS_FOREACH_EVEN_32, _SD_VARARGS_FOREACH_EVEN_31, \
+                                     _SD_VARARGS_FOREACH_EVEN_30, _SD_VARARGS_FOREACH_EVEN_29, \
+                                     _SD_VARARGS_FOREACH_EVEN_28, _SD_VARARGS_FOREACH_EVEN_27, \
+                                     _SD_VARARGS_FOREACH_EVEN_26, _SD_VARARGS_FOREACH_EVEN_25, \
+                                     _SD_VARARGS_FOREACH_EVEN_24, _SD_VARARGS_FOREACH_EVEN_23, \
+                                     _SD_VARARGS_FOREACH_EVEN_22, _SD_VARARGS_FOREACH_EVEN_21, \
+                                     _SD_VARARGS_FOREACH_EVEN_20, _SD_VARARGS_FOREACH_EVEN_19, \
+                                     _SD_VARARGS_FOREACH_EVEN_18, _SD_VARARGS_FOREACH_EVEN_17, \
+                                     _SD_VARARGS_FOREACH_EVEN_16, _SD_VARARGS_FOREACH_EVEN_15, \
+                                     _SD_VARARGS_FOREACH_EVEN_14, _SD_VARARGS_FOREACH_EVEN_13, \
+                                     _SD_VARARGS_FOREACH_EVEN_12, _SD_VARARGS_FOREACH_EVEN_11, \
+                                     _SD_VARARGS_FOREACH_EVEN_10, _SD_VARARGS_FOREACH_EVEN_09, \
+                                     _SD_VARARGS_FOREACH_EVEN_08, _SD_VARARGS_FOREACH_EVEN_07, \
+                                     _SD_VARARGS_FOREACH_EVEN_06, _SD_VARARGS_FOREACH_EVEN_05, \
+                                     _SD_VARARGS_FOREACH_EVEN_04, _SD_VARARGS_FOREACH_EVEN_03, \
+                                     _SD_VARARGS_FOREACH_EVEN_02, _SD_VARARGS_FOREACH_EVEN_01) \
+                                     (FN, __VA_ARGS__)
+
+#define SD_BUS_ARGS(...) __VA_ARGS__
+#define SD_BUS_RESULT(...) __VA_ARGS__
+
+#define SD_BUS_NO_ARGS SD_BUS_ARGS(NULL,)
+#define SD_BUS_NO_RESULT SD_BUS_RESULT(NULL,)
+
+#define SD_BUS_METHOD_WITH_ARGS(_member, _args, _result, _handler, _flags)                 \
+        SD_BUS_METHOD_WITH_NAMES(_member,                                                  \
+                                _SD_VARARGS_FOREACH_EVEN(_SD_ECHO, _args),                 \
+                                _SD_VARARGS_FOREACH_EVEN(_SD_CONCAT, _args, ""),           \
+                                _SD_VARARGS_FOREACH_EVEN(_SD_ECHO, _result),               \
+                                _SD_VARARGS_FOREACH_EVEN(_SD_CONCAT, _result, ""),         \
+                                _handler, _flags)
+
+#define SD_BUS_METHOD_WITH_ARGS_OFFSET(_member, _args, _result, _handler, _offset, _flags) \
+        SD_BUS_METHOD_WITH_NAMES_OFFSET(_member,                                           \
+                                        _SD_VARARGS_FOREACH_EVEN(_SD_ECHO, _args),         \
+                                        _SD_VARARGS_FOREACH_EVEN(_SD_CONCAT, _args, ""),   \
+                                        _SD_VARARGS_FOREACH_EVEN(_SD_ECHO, _result),       \
+                                        _SD_VARARGS_FOREACH_EVEN(_SD_CONCAT, _result, ""), \
+                                        _handler, _offset, _flags)
+
+#define SD_BUS_SIGNAL_WITH_ARGS(_member, _args, _flags)                                    \
+        SD_BUS_SIGNAL_WITH_NAMES(_member,                                                  \
+                                 _SD_VARARGS_FOREACH_EVEN(_SD_ECHO, _args),                \
+                                 _SD_VARARGS_FOREACH_EVEN(_SD_CONCAT, _args, ""),          \
+                                 _flags)
+
 _SD_END_DECLARATIONS;
 
 #endif
index 31dd421250c2c9f0e1cdcc01f38ab5e01ce18073..61b5a493c7cad857880831b0a99e5b25f1c5f03e 100644 (file)
@@ -385,8 +385,8 @@ int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *inte
 int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces);
 int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interface, ...) _sd_sentinel_;
 
-int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds);
-int sd_bus_query_sender_privilege(sd_bus_message *call, int capability);
+int sd_bus_query_sender_creds(sd_bus_message *m, uint64_t mask, sd_bus_creds **creds);
+int sd_bus_query_sender_privilege(sd_bus_message *m, int capability);
 
 int sd_bus_match_signal(sd_bus *bus, sd_bus_slot **ret, const char *sender, const char *path, const char *interface, const char *member, sd_bus_message_handler_t callback, void *userdata);
 int sd_bus_match_signal_async(sd_bus *bus, sd_bus_slot **ret, const char *sender, const char *path, const char *interface, const char *member, sd_bus_message_handler_t match_callback, sd_bus_message_handler_t add_callback, void *userdata);
index 62b0f723c7a1a316c0d496822c5b29608645e87a..b47b15a445a9693aa7238b9eebedf4861ef7c4b5 100644 (file)
@@ -286,6 +286,19 @@ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) _s
 */
 int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char *state, const int *fds, unsigned n_fds);
 
+/*
+  Returns > 0 if synchronization with systemd succeeded.  Returns < 0
+  on error. Returns 0 if $NOTIFY_SOCKET was not set. Note that the
+  timeout parameter of this function call takes the timeout in µs, and
+  will be passed to ppoll(2), hence the behaviour will be similar to
+  ppoll(2). This function can be called after sending a status message
+  to systemd, if one needs to synchronize against reception of the
+  status messages sent before this call is made. Therefore, this
+  cannot be used to know if the status message was processed
+  successfully, but to only synchronize against its consumption.
+*/
+int sd_notify_barrier(int unset_environment, uint64_t timeout);
+
 /*
   Returns > 0 if the system was booted with systemd. Returns < 0 on
   error. Returns 0 if the system was not booted with systemd. Note
index 032afc9f127511e1f1531ff165d22a8289acca90..85b49bae74b872a867579b64cf251fbf311387ea 100644 (file)
@@ -185,6 +185,9 @@ int sd_dhcp_client_get_lease(
 int sd_dhcp_client_set_service_type(
                 sd_dhcp_client *client,
                 int type);
+int sd_dhcp_client_set_fallback_lease_lifetime(
+                sd_dhcp_client *client,
+                uint32_t fallback_lease_lifetime);
 
 int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v);
 int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v);
index 017d2d9cbb58dab1168365020931da0968dfeed4..4697f3dd3d75b630f4d180179df039a14761d27d 100644 (file)
@@ -45,7 +45,7 @@ int sd_dhcp_server_is_running(sd_dhcp_server *server);
 int sd_dhcp_server_start(sd_dhcp_server *server);
 int sd_dhcp_server_stop(sd_dhcp_server *server);
 
-int sd_dhcp_server_configure_pool(sd_dhcp_server *server, struct in_addr *address, unsigned char prefixlen, uint32_t offset, uint32_t size);
+int sd_dhcp_server_configure_pool(sd_dhcp_server *server, const struct in_addr *address, unsigned char prefixlen, uint32_t offset, uint32_t size);
 
 int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *timezone);
 int sd_dhcp_server_set_emit_router(sd_dhcp_server *server, int enabled);
@@ -54,14 +54,14 @@ int sd_dhcp_server_set_servers(
                 sd_dhcp_server *server,
                 sd_dhcp_lease_info what,
                 const struct in_addr addresses[],
-                unsigned n_addresses);
-
-int sd_dhcp_server_set_lpr(sd_dhcp_server *server, const struct in_addr lpr[], unsigned n);
-int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr dns[], unsigned n);
-int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr ntp[], unsigned n);
-int sd_dhcp_server_set_sip(sd_dhcp_server *server, const struct in_addr sip[], unsigned n);
-int sd_dhcp_server_set_pop3_server(sd_dhcp_server *server, const struct in_addr pop3_server[], unsigned n);
-int sd_dhcp_server_set_smtp_server(sd_dhcp_server *server, const struct in_addr smtp_server[], unsigned n);
+                size_t n_addresses);
+
+int sd_dhcp_server_set_lpr(sd_dhcp_server *server, const struct in_addr lpr[], size_t n);
+int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr dns[], size_t n);
+int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr ntp[], size_t n);
+int sd_dhcp_server_set_sip(sd_dhcp_server *server, const struct in_addr sip[], size_t n);
+int sd_dhcp_server_set_pop3(sd_dhcp_server *server, const struct in_addr pop3_server[], size_t n);
+int sd_dhcp_server_set_smtp(sd_dhcp_server *server, const struct in_addr smtp_server[], size_t n);
 
 int sd_dhcp_server_add_option(sd_dhcp_server *server, sd_dhcp_option *v);
 int sd_dhcp_server_add_vendor_option(sd_dhcp_server *server, sd_dhcp_option *v);
index 42d4ec752c3c9afd4076b0abad1c9f0fae7084a4..c342be4b294b7ef972908c64e5fff5e8a21e764c 100644 (file)
@@ -24,6 +24,7 @@
 #include <sys/types.h>
 
 #include "sd-dhcp6-lease.h"
+#include "sd-dhcp6-option.h"
 #include "sd-event.h"
 
 #include "_sd-common.h"
@@ -123,7 +124,13 @@ int sd_dhcp6_client_set_request_option(
                 uint16_t option);
 int sd_dhcp6_client_set_request_mud_url(
                 sd_dhcp6_client *client,
-                char *mudurl);
+                const char *mudurl);
+int sd_dhcp6_client_set_request_user_class(
+                sd_dhcp6_client *client,
+                char** user_class);
+int sd_dhcp6_client_set_request_vendor_class(
+                sd_dhcp6_client *client,
+                char** vendor_class);
 int sd_dhcp6_client_set_prefix_delegation_hint(
                 sd_dhcp6_client *client,
                 uint8_t prefixlen,
@@ -142,6 +149,8 @@ int sd_dhcp6_client_get_lease(
                 sd_dhcp6_client *client,
                 sd_dhcp6_lease **ret);
 
+int sd_dhcp6_client_add_option(sd_dhcp6_client *client, sd_dhcp6_option *v);
+
 int sd_dhcp6_client_stop(sd_dhcp6_client *client);
 int sd_dhcp6_client_start(sd_dhcp6_client *client);
 int sd_dhcp6_client_is_running(sd_dhcp6_client *client);
diff --git a/src/systemd/sd-dhcp6-option.h b/src/systemd/sd-dhcp6-option.h
new file mode 100644 (file)
index 0000000..c0f1c4d
--- /dev/null
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#ifndef foosddhcp6optionhfoo
+#define foosddhcp6optionhfoo
+
+/***
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <inttypes.h>
+#include <sys/types.h>
+
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
+
+typedef struct sd_dhcp6_option sd_dhcp6_option;
+
+int sd_dhcp6_option_new(uint16_t option, const void *data, size_t length, sd_dhcp6_option **ret);
+sd_dhcp6_option *sd_dhcp6_option_ref(sd_dhcp6_option *ra);
+sd_dhcp6_option *sd_dhcp6_option_unref(sd_dhcp6_option *ra);
+
+_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp6_option, sd_dhcp6_option_unref);
+
+_SD_END_DECLARATIONS;
+
+#endif
index c3e5457fc171df647d1e799bd67a68a91cdcb7af..847aebc5169339aa5714157d4abf02f4cdb07e02 100644 (file)
@@ -529,7 +529,7 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char
         ORDERED_HASHMAP_FOREACH(i, todo_uids, iterator) {
                 struct spwd n = {
                         .sp_namp = i->name,
-                        .sp_pwdp = (char*) "!!", /* lock this password, and make it invalid */
+                        .sp_pwdp = (char*) "!*", /* lock this password, and make it invalid */
                         .sp_lstchg = lstchg,
                         .sp_min = -1,
                         .sp_max = -1,
@@ -1389,12 +1389,18 @@ static bool item_equal(Item *a, Item *b) {
 static int parse_line(const char *fname, unsigned line, const char *buffer) {
 
         static const Specifier specifier_table[] = {
-                { 'm', specifier_machine_id,     NULL },
-                { 'b', specifier_boot_id,        NULL },
-                { 'H', specifier_host_name,      NULL },
-                { 'v', specifier_kernel_release, NULL },
-                { 'T', specifier_tmp_dir,        NULL },
-                { 'V', specifier_var_tmp_dir,    NULL },
+                { 'm', specifier_machine_id,      NULL },
+                { 'b', specifier_boot_id,         NULL },
+                { 'H', specifier_host_name,       NULL },
+                { 'l', specifier_short_host_name, NULL },
+                { 'v', specifier_kernel_release,  NULL },
+                { 'a', specifier_architecture,    NULL },
+                { 'o', specifier_os_id,           NULL },
+                { 'w', specifier_os_version_id,   NULL },
+                { 'B', specifier_os_build_id,     NULL },
+                { 'W', specifier_os_variant_id,   NULL },
+                { 'T', specifier_tmp_dir,         NULL },
+                { 'V', specifier_var_tmp_dir,     NULL },
                 {}
         };
 
@@ -1443,7 +1449,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         if (name) {
                 r = specifier_printf(name, specifier_table, NULL, &resolved_name);
                 if (r < 0)
-                        log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s", fname, line, name);
+                        return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m", fname, line, name);
 
                 if (!valid_user_group_name(resolved_name, 0))
                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
@@ -1458,7 +1464,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         if (id) {
                 r = specifier_printf(id, specifier_table, NULL, &resolved_id);
                 if (r < 0)
-                        return log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s",
+                        return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m",
                                                fname, line, name);
         }
 
@@ -1469,7 +1475,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         if (description) {
                 r = specifier_printf(description, specifier_table, NULL, &resolved_description);
                 if (r < 0)
-                        return log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s",
+                        return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m",
                                                fname, line, description);
 
                 if (!valid_gecos(resolved_description))
@@ -1485,7 +1491,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         if (home) {
                 r = specifier_printf(home, specifier_table, NULL, &resolved_home);
                 if (r < 0)
-                        return log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s",
+                        return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m",
                                                fname, line, home);
 
                 if (!valid_home(resolved_home))
@@ -1501,7 +1507,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         if (shell) {
                 r = specifier_printf(shell, specifier_table, NULL, &resolved_shell);
                 if (r < 0)
-                        return log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s",
+                        return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m",
                                                fname, line, shell);
 
                 if (!valid_shell(resolved_shell))
@@ -1808,7 +1814,7 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_ROOT:
-                        r = parse_path_argument_and_warn(optarg, true, &arg_root);
+                        r = parse_path_argument_and_warn(optarg, /* suppress_root= */ false, &arg_root);
                         if (r < 0)
                                 return r;
                         break;
index 7f96be8f55afabe88f0f0e4093e57bf5321858d6..318dc25906be9e1754283e10f376970846253e16 100644 (file)
@@ -470,7 +470,7 @@ tests += [
          '', 'timeout=90'],
 
         [['src/test/test-set.c'],
-         [],
+         [libbasic],
          []],
 
         [['src/test/test-ordered-set.c'],
@@ -893,12 +893,14 @@ tests += [
          [libjournal_core,
           libshared],
          [liblz4,
+          libzstd,
           libxz]],
 
         [['src/journal/test-compress-benchmark.c'],
          [libjournal_core,
           libshared],
          [liblz4,
+          libzstd,
           libxz],
          '', 'timeout=90'],
 
index 758b753237903aa238b7226d8fa9251252271648..d85f705504403cdd9240e966adb17c8cce9e29b4 100644 (file)
@@ -99,13 +99,13 @@ static void test_bool_assign(void) {
         g = cp;    /* cast from pointer */
         h = NULL;  /* cast from pointer */
 
-        assert(b);
-        assert(c);
-        assert(d);
-        assert(e);
-        assert(!f);
-        assert(g);
-        assert(!h);
+        assert_se(b);
+        assert_se(c);
+        assert_se(d);
+        assert_se(e);
+        assert_se(!f);
+        assert_se(g);
+        assert_se(!h);
 }
 
 static int cleanup_counter = 0;
index 3c7f7a98cf8aa5d19798dcf45ab58d66733ac892..29074ecccd38de6517430c0c59d2c21dfe49c7e5 100644 (file)
@@ -17,7 +17,7 @@ static int test_acpi_fpdt(void) {
 
         r = acpi_get_boot_usec(&loader_start, &loader_exit);
         if (r < 0) {
-                bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES) || r == -ENODATA;
+                bool ok = r == -ENOENT || r == -EACCES || r == -ENODATA;
 
                 log_full_errno(ok ? LOG_DEBUG : LOG_ERR, r, "Failed to read ACPI FPDT: %m");
                 return ok ? 0 : r;
@@ -37,7 +37,7 @@ static int test_efi_loader(void) {
 
         r = efi_loader_get_boot_usec(&loader_start, &loader_exit);
         if (r < 0) {
-                bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES) || r == -EOPNOTSUPP;
+                bool ok = r == -ENOENT || r == -EACCES || r == -EOPNOTSUPP;
 
                 log_full_errno(ok ? LOG_DEBUG : LOG_ERR, r, "Failed to read EFI loader data: %m");
                 return ok ? 0 : r;
@@ -59,7 +59,7 @@ static int test_boot_timestamps(void) {
 
         r = boot_timestamps(NULL, &fw, &l);
         if (r < 0) {
-                bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES) || r == -EOPNOTSUPP;
+                bool ok = r == -ENOENT || r == -EACCES || r == -EOPNOTSUPP;
 
                 log_full_errno(ok ? LOG_DEBUG : LOG_ERR, r, "Failed to read variables: %m");
                 return ok ? 0 : r;
index 9c2be7f44566cc342583d6865ef93d68e888a2e9..9e2ae55ab60c8f9d9f9aff904184f5d151f752f7 100644 (file)
@@ -185,6 +185,8 @@ int main(int argc, char* argv[]) {
         test_one("@1493187147 UTC", "2017-04-26 06:12:27 UTC");
         test_one("@0", "1970-01-01 00:00:00 UTC");
         test_one("@0 UTC", "1970-01-01 00:00:00 UTC");
+        test_one("*:05..05", "*-*-* *:05:00");
+        test_one("*:05..10/6", "*-*-* *:05:00");
 
         test_next("2016-03-27 03:17:00", "", 12345, 1459048620000000);
         test_next("2016-03-27 03:17:00", "CET", 12345, 1459041420000000);
@@ -237,8 +239,6 @@ int main(int argc, char* argv[]) {
         assert_se(calendar_spec_from_string("*~29", &c) < 0);
         assert_se(calendar_spec_from_string("*~16..31", &c) < 0);
         assert_se(calendar_spec_from_string("12..1/2-*", &c) < 0);
-        assert_se(calendar_spec_from_string("*:05..05", &c) < 0);
-        assert_se(calendar_spec_from_string("*:05..10/6", &c) < 0);
         assert_se(calendar_spec_from_string("20/4:00", &c) < 0);
         assert_se(calendar_spec_from_string("00:00/60", &c) < 0);
         assert_se(calendar_spec_from_string("00:00:2300", &c) < 0);
index 74b27379ea47df4f388e71df72461394ad077028..f8766256e2fb420a2be16dfa3768d49a788c99c1 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "alloc-util.h"
 #include "capability-util.h"
+#include "errno-util.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "macro.h"
@@ -35,6 +36,8 @@ static void test_last_cap_file(void) {
         int r;
 
         r = read_one_line_file("/proc/sys/kernel/cap_last_cap", &content);
+        if (r == -ENOENT || ERRNO_IS_PRIVILEGE(r)) /* kernel pre 3.2 or no access */
+                return;
         assert_se(r >= 0);
 
         r = safe_atolu(content, &val);
@@ -230,7 +233,7 @@ static void test_ensure_cap_64bit(void) {
         int r;
 
         r = read_one_line_file("/proc/sys/kernel/cap_last_cap", &content);
-        if (r == -ENOENT) /* kernel pre 3.2 */
+        if (r == -ENOENT || ERRNO_IS_PRIVILEGE(r)) /* kernel pre 3.2 or no access */
                 return;
         assert_se(r >= 0);
 
index 330631a9101f8d1db817c6cee10486742fe663a9..25fa0d75df0c0ee78ad008e971f2926c5df333c8 100644 (file)
@@ -1,8 +1,11 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <unistd.h>
+
 #include "alloc-util.h"
 #include "build.h"
 #include "cgroup-setup.h"
+#include "errno-util.h"
 #include "log.h"
 #include "proc-cmdline.h"
 #include "string-util.h"
@@ -59,6 +62,9 @@ static void test_is_wanted(void) {
 int main(void) {
         test_setup_logging(LOG_DEBUG);
 
+        if (access("/proc/cmdline", R_OK) < 0 && ERRNO_IS_PRIVILEGE(errno))
+                return log_tests_skipped("can't read /proc/cmdline");
+
         test_is_wanted_print(true);
         test_is_wanted_print(false); /* run twice to test caching */
         test_is_wanted();
index 83b5156c11eb640ecb684acdc4ff436274a9493e..ea47f5affaba4fe0b99ea3e6f158313771087982 100644 (file)
@@ -4,6 +4,7 @@
 #include "build.h"
 #include "cgroup-util.h"
 #include "dirent-util.h"
+#include "errno-util.h"
 #include "fd-util.h"
 #include "format-util.h"
 #include "parse-util.h"
@@ -369,7 +370,7 @@ static void test_cg_get_keyed_attribute(void) {
         int i, r;
 
         r = cg_get_keyed_attribute("cpu", "/init.scope", "no_such_file", STRV_MAKE("no_such_attr"), &val);
-        if (r == -ENOMEDIUM) {
+        if (r == -ENOMEDIUM || ERRNO_IS_PRIVILEGE(r)) {
                 log_info_errno(r, "Skipping most of %s, /sys/fs/cgroup not accessible: %m", __func__);
                 return;
         }
@@ -383,22 +384,42 @@ static void test_cg_get_keyed_attribute(void) {
         }
 
         assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat", STRV_MAKE("no_such_attr"), &val) == -ENXIO);
+        assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat", STRV_MAKE("no_such_attr"), &val) == 0);
         assert_se(val == NULL);
 
         assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec"), &val) == 0);
+        val = mfree(val);
+
+        assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec"), &val) == 1);
         log_info("cpu /init.scope cpu.stat [usage_usec] → \"%s\"", val);
 
         assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec", "no_such_attr"), vals3) == -ENXIO);
+        assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec", "no_such_attr"), vals3) == 1);
+        assert(vals3[0] && !vals3[1]);
+        free(vals3[0]);
 
         assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec", "usage_usec"), vals3) == -ENXIO);
+        assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec", "usage_usec"), vals3) == 1);
+        assert(vals3[0] && !vals3[1]);
+        free(vals3[0]);
 
         assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat",
                                          STRV_MAKE("usage_usec", "user_usec", "system_usec"), vals3) == 0);
+        for (i = 0; i < 3; i++)
+                free(vals3[i]);
+
+        assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat",
+                                         STRV_MAKE("usage_usec", "user_usec", "system_usec"), vals3) == 3);
         log_info("cpu /init.scope cpu.stat [usage_usec user_usec system_usec] → \"%s\", \"%s\", \"%s\"",
                  vals3[0], vals3[1], vals3[2]);
 
         assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat",
                                          STRV_MAKE("system_usec", "user_usec", "usage_usec"), vals3a) == 0);
+        for (i = 0; i < 3; i++)
+                free(vals3a[i]);
+
+        assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat",
+                                         STRV_MAKE("system_usec", "user_usec", "usage_usec"), vals3a) == 3);
         log_info("cpu /init.scope cpu.stat [system_usec user_usec usage_usec] → \"%s\", \"%s\", \"%s\"",
                  vals3a[0], vals3a[1], vals3a[2]);
 
index 853c6c4ab4de37fc2eb830aae75321e1beb7d0d1..4fbb186f52cfe622d1fe8af724d167fcf5c58f7c 100644 (file)
@@ -44,6 +44,13 @@ static void test_cg_split_spec(void) {
 
 static void test_cg_create(void) {
         log_info("/* %s */", __func__);
+        int r;
+
+        r = cg_unified_cached(false);
+        if (r < 0) {
+                log_info_errno(r, "Skipping %s: %m", __func__);
+                return;
+        }
 
         _cleanup_free_ char *here = NULL;
         assert_se(cg_pid_get_path_shifted(0, NULL, &here) >= 0);
@@ -53,7 +60,6 @@ static void test_cg_create(void) {
                    *test_c = prefix_roota(here, "/test-b/test-c"),
                    *test_d = prefix_roota(here, "/test-b/test-d");
         char *path;
-        int r;
 
         log_info("Paths for test:\n%s\n%s", test_a, test_b);
 
index 018e679b4544962ddfe69022838a1439961e30d1..e5a3de8a59a65bdf7a7872cad052efdf507a8539 100644 (file)
@@ -60,14 +60,14 @@ static void test_clock_is_localtime_system(void) {
         int r;
         r = clock_is_localtime(NULL);
 
-        if (access("/etc/adjtime", F_OK) == 0) {
-                log_info("/etc/adjtime exists, clock_is_localtime() == %i", r);
+        if (access("/etc/adjtime", R_OK) == 0) {
+                log_info("/etc/adjtime is readable, clock_is_localtime() == %i", r);
                 /* if /etc/adjtime exists we expect some answer, no error or
                  * crash */
                 assert_se(IN_SET(r, 0, 1));
         } else
                 /* default is UTC if there is no /etc/adjtime */
-                assert_se(r == 0);
+                assert_se(r == 0 || ERRNO_IS_PRIVILEGE(r));
 }
 
 int main(int argc, char *argv[]) {
index 28b5b780c35b75677ee038d6fc8dfd340418f6f0..ddf2e669c03c4f98fa3e795beb1c9069e1cd02bb 100644 (file)
@@ -15,6 +15,7 @@
 #include "condition.h"
 #include "cpu-set-util.h"
 #include "efi-loader.h"
+#include "errno-util.h"
 #include "hostname-util.h"
 #include "id128-util.h"
 #include "ima-util.h"
@@ -38,82 +39,87 @@ static void test_condition_test_path(void) {
 
         condition = condition_new(CONDITION_PATH_EXISTS, "/bin/sh", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition));
+        assert_se(condition_test(condition, environ));
         condition_free(condition);
 
         condition = condition_new(CONDITION_PATH_EXISTS, "/bin/s?", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == 0);
+        assert_se(condition_test(condition, environ) == 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_PATH_EXISTS_GLOB, "/bin/s?", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_PATH_EXISTS_GLOB, "/bin/s?", false, true);
         assert_se(condition);
-        assert_se(condition_test(condition) == 0);
+        assert_se(condition_test(condition, environ) == 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_PATH_EXISTS, "/thiscertainlywontexist", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == 0);
+        assert_se(condition_test(condition, environ) == 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_PATH_EXISTS, "/thiscertainlywontexist", false, true);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_PATH_IS_DIRECTORY, "/bin", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_DIRECTORY_NOT_EMPTY, "/bin", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_FILE_NOT_EMPTY, "/bin/sh", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_FILE_IS_EXECUTABLE, "/bin/sh", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_FILE_IS_EXECUTABLE, "/etc/passwd", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == 0);
+        assert_se(condition_test(condition, environ) == 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_PATH_IS_MOUNT_POINT, "/proc", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_PATH_IS_MOUNT_POINT, "/", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_PATH_IS_MOUNT_POINT, "/bin", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == 0);
+        assert_se(condition_test(condition, environ) == 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_PATH_IS_READ_WRITE, "/tmp", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
+        condition_free(condition);
+
+        condition = condition_new(CONDITION_PATH_IS_ENCRYPTED, "/sys", false, false);
+        assert_se(condition);
+        assert_se(condition_test(condition, environ) == 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_PATH_IS_SYMBOLIC_LINK, "/dev/stdout", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 }
 
@@ -133,12 +139,12 @@ static void test_condition_test_control_group_controller(void) {
         /* Invalid controllers are ignored */
         condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, "thisisnotarealcontroller", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, "thisisnotarealcontroller", false, true);
         assert_se(condition);
-        assert_se(condition_test(condition) == 0);
+        assert_se(condition_test(condition, environ) == 0);
         condition_free(condition);
 
         assert_se(cg_mask_supported(&system_mask) >= 0);
@@ -151,23 +157,23 @@ static void test_condition_test_control_group_controller(void) {
                         log_info("this controller is available");
                         condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, local_controller_name, false, false);
                         assert_se(condition);
-                        assert_se(condition_test(condition) > 0);
+                        assert_se(condition_test(condition, environ) > 0);
                         condition_free(condition);
 
                         condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, local_controller_name, false, true);
                         assert_se(condition);
-                        assert_se(condition_test(condition) == 0);
+                        assert_se(condition_test(condition, environ) == 0);
                         condition_free(condition);
                 } else {
                         log_info("this controller is unavailable");
                         condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, local_controller_name, false, false);
                         assert_se(condition);
-                        assert_se(condition_test(condition) == 0);
+                        assert_se(condition_test(condition, environ) == 0);
                         condition_free(condition);
 
                         condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, local_controller_name, false, true);
                         assert_se(condition);
-                        assert_se(condition_test(condition) > 0);
+                        assert_se(condition_test(condition, environ) > 0);
                         condition_free(condition);
                 }
         }
@@ -177,12 +183,12 @@ static void test_condition_test_control_group_controller(void) {
 
         condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, strempty(controller_name), false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, strempty(controller_name), false, true);
         assert_se(condition);
-        assert_se(condition_test(condition) == 0);
+        assert_se(condition_test(condition, environ) == 0);
         condition_free(condition);
 }
 
@@ -191,17 +197,17 @@ static void test_condition_test_ac_power(void) {
 
         condition = condition_new(CONDITION_AC_POWER, "true", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == on_ac_power());
+        assert_se(condition_test(condition, environ) == on_ac_power());
         condition_free(condition);
 
         condition = condition_new(CONDITION_AC_POWER, "false", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) != on_ac_power());
+        assert_se(condition_test(condition, environ) != on_ac_power());
         condition_free(condition);
 
         condition = condition_new(CONDITION_AC_POWER, "false", false, true);
         assert_se(condition);
-        assert_se(condition_test(condition) == on_ac_power());
+        assert_se(condition_test(condition, environ) == on_ac_power());
         condition_free(condition);
 }
 
@@ -218,17 +224,17 @@ static void test_condition_test_host(void) {
 
         condition = condition_new(CONDITION_HOST, sid, false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_HOST, "garbage value jjjjjjjjjjjjjj", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == 0);
+        assert_se(condition_test(condition, environ) == 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_HOST, sid, false, true);
         assert_se(condition);
-        assert_se(condition_test(condition) == 0);
+        assert_se(condition_test(condition, environ) == 0);
         condition_free(condition);
 
         hostname = gethostname_malloc();
@@ -240,7 +246,7 @@ static void test_condition_test_host(void) {
         else {
                 condition = condition_new(CONDITION_HOST, hostname, false, false);
                 assert_se(condition);
-                assert_se(condition_test(condition) > 0);
+                assert_se(condition_test(condition, environ) > 0);
                 condition_free(condition);
         }
 }
@@ -258,31 +264,35 @@ static void test_condition_test_architecture(void) {
 
         condition = condition_new(CONDITION_ARCHITECTURE, sa, false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_ARCHITECTURE, "garbage value", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == 0);
+        assert_se(condition_test(condition, environ) == 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_ARCHITECTURE, sa, false, true);
         assert_se(condition);
-        assert_se(condition_test(condition) == 0);
+        assert_se(condition_test(condition, environ) == 0);
         condition_free(condition);
 }
 
 static void test_condition_test_kernel_command_line(void) {
         Condition *condition;
+        int r;
 
         condition = condition_new(CONDITION_KERNEL_COMMAND_LINE, "thisreallyshouldntbeonthekernelcommandline", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == 0);
+        r = condition_test(condition, environ);
+        if (ERRNO_IS_PRIVILEGE(r))
+                return;
+        assert_se(r == 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_KERNEL_COMMAND_LINE, "andthis=neither", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == 0);
+        assert_se(condition_test(condition, environ) == 0);
         condition_free(condition);
 }
 
@@ -293,26 +303,26 @@ static void test_condition_test_kernel_version(void) {
 
         condition = condition_new(CONDITION_KERNEL_VERSION, "*thisreallyshouldntbeinthekernelversion*", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == 0);
+        assert_se(condition_test(condition, environ) == 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_KERNEL_VERSION, "*", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 
         /* An artificially empty condition. It evaluates to true, but normally
          * such condition cannot be created, because the condition list is reset instead. */
         condition = condition_new(CONDITION_KERNEL_VERSION, "", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 
         assert_se(uname(&u) >= 0);
 
         condition = condition_new(CONDITION_KERNEL_VERSION, u.release, false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 
         strshorten(u.release, 4);
@@ -320,79 +330,79 @@ static void test_condition_test_kernel_version(void) {
 
         condition = condition_new(CONDITION_KERNEL_VERSION, u.release, false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 
         /* 0.1.2 would be a very very very old kernel */
         condition = condition_new(CONDITION_KERNEL_VERSION, "> 0.1.2", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_KERNEL_VERSION, ">0.1.2", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_KERNEL_VERSION, "'>0.1.2' '<9.0.0'", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_KERNEL_VERSION, "> 0.1.2 < 9.0.0", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == -EINVAL);
+        assert_se(condition_test(condition, environ) == -EINVAL);
         condition_free(condition);
 
         condition = condition_new(CONDITION_KERNEL_VERSION, ">", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == -EINVAL);
+        assert_se(condition_test(condition, environ) == -EINVAL);
         condition_free(condition);
 
         condition = condition_new(CONDITION_KERNEL_VERSION, ">= 0.1.2", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_KERNEL_VERSION, "< 0.1.2", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == 0);
+        assert_se(condition_test(condition, environ) == 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_KERNEL_VERSION, "<= 0.1.2", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == 0);
+        assert_se(condition_test(condition, environ) == 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_KERNEL_VERSION, "= 0.1.2", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == 0);
+        assert_se(condition_test(condition, environ) == 0);
         condition_free(condition);
 
         /* 4711.8.15 is a very very very future kernel */
         condition = condition_new(CONDITION_KERNEL_VERSION, "< 4711.8.15", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_KERNEL_VERSION, "<= 4711.8.15", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_KERNEL_VERSION, "= 4711.8.15", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == 0);
+        assert_se(condition_test(condition, environ) == 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_KERNEL_VERSION, "> 4711.8.15", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == 0);
+        assert_se(condition_test(condition, environ) == 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_KERNEL_VERSION, ">= 4711.8.15", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == 0);
+        assert_se(condition_test(condition, environ) == 0);
         condition_free(condition);
 
         assert_se(uname(&u) >= 0);
@@ -400,31 +410,31 @@ static void test_condition_test_kernel_version(void) {
         v = strjoina(">=", u.release);
         condition = condition_new(CONDITION_KERNEL_VERSION, v, false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 
         v = strjoina("=  ", u.release);
         condition = condition_new(CONDITION_KERNEL_VERSION, v, false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 
         v = strjoina("<=", u.release);
         condition = condition_new(CONDITION_KERNEL_VERSION, v, false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 
         v = strjoina("> ", u.release);
         condition = condition_new(CONDITION_KERNEL_VERSION, v, false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == 0);
+        assert_se(condition_test(condition, environ) == 0);
         condition_free(condition);
 
         v = strjoina("<   ", u.release);
         condition = condition_new(CONDITION_KERNEL_VERSION, v, false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == 0);
+        assert_se(condition_test(condition, environ) == 0);
         condition_free(condition);
 }
 
@@ -433,12 +443,12 @@ static void test_condition_test_null(void) {
 
         condition = condition_new(CONDITION_NULL, NULL, false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) > 0);
+        assert_se(condition_test(condition, environ) > 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_NULL, NULL, false, true);
         assert_se(condition);
-        assert_se(condition_test(condition) == 0);
+        assert_se(condition_test(condition, environ) == 0);
         condition_free(condition);
 }
 
@@ -447,42 +457,42 @@ static void test_condition_test_security(void) {
 
         condition = condition_new(CONDITION_SECURITY, "garbage oifdsjfoidsjoj", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == 0);
+        assert_se(condition_test(condition, environ) == 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_SECURITY, "selinux", false, true);
         assert_se(condition);
-        assert_se(condition_test(condition) != mac_selinux_use());
+        assert_se(condition_test(condition, environ) != mac_selinux_use());
         condition_free(condition);
 
         condition = condition_new(CONDITION_SECURITY, "apparmor", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == mac_apparmor_use());
+        assert_se(condition_test(condition, environ) == mac_apparmor_use());
         condition_free(condition);
 
         condition = condition_new(CONDITION_SECURITY, "tomoyo", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == mac_tomoyo_use());
+        assert_se(condition_test(condition, environ) == mac_tomoyo_use());
         condition_free(condition);
 
         condition = condition_new(CONDITION_SECURITY, "ima", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == use_ima());
+        assert_se(condition_test(condition, environ) == use_ima());
         condition_free(condition);
 
         condition = condition_new(CONDITION_SECURITY, "smack", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == mac_smack_use());
+        assert_se(condition_test(condition, environ) == mac_smack_use());
         condition_free(condition);
 
         condition = condition_new(CONDITION_SECURITY, "audit", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == use_audit());
+        assert_se(condition_test(condition, environ) == use_audit());
         condition_free(condition);
 
         condition = condition_new(CONDITION_SECURITY, "uefi-secureboot", false, false);
         assert_se(condition);
-        assert_se(condition_test(condition) == is_efi_secure_boot());
+        assert_se(condition_test(condition, environ) == is_efi_secure_boot());
         condition_free(condition);
 }
 
@@ -505,28 +515,30 @@ static void test_condition_test_virtualization(void) {
 
         condition = condition_new(CONDITION_VIRTUALIZATION, "garbage oifdsjfoidsjoj", false, false);
         assert_se(condition);
-        r = condition_test(condition);
+        r = condition_test(condition, environ);
+        if (ERRNO_IS_PRIVILEGE(r))
+                return;
         log_info("ConditionVirtualization=garbage → %i", r);
         assert_se(r == 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_VIRTUALIZATION, "container", false, false);
         assert_se(condition);
-        r = condition_test(condition);
+        r = condition_test(condition, environ);
         log_info("ConditionVirtualization=container → %i", r);
         assert_se(r == !!detect_container());
         condition_free(condition);
 
         condition = condition_new(CONDITION_VIRTUALIZATION, "vm", false, false);
         assert_se(condition);
-        r = condition_test(condition);
+        r = condition_test(condition, environ);
         log_info("ConditionVirtualization=vm → %i", r);
         assert_se(r == (detect_vm() && !detect_container()));
         condition_free(condition);
 
         condition = condition_new(CONDITION_VIRTUALIZATION, "private-users", false, false);
         assert_se(condition);
-        r = condition_test(condition);
+        r = condition_test(condition, environ);
         log_info("ConditionVirtualization=private-users → %i", r);
         assert_se(r == !!running_in_userns());
         condition_free(condition);
@@ -547,7 +559,7 @@ static void test_condition_test_virtualization(void) {
 
                 condition = condition_new(CONDITION_VIRTUALIZATION, virt, false, false);
                 assert_se(condition);
-                r = condition_test(condition);
+                r = condition_test(condition, environ);
                 log_info("ConditionVirtualization=%s → %i", virt, r);
                 assert_se(r >= 0);
                 condition_free(condition);
@@ -562,7 +574,7 @@ static void test_condition_test_user(void) {
 
         condition = condition_new(CONDITION_USER, "garbage oifdsjfoidsjoj", false, false);
         assert_se(condition);
-        r = condition_test(condition);
+        r = condition_test(condition, environ);
         log_info("ConditionUser=garbage → %i", r);
         assert_se(r == 0);
         condition_free(condition);
@@ -570,7 +582,7 @@ static void test_condition_test_user(void) {
         assert_se(asprintf(&uid, "%"PRIu32, UINT32_C(0xFFFF)) > 0);
         condition = condition_new(CONDITION_USER, uid, false, false);
         assert_se(condition);
-        r = condition_test(condition);
+        r = condition_test(condition, environ);
         log_info("ConditionUser=%s → %i", uid, r);
         assert_se(r == 0);
         condition_free(condition);
@@ -579,7 +591,7 @@ static void test_condition_test_user(void) {
         assert_se(asprintf(&uid, "%u", (unsigned)getuid()) > 0);
         condition = condition_new(CONDITION_USER, uid, false, false);
         assert_se(condition);
-        r = condition_test(condition);
+        r = condition_test(condition, environ);
         log_info("ConditionUser=%s → %i", uid, r);
         assert_se(r > 0);
         condition_free(condition);
@@ -588,7 +600,7 @@ static void test_condition_test_user(void) {
         assert_se(asprintf(&uid, "%u", (unsigned)getuid()+1) > 0);
         condition = condition_new(CONDITION_USER, uid, false, false);
         assert_se(condition);
-        r = condition_test(condition);
+        r = condition_test(condition, environ);
         log_info("ConditionUser=%s → %i", uid, r);
         assert_se(r == 0);
         condition_free(condition);
@@ -598,7 +610,7 @@ static void test_condition_test_user(void) {
         assert_se(username);
         condition = condition_new(CONDITION_USER, username, false, false);
         assert_se(condition);
-        r = condition_test(condition);
+        r = condition_test(condition, environ);
         log_info("ConditionUser=%s → %i", username, r);
         assert_se(r > 0);
         condition_free(condition);
@@ -607,14 +619,14 @@ static void test_condition_test_user(void) {
         username = (char*)(geteuid() == 0 ? NOBODY_USER_NAME : "root");
         condition = condition_new(CONDITION_USER, username, false, false);
         assert_se(condition);
-        r = condition_test(condition);
+        r = condition_test(condition, environ);
         log_info("ConditionUser=%s → %i", username, r);
         assert_se(r == 0);
         condition_free(condition);
 
         condition = condition_new(CONDITION_USER, "@system", false, false);
         assert_se(condition);
-        r = condition_test(condition);
+        r = condition_test(condition, environ);
         log_info("ConditionUser=@system → %i", r);
         if (uid_is_system(getuid()) || uid_is_system(geteuid()))
                 assert_se(r > 0);
@@ -633,7 +645,7 @@ static void test_condition_test_group(void) {
         assert_se(0 < asprintf(&gid, "%u", UINT32_C(0xFFFF)));
         condition = condition_new(CONDITION_GROUP, gid, false, false);
         assert_se(condition);
-        r = condition_test(condition);
+        r = condition_test(condition, environ);
         log_info("ConditionGroup=%s → %i", gid, r);
         assert_se(r == 0);
         condition_free(condition);
@@ -642,7 +654,7 @@ static void test_condition_test_group(void) {
         assert_se(0 < asprintf(&gid, "%u", getgid()));
         condition = condition_new(CONDITION_GROUP, gid, false, false);
         assert_se(condition);
-        r = condition_test(condition);
+        r = condition_test(condition, environ);
         log_info("ConditionGroup=%s → %i", gid, r);
         assert_se(r > 0);
         condition_free(condition);
@@ -661,7 +673,7 @@ static void test_condition_test_group(void) {
                 assert_se(0 < asprintf(&gid, "%u", gids[i]));
                 condition = condition_new(CONDITION_GROUP, gid, false, false);
                 assert_se(condition);
-                r = condition_test(condition);
+                r = condition_test(condition, environ);
                 log_info("ConditionGroup=%s → %i", gid, r);
                 assert_se(r > 0);
                 condition_free(condition);
@@ -672,7 +684,7 @@ static void test_condition_test_group(void) {
                 assert_se(groupname);
                 condition = condition_new(CONDITION_GROUP, groupname, false, false);
                 assert_se(condition);
-                r = condition_test(condition);
+                r = condition_test(condition, environ);
                 log_info("ConditionGroup=%s → %i", groupname, r);
                 assert_se(r > 0);
                 condition_free(condition);
@@ -683,7 +695,7 @@ static void test_condition_test_group(void) {
         assert_se(0 < asprintf(&gid, "%u", max_gid+1));
         condition = condition_new(CONDITION_GROUP, gid, false, false);
         assert_se(condition);
-        r = condition_test(condition);
+        r = condition_test(condition, environ);
         log_info("ConditionGroup=%s → %i", gid, r);
         assert_se(r == 0);
         condition_free(condition);
@@ -692,7 +704,7 @@ static void test_condition_test_group(void) {
         groupname = (char*)(getegid() == 0 ? NOBODY_GROUP_NAME : "root");
         condition = condition_new(CONDITION_GROUP, groupname, false, false);
         assert_se(condition);
-        r = condition_test(condition);
+        r = condition_test(condition, environ);
         log_info("ConditionGroup=%s → %i", groupname, r);
         assert_se(r == 0);
         condition_free(condition);
@@ -707,7 +719,7 @@ static void test_condition_test_cpus_one(const char *s, bool result) {
         condition = condition_new(CONDITION_CPUS, s, false, false);
         assert_se(condition);
 
-        r = condition_test(condition);
+        r = condition_test(condition, environ);
         assert_se(r >= 0);
         assert_se(r == result);
         condition_free(condition);
@@ -768,7 +780,7 @@ static void test_condition_test_memory_one(const char *s, bool result) {
         condition = condition_new(CONDITION_MEMORY, s, false, false);
         assert_se(condition);
 
-        r = condition_test(condition);
+        r = condition_test(condition, environ);
         assert_se(r >= 0);
         assert_se(r == result);
         condition_free(condition);
@@ -819,6 +831,34 @@ static void test_condition_test_memory(void) {
         t = mfree(t);
 }
 
+static void test_condition_test_environment_one(const char *s, bool result) {
+        Condition *condition;
+        int r;
+
+        log_debug("%s=%s", condition_type_to_string(CONDITION_ENVIRONMENT), s);
+
+        condition = condition_new(CONDITION_ENVIRONMENT, s, false, false);
+        assert_se(condition);
+
+        r = condition_test(condition, environ);
+        assert_se(r >= 0);
+        assert_se(r == result);
+        condition_free(condition);
+}
+
+static void test_condition_test_environment(void) {
+        assert_se(setenv("EXISTINGENVVAR", "foo", false) >= 0);
+
+        test_condition_test_environment_one("MISSINGENVVAR", false);
+        test_condition_test_environment_one("MISSINGENVVAR=foo", false);
+        test_condition_test_environment_one("MISSINGENVVAR=", false);
+
+        test_condition_test_environment_one("EXISTINGENVVAR", true);
+        test_condition_test_environment_one("EXISTINGENVVAR=foo", true);
+        test_condition_test_environment_one("EXISTINGENVVAR=bar", false);
+        test_condition_test_environment_one("EXISTINGENVVAR=", false);
+}
+
 int main(int argc, char *argv[]) {
         test_setup_logging(LOG_DEBUG);
 
@@ -837,6 +877,7 @@ int main(int argc, char *argv[]) {
         test_condition_test_control_group_controller();
         test_condition_test_cpus();
         test_condition_test_memory();
+        test_condition_test_environment();
 
         return 0;
 }
index 68905c662d96ec5bde742c3582a557833b68eb7a..0e8d68795153bacae92515e4cf0a06a2665e9d81 100644 (file)
@@ -78,8 +78,8 @@ static void test_copy_file_fd(void) {
 }
 
 static void test_copy_tree(void) {
-        char original_dir[] = "/var/tmp/test-copy_tree/";
-        char copy_dir[] = "/var/tmp/test-copy_tree-copy/";
+        char original_dir[] = "/tmp/test-copy_tree/";
+        char copy_dir[] = "/tmp/test-copy_tree-copy/";
         char **files = STRV_MAKE("file", "dir1/file", "dir1/dir2/file", "dir1/dir2/dir3/dir4/dir5/file");
         char **links = STRV_MAKE("link", "file",
                                  "link2", "dir1/file");
@@ -270,7 +270,7 @@ static void test_copy_atomic(void) {
         q = strjoina(p, "/fstab");
 
         r = copy_file_atomic("/etc/fstab", q, 0644, 0, 0, COPY_REFLINK);
-        if (r == -ENOENT)
+        if (r == -ENOENT || ERRNO_IS_PRIVILEGE(r))
                 return;
 
         assert_se(copy_file_atomic("/etc/fstab", q, 0644, 0, 0, COPY_REFLINK) == -EEXIST);
index 3168411d8bf1cf8abc498a2d9ec0152f65c90620..f5d640a69037976e2e6513cb047faf2bcae05865 100644 (file)
@@ -115,6 +115,9 @@ static void test_execute_directory(bool gather_stdout) {
         assert_se(chmod(masked2e, 0755) == 0);
         assert_se(chmod(mask2e, 0755) == 0);
 
+        if (access(name, X_OK) < 0 && ERRNO_IS_PRIVILEGE(errno))
+                return;
+
         if (gather_stdout)
                 execute_directories(dirs, DEFAULT_TIMEOUT_USEC, ignore_stdout, ignore_stdout_args, NULL, NULL, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
         else
@@ -183,6 +186,9 @@ static void test_execution_order(void) {
         assert_se(chmod(override, 0755) == 0);
         assert_se(chmod(masked, 0755) == 0);
 
+        if (access(name, X_OK) < 0 && ERRNO_IS_PRIVILEGE(errno))
+                return;
+
         execute_directories(dirs, DEFAULT_TIMEOUT_USEC, ignore_stdout, ignore_stdout_args, NULL, NULL, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
 
         assert_se(read_full_file(output, &contents, NULL) >= 0);
@@ -265,6 +271,9 @@ static void test_stdout_gathering(void) {
         assert_se(chmod(name2, 0755) == 0);
         assert_se(chmod(name3, 0755) == 0);
 
+        if (access(name, X_OK) < 0 && ERRNO_IS_PRIVILEGE(errno))
+                return;
+
         r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, gather_stdout, args, NULL, NULL, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
         assert_se(r >= 0);
 
@@ -331,6 +340,9 @@ static void test_environment_gathering(void) {
         r = setenv("PATH", "no-sh-built-in-path", 1);
         assert_se(r >= 0);
 
+        if (access(name, X_OK) < 0 && ERRNO_IS_PRIVILEGE(errno))
+                return;
+
         r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, gather_environment, args, NULL, NULL, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
         assert_se(r >= 0);
 
@@ -395,6 +407,9 @@ static void test_error_catching(void) {
         assert_se(chmod(name2, 0755) == 0);
         assert_se(chmod(name3, 0755) == 0);
 
+        if (access(name, X_OK) < 0 && ERRNO_IS_PRIVILEGE(errno))
+                return;
+
         r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, NULL, NULL, EXEC_DIR_NONE);
 
         /* we should exit with the error code of the first script that failed */
index 5a96b46a773244f81beac991e106a1bdde54d285..43f66efa6c92117049e94edae9d4bca2e882a1b9 100644 (file)
@@ -866,6 +866,7 @@ int main(int argc, char *argv[]) {
         (void) unsetenv("LOGNAME");
         (void) unsetenv("SHELL");
         (void) unsetenv("HOME");
+        (void) unsetenv("TMPDIR");
 
         can_unshare = have_namespaces();
 
index 713795814dfab36b12a08e42e8cc89b63fea92e7..44c74987c58227f631fa40687c53bfc821162eda 100644 (file)
@@ -233,17 +233,17 @@ static void assert_equal_fd(int fd1, int fd2) {
                 ssize_t x, y;
 
                 x = read(fd1, a, sizeof(a));
-                assert(x >= 0);
+                assert_se(x >= 0);
 
                 y = read(fd2, b, sizeof(b));
-                assert(y >= 0);
+                assert_se(y >= 0);
 
-                assert(x == y);
+                assert_se(x == y);
 
                 if (x == 0)
                         break;
 
-                assert(memcmp(a, b, x) == 0);
+                assert_se(memcmp(a, b, x) == 0);
         }
 }
 
index 32a00349acb22a976a39d82c22cf2ff06017f77a..8c04346721f7c2755f290ed59c834dbaca0d37cf 100644 (file)
@@ -444,7 +444,10 @@ static void test_write_string_file_verify(void) {
         _cleanup_free_ char *buf = NULL, *buf2 = NULL;
         int r;
 
-        assert_se(read_one_line_file("/proc/version", &buf) >= 0);
+        r = read_one_line_file("/proc/version", &buf);
+        if (ERRNO_IS_PRIVILEGE(r))
+                return;
+        assert_se(r >= 0);
         assert_se(buf2 = strjoin(buf, "\n"));
 
         r = write_string_file("/proc/version", buf, 0);
index d97ccfda3bcc7c59adaa01aef67fbe649b01a5a9..80c4c209b3f5727c7c3ff82f299e6e39fe19ec81 100644 (file)
@@ -670,7 +670,7 @@ static void test_unlinkat_deallocate(void) {
         assert_se(st.st_blocks > 0);
         assert_se(st.st_nlink == 1);
 
-        assert_se(unlinkat_deallocate(AT_FDCWD, p, 0) >= 0);
+        assert_se(unlinkat_deallocate(AT_FDCWD, p, UNLINK_ERASE) >= 0);
 
         assert_se(fstat(fd, &st) >= 0);
         assert_se(IN_SET(st.st_size, 0, 6)); /* depending on whether hole punching worked the size will be 6
@@ -846,6 +846,34 @@ static void test_chmod_and_chown_unsafe(void) {
         assert_se(S_ISLNK(st.st_mode));
 }
 
+static void test_path_is_encrypted_one(const char *p, int expect) {
+        int r;
+
+        r = path_is_encrypted(p);
+        if (r == -ENOENT) /* This might fail, if btrfs is used and we run in a container. In that case we
+                           * cannot resolve the device node paths that BTRFS_IOC_DEV_INFO returns, because
+                           * the device nodes are unlikely to exist in the container. But if we can't stat()
+                           * them we cannot determine the dev_t of them, and thus cannot figure out if they
+                           * are enrypted. Hence let's just ignore ENOENT here. */
+                return;
+        assert_se(r >= 0);
+
+        printf("%s encrypted: %s\n", p, yes_no(r));
+
+        assert_se(expect < 0 || ((r > 0) == (expect > 0)));
+}
+
+static void test_path_is_encrypted(void) {
+        log_info("/* %s */", __func__);
+
+        test_path_is_encrypted_one("/home", -1);
+        test_path_is_encrypted_one("/var", -1);
+        test_path_is_encrypted_one("/", -1);
+        test_path_is_encrypted_one("/proc", false);
+        test_path_is_encrypted_one("/sys", false);
+        test_path_is_encrypted_one("/dev", false);
+}
+
 int main(int argc, char *argv[]) {
         test_setup_logging(LOG_INFO);
 
@@ -864,6 +892,7 @@ int main(int argc, char *argv[]) {
         test_rename_noreplace();
         test_chmod_and_chown();
         test_chmod_and_chown_unsafe();
+        test_path_is_encrypted();
 
         return 0;
 }
index c1c7ec911483345cfd03c5340fa8091150504fb1..187be69d15e2cccfdaa003903161fff7af03a51e 100644 (file)
@@ -21,7 +21,7 @@ static void do_fstab_filter_options(const char *opts,
 
         int r;
         const char *name;
-        _cleanup_free_ char *value, *filtered;
+        _cleanup_free_ char *value = NULL, *filtered = NULL;
 
         r = fstab_filter_options(opts, remove, &name, &value, &filtered);
         log_info("\"%s\" → %d, \"%s\", \"%s\", \"%s\", expected %d, \"%s\", \"%s\", \"%s\"",
index 1a6e8ffa58e98c2246c44333537e4cf191e17a4e..94dbbf157692f03329fb1aedcae1c36fb30e67ff 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include "hashmap.h"
+#include "string-util.h"
 #include "util.h"
 
 unsigned custom_counter = 0;
@@ -109,6 +110,58 @@ static void test_iterated_cache(void) {
         assert_se(iterated_cache_free(c) == NULL);
 }
 
+static void test_hashmap_put_strdup(void) {
+        _cleanup_hashmap_free_ Hashmap *m = NULL;
+        char *s;
+
+        /* We don't have ordered_hashmap_put_strdup() yet. If it is added,
+         * these tests should be moved to test-hashmap-plain.c. */
+
+        log_info("/* %s */", __func__);
+
+        assert_se(hashmap_put_strdup(&m, "foo", "bar") == 1);
+        assert_se(hashmap_put_strdup(&m, "foo", "bar") == 0);
+        assert_se(hashmap_put_strdup(&m, "foo", "BAR") == -EEXIST);
+        assert_se(hashmap_put_strdup(&m, "foo", "bar") == 0);
+        assert_se(hashmap_contains(m, "foo"));
+
+        s = hashmap_get(m, "foo");
+        assert_se(streq(s, "bar"));
+
+        assert_se(hashmap_put_strdup(&m, "xxx", "bar") == 1);
+        assert_se(hashmap_put_strdup(&m, "xxx", "bar") == 0);
+        assert_se(hashmap_put_strdup(&m, "xxx", "BAR") == -EEXIST);
+        assert_se(hashmap_put_strdup(&m, "xxx", "bar") == 0);
+        assert_se(hashmap_contains(m, "xxx"));
+
+        s = hashmap_get(m, "xxx");
+        assert_se(streq(s, "bar"));
+}
+
+static void test_hashmap_put_strdup_null(void) {
+        _cleanup_hashmap_free_ Hashmap *m = NULL;
+        char *s;
+
+        log_info("/* %s */", __func__);
+
+        assert_se(hashmap_put_strdup(&m, "foo", "bar") == 1);
+        assert_se(hashmap_put_strdup(&m, "foo", "bar") == 0);
+        assert_se(hashmap_put_strdup(&m, "foo", NULL) == -EEXIST);
+        assert_se(hashmap_put_strdup(&m, "foo", "bar") == 0);
+        assert_se(hashmap_contains(m, "foo"));
+
+        s = hashmap_get(m, "foo");
+        assert_se(streq(s, "bar"));
+
+        assert_se(hashmap_put_strdup(&m, "xxx", NULL) == 1);
+        assert_se(hashmap_put_strdup(&m, "xxx", "bar") == -EEXIST);
+        assert_se(hashmap_put_strdup(&m, "xxx", NULL) == 0);
+        assert_se(hashmap_contains(m, "xxx"));
+
+        s = hashmap_get(m, "xxx");
+        assert_se(s == NULL);
+}
+
 int main(int argc, const char *argv[]) {
         /* This file tests in test-hashmap-plain.c, and tests in test-hashmap-ordered.c, which is generated
          * from test-hashmap-plain.c. Hashmap tests should be added to test-hashmap-plain.c, and here only if
@@ -127,6 +180,8 @@ int main(int argc, const char *argv[]) {
         test_trivial_compare_func();
         test_string_compare_func();
         test_iterated_cache();
+        test_hashmap_put_strdup();
+        test_hashmap_put_strdup_null();
 
         return 0;
 }
index ec34f9cd716b5622199de9b9894dfff1b73c8e2b..5ab82bba618e7162a172f5eefb0c0d608338d8fe 100644 (file)
@@ -140,6 +140,23 @@ static void test_read_etc_hostname(void) {
         unlink(path);
 }
 
+static void test_hostname_malloc(void) {
+        _cleanup_free_ char *h = NULL, *l = NULL;
+
+        assert_se(h = gethostname_malloc());
+        log_info("hostname_malloc: \"%s\"", h);
+
+        assert_se(l = gethostname_short_malloc());
+        log_info("hostname_short_malloc: \"%s\"", l);
+}
+
+static void test_fallback_hostname(void) {
+        if (!hostname_is_valid(FALLBACK_HOSTNAME, false)) {
+                log_error("Configured fallback hostname \"%s\" is not valid.", FALLBACK_HOSTNAME);
+                exit(EXIT_FAILURE);
+        }
+}
+
 int main(int argc, char *argv[]) {
         log_parse_environment();
         log_open();
@@ -147,6 +164,9 @@ int main(int argc, char *argv[]) {
         test_hostname_is_valid();
         test_hostname_cleanup();
         test_read_etc_hostname();
+        test_hostname_malloc();
+
+        test_fallback_hostname();
 
         return 0;
 }
index 79a105c5c3762141a03181849c15b312f654dd10..515f14b8ca9209ea46a65d0edd457e84b8a0e35f 100644 (file)
@@ -36,20 +36,20 @@ static void test_basic_mask_and_enable(const char *root) {
         assert_se(symlink("a.service", p) >= 0);
 
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) >= 0);
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
 
         p = strjoina(root, "/usr/lib/systemd/system/c.service");
         assert_se(symlink("/usr/lib/systemd/system/a.service", p) >= 0);
 
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) >= 0);
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
 
         p = strjoina(root, "/usr/lib/systemd/system/d.service");
         assert_se(symlink("c.service", p) >= 0);
 
         /* This one is interesting, as d follows a relative, then an absolute symlink */
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) >= 0);
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
 
         assert_se(unit_file_mask(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0);
         assert_se(n_changes == 1);
@@ -89,9 +89,9 @@ static void test_basic_mask_and_enable(const char *root) {
         changes = NULL; n_changes = 0;
 
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
 
         /* Enabling it again should succeed but be a NOP */
         assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0);
@@ -108,9 +108,9 @@ static void test_basic_mask_and_enable(const char *root) {
         changes = NULL; n_changes = 0;
 
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
 
         /* Disabling a disabled unit must succeed but be a NOP */
         assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0);
@@ -129,9 +129,9 @@ static void test_basic_mask_and_enable(const char *root) {
         changes = NULL; n_changes = 0;
 
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
 
         /* Let's try to reenable */
 
@@ -147,9 +147,9 @@ static void test_basic_mask_and_enable(const char *root) {
         changes = NULL; n_changes = 0;
 
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
 }
 
 static void test_linked_units(const char *root) {
@@ -386,7 +386,7 @@ static void test_template_enable(const char *root) {
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
 
@@ -404,7 +404,7 @@ static void test_template_enable(const char *root) {
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
 
@@ -418,7 +418,7 @@ static void test_template_enable(const char *root) {
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
 
@@ -450,7 +450,7 @@ static void test_template_enable(const char *root) {
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
@@ -469,7 +469,7 @@ static void test_template_enable(const char *root) {
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
@@ -500,7 +500,7 @@ static void test_indirect(const char *root) {
 
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
 
         assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0);
         assert_se(n_changes == 1);
@@ -513,7 +513,7 @@ static void test_indirect(const char *root) {
 
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
 
         assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0);
         assert_se(n_changes == 1);
@@ -624,7 +624,7 @@ static void test_preset_and_list(const char *root) {
                         got_no = true;
                         assert_se(fl->state == UNIT_FILE_DISABLED);
                 } else
-                        assert_se(IN_SET(fl->state, UNIT_FILE_DISABLED, UNIT_FILE_STATIC, UNIT_FILE_INDIRECT));
+                        assert_se(IN_SET(fl->state, UNIT_FILE_DISABLED, UNIT_FILE_STATIC, UNIT_FILE_INDIRECT, UNIT_FILE_ALIAS));
         }
 
         unit_file_list_free(h);
index e7a22797bb65fe87acdf8274a0dfc20b5bb0fefa..728196be0862b0e730f0005f032c77f6640a8ce9 100644 (file)
@@ -36,6 +36,28 @@ static void test_locale_is_valid(void) {
         assert_se(!locale_is_valid("\x01gar\x02 bage\x03"));
 }
 
+static void test_locale_is_installed(void) {
+        log_info("/* %s */", __func__);
+
+        /* Always available */
+        assert_se(locale_is_installed("POSIX") > 0);
+        assert_se(locale_is_installed("C") > 0);
+
+        /* Might, or might not be installed. */
+        assert_se(locale_is_installed("en_EN.utf8") >= 0);
+        assert_se(locale_is_installed("fr_FR.utf8") >= 0);
+        assert_se(locale_is_installed("fr_FR@euro") >= 0);
+        assert_se(locale_is_installed("fi_FI") >= 0);
+
+        /* Definitely not valid */
+        assert_se(locale_is_installed("") == 0);
+        assert_se(locale_is_installed("/usr/bin/foo") == 0);
+        assert_se(locale_is_installed("\x01gar\x02 bage\x03") == 0);
+
+        /* Definitely not installed */
+        assert_se(locale_is_installed("zz_ZZ") == 0);
+}
+
 static void test_keymaps(void) {
         _cleanup_strv_free_ char **kmaps = NULL;
         char **p;
@@ -98,6 +120,7 @@ static void dump_special_glyphs(void) {
 int main(int argc, char *argv[]) {
         test_get_locales();
         test_locale_is_valid();
+        test_locale_is_installed();
         test_keymaps();
 
         dump_special_glyphs();
index 21d5b44fbb69454c69f1fec7adbd5cf03ba0d634..50f66cb970b280f49d62e2d2bb768cbdd8f1bdff 100644 (file)
@@ -60,7 +60,7 @@ DEFINE_PRIVATE_HASH_OPS(test_hash_ops, struct test, test_hash, test_compare);
 
 static void test_struct(void) {
         _cleanup_(prioq_freep) Prioq *q = NULL;
-        _cleanup_(set_freep) Set *s = NULL;
+        _cleanup_set_free_ Set *s = NULL;
         unsigned previous = 0, i;
         struct test *t;
 
index 370b041189956dae7f38199ff563d2f87378528f..4a9b111a20ab5bc0bfd56c60de3fa197ca813618 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "alloc-util.h"
 #include "env-util.h"
+#include "errno-util.h"
 #include "log.h"
 #include "macro.h"
 #include "proc-cmdline.h"
@@ -250,6 +251,9 @@ static void test_proc_cmdline_key_startswith(void) {
 int main(void) {
         test_setup_logging(LOG_INFO);
 
+        if (access("/proc/cmdline", R_OK) < 0 && ERRNO_IS_PRIVILEGE(errno))
+                return log_tests_skipped("can't read /proc/cmdline");
+
         test_proc_cmdline_parse();
         test_proc_cmdline_override();
         test_proc_cmdline_given(false);
index 662688e0f0d18c9f42b27dc514154c887c714fc2..61434578b0b87865a5cfd02d447552a1f8605c46 100644 (file)
@@ -2,9 +2,11 @@
 
 #include <errno.h>
 
+#include "errno-util.h"
 #include "format-util.h"
 #include "log.h"
 #include "procfs-util.h"
+#include "tests.h"
 
 int main(int argc, char *argv[]) {
         char buf[CONST_MAX(FORMAT_TIMESPAN_MAX, FORMAT_BYTES_MAX)];
@@ -24,7 +26,11 @@ int main(int argc, char *argv[]) {
         assert_se(procfs_tasks_get_current(&v) >= 0);
         log_info("Current number of tasks: %" PRIu64, v);
 
-        assert_se(procfs_tasks_get_limit(&v) >= 0);
+        r = procfs_tasks_get_limit(&v);
+        if (r == -ENOENT || ERRNO_IS_PRIVILEGE(r))
+                return log_tests_skipped("can't read /proc/sys/kernel/pid_max");
+
+        assert_se(r >= 0);
         log_info("Limit of tasks: %" PRIu64, v);
         assert_se(v > 0);
         assert_se(procfs_tasks_set_limit(v) >= 0);
index 94c431f7e6084ea88c649efada378ec91852c145..ad5bc72a4e138c0e1e3ca68155a3b47765130541 100644 (file)
@@ -58,6 +58,7 @@ int main(int argc, char **argv) {
         test_genuine_random_bytes(0);
         test_genuine_random_bytes(RANDOM_BLOCK);
         test_genuine_random_bytes(RANDOM_ALLOW_RDRAND);
+        test_genuine_random_bytes(RANDOM_ALLOW_INSECURE);
 
         test_pseudo_random_bytes();
 
index 17ca6a0e279861e5305f595a6dfa1d41b16846df..eb34d8eab2d83cfaf286b5e7e25abedcd03085bd 100644 (file)
@@ -1,6 +1,7 @@
 #include "sd-hwdb.h"
 
 #include "alloc-util.h"
+#include "errno-util.h"
 #include "errno.h"
 #include "tests.h"
 
@@ -12,7 +13,7 @@ static int test_failed_enumerate(void) {
         log_info("/* %s */", __func__);
 
         r = sd_hwdb_new(&hwdb);
-        if (r == -ENOENT)
+        if (r == -ENOENT || ERRNO_IS_PRIVILEGE(r))
                 return r;
         assert_se(r == 0);
 
index 67900d85e9ac04f692621174692fafafcda3f445..b09d031f5d6eebd996aebf3142bcedb9c7a0359e 100644 (file)
@@ -13,6 +13,7 @@
 
 #include "alloc-util.h"
 #include "fd-util.h"
+#include "fileio.h"
 #include "macro.h"
 #include "memory-util.h"
 #include "missing_sched.h"
@@ -283,6 +284,7 @@ static void test_restrict_namespace(void) {
 
 static void test_protect_sysctl(void) {
         pid_t pid;
+        _cleanup_free_ char *seccomp = NULL;
 
         log_info("/* %s */", __func__);
 
@@ -301,6 +303,10 @@ static void test_protect_sysctl(void) {
                 return;
         }
 
+        assert_se(get_proc_field("/proc/self/status", "Seccomp", WHITESPACE, &seccomp) == 0);
+        if (!streq(seccomp, "0"))
+                log_warning("Warning: seccomp filter detected, results may be unreliable for %s", __func__);
+
         pid = fork();
         assert_se(pid >= 0);
 
index b4e7a52fd964aef5713d42283526be2ab18106b3..9c93685dbce975ac1c52069a1ccfd3c6f4b5824d 100644 (file)
@@ -3,6 +3,8 @@
 #include "set.h"
 #include "strv.h"
 
+const bool mempool_use_allowed = VALGRIND;
+
 static void test_set_steal_first(void) {
         _cleanup_set_free_ Set *m = NULL;
         int seen[3] = {};
@@ -86,11 +88,32 @@ static void test_set_put(void) {
         assert_se(strv_length(t) == 3);
 }
 
+static void test_set_put_strdup(void) {
+        _cleanup_set_free_ Set *m = NULL;
+
+        assert_se(set_put_strdup(&m, "aaa") == 1);
+        assert_se(set_put_strdup(&m, "aaa") == 0);
+        assert_se(set_put_strdup(&m, "bbb") == 1);
+        assert_se(set_put_strdup(&m, "bbb") == 0);
+        assert_se(set_put_strdup(&m, "aaa") == 0);
+        assert_se(set_size(m) == 2);
+}
+
+static void test_set_put_strdupv(void) {
+        _cleanup_set_free_ Set *m = NULL;
+
+        assert_se(set_put_strdupv(&m, STRV_MAKE("aaa", "aaa", "bbb", "bbb", "aaa")) == 2);
+        assert_se(set_put_strdupv(&m, STRV_MAKE("aaa", "aaa", "bbb", "bbb", "ccc")) == 1);
+        assert_se(set_size(m) == 3);
+}
+
 int main(int argc, const char *argv[]) {
         test_set_steal_first();
         test_set_free_with_destructor();
         test_set_free_with_hash_ops();
         test_set_put();
+        test_set_put_strdup();
+        test_set_put_strdupv();
 
         return 0;
 }
index 014b1aa7a2f0eea88d54564cb61b9748159408c5..2e63aace0201ab696fb5ba04af384dd2f6459d2a 100644 (file)
@@ -20,7 +20,7 @@ static void test_parse_sleep_config(void) {
         _cleanup_(free_sleep_configp) SleepConfig *sleep_config = NULL;
         log_info("/* %s */", __func__);
 
-        assert(parse_sleep_config(&sleep_config) == 0);
+        assert_se(parse_sleep_config(&sleep_config) == 0);
 
         _cleanup_free_ char *sum, *sus, *him, *his, *hym, *hys;
 
index d36caaa71e73375637af4cbc61d09332625c3644..05c375d79ba0848b8b62f5314792aa897d1755eb 100644 (file)
@@ -245,6 +245,24 @@ static void test_in_addr_ifindex_from_string_auto(void) {
         assert_se(in_addr_ifindex_from_string_auto("fe80::19%thisinterfacecantexist", &family, &ua, &ifindex) == -ENODEV);
 }
 
+static void test_in_addr_ifindex_name_from_string_auto_one(const char *a, const char *expected) {
+        int family, ifindex;
+        union in_addr_union ua;
+        _cleanup_free_ char *server_name = NULL;
+
+        assert_se(in_addr_ifindex_name_from_string_auto(a, &family, &ua, &ifindex, &server_name) >= 0);
+        assert_se(streq_ptr(server_name, expected));
+}
+
+static void test_in_addr_ifindex_name_from_string_auto(void) {
+        log_info("/* %s */", __func__);
+
+        test_in_addr_ifindex_name_from_string_auto_one("192.168.0.1", NULL);
+        test_in_addr_ifindex_name_from_string_auto_one("192.168.0.1#test.com", "test.com");
+        test_in_addr_ifindex_name_from_string_auto_one("fe80::18%19", NULL);
+        test_in_addr_ifindex_name_from_string_auto_one("fe80::18%19#another.test.com", "another.test.com");
+}
+
 static void test_sockaddr_equal(void) {
         union sockaddr_union a = {
                 .in.sin_family = AF_INET,
@@ -676,6 +694,7 @@ int main(int argc, char *argv[]) {
         test_in_addr_to_string();
         test_in_addr_ifindex_to_string();
         test_in_addr_ifindex_from_string_auto();
+        test_in_addr_ifindex_name_from_string_auto();
 
         test_sockaddr_equal();
 
index a0ffdf6cb6aa54c340cdbbe854d7a852d56c628b..e81b12b418a63fb0e170e62b5f8464cb29599bb5 100644 (file)
@@ -3,6 +3,7 @@
 #include "alloc-util.h"
 #include "log.h"
 #include "specifier.h"
+#include "stdio-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "tests.h"
@@ -15,6 +16,8 @@ static void test_specifier_escape_one(const char *a, const char *b) {
 }
 
 static void test_specifier_escape(void) {
+        log_info("/* %s */", __func__);
+
         test_specifier_escape_one(NULL, NULL);
         test_specifier_escape_one("", "");
         test_specifier_escape_one("%", "%%");
@@ -31,12 +34,54 @@ static void test_specifier_escape_strv_one(char **a, char **b) {
 }
 
 static void test_specifier_escape_strv(void) {
+        log_info("/* %s */", __func__);
+
         test_specifier_escape_strv_one(NULL, NULL);
         test_specifier_escape_strv_one(STRV_MAKE(NULL), STRV_MAKE(NULL));
         test_specifier_escape_strv_one(STRV_MAKE(""), STRV_MAKE(""));
         test_specifier_escape_strv_one(STRV_MAKE("foo"), STRV_MAKE("foo"));
         test_specifier_escape_strv_one(STRV_MAKE("%"), STRV_MAKE("%%"));
-        test_specifier_escape_strv_one(STRV_MAKE("foo", "%", "foo%", "%foo", "foo%foo", "quux", "%%%"), STRV_MAKE("foo", "%%", "foo%%", "%%foo", "foo%%foo", "quux", "%%%%%%"));
+        test_specifier_escape_strv_one(STRV_MAKE("foo", "%", "foo%", "%foo", "foo%foo", "quux", "%%%"),
+                                       STRV_MAKE("foo", "%%", "foo%%", "%%foo", "foo%%foo", "quux", "%%%%%%"));
+}
+
+/* Any specifier functions which don't need an argument. */
+static const Specifier specifier_table[] = {
+        { 'm', specifier_machine_id,      NULL },
+        { 'b', specifier_boot_id,         NULL },
+        { 'H', specifier_host_name,       NULL },
+        { 'l', specifier_short_host_name, NULL },
+        { 'v', specifier_kernel_release,  NULL },
+        { 'a', specifier_architecture,    NULL },
+        { 'o', specifier_os_id,           NULL },
+        { 'w', specifier_os_version_id,   NULL },
+        { 'B', specifier_os_build_id,     NULL },
+        { 'W', specifier_os_variant_id,   NULL },
+
+        { 'g', specifier_group_name,      NULL },
+        { 'G', specifier_group_id,        NULL },
+        { 'U', specifier_user_id,         NULL },
+        { 'u', specifier_user_name,       NULL },
+        { 'h', specifier_user_home,       NULL },
+
+        { 'T', specifier_tmp_dir,         NULL },
+        { 'V', specifier_var_tmp_dir,     NULL },
+        {}
+};
+
+static void test_specifiers(void) {
+        log_info("/* %s */", __func__);
+
+        for (const Specifier *s = specifier_table; s->specifier; s++) {
+                char spec[3];
+                _cleanup_free_ char *resolved = NULL;
+
+                xsprintf(spec, "%%%c", s->specifier);
+
+                assert_se(specifier_printf(spec, specifier_table, NULL, &resolved) >= 0);
+
+                log_info("%%%c → %s", s->specifier, resolved);
+        }
 }
 
 int main(int argc, char *argv[]) {
@@ -44,6 +89,7 @@ int main(int argc, char *argv[]) {
 
         test_specifier_escape();
         test_specifier_escape_strv();
+        test_specifiers();
 
         return 0;
 }
index ae128dd7e5968cc36cd4802b528cae3bf4ed499b..cba5441d4b3c0e0334da10449196b12200022679 100644 (file)
@@ -9,12 +9,17 @@
 
 static void test_specifier_printf(void) {
         static const Specifier table[] = {
-                { 'a', specifier_string, (char*) "AAAA" },
-                { 'b', specifier_string, (char*) "BBBB" },
-                { 'm', specifier_machine_id, NULL },
-                { 'B', specifier_boot_id, NULL },
-                { 'H', specifier_host_name, NULL },
+                { 'X', specifier_string,         (char*) "AAAA" },
+                { 'Y', specifier_string,         (char*) "BBBB" },
+                { 'm', specifier_machine_id,     NULL },
+                { 'b', specifier_boot_id,        NULL },
+                { 'H', specifier_host_name,      NULL },
                 { 'v', specifier_kernel_release, NULL },
+                { 'a', specifier_architecture,   NULL },
+                { 'o', specifier_os_id,          NULL },
+                { 'w', specifier_os_version_id,  NULL },
+                { 'B', specifier_os_build_id,    NULL },
+                { 'W', specifier_os_variant_id,  NULL },
                 {}
         };
 
@@ -23,7 +28,7 @@ static void test_specifier_printf(void) {
 
         log_info("/* %s */", __func__);
 
-        r = specifier_printf("xxx a=%a b=%b yyy", table, NULL, &w);
+        r = specifier_printf("xxx a=%X b=%Y yyy", table, NULL, &w);
         assert_se(r >= 0);
         assert_se(w);
 
@@ -31,10 +36,15 @@ static void test_specifier_printf(void) {
         assert_se(streq(w, "xxx a=AAAA b=BBBB yyy"));
 
         free(w);
-        r = specifier_printf("machine=%m, boot=%B, host=%H, version=%v", table, NULL, &w);
+        r = specifier_printf("machine=%m, boot=%b, host=%H, version=%v, arch=%a", table, NULL, &w);
         assert_se(r >= 0);
         assert_se(w);
         puts(w);
+
+        w = mfree(w);
+        specifier_printf("os=%o, os-version=%w, build=%B, variant=%W", table, NULL, &w);
+        if (w)
+                puts(w);
 }
 
 static void test_str_in_set(void) {
index a422cc8ddc63e5a4e1a5c5a686cf65e7b6400241..e3b1f6f8ca07c0fe29f2010c1d1313c670a81004 100644 (file)
@@ -433,7 +433,7 @@ static void assert_similar(usec_t a, usec_t b) {
         else
                 d = b - a;
 
-        assert(d < 10*USEC_PER_SEC);
+        assert_se(d < 10*USEC_PER_SEC);
 }
 
 static void test_usec_shift_clock(void) {
index b27b75b352c519d248b2c966419f92028e432cd8..02852bc089e2aa11f3541250bfc4387098bc429f 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include "alloc-util.h"
+#include "errno-util.h"
 #include "log.h"
 #include "path-util.h"
 #include "string-util.h"
@@ -36,6 +37,7 @@ static void test_swap_list(const char *fname) {
         _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, mp_list_head);
         _cleanup_free_ char *testdata_fname = NULL;
         MountPoint *m;
+        int r;
 
         log_info("/* %s(\"%s\") */", __func__, fname ?: "/proc/swaps");
 
@@ -45,7 +47,10 @@ static void test_swap_list(const char *fname) {
         }
 
         LIST_HEAD_INIT(mp_list_head);
-        assert_se(swap_list_get(fname, &mp_list_head) >= 0);
+        r = swap_list_get(fname, &mp_list_head);
+        if (ERRNO_IS_PRIVILEGE(r))
+                return;
+        assert_se(r >= 0);
 
         LIST_FOREACH(mount_point, m, mp_list_head)
                 log_debug("path=%s o=%s f=0x%lx try-ro=%s dev=%u:%u",
index 84962248481e9960d7b1a57982dae711203be5c3..9c9791c7062dc26c2cc9a66557b3c9266da0e2d2 100644 (file)
@@ -239,14 +239,13 @@ static int set_time(int argc, char **argv, void *userdata) {
         if (r < 0)
                 return log_error_errno(r, "Failed to parse time specification '%s': %m", argv[1]);
 
-        r = sd_bus_call_method(bus,
-                               "org.freedesktop.timedate1",
-                               "/org/freedesktop/timedate1",
-                               "org.freedesktop.timedate1",
-                               "SetTime",
-                               &error,
-                               NULL,
-                               "xbb", (int64_t) t, relative, interactive);
+        r = bus_call_method(
+                        bus,
+                        bus_timedate,
+                        "SetTime",
+                        &error,
+                        NULL,
+                        "xbb", (int64_t) t, relative, interactive);
         if (r < 0)
                 return log_error_errno(r, "Failed to set time: %s", bus_error_message(&error, r));
 
@@ -260,14 +259,7 @@ static int set_timezone(int argc, char **argv, void *userdata) {
 
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
-        r = sd_bus_call_method(bus,
-                               "org.freedesktop.timedate1",
-                               "/org/freedesktop/timedate1",
-                               "org.freedesktop.timedate1",
-                               "SetTimezone",
-                               &error,
-                               NULL,
-                               "sb", argv[1], arg_ask_password);
+        r = bus_call_method(bus, bus_timedate, "SetTimezone", &error, NULL, "sb", argv[1], arg_ask_password);
         if (r < 0)
                 return log_error_errno(r, "Failed to set time zone: %s", bus_error_message(&error, r));
 
@@ -285,14 +277,13 @@ static int set_local_rtc(int argc, char **argv, void *userdata) {
         if (b < 0)
                 return log_error_errno(b, "Failed to parse local RTC setting '%s': %m", argv[1]);
 
-        r = sd_bus_call_method(bus,
-                               "org.freedesktop.timedate1",
-                               "/org/freedesktop/timedate1",
-                               "org.freedesktop.timedate1",
-                               "SetLocalRTC",
-                               &error,
-                               NULL,
-                               "bbb", b, arg_adjust_system_clock, arg_ask_password);
+        r = bus_call_method(
+                        bus,
+                        bus_timedate,
+                        "SetLocalRTC",
+                        &error,
+                        NULL,
+                        "bbb", b, arg_adjust_system_clock, arg_ask_password);
         if (r < 0)
                 return log_error_errno(r, "Failed to set local RTC: %s", bus_error_message(&error, r));
 
@@ -310,14 +301,7 @@ static int set_ntp(int argc, char **argv, void *userdata) {
         if (b < 0)
                 return log_error_errno(b, "Failed to parse NTP setting '%s': %m", argv[1]);
 
-        r = sd_bus_call_method(bus,
-                               "org.freedesktop.timedate1",
-                               "/org/freedesktop/timedate1",
-                               "org.freedesktop.timedate1",
-                               "SetNTP",
-                               &error,
-                               NULL,
-                               "bb", b, arg_ask_password);
+        r = bus_call_method(bus, bus_timedate, "SetNTP", &error, NULL, "bb", b, arg_ask_password);
         if (r < 0)
                 return log_error_errno(r, "Failed to set ntp: %s", bus_error_message(&error, r));
 
@@ -331,14 +315,7 @@ static int list_timezones(int argc, char **argv, void *userdata) {
         int r;
         char** zones;
 
-        r = sd_bus_call_method(bus,
-                               "org.freedesktop.timedate1",
-                               "/org/freedesktop/timedate1",
-                               "org.freedesktop.timedate1",
-                               "ListTimezones",
-                               &error,
-                               &reply,
-                               NULL);
+        r = bus_call_method(bus, bus_timedate, "ListTimezones", &error, &reply, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to request list of time zones: %s",
                                        bus_error_message(&error, r));
@@ -843,15 +820,7 @@ static int parse_ifindex_bus(sd_bus *bus, const char *str) {
                 return r;
         assert(r < 0);
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.network1",
-                        "/org/freedesktop/network1",
-                        "org.freedesktop.network1.Manager",
-                        "GetLinkByName",
-                        &error,
-                        &reply,
-                        "s", str);
+        r = bus_call_method(bus, bus_network_mgr, "GetLinkByName", &error, &reply, "s", str);
         if (r < 0)
                 return log_error_errno(r, "Failed to get ifindex of interfaces %s: %s", str, bus_error_message(&error, r));
 
@@ -876,13 +845,7 @@ static int verb_ntp_servers(int argc, char **argv, void *userdata) {
 
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
-        r = sd_bus_message_new_method_call(
-                        bus,
-                        &req,
-                        "org.freedesktop.network1",
-                        "/org/freedesktop/network1",
-                        "org.freedesktop.network1.Manager",
-                        "SetLinkNTP");
+        r = bus_message_new_method_call(bus, &req, bus_network_mgr, "SetLinkNTP");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -914,15 +877,7 @@ static int verb_revert(int argc, char **argv, void *userdata) {
 
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.network1",
-                        "/org/freedesktop/network1",
-                        "org.freedesktop.network1.Manager",
-                        "RevertLinkNTP",
-                        &error,
-                        NULL,
-                        "i", ifindex);
+        r = bus_call_method(bus, bus_network_mgr, "RevertLinkNTP", &error, NULL, "i", ifindex);
         if (r < 0)
                 return log_error_errno(r, "Failed to revert interface configuration: %s", bus_error_message(&error, r));
 
index 8e15cd4f06e35e319746a700e073e6e5bf7b03fe..da59dd33148601b412c4cf49e7673bcdbf340909 100644 (file)
@@ -14,6 +14,7 @@
 #include "bus-error.h"
 #include "bus-log-control-api.h"
 #include "bus-polkit.h"
+#include "bus-util.h"
 #include "clock-util.h"
 #include "conf-files.h"
 #include "def.h"
@@ -28,6 +29,7 @@
 #include "missing_capability.h"
 #include "path-util.h"
 #include "selinux-util.h"
+#include "service-util.h"
 #include "signal-util.h"
 #include "string-util.h"
 #include "strv.h"
@@ -469,11 +471,9 @@ static int unit_start_or_stop(UnitStatusInfo *u, sd_bus *bus, sd_bus_error *erro
         assert(bus);
         assert(error);
 
-        r = sd_bus_call_method(
+        r = bus_call_method(
                 bus,
-                "org.freedesktop.systemd1",
-                "/org/freedesktop/systemd1",
-                "org.freedesktop.systemd1.Manager",
+                bus_systemd_mgr,
                 start ? "StartUnit" : "StopUnit",
                 error,
                 &reply,
@@ -513,11 +513,9 @@ static int unit_enable_or_disable(UnitStatusInfo *u, sd_bus *bus, sd_bus_error *
         log_unit_info(u, "%s unit.", enable ? "Enabling" : "Disabling");
 
         if (enable)
-                r = sd_bus_call_method(
+                r = bus_call_method(
                                 bus,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
+                                bus_systemd_mgr,
                                 "EnableUnitFiles",
                                 error,
                                 NULL,
@@ -525,11 +523,9 @@ static int unit_enable_or_disable(UnitStatusInfo *u, sd_bus *bus, sd_bus_error *
                                 u->name,
                                 false, true);
         else
-                r = sd_bus_call_method(
+                r = bus_call_method(
                                 bus,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
+                                bus_systemd_mgr,
                                 "DisableUnitFiles",
                                 error,
                                 NULL,
@@ -539,15 +535,7 @@ static int unit_enable_or_disable(UnitStatusInfo *u, sd_bus *bus, sd_bus_error *
         if (r < 0)
                 return r;
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "Reload",
-                        error,
-                        NULL,
-                        NULL);
+        r = bus_call_method(bus, bus_systemd_mgr, "Reload", error, NULL, NULL);
         if (r < 0)
                 return r;
 
@@ -950,12 +938,10 @@ static int method_set_ntp(sd_bus_message *m, void *userdata, sd_bus_error *error
                 u->path = mfree(u->path);
 
         if (!c->slot_job_removed) {
-                r = sd_bus_match_signal_async(
+                r = bus_match_signal_async(
                                 bus,
                                 &slot,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
+                                bus_systemd_mgr,
                                 "JobRemoved",
                                 match_job_removed, NULL, c);
                 if (r < 0)
@@ -1085,6 +1071,12 @@ static const sd_bus_vtable timedate_vtable[] = {
         SD_BUS_VTABLE_END,
 };
 
+const BusObjectImplementation manager_object = {
+        "/org/freedesktop/timedate1",
+        "org.freedesktop.timedate1",
+        .vtables = BUS_VTABLES(timedate_vtable),
+};
+
 static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
         int r;
@@ -1097,9 +1089,9 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
         if (r < 0)
                 return log_error_errno(r, "Failed to get system bus connection: %m");
 
-        r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/timedate1", "org.freedesktop.timedate1", timedate_vtable, c);
+        r = bus_add_implementation(bus, &manager_object, c);
         if (r < 0)
-                return log_error_errno(r, "Failed to register object: %m");
+                return r;
 
         r = bus_log_control_api_register(bus);
         if (r < 0)
@@ -1126,10 +1118,15 @@ static int run(int argc, char *argv[]) {
 
         log_setup_service();
 
-        umask(0022);
+        r = service_parse_argv("systemd-timedated.service",
+                               "Manage the system clock and timezone and NTP enablement.",
+                               BUS_IMPLEMENTATIONS(&manager_object,
+                                                   &log_control_object),
+                               argc, argv);
+        if (r <= 0)
+                return r;
 
-        if (argc != 1)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments.");
+        umask(0022);
 
         assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
 
index e18e1e6c04853597c03dc97cb73ce266ccd543f4..dadf213a809ff741fe18eb05031c09d55be3ed83 100644 (file)
@@ -407,10 +407,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
                 .iov_base = &ntpmsg,
                 .iov_len = sizeof(ntpmsg),
         };
-        union {
-                struct cmsghdr cmsghdr;
-                uint8_t buf[CMSG_SPACE(sizeof(struct timeval))];
-        } control;
+        CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct timeval))) control;
         union sockaddr_union server_addr;
         struct msghdr msghdr = {
                 .msg_iov = &iov,
@@ -438,12 +435,11 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
                 return manager_connect(m);
         }
 
-        len = recvmsg(fd, &msghdr, MSG_DONTWAIT);
+        len = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT);
+        if (len == -EAGAIN)
+                return 0;
         if (len < 0) {
-                if (errno == EAGAIN)
-                        return 0;
-
-                log_warning("Error receiving message. Disconnecting.");
+                log_warning_errno(len, "Error receiving message, disconnecting: %m");
                 return manager_connect(m);
         }
 
diff --git a/src/tmpfiles/offline-passwd.c b/src/tmpfiles/offline-passwd.c
new file mode 100644 (file)
index 0000000..8ac5431
--- /dev/null
@@ -0,0 +1,122 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "fd-util.h"
+#include "offline-passwd.h"
+#include "path-util.h"
+#include "user-util.h"
+
+DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(uid_gid_hash_ops, char, string_hash_func, string_compare_func, free);
+
+int name_to_uid_offline(
+                const char *root,
+                const char *user,
+                uid_t *ret_uid,
+                Hashmap **cache) {
+
+        void *found;
+        int r;
+
+        assert(user);
+        assert(ret_uid);
+        assert(cache);
+
+        if (!*cache) {
+                _cleanup_(hashmap_freep) Hashmap *uid_by_name = NULL;
+                _cleanup_fclose_ FILE *f = NULL;
+                struct passwd *pw;
+                const char *passwd_path;
+
+                passwd_path = prefix_roota(root, "/etc/passwd");
+                f = fopen(passwd_path, "re");
+                if (!f)
+                        return errno == ENOENT ? -ESRCH : -errno;
+
+                uid_by_name = hashmap_new(&uid_gid_hash_ops);
+                if (!uid_by_name)
+                        return -ENOMEM;
+
+                while ((r = fgetpwent_sane(f, &pw)) > 0) {
+                        _cleanup_free_ char *n = NULL;
+
+                        n = strdup(pw->pw_name);
+                        if (!n)
+                                return -ENOMEM;
+
+                        r = hashmap_put(uid_by_name, n, UID_TO_PTR(pw->pw_uid));
+                        if (r == -EEXIST) {
+                                log_warning_errno(r, "Duplicate entry in %s for %s: %m", passwd_path, pw->pw_name);
+                                continue;
+                        }
+                        if (r < 0)
+                                return r;
+
+                        TAKE_PTR(n);
+                }
+
+                *cache = TAKE_PTR(uid_by_name);
+        }
+
+        found = hashmap_get(*cache, user);
+        if (!found)
+                return -ESRCH;
+
+        *ret_uid = PTR_TO_UID(found);
+        return 0;
+}
+
+int name_to_gid_offline(
+                const char *root,
+                const char *group,
+                gid_t *ret_gid,
+                Hashmap **cache) {
+
+        void *found;
+        int r;
+
+        assert(group);
+        assert(ret_gid);
+        assert(cache);
+
+        if (!*cache) {
+                _cleanup_(hashmap_freep) Hashmap *gid_by_name = NULL;
+                _cleanup_fclose_ FILE *f = NULL;
+                struct group *gr;
+                const char *group_path;
+
+                group_path = prefix_roota(root, "/etc/group");
+                f = fopen(group_path, "re");
+                if (!f)
+                        return errno == ENOENT ? -ESRCH : -errno;
+
+                gid_by_name = hashmap_new(&uid_gid_hash_ops);
+                if (!gid_by_name)
+                        return -ENOMEM;
+
+                while ((r = fgetgrent_sane(f, &gr)) > 0) {
+                        _cleanup_free_ char *n = NULL;
+
+                        n = strdup(gr->gr_name);
+                        if (!n)
+                                return -ENOMEM;
+
+                        r = hashmap_put(gid_by_name, n, GID_TO_PTR(gr->gr_gid));
+                        if (r == -EEXIST) {
+                                log_warning_errno(r, "Duplicate entry in %s for %s: %m", group_path, gr->gr_name);
+                                continue;
+                        }
+                        if (r < 0)
+                                return r;
+
+                        TAKE_PTR(n);
+                }
+
+                *cache = TAKE_PTR(gid_by_name);
+        }
+
+        found = hashmap_get(*cache, group);
+        if (!found)
+                return -ESRCH;
+
+        *ret_gid = PTR_TO_GID(found);
+        return 0;
+}
diff --git a/src/tmpfiles/offline-passwd.h b/src/tmpfiles/offline-passwd.h
new file mode 100644 (file)
index 0000000..90bdfc7
--- /dev/null
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <sys/types.h>
+
+#include "hashmap.h"
+
+int name_to_uid_offline(const char *root, const char *user, uid_t *ret_uid, Hashmap **cache);
+int name_to_gid_offline(const char *root, const char *group, gid_t *ret_gid, Hashmap **cache);
index 6ab30cdecfe10a6975815809053883a448c489c7..e9453d39351d329f355ee65c18e7220ad26841e0 100644 (file)
@@ -39,6 +39,7 @@
 #include "main-func.h"
 #include "mkdir.h"
 #include "mountpoint-util.h"
+#include "offline-passwd.h"
 #include "pager.h"
 #include "parse-util.h"
 #include "path-lookup.h"
@@ -184,7 +185,13 @@ static const Specifier specifier_table[] = {
         { 'm', specifier_machine_id_safe, NULL },
         { 'b', specifier_boot_id,         NULL },
         { 'H', specifier_host_name,       NULL },
+        { 'l', specifier_short_host_name, NULL },
         { 'v', specifier_kernel_release,  NULL },
+        { 'a', specifier_architecture,    NULL },
+        { 'o', specifier_os_id,           NULL },
+        { 'w', specifier_os_version_id,   NULL },
+        { 'B', specifier_os_build_id,     NULL },
+        { 'W', specifier_os_variant_id,   NULL },
 
         { 'g', specifier_group_name,      NULL },
         { 'G', specifier_group_id,        NULL },
@@ -256,10 +263,11 @@ static int log_unresolvable_specifier(const char *filename, unsigned line) {
          * not considered as an error so log at LOG_NOTICE only for the first time
          * and then downgrade this to LOG_DEBUG for the rest. */
 
-        log_full(notified ? LOG_DEBUG : LOG_NOTICE,
-                 "[%s:%u] Failed to resolve specifier: %s, skipping",
-                 filename, line,
-                 arg_user ? "Required $XDG_... variable not defined" : "uninitialized /etc detected");
+        log_syntax(NULL,
+                   notified ? LOG_DEBUG : LOG_NOTICE,
+                   filename, line, 0,
+                   "Failed to resolve specifier: %s, skipping",
+                   arg_user ? "Required $XDG_... variable not defined" : "uninitialized /etc detected");
 
         if (!notified)
                 log_notice("All rules containing unresolvable specifiers will be skipped.");
@@ -1078,6 +1086,11 @@ static int fd_set_acls(Item *item, int fd, const char *path, const struct stat *
 
         if (r > 0)
                 return -r; /* already warned */
+
+        /* The above procfs paths don't work if /proc is not mounted. */
+        if (r == -ENOENT && proc_mounted() == 0)
+                r = -ENOSYS;
+
         if (r == -EOPNOTSUPP) {
                 log_debug_errno(r, "ACLs not supported by file system at %s", path);
                 return 0;
@@ -2426,9 +2439,7 @@ static int specifier_expansion_from_arg(Item *i) {
 
         case SET_XATTR:
         case RECURSIVE_SET_XATTR:
-                assert(i->xattrs);
-
-                STRV_FOREACH (xattr, i->xattrs) {
+                STRV_FOREACH(xattr, i->xattrs) {
                         r = specifier_printf(*xattr, specifier_table, NULL, &resolved);
                         if (r < 0)
                                 return r;
@@ -2478,7 +2489,63 @@ static int patch_var_run(const char *fname, unsigned line, char **path) {
         return 0;
 }
 
-static int parse_line(const char *fname, unsigned line, const char *buffer, bool *invalid_config) {
+static int find_uid(const char *user, uid_t *ret_uid, Hashmap **cache) {
+        int r;
+
+        assert(user);
+        assert(ret_uid);
+
+        /* First: parse as numeric UID string */
+        r = parse_uid(user, ret_uid);
+        if (r >= 0)
+                return r;
+
+        /* Second: pass to NSS if we are running "online" */
+        if (!arg_root)
+                return get_user_creds(&user, ret_uid, NULL, NULL, NULL, 0);
+
+        /* Third, synthesize "root" unconditionally */
+        if (streq(user, "root")) {
+                *ret_uid = 0;
+                return 0;
+        }
+
+        /* Fourth: use fgetpwent() to read /etc/passwd directly, if we are "offline" */
+        return name_to_uid_offline(arg_root, user, ret_uid, cache);
+}
+
+static int find_gid(const char *group, gid_t *ret_gid, Hashmap **cache) {
+        int r;
+
+        assert(group);
+        assert(ret_gid);
+
+        /* First: parse as numeric GID string */
+        r = parse_gid(group, ret_gid);
+        if (r >= 0)
+                return r;
+
+        /* Second: pass to NSS if we are running "online" */
+        if (!arg_root)
+                return get_group_creds(&group, ret_gid, 0);
+
+        /* Third, synthesize "root" unconditionally */
+        if (streq(group, "root")) {
+                *ret_gid = 0;
+                return 0;
+        }
+
+        /* Fourth: use fgetgrent() to read /etc/group directly, if we are "offline" */
+        return name_to_gid_offline(arg_root, group, ret_gid, cache);
+}
+
+static int parse_line(
+                const char *fname,
+                unsigned line,
+                const char *buffer,
+                bool *invalid_config,
+                Hashmap **uid_cache,
+                Hashmap **gid_cache) {
 
         _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
         _cleanup_(item_free_contents) Item i = {};
@@ -2506,11 +2573,10 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
                 if (IN_SET(r, -EINVAL, -EBADSLT))
                         /* invalid quoting and such or an unknown specifier */
                         *invalid_config = true;
-                return log_error_errno(r, "[%s:%u] Failed to parse line: %m", fname, line);
+                return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to parse line: %m");
         } else if (r < 2) {
                 *invalid_config = true;
-                log_error("[%s:%u] Syntax error.", fname, line);
-                return -EIO;
+                return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG), "Syntax error.");
         }
 
         if (!empty_or_dash(buffer)) {
@@ -2521,8 +2587,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
 
         if (isempty(action)) {
                 *invalid_config = true;
-                log_error("[%s:%u] Command too short '%s'.", fname, line, action);
-                return -EINVAL;
+                return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG), "Command too short '%s'.", action);
         }
 
         for (pos = 1; action[pos]; pos++) {
@@ -2534,15 +2599,12 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
                         allow_failure = true;
                 else {
                         *invalid_config = true;
-                        log_error("[%s:%u] Unknown modifiers in command '%s'",
-                                  fname, line, action);
-                        return -EINVAL;
+                        return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG), "Unknown modifiers in command '%s'", action);
                 }
         }
 
         if (boot && !arg_boot) {
-                log_debug("Ignoring entry %s \"%s\" because --boot is not specified.",
-                          action, path);
+                log_syntax(NULL, LOG_DEBUG, fname, line, 0, "Ignoring entry %s \"%s\" because --boot is not specified.", action, path);
                 return 0;
         }
 
@@ -2556,7 +2618,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
         if (r < 0) {
                 if (IN_SET(r, -EINVAL, -EBADSLT))
                         *invalid_config = true;
-                return log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s", fname, line, path);
+                return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to replace specifiers in '%s': %m", path);
         }
 
         r = patch_var_run(fname, line, &i.path);
@@ -2580,7 +2642,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
         case RELABEL_PATH:
         case RECURSIVE_RELABEL_PATH:
                 if (i.argument)
-                        log_warning("[%s:%u] %c lines don't take argument fields, ignoring.", fname, line, i.type);
+                        log_syntax(NULL, LOG_WARNING, fname, line, 0, "%c lines don't take argument fields, ignoring.", i.type);
 
                 break;
 
@@ -2599,23 +2661,23 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
         case WRITE_FILE:
                 if (!i.argument) {
                         *invalid_config = true;
-                        log_error("[%s:%u] Write file requires argument.", fname, line);
-                        return -EBADMSG;
+                        return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG), "Write file requires argument.");
                 }
                 break;
 
         case COPY_FILES:
                 if (!i.argument) {
-                        i.argument = path_join(arg_root, "/usr/share/factory", i.path);
+                        i.argument = path_join("/usr/share/factory", i.path);
                         if (!i.argument)
                                 return log_oom();
 
                 } else if (!path_is_absolute(i.argument)) {
                         *invalid_config = true;
-                        log_error("[%s:%u] Source path is not absolute.", fname, line);
-                        return -EBADMSG;
+                        return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG), "Source path '%s' is not absolute.", i.argument);
+
+                }
 
-                } else if (arg_root) {
+                if (!empty_or_root(arg_root)) {
                         char *p;
 
                         p = path_join(arg_root, i.argument);
@@ -2631,15 +2693,13 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
         case CREATE_BLOCK_DEVICE:
                 if (!i.argument) {
                         *invalid_config = true;
-                        log_error("[%s:%u] Device file requires argument.", fname, line);
-                        return -EBADMSG;
+                        return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG), "Device file requires argument.");
                 }
 
                 r = parse_dev(i.argument, &i.major_minor);
                 if (r < 0) {
                         *invalid_config = true;
-                        log_error_errno(r, "[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i.argument);
-                        return -EBADMSG;
+                        return log_syntax(NULL, LOG_ERR, fname, line, r, "Can't parse device file major/minor '%s'.", i.argument);
                 }
 
                 break;
@@ -2648,8 +2708,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
         case RECURSIVE_SET_XATTR:
                 if (!i.argument) {
                         *invalid_config = true;
-                        log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
-                        return -EBADMSG;
+                        return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
+                                          "Set extended attribute requires argument.");
                 }
                 r = parse_xattrs_from_arg(&i);
                 if (r < 0)
@@ -2660,8 +2720,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
         case RECURSIVE_SET_ACL:
                 if (!i.argument) {
                         *invalid_config = true;
-                        log_error("[%s:%u] Set ACLs requires argument.", fname, line);
-                        return -EBADMSG;
+                        return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
+                                          "Set ACLs requires argument.");
                 }
                 r = parse_acls_from_arg(&i);
                 if (r < 0)
@@ -2672,8 +2732,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
         case RECURSIVE_SET_ATTRIBUTE:
                 if (!i.argument) {
                         *invalid_config = true;
-                        log_error("[%s:%u] Set file attribute requires argument.", fname, line);
-                        return -EBADMSG;
+                        return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
+                                          "Set file attribute requires argument.");
                 }
                 r = parse_attribute_from_arg(&i);
                 if (IN_SET(r, -EINVAL, -EBADSLT))
@@ -2683,15 +2743,15 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
                 break;
 
         default:
-                log_error("[%s:%u] Unknown command type '%c'.", fname, line, (char) i.type);
                 *invalid_config = true;
-                return -EBADMSG;
+                return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
+                                  "Unknown command type '%c'.", (char) i.type);
         }
 
         if (!path_is_absolute(i.path)) {
-                log_error("[%s:%u] Path '%s' not absolute.", fname, line, i.path);
                 *invalid_config = true;
-                return -EBADMSG;
+                return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
+                                  "Path '%s' not absolute.", i.path);
         }
 
         path_simplify(i.path, false);
@@ -2705,11 +2765,10 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
         if (r < 0) {
                 if (IN_SET(r, -EINVAL, -EBADSLT))
                         *invalid_config = true;
-                return log_error_errno(r, "[%s:%u] Failed to substitute specifiers in argument: %m",
-                                       fname, line);
+                return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to substitute specifiers in argument: %m");
         }
 
-        if (arg_root) {
+        if (!empty_or_root(arg_root)) {
                 char *p;
 
                 p = path_join(arg_root, i.path);
@@ -2719,25 +2778,20 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
         }
 
         if (!empty_or_dash(user)) {
-                const char *u = user;
-
-                r = get_user_creds(&u, &i.uid, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING);
+                r = find_uid(user, &i.uid, uid_cache);
                 if (r < 0) {
                         *invalid_config = true;
-                        return log_error_errno(r, "[%s:%u] Unknown user '%s'.", fname, line, user);
+                        return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to resolve user '%s': %m", user);
                 }
 
                 i.uid_set = true;
         }
 
         if (!empty_or_dash(group)) {
-                const char *g = group;
-
-                r = get_group_creds(&g, &i.gid, USER_CREDS_ALLOW_MISSING);
+                r = find_gid(group, &i.gid, gid_cache);
                 if (r < 0) {
                         *invalid_config = true;
-                        log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
-                        return r;
+                        return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to resolve group '%s'.", group);
                 }
 
                 i.gid_set = true;
@@ -2752,10 +2806,10 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
                         mm++;
                 }
 
-                if (parse_mode(mm, &m) < 0) {
+                r = parse_mode(mm, &m);
+                if (r < 0) {
                         *invalid_config = true;
-                        log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
-                        return -EBADMSG;
+                        return log_syntax(NULL, LOG_ERR, fname, line, r, "Invalid mode '%s'.", mode);
                 }
 
                 i.mode = m;
@@ -2771,10 +2825,10 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
                         a++;
                 }
 
-                if (parse_sec(a, &i.age) < 0) {
+                r = parse_sec(a, &i.age);
+                if (r < 0) {
                         *invalid_config = true;
-                        log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
-                        return -EBADMSG;
+                        return log_syntax(NULL, LOG_ERR, fname, line, r, "Invalid age '%s'.", age);
                 }
 
                 i.age_set = true;
@@ -2788,8 +2842,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
 
                 for (n = 0; n < existing->n_items; n++) {
                         if (!item_compatible(existing->items + n, &i) && !i.append_or_force) {
-                                log_notice("[%s:%u] Duplicate line for path \"%s\", ignoring.",
-                                           fname, line, i.path);
+                                log_syntax(NULL, LOG_NOTICE, fname, line, 0, "Duplicate line for path \"%s\", ignoring.", i.path);
                                 return 0;
                         }
                 }
@@ -2943,7 +2996,7 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_ROOT:
-                        r = parse_path_argument_and_warn(optarg, true, &arg_root);
+                        r = parse_path_argument_and_warn(optarg, /* suppress_root= */ false, &arg_root);
                         if (r < 0)
                                 return r;
                         break;
@@ -2984,6 +3037,7 @@ static int parse_argv(int argc, char *argv[]) {
 }
 
 static int read_config_file(char **config_dirs, const char *fn, bool ignore_enoent, bool *invalid_config) {
+        _cleanup_(hashmap_freep) Hashmap *uid_cache = NULL, *gid_cache = NULL;
         _cleanup_fclose_ FILE *_f = NULL;
         Iterator iterator;
         unsigned v = 0;
@@ -3029,7 +3083,7 @@ static int read_config_file(char **config_dirs, const char *fn, bool ignore_enoe
                 if (IN_SET(*l, 0, '#'))
                         continue;
 
-                k = parse_line(fn, v, l, &invalid_line);
+                k = parse_line(fn, v, l, &invalid_line, &uid_cache, &gid_cache);
                 if (k < 0) {
                         if (invalid_line)
                                 /* Allow reporting with a special code if the caller requested this */
index 2784246dd7155547d175f74b58af4704d8deb649..60a9d21c1d11ec1b58badaecf3296030a918a62b 100644 (file)
@@ -59,6 +59,8 @@ Link.OtherChannels,              config_parse_channel,                  0,
 Link.CombinedChannels,           config_parse_channel,                  0,                             offsetof(link_config, channels)
 Link.Advertise,                  config_parse_advertise,                0,                             offsetof(link_config, advertise)
 Link.RxBufferSize,               config_parse_nic_buffer_size,          0,                             offsetof(link_config, ring)
+Link.RxMiniBufferSize,           config_parse_nic_buffer_size,          0,                             offsetof(link_config, ring)
+Link.RxJumboBufferSize,          config_parse_nic_buffer_size,          0,                             offsetof(link_config, ring)
 Link.TxBufferSize,               config_parse_nic_buffer_size,          0,                             offsetof(link_config, ring)
 Link.RxFlowControl,              config_parse_tristate,                 0,                             offsetof(link_config, rx_flow_control)
 Link.TxFlowControl,              config_parse_tristate,                 0,                             offsetof(link_config, tx_flow_control)
index 48039511fa69bc5d778f30e7c1f1cfa1c364cad7..75c2aec491ee1e7c42a545bbb71d5347df9b5db3 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <linux/netdevice.h>
 #include <netinet/ether.h>
+#include <unistd.h>
 
 #include "sd-device.h"
 #include "sd-netlink.h"
@@ -173,7 +174,7 @@ int link_load_one(link_config_ctx *ctx, const char *filename) {
                 return 0;
         }
 
-        if (!condition_test_list(link->conditions, NULL, NULL, NULL)) {
+        if (!condition_test_list(link->conditions, environ, NULL, NULL, NULL)) {
                 log_debug("%s: Conditions do not match the system environment, skipping.", filename);
                 return 0;
         }
@@ -207,7 +208,7 @@ static int link_unsigned_attribute(sd_device *device, const char *attr, unsigned
 }
 
 int link_config_load(link_config_ctx *ctx) {
-        _cleanup_strv_free_ char **files;
+        _cleanup_strv_free_ char **files = NULL;
         char **f;
         int r;
 
@@ -327,7 +328,11 @@ static int get_mac(sd_device *device, MACAddressPolicy policy, struct ether_addr
 
         if (want_random) {
                 log_device_debug(device, "Using random bytes to generate MAC");
-                random_bytes(mac->ether_addr_octet, ETH_ALEN);
+
+                /* We require genuine randomness here, since we want to make sure we won't collide with other
+                 * systems booting up at the very same time. We do allow RDRAND however, since this is not
+                 * cryptographic key material. */
+                genuine_random_bytes(mac->ether_addr_octet, ETH_ALEN, RANDOM_ALLOW_RDRAND);
         } else {
                 uint64_t result;
 
@@ -407,15 +412,17 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
                         log_warning_errno(r, "Could not set channels of %s: %m", old_name);
         }
 
-        if (config->ring.rx_pending_set || config->ring.tx_pending_set) {
+        if (config->ring.rx_pending_set || config->ring.rx_mini_pending_set || config->ring.rx_jumbo_pending_set || config->ring.tx_pending_set) {
                 r = ethtool_set_nic_buffer_size(&ctx->ethtool_fd, old_name, &config->ring);
                 if (r < 0)
                         log_warning_errno(r, "Could not set ring buffer of %s: %m", old_name);
         }
 
-        r = ethtool_set_flow_control(&ctx->ethtool_fd, old_name, config->rx_flow_control, config->tx_flow_control, config->autoneg_flow_control);
-        if (r < 0)
-                log_warning_errno(r, "Could not set flow control of %s: %m", old_name);
+        if (config->rx_flow_control >= 0 || config->tx_flow_control >= 0 || config->autoneg_flow_control >= 0) {
+                r = ethtool_set_flow_control(&ctx->ethtool_fd, old_name, config->rx_flow_control, config->tx_flow_control, config->autoneg_flow_control);
+                if (r < 0)
+                        log_warning_errno(r, "Could not set flow control of %s: %m", old_name);
+        }
 
         r = sd_device_get_ifindex(device, &ifindex);
         if (r < 0)
index b8c0d83a022c1729211d0c96fe5231d08502d746..1e51f22e26035c41b0873e9a314c1488d430f004 100644 (file)
@@ -189,12 +189,12 @@ static int udev_ctrl_connection_event_handler(sd_event_source *s, int fd, uint32
         _cleanup_(udev_ctrl_disconnect_and_listen_againp) struct udev_ctrl *uctrl = NULL;
         struct udev_ctrl_msg_wire msg_wire;
         struct iovec iov = IOVEC_MAKE(&msg_wire, sizeof(struct udev_ctrl_msg_wire));
-        char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
+        CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
         struct msghdr smsg = {
                 .msg_iov = &iov,
                 .msg_iovlen = 1,
-                .msg_control = cred_msg,
-                .msg_controllen = sizeof(cred_msg),
+                .msg_control = &control,
+                .msg_controllen = sizeof(control),
         };
         struct cmsghdr *cmsg;
         struct ucred *cred;
@@ -212,13 +212,11 @@ static int udev_ctrl_connection_event_handler(sd_event_source *s, int fd, uint32
         if (size == 0)
                 return 0; /* Client disconnects? */
 
-        size = recvmsg(fd, &smsg, 0);
-        if (size < 0) {
-                if (errno != EINTR)
-                        return log_error_errno(errno, "Failed to receive ctrl message: %m");
-
+        size = recvmsg_safe(fd, &smsg, 0);
+        if (size == -EINTR)
                 return 0;
-        }
+        if (size < 0)
+                return log_error_errno(size, "Failed to receive ctrl message: %m");
 
         cmsg_close_all(&smsg);
 
index 6030ffb1f088f46fb582c80a45c8219e2819e50b..4c955b0c079c3ee0a67db3a3001d681800ba871f 100644 (file)
@@ -1092,7 +1092,9 @@ static int rule_add_line(UdevRules *rules, const char *line_str, unsigned line_n
         if (isempty(line_str))
                 return 0;
 
-        line = strdup(line_str);
+        /* 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);
         if (!line)
                 return log_oom();
 
@@ -1328,11 +1330,7 @@ static bool token_match_string(UdevRuleToken *token, const char *str) {
                 match = isempty(str);
                 break;
         case MATCH_TYPE_SUBSYSTEM:
-                NULSTR_FOREACH(i, "subsystem\0class\0bus\0")
-                        if (streq(i, str)) {
-                                match = true;
-                                break;
-                        }
+                match = STR_IN_SET(str, "subsystem", "class", "bus");
                 break;
         case MATCH_TYPE_PLAIN_WITH_EMPTY:
                 if (isempty(str)) {
index 60c68b5029cf986981902c287d50d9309be291d8..39113d2fa23294b5ad3dc963681b42389c52f7b3 100644 (file)
@@ -23,7 +23,7 @@
 static bool arg_verbose = false;
 static bool arg_dry_run = false;
 
-static int exec_list(sd_device_enumerator *e, const char *action, Set *settle_set) {
+static int exec_list(sd_device_enumerator *e, const char *action, Set **settle_set) {
         sd_device *d;
         int r, ret = 0;
 
@@ -172,7 +172,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
         _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *m = NULL;
         _cleanup_(sd_event_unrefp) sd_event *event = NULL;
-        _cleanup_set_free_free_ Set *settle_set = NULL;
+        _cleanup_set_free_ Set *settle_set = NULL;
         usec_t ping_timeout_usec = 5 * USEC_PER_SEC;
         bool settle = false, ping = false;
         int c, r;
@@ -342,7 +342,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
         }
 
         if (settle) {
-                settle_set = set_new(&string_hash_ops);
+                settle_set = set_new(&string_hash_ops_free);
                 if (!settle_set)
                         return log_oom();
 
@@ -377,7 +377,8 @@ int trigger_main(int argc, char *argv[], void *userdata) {
         default:
                 assert_not_reached("Unknown device type");
         }
-        r = exec_list(e, action, settle_set);
+
+        r = exec_list(e, action, settle ? &settle_set : NULL);
         if (r < 0)
                 return r;
 
index 456bc8c479a39e0bd268e849748f1ef2c433b5be..d3f9d532e18ff0335ce980ae57178161ea145184 100644 (file)
@@ -906,41 +906,34 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
                         .iov_base = &msg,
                         .iov_len = sizeof(msg),
                 };
-                union {
-                        struct cmsghdr cmsghdr;
-                        uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
-                } control = {};
+                CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
                 struct msghdr msghdr = {
                         .msg_iov = &iovec,
                         .msg_iovlen = 1,
                         .msg_control = &control,
                         .msg_controllen = sizeof(control),
                 };
-                struct cmsghdr *cmsg;
                 ssize_t size;
-                struct ucred *ucred = NULL;
+                struct ucred *ucred;
                 struct worker *worker;
 
-                size = recvmsg(fd, &msghdr, MSG_DONTWAIT);
-                if (size < 0) {
-                        if (errno == EINTR)
-                                continue;
-                        else if (errno == EAGAIN)
-                                /* nothing more to read */
-                                break;
+                size = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT);
+                if (size == -EINTR)
+                        continue;
+                if (size == -EAGAIN)
+                        /* nothing more to read */
+                        break;
+                if (size < 0)
+                        return log_error_errno(size, "Failed to receive message: %m");
 
-                        return log_error_errno(errno, "Failed to receive message: %m");
-                } else if (size != sizeof(struct worker_message)) {
+                cmsg_close_all(&msghdr);
+
+                if (size != sizeof(struct worker_message)) {
                         log_warning("Ignoring worker message with invalid size %zi bytes", size);
                         continue;
                 }
 
-                CMSG_FOREACH(cmsg, &msghdr)
-                        if (cmsg->cmsg_level == SOL_SOCKET &&
-                            cmsg->cmsg_type == SCM_CREDENTIALS &&
-                            cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
-                                ucred = (struct ucred*) CMSG_DATA(cmsg);
-
+                ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred);
                 if (!ucred || ucred->pid <= 0) {
                         log_warning("Ignoring worker message without valid PID");
                         continue;
index 947444cc0048d43621baecbe86d4d6fedcd0e556..4b5eb34ca6225d7a2473bae1029ce217f745e59b 100644 (file)
@@ -581,24 +581,24 @@ static int help(int argc, char *argv[], void *userdata) {
         printf("%s [OPTIONS...] COMMAND ...\n\n"
                "%sShow user and group information.%s\n"
                "\nCommands:\n"
-               "  user [USER…]                Inspect user\n"
-               "  group [GROUP…]              Inspect group\n"
-               "  users-in-group [GROUP…]     Show users that are members of specified group(s)\n"
-               "  groups-of-user [USER…]      Show groups the specified user(s) is a member of\n"
-               "  services                    Show enabled database services\n"
+               "  user [USER…]               Inspect user\n"
+               "  group [GROUP…]             Inspect group\n"
+               "  users-in-group [GROUP…]    Show users that are members of specified group(s)\n"
+               "  groups-of-user [USER…]     Show groups the specified user(s) is a member of\n"
+               "  services                   Show enabled database services\n"
                "\nOptions:\n"
-               "  -h --help                   Show this help\n"
-               "     --version                Show package version\n"
-               "     --no-pager               Do not pipe output into a pager\n"
-               "     --no-legend              Do not show the headers and footers\n"
-               "     --output=MODE            Select output mode (classic, friendly, table, json)\n"
-               "  -j                          Equivalent to --output=json\n"
+               "  -h --help                  Show this help\n"
+               "     --version               Show package version\n"
+               "     --no-pager              Do not pipe output into a pager\n"
+               "     --no-legend             Do not show the headers and footers\n"
+               "     --output=MODE           Select output mode (classic, friendly, table, json)\n"
+               "  -j                         Equivalent to --output=json\n"
                "  -s --service=SERVICE[:SERVICE…]\n"
-               "                              Query the specified service\n"
-               "     --with-nss=BOOL          Control whether to include glibc NSS data\n"
-               "  -N                          Disable inclusion of glibc NSS data and disable synthesizing\n"
-               "                              (Same as --with-nss=no --synthesize=no)\n"
-               "     --synthesize=BOOL        Synthesize root/nobody user\n"
+               "                             Query the specified service\n"
+               "     --with-nss=BOOL         Control whether to include glibc NSS data\n"
+               "  -N                         Do not synthesize or include glibc NSS data\n"
+               "                             (Same as --synthesize=no --with-nss=no)\n"
+               "     --synthesize=BOOL       Synthesize root/nobody user\n"
                "\nSee the %s for details.\n"
                , program_invocation_short_name
                , ansi_highlight(), ansi_normal()
index af78a87d6feff1a8b50f07f672c39a80c06c4433..e55864d6cc14665b615d734dc0a17a20986d7260 100644 (file)
@@ -29,7 +29,7 @@ static int make_volatile(const char *path) {
         if (r < 0)
                 return log_error_errno(r, "Couldn't generate volatile sysroot directory: %m");
 
-        r = mount_verbose(LOG_ERR, "tmpfs", "/run/systemd/volatile-sysroot", "tmpfs", MS_STRICTATIME, "mode=755");
+        r = mount_verbose(LOG_ERR, "tmpfs", "/run/systemd/volatile-sysroot", "tmpfs", MS_STRICTATIME, "mode=755" TMPFS_LIMITS_ROOTFS);
         if (r < 0)
                 goto finish_rmdir;
 
@@ -80,7 +80,7 @@ static int make_overlay(const char *path) {
         if (r < 0)
                 return log_error_errno(r, "Couldn't create overlay sysroot directory: %m");
 
-        r = mount_verbose(LOG_ERR, "tmpfs", "/run/systemd/overlay-sysroot", "tmpfs", MS_STRICTATIME, "mode=755");
+        r = mount_verbose(LOG_ERR, "tmpfs", "/run/systemd/overlay-sysroot", "tmpfs", MS_STRICTATIME, "mode=755" TMPFS_LIMITS_ROOTFS);
         if (r < 0)
                 goto finish;
 
diff --git a/test/TEST-38-FREEZER/Makefile b/test/TEST-38-FREEZER/Makefile
new file mode 120000 (symlink)
index 0000000..e9f93b1
--- /dev/null
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile
\ No newline at end of file
diff --git a/test/TEST-38-FREEZER/test.sh b/test/TEST-38-FREEZER/test.sh
new file mode 100755 (executable)
index 0000000..3821db9
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/bash
+set -e
+TEST_DESCRIPTION="test unit freezing and thawing via DBus and systemctl"
+TEST_NO_NSPAWN=1
+. $TEST_BASE_DIR/test-functions
+
+do_test "$@" 38
diff --git a/test/fuzz/fuzz-bus-message/oss-fuzz-19446 b/test/fuzz/fuzz-bus-message/oss-fuzz-19446
new file mode 100644 (file)
index 0000000..f937ef8
Binary files /dev/null and b/test/fuzz/fuzz-bus-message/oss-fuzz-19446 differ
diff --git a/test/fuzz/fuzz-calendarspec/oss-fuzz-22208 b/test/fuzz/fuzz-calendarspec/oss-fuzz-22208
new file mode 100644 (file)
index 0000000..2bbe762
--- /dev/null
@@ -0,0 +1 @@
+4:3:2147..2
\ No newline at end of file
index fe71d26d89e866e4dee775b5f1ee83f78be65b8f..7d23a9ecf8e0bb59d7e4619623e8f967b75c653b 100644 (file)
@@ -40,6 +40,8 @@ OtherChannels=
 CombinedChannels=
 Advertise=
 RxBufferSize=
+RxMiniBufferSize=
+RxJumboBufferSize=
 TxBufferSize=
 RxFlowControl=
 TxFlowControl=
index e8391dab780cfad2385a3a6f641d09a08f2b43b1..d69ac09f1fb81900e01c5fef97452a318370a43e 100644 (file)
@@ -45,6 +45,7 @@ AgeingTimeSec=
 Priority=
 GroupForwardMask=
 VLANFiltering=
+VLANProtocol=
 MulticastIGMPVersion=
 [VRF]
 TableId=
index 1cd18202f40b4237fa565e7b640c45b7f893cbef..625842a9ba18dc0c43483d337c887b5393e7c3b3 100644 (file)
@@ -37,6 +37,7 @@ Unmanaged=
 MTUBytes=
 Multicast=
 MACAddress=
+Group=
 [BridgeFDB]
 VLANId=
 MACAddress=
@@ -104,6 +105,7 @@ SendVendorOption=
 SendDecline=
 MUDURL=
 RouteMTUBytes=
+FallbackLeaseLifetimeSec=
 [DHCPv6]
 UseNTP=
 UseDNS=
@@ -112,6 +114,10 @@ ForceDHCPv6PDOtherInformation=
 PrefixDelegationHint=
 WithoutRA=
 MUDURL=
+SendOption=
+RequestOptions=
+UserClass=
+VendorClass=
 [Route]
 Destination=
 Protocol=
index 98cddad3494addaaa333ee33d364c32894820309..6fa96e1d588457c9787344058c1dcc0f7531ba26 100644 (file)
@@ -856,6 +856,7 @@ RateLimitIntervalSec=
 ReadKMsg=
 ReadOnly=
 ReadOnlyPaths=
+ReadWriteOnly=
 ReadWritePaths=
 RemoveIPC=
 ReserveVT=
index c514f57fe3d1618667bd65122f0efb01983239a5..7d61e270fd9643c86b7eecb41f986e30114a55fd 100644 (file)
@@ -1,17 +1,17 @@
 # SPDX-License-Identifier: LGPL-2.1+
 
-sanitize_address = custom_target(
-        'sanitize-address-fuzzers',
-        output : 'sanitize-address-fuzzers',
+sanitize_address_undefined = custom_target(
+        'sanitize-address-undefined-fuzzers',
+        output : 'sanitize-address-undefined-fuzzers',
         command : [meson_build_sh,
                    project_source_root,
                    '@OUTPUT@',
                    'fuzzers',
-                   '-Db_lundef=false -Db_sanitize=address',
+                   '-Db_lundef=false -Db_sanitize=address,undefined',
                    ' '.join(cc.cmd_array()),
                    cxx_cmd])
 
-sanitizers = [['address', sanitize_address]]
+sanitizers = [['address,undefined', sanitize_address_undefined]]
 
 if git.found()
         out = run_command(
index 8389623c20c97f1da16aac4ab21dbe1ae0af7a51..79130c3984dd1af7709171c01d874c99e001fe9c 100644 (file)
@@ -38,6 +38,7 @@ fi
 
 PATH_TO_INIT=$ROOTLIBDIR/systemd
 [ "$SYSTEMD_JOURNALD" ] || SYSTEMD_JOURNALD=$(which -a $BUILD_DIR/systemd-journald $ROOTLIBDIR/systemd-journald 2>/dev/null | grep '^/' -m1)
+[ "$SYSTEMD_JOURNAL_REMOTE" ] || SYSTEMD_JOURNAL_REMOTE=$(which -a $BUILD_DIR/systemd-journal-remote $ROOTLIBDIR/systemd-journal-remote 2>/dev/null | grep '^/' -m1)
 [ "$SYSTEMD" ] || SYSTEMD=$(which -a $BUILD_DIR/systemd $ROOTLIBDIR/systemd 2>/dev/null | grep '^/' -m1)
 [ "$SYSTEMD_NSPAWN" ] || SYSTEMD_NSPAWN=$(which -a $BUILD_DIR/systemd-nspawn systemd-nspawn 2>/dev/null | grep '^/' -m1)
 [ "$JOURNALCTL" ] || JOURNALCTL=$(which -a $BUILD_DIR/journalctl journalctl 2>/dev/null | grep '^/' -m1)
@@ -101,6 +102,7 @@ BASICTOOLS=(
     tar
     tee
     test
+    timeout
     touch
     tr
     true
@@ -800,13 +802,13 @@ save_journal() {
     fi
 
     for j in $1/*; do
-        /usr/lib/systemd/systemd-journal-remote \
+        $SYSTEMD_JOURNAL_REMOTE \
             -o $dest \
-            --getter="journalctl -o export -D $j"
+            --getter="$JOURNALCTL -o export -D $j"
 
         if [ -n "${TEST_SHOW_JOURNAL}" ]; then
             echo "---- $j ----"
-            journalctl --no-pager -o short-monotonic --no-hostname --priority=${TEST_SHOW_JOURNAL} -D $j
+            $JOURNALCTL --no-pager -o short-monotonic --no-hostname --priority=${TEST_SHOW_JOURNAL} -D $j
         fi
 
         rm -r $j
@@ -906,7 +908,7 @@ install_plymouth() {
     #         /usr/libexec/plymouth/plymouth-populate-initrd -t $initdir
     #         dracut_install plymouth plymouthd
     # else
-        rm -f $initdir/{usr/lib,etc}/systemd/system/plymouth* $initdir/{usr/lib,etc}/systemd/system/*/plymouth*
+        rm -f $initdir/{usr/lib,lib,etc}/systemd/system/plymouth* $initdir/{usr/lib,lib,etc}/systemd/system/*/plymouth*
     # fi
 }
 
index 1431dad862bf86af4d47bfb59920ef4112281e7c..3dce73b778250854dbde499123242101931540c5 100755 (executable)
@@ -87,6 +87,18 @@ journalctl -b -o export -t "$ID" --output-fields=_PID | grep '^_PID=' >/output
 grep -q "^_PID=$PID" /output
 grep -vq "^_PID=$PID" /output
 
+# https://github.com/systemd/systemd/issues/15654
+ID=$(journalctl --new-id128 | sed -n 2p)
+printf "This will\nusually fail\nand be truncated\n">/expected
+systemd-cat -t "$ID" /bin/sh -c 'env echo -n "This will";echo;env echo -n "usually fail";echo;env echo -n "and be truncated";echo;'
+journalctl --sync
+journalctl -b -o cat -t "$ID" >/output
+cmp /expected /output
+[[ $(journalctl -b -o cat -t "$ID" --output-fields=_TRANSPORT | grep -Pc "^stdout$") -eq 3 ]]
+[[ $(journalctl -b -o cat -t "$ID" --output-fields=_LINE_BREAK | grep -Pc "^pid-change$") -eq 3 ]]
+[[ $(journalctl -b -o cat -t "$ID" --output-fields=_PID | sort -u | grep -c "^.*$") -eq 3 ]]
+[[ $(journalctl -b -o cat -t "$ID" --output-fields=MESSAGE | grep -Pc "^(This will|usually fail|and be truncated)$") -eq 3 ]]
+
 # Add new tests before here, the journald restarts below
 # may make tests flappy.
 
@@ -106,4 +118,7 @@ systemctl kill --signal=SIGKILL systemd-journald
 sleep 3
 [[ ! -f "/i-lose-my-logs" ]]
 
+# https://github.com/systemd/systemd/issues/15528
+journalctl --follow --file=/var/log/journal/*/* | head -n1 || [[ $? -eq 1 ]]
+
 touch /testok
diff --git a/test/units/testsuite-38-sleep.service b/test/units/testsuite-38-sleep.service
new file mode 100644 (file)
index 0000000..859f97b
--- /dev/null
@@ -0,0 +1,2 @@
+[Service]
+ExecStart=/bin/sleep 3600
diff --git a/test/units/testsuite-38.service b/test/units/testsuite-38.service
new file mode 100644 (file)
index 0000000..c848840
--- /dev/null
@@ -0,0 +1,6 @@
+[Unit]
+Description=TEST-38-FREEZER
+
+[Service]
+ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh
+Type=oneshot
diff --git a/test/units/testsuite-38.sh b/test/units/testsuite-38.sh
new file mode 100755 (executable)
index 0000000..6fcadb8
--- /dev/null
@@ -0,0 +1,293 @@
+#!/usr/bin/env bash
+
+set -ex
+set -o pipefail
+
+systemd-analyze log-level debug
+systemd-analyze log-target console
+
+unit=testsuite-38-sleep.service
+
+start_test_service() {
+    systemctl daemon-reload
+    systemctl start "${unit}"
+}
+
+dbus_freeze() {
+    local suffix=
+    suffix="${1##*.}"
+
+    local name="$(echo ${1%.$suffix} | sed s/-/_2d/g)"
+    local object_path="/org/freedesktop/systemd1/unit/${name}_2e${suffix}"
+
+    busctl call \
+           org.freedesktop.systemd1 \
+           "${object_path}" \
+           org.freedesktop.systemd1.Unit \
+           Freeze
+}
+
+dbus_thaw() {
+    local suffix=
+    suffix="${1##*.}"
+
+    local name="$(echo ${1%.$suffix} | sed s/-/_2d/g)"
+    local object_path="/org/freedesktop/systemd1/unit/${name}_2e${suffix}"
+
+    busctl call \
+           org.freedesktop.systemd1 \
+           "${object_path}" \
+           org.freedesktop.systemd1.Unit \
+           Thaw
+}
+
+dbus_freeze_unit() {
+    busctl call \
+           org.freedesktop.systemd1 \
+           /org/freedesktop/systemd1 \
+           org.freedesktop.systemd1.Manager \
+           FreezeUnit \
+           s \
+           "$1"
+}
+
+dbus_thaw_unit() {
+    busctl call \
+           org.freedesktop.systemd1 \
+           /org/freedesktop/systemd1 \
+           org.freedesktop.systemd1.Manager \
+           ThawUnit \
+           s \
+           "$1"
+}
+
+dbus_can_freeze() {
+    local suffix=
+    suffix="${1##*.}"
+
+    local name="$(echo ${1%.$suffix} | sed s/-/_2d/g)"
+    local object_path="/org/freedesktop/systemd1/unit/${name}_2e${suffix}"
+
+    busctl get-property \
+           org.freedesktop.systemd1 \
+           "${object_path}" \
+           org.freedesktop.systemd1.Unit \
+           CanFreeze
+}
+
+check_freezer_state() {
+    local suffix=
+    suffix="${1##*.}"
+
+    local name="$(echo ${1%.$suffix} | sed s/-/_2d/g)"
+    local object_path="/org/freedesktop/systemd1/unit/${name}_2e${suffix}"
+
+    state=$(busctl get-property \
+                   org.freedesktop.systemd1 \
+                   "${object_path}" \
+                   org.freedesktop.systemd1.Unit \
+                   FreezerState | cut -d " " -f2 | tr -d '"')
+
+    [ "$state" = "$2" ] || {
+        echo "error: unexpected freezer state, expected: $2, actual: $state" >&2
+        exit 1
+    }
+}
+
+check_cgroup_state() {
+    grep -q "frozen $2" /sys/fs/cgroup/system.slice/"$1"/cgroup.events
+}
+
+test_dbus_api() {
+    echo "Test that DBus API works:"
+    echo -n "  - Freeze(): "
+    dbus_freeze "${unit}"
+    check_freezer_state "${unit}" "frozen"
+    check_cgroup_state "$unit" 1
+    echo "[ OK ]"
+
+    echo -n "  - Thaw(): "
+    dbus_thaw "${unit}"
+    check_freezer_state "${unit}" "running"
+    check_cgroup_state "$unit" 0
+    echo "[ OK ]"
+
+    echo -n "  - FreezeUnit(): "
+    dbus_freeze_unit "${unit}"
+    check_freezer_state "${unit}" "frozen"
+    check_cgroup_state "$unit" 1
+    echo "[ OK ]"
+
+    echo -n "  - ThawUnit(): "
+    dbus_thaw_unit "${unit}"
+    check_freezer_state "${unit}" "running"
+    check_cgroup_state "$unit" 0
+    echo "[ OK ]"
+
+    echo -n "  - CanFreeze(): "
+    output=$(dbus_can_freeze "${unit}")
+    [ "$output" = "b true" ]
+    echo "[ OK ]"
+
+    echo
+}
+
+test_jobs() {
+    local pid_before=
+    local pid_after=
+    echo "Test that it is possible to apply jobs on frozen units:"
+
+    systemctl start "${unit}"
+    dbus_freeze "${unit}"
+    check_freezer_state "${unit}" "frozen"
+
+    echo -n "  - restart: "
+    pid_before=$(systemctl show -p MainPID "${unit}" --value)
+    systemctl restart "${unit}"
+    pid_after=$(systemctl show -p MainPID "${unit}" --value)
+    [ "$pid_before" != "$pid_after" ] && echo "[ OK ]"
+
+    dbus_freeze "${unit}"
+    check_freezer_state "${unit}" "frozen"
+
+    echo -n "  - stop: "
+    timeout 5s systemctl stop "${unit}"
+    echo "[ OK ]"
+
+    echo
+}
+
+test_systemctl() {
+    echo "Test that systemctl freeze/thaw verbs:"
+
+    systemctl start "$unit"
+
+    echo -n "  - freeze: "
+    systemctl freeze "$unit"
+    check_freezer_state "${unit}" "frozen"
+    check_cgroup_state "$unit" 1
+    # Freezing already frozen unit should be NOP and return quickly
+    timeout 3s systemctl freeze "$unit"
+    echo "[ OK ]"
+
+    echo -n "  - thaw: "
+    systemctl thaw "$unit"
+    check_freezer_state "${unit}" "running"
+    check_cgroup_state "$unit" 0
+    # Likewise thawing already running unit shouldn't block
+    timeout 3s systemctl thaw "$unit"
+    echo "[ OK ]"
+
+    systemctl stop "$unit"
+
+    echo
+}
+
+test_systemctl_show() {
+    echo "Test systemctl show integration:"
+
+    systemctl start "$unit"
+
+    echo -n "  - FreezerState property: "
+    state=$(systemctl show -p FreezerState --value "$unit")
+    [ "$state" = "running" ]
+    systemctl freeze "$unit"
+    state=$(systemctl show -p FreezerState --value "$unit")
+    [ "$state" = "frozen" ]
+    systemctl thaw "$unit"
+    echo "[ OK ]"
+
+    echo -n "  - CanFreeze property: "
+    state=$(systemctl show -p CanFreeze --value "$unit")
+    [ "$state" = "yes" ]
+    echo "[ OK ]"
+
+    systemctl stop "$unit"
+    echo
+}
+
+test_recursive() {
+    local slice="bar.slice"
+    local unit="baz.service"
+
+    systemd-run --unit "$unit" --slice "$slice" sleep 3600 >/dev/null 2>&1
+
+    echo "Test recursive freezing:"
+
+    echo -n "  - freeze: "
+    systemctl freeze "$slice"
+    check_freezer_state "${slice}" "frozen"
+    check_freezer_state "${unit}" "frozen"
+    grep -q "frozen 1" /sys/fs/cgroup/"${slice}"/cgroup.events
+    grep -q "frozen 1" /sys/fs/cgroup/"${slice}"/"${unit}"/cgroup.events
+    echo "[ OK ]"
+
+    echo -n "  - thaw: "
+    systemctl thaw "$slice"
+    check_freezer_state "${unit}" "running"
+    check_freezer_state "${slice}" "running"
+    grep -q "frozen 0" /sys/fs/cgroup/"${slice}"/cgroup.events
+    grep -q "frozen 0" /sys/fs/cgroup/"${slice}"/"${unit}"/cgroup.events
+    echo "[ OK ]"
+
+    systemctl stop "$unit"
+    systemctl stop "$slice"
+
+    echo
+}
+
+test_preserve_state() {
+    local slice="bar.slice"
+    local unit="baz.service"
+
+    systemd-run --unit "$unit" --slice "$slice" sleep 3600 >/dev/null 2>&1
+
+    echo "Test that freezer state is preserved when recursive freezing is initiated from outside (e.g. by manager up the tree):"
+
+    echo -n "  - freeze from outside: "
+    echo 1 > /sys/fs/cgroup/"${slice}"/cgroup.freeze
+
+    # Our state should not be affected
+    check_freezer_state "${slice}" "running"
+    check_freezer_state "${unit}" "running"
+
+    # However actual kernel state should be frozen
+    grep -q "frozen 1" /sys/fs/cgroup/"${slice}"/cgroup.events
+    grep -q "frozen 1" /sys/fs/cgroup/"${slice}"/"${unit}"/cgroup.events
+    echo "[ OK ]"
+
+    echo -n "  - thaw from outside: "
+    echo 0 > /sys/fs/cgroup/"${slice}"/cgroup.freeze
+    check_freezer_state "${unit}" "running"
+    check_freezer_state "${slice}" "running"
+    grep -q "frozen 0" /sys/fs/cgroup/"${slice}"/cgroup.events
+    grep -q "frozen 0" /sys/fs/cgroup/"${slice}"/"${unit}"/cgroup.events
+    echo "[ OK ]"
+
+    echo -n "  - thaw from outside while inner service is frozen: "
+    systemctl freeze "$unit"
+    check_freezer_state "${unit}" "frozen"
+    echo 1 > /sys/fs/cgroup/"${slice}"/cgroup.freeze
+    echo 0 > /sys/fs/cgroup/"${slice}"/cgroup.freeze
+    check_freezer_state "${slice}" "running"
+    check_freezer_state "${unit}" "frozen"
+    echo "[ OK ]"
+
+    systemctl stop "$unit"
+    systemctl stop "$slice"
+
+    echo
+}
+
+test -e /sys/fs/cgroup/system.slice/cgroup.freeze && {
+    start_test_service
+    test_dbus_api
+    test_systemctl
+    test_systemctl_show
+    test_jobs
+    test_recursive
+    test_preserve_state
+}
+
+echo OK > /testok
+exit 0
index e77f46d06b77fbe3fbe2514db07d60849c6e9f0a..0a9582d8b96456d7c0d19b55769fe1efd603915b 100644 (file)
@@ -8,6 +8,7 @@ tmpfiles = [['home.conf',            ''],
             ['systemd-nspawn.conf',  'ENABLE_MACHINED'],
             ['systemd-tmp.conf',     ''],
             ['portables.conf',       'ENABLE_PORTABLED'],
+            ['systemd-pstore.conf',  'ENABLE_PSTORE'],
             ['tmp.conf',             ''],
             ['x11.conf',             ''],
             ['legacy.conf',          'HAVE_SYSV_COMPAT'],
diff --git a/tmpfiles.d/systemd-pstore.conf b/tmpfiles.d/systemd-pstore.conf
new file mode 100644 (file)
index 0000000..cb600ec
--- /dev/null
@@ -0,0 +1,29 @@
+# SPDX-License-Identifier: LGPL-2.1+
+#
+# The systemd-pstore.service(1) archives the contents of /sys/fs/pstore
+# upon boot so that there is room for a subsequent dump. This service
+# is enabled with:
+#  systemctl enable systemd-pstore
+#
+# With the service enabled, the kernel still needs to be configured
+# to write data into the pstore. The kernel has two parameters,
+# crash_kexec_post_notifiers and printk.always_kmsg_dump, that
+# control writes into pstore.
+#
+# The crash_kexec_post_notifiers parameter enables the kernel to write
+# dmesg (including stack trace) into pstore upon a panic, and
+# printk.always_kmsg_dump parameter enables the kernel to write dmesg
+# upon a normal shutdown (shutdown, reboot, halt).
+#
+# To configure the kernel parameters, uncomment the appropriate
+# line(s) below. The value written is either 'Y' to enable the
+# kernel parameter, or 'N' to disable the kernel parameter.
+#
+# After making a change to this file, do:
+#  systemd-tmpfiles --create path/to/tmpfiles.d/systemd-pstore.conf
+#
+# These changes are automatically applied on future re-boots.
+
+d /var/lib/systemd/pstore 0755 root root 14d
+#w /sys/module/printk/parameters/always_kmsg_dump - - - - Y
+w /sys/module/kernel/parameters/crash_kexec_post_notifiers - - - - Y
index ae00c8cab28d6c079cc2c8d7c83eb02d7ebba0c2..b04281490d6089ee4726ca6af5397f21659ffd4c 100755 (executable)
@@ -7,198 +7,6 @@ import re
 from xml_helper import xml_parse, xml_print, tree
 from copy import deepcopy
 
-TEMPLATE = '''\
-<refentry id="systemd.directives" conditional="HAVE_PYTHON">
-
-        <refentryinfo>
-                <title>systemd.directives</title>
-                <productname>systemd</productname>
-        </refentryinfo>
-
-        <refmeta>
-                <refentrytitle>systemd.directives</refentrytitle>
-                <manvolnum>7</manvolnum>
-        </refmeta>
-
-        <refnamediv>
-                <refname>systemd.directives</refname>
-                <refpurpose>Index of configuration directives</refpurpose>
-        </refnamediv>
-
-        <refsect1>
-                <title>Unit directives</title>
-
-                <para>Directives for configuring units, used in unit
-                files.</para>
-
-                <variablelist id='unit-directives' />
-        </refsect1>
-
-        <refsect1>
-                <title>Options on the kernel command line</title>
-
-                <para>Kernel boot options for configuring the behaviour of the
-                systemd process.</para>
-
-                <variablelist id='kernel-commandline-options' />
-        </refsect1>
-
-        <refsect1>
-                <title>Environment variables</title>
-
-                <para>Environment variables understood by the systemd manager
-                and other programs and environment variable-compatible settings.</para>
-
-                <variablelist id='environment-variables' />
-        </refsect1>
-
-        <refsect1>
-                <title>EFI variables</title>
-
-                <para>EFI variables understood by
-                <citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry>
-                and other programs.</para>
-
-                <variablelist id='efi-variables' />
-        </refsect1>
-
-        <refsect1>
-                <title>UDEV directives</title>
-
-                <para>Directives for configuring systemd units through the
-                udev database.</para>
-
-                <variablelist id='udev-directives' />
-        </refsect1>
-
-        <refsect1>
-                <title>Network directives</title>
-
-                <para>Directives for configuring network links through the
-                net-setup-link udev builtin and networks through
-                systemd-networkd.</para>
-
-                <variablelist id='network-directives' />
-        </refsect1>
-
-        <refsect1>
-                <title>Journal fields</title>
-
-                <para>Fields in the journal events with a well known meaning.</para>
-
-                <variablelist id='journal-directives' />
-        </refsect1>
-
-        <refsect1>
-                <title>PAM configuration directives</title>
-
-                <para>Directives for configuring PAM behaviour.</para>
-
-                <variablelist id='pam-directives' />
-        </refsect1>
-
-        <refsect1>
-                <title><filename>/etc/crypttab</filename> and
-                <filename>/etc/fstab</filename> options</title>
-
-                <para>Options which influence mounted filesystems and
-                encrypted volumes.</para>
-
-                <variablelist id='fstab-options' />
-        </refsect1>
-
-        <refsect1>
-                <title><citerefentry><refentrytitle>systemd.nspawn</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-                directives</title>
-
-                <para>Directives for configuring systemd-nspawn containers.</para>
-
-                <variablelist id='nspawn-directives' />
-        </refsect1>
-
-        <refsect1>
-                <title>Program configuration options</title>
-
-                <para>Directives for configuring the behaviour of the
-                systemd process and other tools through configuration files.</para>
-
-                <variablelist id='config-directives' />
-        </refsect1>
-
-        <refsect1>
-                <title>Command line options</title>
-
-                <para>Command-line options accepted by programs in the
-                systemd suite.</para>
-
-                <variablelist id='options' />
-        </refsect1>
-
-        <refsect1>
-                <title>Constants</title>
-
-                <para>Various constant used and/or defined by systemd.</para>
-
-                <variablelist id='constants' />
-        </refsect1>
-
-        <refsect1>
-                <title>Miscellaneous options and directives</title>
-
-                <para>Other configuration elements which don't fit in
-                any of the above groups.</para>
-
-                <variablelist id='miscellaneous' />
-        </refsect1>
-
-        <refsect1>
-                <title>Files and directories</title>
-
-                <para>Paths and file names referred to in the
-                documentation.</para>
-
-                <variablelist id='filenames' />
-        </refsect1>
-
-        <refsect1>
-                <title>D-Bus interfaces</title>
-
-                <para>Interfaces exposed over D-Bus.</para>
-
-                <variablelist id='dbus-interface' />
-        </refsect1>
-
-        <refsect1>
-                <title>D-Bus methods</title>
-
-                <para>Methods exposed in the D-Bus interface.</para>
-
-                <variablelist id='dbus-method' />
-        </refsect1>
-
-        <refsect1>
-                <title>D-Bus properties</title>
-
-                <para>Properties exposed in the D-Bus interface.</para>
-
-                <variablelist id='dbus-property' />
-        </refsect1>
-
-        <refsect1>
-                <title>D-Bus signals</title>
-
-                <para>Signals emitted in the D-Bus interface.</para>
-
-                <variablelist id='dbus-signal' />
-        </refsect1>
-
-        <refsect1>
-                <title>Colophon</title>
-                <para id='colophon' />
-        </refsect1>
-</refentry>
-'''
-
 COLOPHON = '''\
 This index contains {count} entries in {sections} sections,
 referring to {pages} individual manual pages.
@@ -279,6 +87,18 @@ def _extract_directives(directive_groups, formatting, page):
         storfile[name.text].append((pagename, section))
         formatting[name.text] = name
 
+    storfile = directive_groups['specifiers']
+    for name in t.iterfind(".//table[@class='specifiers']//entry/literal"):
+        if name.text[0] != '%' or name.getparent().text is not None:
+            continue
+        if name.attrib.get('index') == 'false':
+            continue
+        storfile[name.text].append((pagename, section))
+        formatting[name.text] = name
+    for name in t.iterfind(".//literal[@class='specifiers']"):
+        storfile[name.text].append((pagename, section))
+        formatting[name.text] = name
+
 def _make_section(template, name, directives, formatting):
     varlist = template.find(".//*[@id='{}']".format(name))
     for varname, manpages in sorted(directives.items()):
@@ -330,9 +150,9 @@ def _make_page(template, directive_groups, formatting):
 
     return template
 
-def make_page(*xml_files):
+def make_page(template_path, xml_files):
     "Extract directives from xml_files and return XML index tree."
-    template = tree.fromstring(TEMPLATE)
+    template = xml_parse(template_path)
     names = [vl.get('id') for vl in template.iterfind('.//variablelist')]
     directive_groups = {name:collections.defaultdict(list)
                         for name in names}
@@ -347,4 +167,7 @@ def make_page(*xml_files):
 
 if __name__ == '__main__':
     with open(sys.argv[1], 'wb') as f:
-        f.write(xml_print(make_page(*sys.argv[2:])))
+        template_path = sys.argv[2]
+        xml_files = sys.argv[3:]
+        xml = make_page(template_path, xml_files)
+        f.write(xml_print(xml))
index 95a22bebfac3d38a49781a68c97c070b38a13b5c..f95faaaf22a809440c0a041d3d1994bb81bc7aa3 100755 (executable)
@@ -3,10 +3,10 @@
 
 import collections
 import sys
+import os
 import shlex
 import subprocess
 import io
-import pprint
 from lxml import etree
 
 PARSER = etree.XMLParser(no_network=True,
@@ -19,23 +19,6 @@ PRINT_ERRORS = True
 class NoCommand(Exception):
     pass
 
-def find_command(lines):
-    acc = []
-    for num, line in enumerate(lines):
-        # skip empty leading line
-        if num == 0 and not line:
-            continue
-        cont = line.endswith('\\')
-        if cont:
-            line = line[:-1].rstrip()
-        acc.append(line if not acc else line.lstrip())
-        if not cont:
-            break
-    joined = ' '.join(acc)
-    if not joined.startswith('$ '):
-        raise NoCommand
-    return joined[2:], lines[:num+1] + [''], lines[-1]
-
 BORING_INTERFACES = [
     'org.freedesktop.DBus.Peer',
     'org.freedesktop.DBus.Introspectable',
@@ -183,31 +166,27 @@ def xml_to_text(destination, xml, *, only_interface=None):
     return file.getvalue(), declarations, interfaces
 
 def subst_output(document, programlisting):
-    try:
-        cmd, prefix_lines, footer = find_command(programlisting.text.splitlines())
-    except NoCommand:
+    executable = programlisting.get('executable', None)
+    if executable is None:
+        # Not our thing
         return
+    executable = programlisting.get('executable')
+    node = programlisting.get('node')
+    interface = programlisting.get('interface')
 
-    only_interface = programlisting.get('interface', None)
-
-    argv = shlex.split(cmd)
-    argv += ['--xml']
+    argv = [f'{build_dir}/{executable}', f'--bus-introspect={interface}']
     print(f'COMMAND: {shlex.join(argv)}')
 
-    object_idx = argv.index('--object-path')
-    object_path = argv[object_idx + 1]
-
     try:
         out = subprocess.check_output(argv, text=True)
-    except subprocess.CalledProcessError:
-        print('command failed, ignoring', file=sys.stderr)
+    except FileNotFoundError:
+        print(f'{executable} not found, ignoring', file=sys.stderr)
         return
 
     xml = etree.fromstring(out, parser=PARSER)
 
-    new_text, declarations, interfaces = xml_to_text(object_path, xml, only_interface=only_interface)
-
-    programlisting.text = '\n'.join(prefix_lines) + '\n' + new_text + footer
+    new_text, declarations, interfaces = xml_to_text(node, xml, only_interface=interface)
+    programlisting.text = '\n' + new_text + '    '
 
     if declarations:
         missing = check_documented(document, declarations)
@@ -291,5 +270,14 @@ def process(page):
 if __name__ == '__main__':
     pages = sys.argv[1:]
 
+    if pages[0].startswith('--build-dir='):
+        build_dir = pages[0].partition('=')[2]
+        pages = pages[1:]
+    else:
+        build_dir = 'build'
+
+    if not os.path.exists(f'{build_dir}/systemd'):
+        exit(f"{build_dir}/systemd doesn't exist. Use --build-dir=.")
+
     for page in pages:
         process(page)
similarity index 98%
rename from tools/make-man-rules.py
rename to tools/update-man-rules.py
index d86afcbc15ac9d115ac4c3c00c802ad5a5675760..c404579a2ad1754e704a0f7aa77138634d097098 100755 (executable)
@@ -50,7 +50,7 @@ def mjoin(files):
     return ' \\\n\t'.join(sorted(files) or '#')
 
 MESON_HEADER = '''\
-# Do not edit. Generated by make-man-rules.py.
+# Do not edit. Generated by update-man-rules.py.
 # Update with:
 #     ninja -C build man/update-man-rules
 manpages = ['''
index ac86e6274e0c86f2643a9abd3c44f758971d3a0f..2851d9229da57a416829f33781517c22d06f1e16 100755 (executable)
@@ -20,9 +20,12 @@ ADDITIONAL_DEPS=(python3-libevdev
                  clang
                  perl
                  libpwquality-dev
+                 fdisk
                  libfdisk-dev
                  libp11-kit-dev
-                 libssl-dev)
+                 libssl-dev
+                 libzstd-dev
+                 zstd)
 
 function info() {
     echo -e "\033[33;1m$1\033[0m"
index 3e78b2ef9abdc0f5ce4680ceeb4ac844551093c0..ca7fa6aab0666f1d0e00834c3a788dd6c32fdffb 100755 (executable)
@@ -22,11 +22,10 @@ cd $REPO_ROOT
 export PATH="$HOME/.local/bin/:$PATH"
 
 # We use a subset of https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#available-checks instead of "undefined"
-# because our fuzzers crash with "pointer-overflow" and "float-cast-overflow":
-# https://github.com/systemd/systemd/pull/12771#issuecomment-502139157
+# because our fuzzers crash with "float-cast-overflow":
 # https://github.com/systemd/systemd/pull/12812#issuecomment-502780455
 # TODO: figure out what to do about unsigned-integer-overflow: https://github.com/google/oss-fuzz/issues/910
-export SANITIZER="address -fsanitize=alignment,array-bounds,bool,bounds,builtin,enum,float-divide-by-zero,function,integer-divide-by-zero,nonnull-attribute,null,object-size,return,returns-nonnull-attribute,shift,signed-integer-overflow,unreachable,unsigned-integer-overflow,vla-bound,vptr -fno-sanitize-recover=alignment,array-bounds,bool,bounds,builtin,enum,float-divide-by-zero,function,integer-divide-by-zero,nonnull-attribute,null,object-size,return,returns-nonnull-attribute,shift,signed-integer-overflow,unreachable,vla-bound,vptr"
+export SANITIZER="address -fsanitize=alignment,array-bounds,bool,bounds,builtin,enum,float-divide-by-zero,function,integer-divide-by-zero,nonnull-attribute,null,object-size,pointer-overflow,return,returns-nonnull-attribute,shift,signed-integer-overflow,unreachable,unsigned-integer-overflow,vla-bound,vptr -fno-sanitize-recover=alignment,array-bounds,bool,bounds,builtin,enum,float-divide-by-zero,function,integer-divide-by-zero,nonnull-attribute,null,object-size,pointer-overflow,return,returns-nonnull-attribute,shift,signed-integer-overflow,unreachable,vla-bound,vptr"
 tools/oss-fuzz.sh
 
 FUZZING_TYPE=${1:-regression}
@@ -48,10 +47,30 @@ FUZZIT_ARGS="--type ${FUZZING_TYPE} --branch ${FUZZIT_BRANCH} --revision ${TRAVI
 wget -O fuzzit https://github.com/fuzzitdev/fuzzit/releases/latest/download/fuzzit_Linux_x86_64
 chmod +x fuzzit
 
-find out/ -maxdepth 1 -name 'fuzz-*' -executable -type f -exec basename '{}' \; | xargs --verbose -n1 -I%FUZZER% ./fuzzit create job ${FUZZIT_ARGS} %FUZZER%-asan-ubsan out/%FUZZER% ${FUZZIT_ADDITIONAL_FILES}
+# Simple wrapper which retries given command up to three times if it fails
+_retry() {
+    local EC=1
+
+    for _ in {0..2}; do
+        if "$@"; then
+            EC=0
+            break
+        fi
+
+        sleep 1
+    done
+
+    return $EC
+}
+
+find out/ -maxdepth 1 -name 'fuzz-*' -executable -type f -exec basename '{}' \; | while read -r fuzzer; do
+    _retry ./fuzzit create job ${FUZZIT_ARGS} ${fuzzer}-asan-ubsan out/${fuzzer} ${FUZZIT_ADDITIONAL_FILES}
+done
 
 export SANITIZER="memory -fsanitize-memory-track-origins"
 FUZZIT_ARGS="--type ${FUZZING_TYPE} --branch ${FUZZIT_BRANCH} --revision ${TRAVIS_COMMIT}"
 tools/oss-fuzz.sh
 
-find out/ -maxdepth 1 -name 'fuzz-*' -executable -type f -exec basename '{}' \; | xargs --verbose -n1 -I%FUZZER% ./fuzzit create job ${FUZZIT_ARGS} %FUZZER%-msan out/%FUZZER% ${FUZZIT_ADDITIONAL_FILES}
+find out/ -maxdepth 1 -name 'fuzz-*' -executable -type f -exec basename '{}' \; | while read -r fuzzer; do
+    _retry ./fuzzit create job ${FUZZIT_ARGS} ${fuzzer}-msan out/${fuzzer} ${FUZZIT_ADDITIONAL_FILES}
+done
index ba3abc29ea535017ce49f8cb4437c0db984fb6d0..a0677196deae0f15fbbadc0b2e0ace3f91199563 100644 (file)
@@ -24,15 +24,15 @@ units = [
         ['hibernate.target',                    'ENABLE_HIBERNATE'],
         ['hybrid-sleep.target',                 'ENABLE_HIBERNATE'],
         ['suspend-then-hibernate.target',       'ENABLE_HIBERNATE'],
-        ['initrd-cleanup.service',              ''],
-        ['initrd-fs.target',                    ''],
-        ['initrd-parse-etc.service',            ''],
-        ['initrd-root-device.target',           ''],
-        ['initrd-root-fs.target',               ''],
-        ['initrd-switch-root.service',          ''],
-        ['initrd-switch-root.target',           ''],
-        ['initrd-udevadm-cleanup-db.service',   ''],
-        ['initrd.target',                       ''],
+        ['initrd-cleanup.service',              'ENABLE_INITRD'],
+        ['initrd-fs.target',                    'ENABLE_INITRD'],
+        ['initrd-parse-etc.service',            'ENABLE_INITRD'],
+        ['initrd-root-device.target',           'ENABLE_INITRD'],
+        ['initrd-root-fs.target',               'ENABLE_INITRD'],
+        ['initrd-switch-root.service',          'ENABLE_INITRD'],
+        ['initrd-switch-root.target',           'ENABLE_INITRD'],
+        ['initrd-udevadm-cleanup-db.service',   'ENABLE_INITRD'],
+        ['initrd.target',                       'ENABLE_INITRD'],
         ['kexec.target',                        ''],
         ['ldconfig.service',                    'ENABLE_LDCONFIG',
          'sysinit.target.wants/'],
@@ -225,7 +225,7 @@ in_units = [
         ['systemd-user-sessions.service',        'HAVE_PAM',
          'multi-user.target.wants/'],
         ['systemd-vconsole-setup.service',       'ENABLE_VCONSOLE'],
-        ['systemd-volatile-root.service',        ''],
+        ['systemd-volatile-root.service',        'ENABLE_INITRD'],
         ['systemd-repart.service',               'ENABLE_REPART',
          'sysinit.target.wants/ initrd-root-fs.target.wants/'],
         ['user-runtime-dir@.service',            ''],
index 0c0f26451b675283ca749356430fb539c42e114d..e54e95e11d5daed387793670c3f850f65277bcb9 100644 (file)
@@ -28,4 +28,5 @@ ConditionDirectoryNotEmpty=|/run/binfmt.d
 Type=oneshot
 RemainAfterExit=yes
 ExecStart=@rootlibexecdir@/systemd-binfmt
+ExecStop=@rootlibexecdir@/systemd-binfmt --unregister
 TimeoutSec=90s
index ed573b8f3c7c7d9afab394f5ebddb0de64348a0f..0147b30e0db91804bf1a6f8ca0b741f0e3ce3320 100644 (file)
@@ -8,7 +8,7 @@
 #  (at your option) any later version.
 
 [Unit]
-Description=Login Service
+Description=User Login Management
 Documentation=man:systemd-logind.service(8) man:logind.conf(5)
 Documentation=https://www.freedesktop.org/wiki/Software/systemd/logind
 Documentation=https://www.freedesktop.org/wiki/Software/systemd/multiseat
index 27bd0f235cd621e6b51e03bdf49fb31f7e52338e..7066e522612514c1ad0dc92f71953fee1e322d50 100644 (file)
@@ -22,4 +22,4 @@ After=swap.target
 What=tmpfs
 Where=/tmp
 Type=tmpfs
-Options=mode=1777,strictatime,nosuid,nodev
+Options=mode=1777,strictatime,nosuid,nodev,size=10%,nr_inodes=400k