]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #22759 from msekletar/issue-18077-long-sysfs-paths-hashing
authorLennart Poettering <lennart@poettering.net>
Wed, 13 Apr 2022 20:21:38 +0000 (22:21 +0200)
committerGitHub <noreply@github.com>
Wed, 13 Apr 2022 20:21:38 +0000 (22:21 +0200)
Create "hashed" unit names from long paths

168 files changed:
NEWS
README
TODO
docs/CODE_QUALITY.md
docs/ENVIRONMENT.md
docs/HACKING.md
docs/RELEASE.md
docs/TRANSLATORS.md
man/libudev.xml
man/os-release.xml
man/rules/meson.build
man/sd-device.xml [new file with mode: 0644]
man/sd_bus_message_new.xml
man/sd_bus_new.xml
man/sd_bus_slot_ref.xml
man/sd_device_ref.xml [new file with mode: 0644]
man/sd_event_source_unref.xml
man/standard-specifiers.xml
man/systemd-cryptenroll.xml
man/systemd-integritysetup@.service.xml
man/systemd-run.xml
man/systemd-stub.xml
man/systemd-sysusers.xml
man/systemd.generator.xml
man/systemd.netdev.xml
man/systemd.unit.xml
man/udevadm.xml
meson.build
src/basic/chase-symlinks.c
src/basic/chase-symlinks.h
src/basic/coverage.h [new file with mode: 0644]
src/basic/devnum-util.c [new file with mode: 0644]
src/basic/devnum-util.h [new file with mode: 0644]
src/basic/glyph-util.c
src/basic/glyph-util.h
src/basic/macro.h
src/basic/meson.build
src/basic/missing_syscall_def.h
src/basic/missing_syscalls.py
src/basic/namespace-util.c
src/basic/parse-util.c
src/basic/parse-util.h
src/basic/path-util.c
src/basic/path-util.h
src/basic/stat-util.c
src/basic/stat-util.h
src/basic/syscall-list.txt
src/basic/syscalls-alpha.txt
src/basic/syscalls-arc.txt
src/basic/syscalls-arm.txt
src/basic/syscalls-arm64.txt
src/basic/syscalls-i386.txt
src/basic/syscalls-ia64.txt
src/basic/syscalls-loongarch64.txt
src/basic/syscalls-m68k.txt
src/basic/syscalls-mips64.txt
src/basic/syscalls-mips64n32.txt
src/basic/syscalls-mipso32.txt
src/basic/syscalls-powerpc.txt
src/basic/syscalls-powerpc64.txt
src/basic/syscalls-riscv32.txt
src/basic/syscalls-riscv64.txt
src/basic/syscalls-s390.txt
src/basic/syscalls-s390x.txt
src/basic/syscalls-sparc.txt
src/basic/syscalls-x86_64.txt
src/basic/terminal-util.c
src/boot/bless-boot.c
src/boot/bootctl.c
src/boot/efi/xbootldr.h
src/core/bpf-devices.c
src/core/cgroup.c
src/core/dbus-manager.c
src/core/dbus-service.c
src/core/dbus-unit.c
src/core/load-fragment.c
src/core/locale-setup.c
src/core/main.c
src/core/manager.c
src/core/namespace.c
src/core/unit-printf.c
src/creds/creds.c
src/dissect/dissect.c
src/gpt-auto-generator/gpt-auto-generator.c
src/hibernate-resume/hibernate-resume.c
src/home/homed-manager.c
src/home/homework-luks.c
src/home/homework-quota.c
src/journal-remote/journal-upload.c
src/libsystemd/sd-device/device-enumerator.c
src/libsystemd/sd-device/sd-device.c
src/libsystemd/sd-event/sd-event.c
src/login/logind-dbus.c
src/login/logind-session-dbus.c
src/login/logind-session.c
src/machine/machine-dbus.c
src/machine/machined-dbus.c
src/network/netdev/macsec.c
src/network/netdev/wireguard.c
src/network/networkd-manager.c
src/network/networkd-wiphy.h
src/nspawn/meson.build
src/nspawn/nspawn-oci.c
src/nspawn/nspawn-util.c [new file with mode: 0644]
src/nspawn/nspawn-util.h [new file with mode: 0644]
src/nspawn/nspawn.c
src/nspawn/test-nspawn-util.c [new file with mode: 0644]
src/partition/growfs.c
src/partition/repart.c
src/partition/test-repart.sh
src/portable/portable.c
src/resolve/resolved-conf.c
src/resolve/resolved-dns-search-domain.c
src/resolve/resolved-dnssd.c
src/shared/blockdev-util.c
src/shared/bootspec.c
src/shared/btrfs-util.c
src/shared/bus-unit-util.c
src/shared/conf-parser.c
src/shared/discover-image.c
src/shared/dissect-image.c
src/shared/dissect-image.h
src/shared/find-esp.c
src/shared/loop-util.c
src/shared/meson.build
src/shared/parse-helpers.c [moved from src/shared/parse-socket-bind-item.c with 66% similarity]
src/shared/parse-helpers.h [new file with mode: 0644]
src/shared/parse-socket-bind-item.h [deleted file]
src/shared/quota-util.c
src/shared/quota-util.h
src/shared/sleep-config.c
src/shared/specifier.c
src/shared/specifier.h
src/sysext/sysext.c
src/sysupdate/sysupdate-resource.c
src/sysupdate/sysupdate-transfer.c
src/test/meson.build
src/test/test-devnum-util.c [new file with mode: 0644]
src/test/test-locale-util.c
src/test/test-loop-block.c
src/test/test-parse-helpers.c [moved from src/test/test-parse-socket-bind-item.c with 99% similarity]
src/test/test-parse-util.c
src/test/test-path-util.c
src/test/test-specifier.c
src/test/test-stat-util.c
src/test/test-unit-name.c
src/timedate/timedated.c
src/timesync/meson.build
src/timesync/org.freedesktop.timesync1.conf
src/timesync/org.freedesktop.timesync1.policy [new file with mode: 0644]
src/timesync/timesyncd-bus.c
src/timesync/timesyncd-manager.c
src/timesync/timesyncd-manager.h
src/timesync/timesyncd-server.c
src/timesync/timesyncd-server.h
src/tmpfiles/tmpfiles.c
src/udev/net/link-config.c
src/udev/udev-builtin-input_id.c
src/udev/udev-builtin-net_id.c
src/udev/udev-builtin.c
src/udev/udev-builtin.h
src/udev/udev-node.c
src/udev/udevadm-info.c
src/udev/udevadm-lock.c
src/udev/udevd.c
src/volatile-root/volatile-root.c
test/networkd-test.py
test/udev-test.pl

diff --git a/NEWS b/NEWS
index c01bcdab45eaebc638dad49667a029a39931dbf5..330d46d1d12c7f7d3a8b2a0fc4b92f413dfc4d55 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -239,7 +239,7 @@ CHANGES WITH 251:
           normalized unit file path, which is particularly useful for symlinked
           unit files.
 
-          The new %R specifier resolves to the pretty hostname
+          The new %q specifier resolves to the pretty hostname
           (i.e. PRETTY_HOSTNAME= from /etc/machine-info).
 
           The new %d specifier resolves to the credentials directory of a
diff --git a/README b/README
index 6eaba9b0f1eaa390612daadbba34dfa862cf0ce2..f75fb9d5a5261c82fb52c79207af2909a89051d0 100644 (file)
--- a/README
+++ b/README
@@ -37,6 +37,7 @@ REQUIREMENTS:
                      ≥ 4.10 for cgroup-bpf egress and ingress hooks
                      ≥ 4.15 for cgroup-bpf device hook and cpu controller in cgroup v2
                      ≥ 4.17 for cgroup-bpf socket address hooks
+                     ≥ 4.20 for PSI (used by systemd-oomd)
                      ≥ 5.3 for bounded loops in BPF program
                      ≥ 5.4 for signed Verity images
                      ≥ 5.7 for BPF links and the BPF LSM hook
@@ -206,7 +207,7 @@ REQUIREMENTS:
         python-jinja2
         python-lxml (optional, required to build the indices)
         python >= 3.5
-        meson >= 0.53.2 (>= 0.54.0 is required to build with 'meson compile')
+        meson >= 0.53.2
         ninja
         gcc, awk, sed, grep, and similar tools
         clang >= 10.0, llvm >= 10.0 (optional, required to build BPF programs
@@ -224,7 +225,7 @@ REQUIREMENTS:
         polkit (optional)
 
         To build in directory build/:
-          meson setup build/ && meson compile -C build/
+          meson setup build/ && ninja -C build/
 
         Any configuration options can be specified as -Darg=value... arguments
         to meson. After the build directory is initially configured, meson will
@@ -234,13 +235,13 @@ REQUIREMENTS:
         their current values.
 
         Useful commands:
-          meson compile -v -C build/ some/target
+          ninja -C build -v some/target
           meson test -C build/
           sudo meson install -C build/
           DESTDIR=... meson install -C build/
 
         A tarball can be created with:
-          git archive --format=tar --prefix=systemd-222/ v222 | xz > systemd-222.tar.xz
+          v=250 && git archive --prefix=systemd-$v/ v$v | zstd >systemd-$v.tar.zstd
 
         When systemd-hostnamed is used, it is strongly recommended to
         install nss-myhostname to ensure that, in a world of
diff --git a/TODO b/TODO
index 05bbb0f31c0e7027dcc5927845ea6edcf5bef116..678146c3e92ec2d1abd8af01ae30f04c08d56c7f 100644 (file)
--- a/TODO
+++ b/TODO
@@ -78,6 +78,47 @@ Janitorial Clean-ups:
 
 Features:
 
+* systemd-fstab-generator: support addition mount specifications via kernel
+  cmdline. Usecase: invoke a VM, and mount a host homedir into it via
+  virtio-fs.
+
+* for vendor-built signed initrds:
+  - make sysext run in the initrd
+  - sysext should pick up sysext images from /.extra/ in the initrd, and insist
+    on verification if in secureboot mode
+  - kernel-install should be able to install pre-built unified kernel images in
+    type #2 drop-in dir in the ESP.
+  - kernel-install should be able install encrypted creds automatically for
+    machine id, root pw, rootfs uuid, resume partition uuid, and place next to
+    EFI kernel, for sd-stub to pick them up. These creds should be locked to
+    the TPM, and bind to the right PCR the kernel is measured to.
+  - kernel-install should be able to pick up initrd sysexts automatically and
+    place them next to EFI kernel, for sd-stub to pick them up.
+  - systemd-fstab-generator should look for rootfs device to mount in creds
+  - pid 1 should look for machine ID in creds
+  - systemd-resume-generator should look for resume partition uuid in creds
+  - sd-stub: automatically pick up microcode from ESP (/loader/microcode/*)
+    and synthesize initrd from it, and measure it. Signing is not necessary, as
+    microcode does that on its own. Pass as first initrd to kernel.
+  - systemd-creds should have a fallback logic that uses neither TPM nor the
+    system key in /var for encryption and instead some fixed key. This should
+    be opt in (since it provides no security properties) but be used by
+    kernel-install when encrypting the creds it generates on systems that lack
+    a TPM, so that we can have very similar codepaths on TPM and TPM-less
+    systems. i.e. --with-key=tpm-graceful or so.
+
+* Add a new service type very similar to Type=notify, that goes one step
+  further and extends the protocol to cover reloads. Specifically, SIGHUP will
+  become the official way to reload, and daemon has to respond with sd_notify()
+  to report when it starts reloading, and when it is complete reloading. Care
+  must be taken to remove races from this model. I.e. PID 1 needs to take
+  CLOCK_MONOTONIC, then send SIGHUP, then wait for at least one RELOADING=1
+  message that comes with a newer timestamp, then wait for a READY=1 message.
+  while we are at it, also maybe extend the logic to require handling of some
+  specific SIGRT signal for setting debug log level, that carries the level via
+  the sigqueue() data parameter. With that we extended with minimal logic the
+  service runtime logic quite substantially.
+
 * get_color_mode() should probably check the $COLORTERM environment variable
   which most terminal environments appear to set.
 
@@ -99,7 +140,7 @@ Features:
 * mirroring this: maybe support binding to AV_VSOCK in Type=notify services,
   then passing $NOTIFY_SOCKET and $NOTIFY_GUESTCID with PID1's cid (typically
   fixed to "2", i.e. the official host cid) and the expected guest cid, for the
-  two sides of the channe. The latter env var could then be used in an
+  two sides of the channel. The latter env var could then be used in an
   appropriate qemu cmdline. That way qemu payloads could talk sd_notify()
   directly to host service manager.
 
@@ -123,17 +164,8 @@ Features:
   sd_device object, so that data passed into sd_device_new_from_devnum() can
   also be queried.
 
-* udevadm: a new "tree" verb that shows tree of devices as syspath hierarchy,
-  along with their properties. uninitialized devices should be greyed out.
-
 * bootctl: show whether UEFI audit mode is available
 
-* dissect: rework how we access partitions: instead of letting the kernel probe
-  partition tables asynchronously, just pass the stuff we parsed in userspace
-  to the kernel via BLKPG_ADD_PARTITION. Benefit: we don't have to wait for
-  kernel/netlink/udev, but can run this synchronously without chance of losing
-  events or similar.
-
 * sd-event: optionally, if per-event source rate limit is hit, downgrade
   priority, but leave enabled, and once ratelimit window is over, upgrade
   priority again. That way we can combat event source starvation without
@@ -303,7 +335,8 @@ Features:
   credential logic and drops them into /run where nss-systemd can pick them up,
   similar to /run/host/userdb/. Usecase: drop a root user JSON record there,
   and use it in the initrd to log in as root with locally selected password,
-  for debugging purposes.
+  for debugging purposes. Other usecase: boot into qemu with regular user
+  mounted from host. maybe put this in systemd-user-sessions.service?
 
 * drop dependency on libcap, replace by direct syscalls based on
   CapabilityQuintet we already have. (This likely allows us drop drop libcap
@@ -318,10 +351,6 @@ Features:
   to be taken that the resulting logic ends up in RAM, i.e. is copied out of
   on-disk storage.
 
-* sd-stub: automatically pick up microcode from ESP and synthesize initrd from
-  it, and measure it. Signing is not necessary, as microcode does that on its
-  own. Pass as first initrd to kernel.
-
 * userdbd: implement an additional varlink service socket that provides the
   host user db in restricted form, then allow this to be bind mounted into
   sandboxed environments that want the host database in minimal form. All
@@ -409,11 +438,6 @@ Features:
   https://github.com/dvdhrm/docs/blob/master/drm-howto/modeset.c for an example
   for doing that.
 
-* pass systemd-detect-virt result to generators as env var. Modifying behaviour
-  based on whether we are virtualized or not is a pretty common thing, hence
-  maybe just pass that info along for free in an env var. We cache the result
-  anyway, so it's basically free.
-
 * introduce /dev/disk/root/* symlinks that allow referencing partitions on the
   disk the rootfs is on in a reasonably secure way. (or maybe: add
   /dev/gpt-auto-{home,srv,boot,…} similar in style to /dev/gpt-auto-root as we
@@ -1465,7 +1489,7 @@ Features:
   specified, synthesize a definition automatically if we can: enlarge last
   partition on disk, but only if it is marked for growing and not read-only.
 
-* systemd-repart: read LUKS encryption key from $CREDENTIALS_PATH
+* systemd-repart: read LUKS encryption key from $CREDENTIALS_DIRECTORY
 
 * systemd-repart: add a switch to factory reset the partition table without
   immediately applying the new configuration again. i.e. --factory-reset=leave
index b1f7dd109ed904c8782957cadfd055d397ecfc0e..29dfdd8ae09f20b2456714a5b743b86f210ef625 100644 (file)
@@ -38,18 +38,19 @@ available functionality:
    `./tools/find-tabs.sh recpatch` to fix them. (Again, grain of salt, foreign
    headers should usually be left unmodified.)
 
-6. Use `meson compile -C build check-api-docs` to compare the list of exported
-   symbols of `libsystemd.so` and `libudev.so` with the list of man pages. Symbols
+6. Use `ninja -C build check-api-docs` to compare the list of exported symbols
+   of `libsystemd.so` and `libudev.so` with the list of man pages. Symbols
    lacking documentation are highlighted.
 
-7. Use `meson compile -C build update-hwdb` to automatically download and import the
-   PCI, USB and OUI databases into hwdb.
+7. Use `ninja -C build update-hwdb` and `ninja -C build update-hwdb-autosuspend`
+   to automatically download and import the PCI, USB, and OUI databases and the
+   autosuspend quirks into the hwdb.
 
-8. Use `meson compile -C build update-man-rules` to update the meson rules for
-   building man pages automatically from the docbook XML files included in
-   `man/`.
+8. Use `ninja -C build update-man-rules` to update the meson rules for building
+   man pages automatically from the docbook XML files included in `man/`.
 
-9. There are multiple CI systems in use that run on every github PR submission.
+9. There are multiple CI systems in use that run on every github pull request
+   submission or update.
 
 10. [Coverity](https://scan.coverity.com/) is analyzing systemd `main` branch
     in regular intervals. The reports are available
index 0cbe5cfb6bca7c70a7a085bfcd359a5ab39d7786..5f02f888a5ed3a8f61d4b981ecca5a4a82c0c490 100644 (file)
@@ -199,7 +199,7 @@ All tools:
   or whenever they change if it wants to integrate with `systemd-logind`'s
   APIs.
 
-`systemd-udevd`:
+`systemd-udevd` and sd-device library:
 
 * `$NET_NAMING_SCHEME=` — if set, takes a network naming scheme (i.e. one of
   "v238", "v239", "v240"…, or the special value "latest") as parameter. If
@@ -211,6 +211,10 @@ All tools:
   prefixed with `:` in which case the kernel command line option takes
   precedence, if it is specified as well.
 
+* `$SYSTEMD_DEVICE_VERIFY_SYSFS` — if set to "0", disables verification that
+  devices sysfs path are actually backed by sysfs. Relaxing this verification
+  is useful for testing purposes.
+
 `nss-systemd`:
 
 * `$SYSTEMD_NSS_BYPASS_SYNTHETIC=1` — if set, `nss-systemd` won't synthesize
index 4b334715c7eb3a6cd6d42d6e98f57f201f9348b8..f6b42297e0cb7268e37629890a47d2f87365bc6a 100644 (file)
@@ -95,16 +95,16 @@ for systemd:
 # available there or from the github repository otherwise)
 $ git clone https://github.com/systemd/systemd.git
 $ cd systemd
-$ git checkout -b <BRANCH>                # where BRANCH is the name of the branch
-$ vim src/core/main.c                     # or wherever you'd like to make your changes
-$ meson build                             # configure the build
-$ meson compile -C build                  # build it locally, see if everything compiles fine
-$ meson test -C build                     # run some simple regression tests
-$ sudo mkosi                              # build a test image
-$ sudo mkosi boot                         # boot up the test image
-$ git add -p                              # interactively put together your patch
-$ git commit                              # commit it
-$ git push -u <REMOTE>                    # where REMOTE is your "fork" on GitHub
+$ git checkout -b <BRANCH>        # where BRANCH is the name of the branch
+$ vim src/core/main.c             # or wherever you'd like to make your changes
+$ meson build                     # configure the build
+$ ninja -C build                  # build it locally, see if everything compiles fine
+$ meson test -C build             # run some simple regression tests
+$ sudo mkosi                      # build a test image
+$ sudo mkosi boot                 # boot up the test image
+$ git add -p                      # interactively put together your patch
+$ git commit                      # commit it
+$ git push -u <REMOTE>            # where REMOTE is your "fork" on GitHub
 ```
 
 And after that, head over to your repo on GitHub and click "Compare & pull request"
index c5da09b62cc34733380cad7a43ca193b598f2bd0..4a1f394aeeff90511654adb81165410409af927e 100644 (file)
@@ -8,17 +8,18 @@ SPDX-License-Identifier: LGPL-2.1-or-later
 # Steps to a Successful Release
 
 1. Add all items to NEWS
-2. Update the contributors list in NEWS (`meson compile -C build git-contrib`)
+2. Update the contributors list in NEWS (`ninja -C build git-contrib`)
 3. Update the time and place in NEWS
-4. Update hwdb (`meson compile -C build update-hwdb update-hwdb-autosuspend`)
-5. [RC1] Update version and library numbers in `meson.build`
-6. Check dbus docs with `meson compile -C build update-dbus-docs`
-7. Tag the release: `version=vXXX-rcY && git tag -s "${version}" -m "systemd ${version}"`
-8. Do `meson compile -C build`
-9. Make sure that the version string and package string match: `build/systemctl --version`
-10. Upload the documentation: `meson compile -C build doc-sync`
-11. [FINAL] Close the github milestone and open a new one (https://github.com/systemd/systemd/milestones)
-12. "Draft" a new release on github (https://github.com/systemd/systemd/releases/new), mark "This is a pre-release" if appropriate.
-13. Check that announcement to systemd-devel, with a copy&paste from NEWS, was sent. This should happen automatically.
-14. Update IRC topic (`/msg chanserv TOPIC #systemd Version NNN released`)
-15. [FINAL] Push commits to stable, create an empty -stable branch: `git push systemd-stable --atomic origin/main:main origin/main:refs/heads/${version}-stable`, and change the default branch to latest release (https://github.com/systemd/systemd-stable/settings/branches).
+4. Update hwdb (`ninja -C build update-hwdb`, `ninja -C build update-hwdb-autosuspend`, commit separately).
+5. Update syscall numbers (`ninja -C build update-syscall-tables update-syscall-headers`).
+6. [RC1] Update version and library numbers in `meson.build`
+7. Check dbus docs with `ninja -C build update-dbus-docs`
+8. Tag the release: `version=vXXX-rcY && git tag -s "${version}" -m "systemd ${version}"`
+9. Do `ninja -C build`
+10. Make sure that the version string and package string match: `build/systemctl --version`
+11. Upload the documentation: `ninja -C build doc-sync`
+12. [FINAL] Close the github milestone and open a new one (https://github.com/systemd/systemd/milestones)
+13. "Draft" a new release on github (https://github.com/systemd/systemd/releases/new), mark "This is a pre-release" if appropriate.
+14. Check that announcement to systemd-devel, with a copy&paste from NEWS, was sent. This should happen automatically.
+15. Update IRC topic (`/msg chanserv TOPIC #systemd Version NNN released`)
+16. [FINAL] Push commits to stable, create an empty -stable branch: `git push systemd-stable --atomic origin/main:main origin/main:refs/heads/${version}-stable`, and change the default branch to latest release (https://github.com/systemd/systemd-stable/settings/branches).
index 135f35793ba492b0a695487adefd0a3d001db479..58708bcd58ddb8f443a044a83ca51a5bc7096fd8 100644 (file)
@@ -27,7 +27,7 @@ To create a translation to a language not yet available, start by creating the
 initial template:
 
 ```
-$ meson compile -C build/ systemd-pot
+$ ninja -C build/ systemd-pot
 ```
 
 This will generate file `po/systemd.pot` in the source tree.
@@ -51,7 +51,7 @@ using the `poedit` GUI editor.)
 Start by updating the `*.po` files from the latest template:
 
 ```
-$ meson compile -C build/ systemd-update-po
+$ ninja -C build/ systemd-update-po
 ```
 
 This will touch all the `*.po` files, so you'll want to pay attention when
@@ -75,7 +75,7 @@ using `git checkout -- po/` after you commit the changes you do want to keep.)
 You can recompile the `*.po` files using the following command:
 
 ```
-$ meson compile -C build/ systemd-gmo
+$ ninja -C build/ systemd-gmo
 ```
 
 The resulting files will be saved in the `build/po/` directory.
index 4b87962fc0d231dcdc88abb96ebd0832d2f03747..8632ea94204266926733f2ff325bc6f6804bb073 100644 (file)
   <refsect1>
     <title>Description</title>
 
-    <para><filename>libudev.h</filename> provides APIs to introspect
-    and enumerate devices on the local system.</para>
+    <para><filename>libudev.h</filename> provides an API to introspect and enumerate devices on the local
+    system. This library is supported, but should not be used in new projects. Please see
+    <citerefentry><refentrytitle>sd-device</refentrytitle><manvolnum>3</manvolnum></citerefentry> for an
+    equivalent replacement with a more modern API.</para>
 
     <para>All functions require a libudev context to operate. This
     context can be create via
index 7e3e9a73a8cb70900ed0ff2c1b3a6c7896629b56..875ac946f04ed81a4108bf1919084fa02dbf436c 100644 (file)
       change between the build and the deployment phases, it is possible to relax this check: if exactly one
       file whose name matches <literal><filename>extension-release.*</filename></literal> is present in this
       directory, and the file is tagged with a <varname>user.extension-release.strict</varname>
-      <citerefentry><refentrytitle>xattr</refentrytitle><manvolnum>7</manvolnum></citerefentry> set to the
+      <citerefentry project='man-pages'><refentrytitle>xattr</refentrytitle><manvolnum>7</manvolnum></citerefentry> set to the
       string <literal>0</literal>, it will be used instead.</para>
 
       <para>The rest of this document that talks about <filename>os-release</filename> should be understood
@@ -499,14 +499,14 @@ VERSION_ID=32</programlisting>
 
     <example>
       <title>Reading <filename>os-release</filename> in
-      <citerefentry><refentrytitle>sh</refentrytitle><manvolnum>1</manvolnum></citerefentry></title>
+      <citerefentry project='man-pages'><refentrytitle>sh</refentrytitle><manvolnum>1</manvolnum></citerefentry></title>
 
       <programlisting><xi:include href="check-os-release.sh" parse="text" /></programlisting>
     </example>
 
     <example>
       <title>Reading <filename>os-release</filename> in
-      <citerefentry><refentrytitle>python</refentrytitle><manvolnum>1</manvolnum></citerefentry> (versions &gt;= 3.10)</title>
+      <citerefentry project='die-net'><refentrytitle>python</refentrytitle><manvolnum>1</manvolnum></citerefentry> (versions &gt;= 3.10)</title>
 
       <programlisting><xi:include href="check-os-release-simple.py" parse="text" /></programlisting>
 
@@ -517,7 +517,7 @@ VERSION_ID=32</programlisting>
 
     <example>
       <title>Reading <filename>os-release</filename> in
-      <citerefentry><refentrytitle>python</refentrytitle><manvolnum>1</manvolnum></citerefentry> (any version)</title>
+      <citerefentry project='die-net'><refentrytitle>python</refentrytitle><manvolnum>1</manvolnum></citerefentry> (any version)</title>
 
       <programlisting><xi:include href="check-os-release.py" parse="text" /></programlisting>
 
index add28a724cb76f27538e9c43fb0eebe4a36f06d7..55376c0ecc588eae11dd95e7ee2dc2b2b9664e9b 100644 (file)
@@ -117,6 +117,7 @@ manpages = [
    'SD_NOTICE',
    'SD_WARNING'],
   ''],
+ ['sd-device', '3', [], ''],
  ['sd-event', '3', [], ''],
  ['sd-hwdb', '3', [], ''],
  ['sd-id128',
@@ -515,6 +516,7 @@ manpages = [
    'sd_device_get_sysname',
    'sd_device_get_sysnum'],
   ''],
+ ['sd_device_ref', '3', ['sd_device_unref', 'sd_device_unrefp'], ''],
  ['sd_event_add_child',
   '3',
   ['sd_event_add_child_pidfd',
diff --git a/man/sd-device.xml b/man/sd-device.xml
new file mode 100644 (file)
index 0000000..7af839b
--- /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.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
+
+<refentry id="sd-device" xmlns:xi="http://www.w3.org/2001/XInclude">
+
+  <refentryinfo>
+    <title>sd-device</title>
+    <productname>systemd</productname>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>sd-device</refentrytitle>
+    <manvolnum>3</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>sd-device</refname>
+    <refpurpose>API for enumerating and introspecting local devices</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>#include &lt;systemd/sd-device.h&gt;</funcsynopsisinfo>
+    </funcsynopsis>
+
+    <cmdsynopsis>
+      <command>pkg-config --cflags --libs libsystemd</command>
+    </cmdsynopsis>
+
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para><filename>sd-device.h</filename> provides an API to introspect and enumerate devices on the local
+    system. It provides a programmatic interface to the database of devices and their properties mananaged by
+    <citerefentry><refentrytitle>systemd-udevd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+    This API is a replacement for
+    <citerefentry><refentrytitle>libudev</refentrytitle><manvolnum>3</manvolnum></citerefentry> and
+    <filename>libudev.h</filename>.</para>
+
+    <para>See
+    <literallayout><citerefentry><refentrytitle>sd_device_get_syspath</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_device_ref</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+</literallayout>
+    for more information about the functions available.</para>
+  </refsect1>
+
+  <xi:include href="libsystemd-pkgconfig.xml" />
+
+  <refsect1>
+    <title>See Also</title>
+    <para>
+      <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>udevadm</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+    </para>
+  </refsect1>
+
+</refentry>
index 4907c5a7559c66572d28634fe768f4507f790974..c56df615a6b0019b9efc037b5de2b7815ffcd905 100644 (file)
     <citerefentry><refentrytitle>sd_bus_message_set_allow_interactive_authorization</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
     </para>
 
-    <para><function>sd_bus_message_ref()</function> increases the reference counter of
+    <para><function>sd_bus_message_ref()</function> increases the internal reference counter of
     <parameter>m</parameter> by one.</para>
 
-    <para><function>sd_bus_message_unref()</function> decreases the reference counter of
+    <para><function>sd_bus_message_unref()</function> decreases the internal reference counter of
     <parameter>m</parameter> by one. Once the reference count has dropped to zero, message object is
-    destroyed and cannot be used anymore, so further calls to
-    <function>sd_bus_message_ref()</function> or <function>sd_bus_message_unref()</function> are
-    illegal.</para>
+    destroyed and cannot be used anymore, so further calls to <function>sd_bus_message_ref()</function> or
+    <function>sd_bus_message_unref()</function> are illegal.</para>
 
     <para><function>sd_bus_message_unrefp()</function> is similar to
     <function>sd_bus_message_unref()</function> but takes a pointer to a
index 355b34bad8e14be987d895cbcdd2d6bbf7ba97d2..41964640b6673caa8b9783a9e7d555e42d83ba33 100644 (file)
     pointer to an <type>sd_bus</type> object. This call is useful in
     conjunction with GCC's and LLVM's <ulink
     url="https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html">Clean-up
-    Variable Attribute</ulink>. Note that this function is defined as
+    Variable Attribute</ulink>. Note that this function is defined as an
     inline function. Use a declaration like the following, in order to
     allocate a bus object that is freed automatically as the code
     block is left:</para>
   …
 }</programlisting>
 
-    <para><function>sd_bus_ref()</function> and <function>sd_bus_unref()</function>
-    execute no operation if the passed in bus object address is
-    <constant>NULL</constant>. <function>sd_bus_unrefp()</function> will first
-    dereference its argument, which must not be <constant>NULL</constant>, and will
-    execute no operation if <emphasis>that</emphasis> is <constant>NULL</constant>.
-    </para>
+    <para><function>sd_bus_ref()</function> and <function>sd_bus_unref()</function> execute no operation if
+    the argument is <constant>NULL</constant>. <function>sd_bus_unrefp()</function> will first dereference
+    its argument, which must not be <constant>NULL</constant>, and will execute no operation if
+    <emphasis>that</emphasis> is <constant>NULL</constant>.</para>
 
     <para><function>sd_bus_close_unref()</function> is similar to <function>sd_bus_unref()</function>, but
     first executes
index c200bc4a5a9d89703731dc4e3287b50e2de08d9f..8ada3cbcf1ca389fa01cbc1f787d234b661d6ff0 100644 (file)
   <refsect1>
     <title>Description</title>
 
-    <para><function>sd_bus_slot_ref()</function> increases the reference counter of
+    <para><function>sd_bus_slot_ref()</function> increases the internal reference counter of
     <parameter>slot</parameter> by one.</para>
 
-    <para><function>sd_bus_slot_unref()</function> decreases the reference counter of
+    <para><function>sd_bus_slot_unref()</function> decreases the internal reference counter of
     <parameter>slot</parameter> by one. Once the reference count has dropped to zero, slot object is
     destroyed and cannot be used anymore, so further calls to <function>sd_bus_slot_ref()</function>
     or <function>sd_bus_slot_unref()</function> are illegal.</para>
diff --git a/man/sd_device_ref.xml b/man/sd_device_ref.xml
new file mode 100644 (file)
index 0000000..c2ba6b1
--- /dev/null
@@ -0,0 +1,83 @@
+<?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-or-later -->
+
+<refentry id="sd_device_ref" xmlns:xi="http://www.w3.org/2001/XInclude">
+  <refentryinfo>
+    <title>sd_device_ref</title>
+    <productname>systemd</productname>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>sd_device_ref</refentrytitle>
+    <manvolnum>3</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>sd_device_ref</refname>
+    <refname>sd_device_unref</refname>
+    <refname>sd_device_unrefp</refname>
+
+    <refpurpose>Create or destroy references to a device object</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>#include &lt;systemd/sd-device.h&gt;</funcsynopsisinfo>
+
+      <funcprototype>
+        <funcdef>sd_device* <function>sd_device_ref</function></funcdef>
+        <paramdef>sd_device *<parameter>device</parameter></paramdef>
+      </funcprototype>
+
+      <funcprototype>
+        <funcdef>sd_device* <function>sd_device_unref</function></funcdef>
+        <paramdef>sd_device *<parameter>device</parameter></paramdef>
+      </funcprototype>
+
+      <funcprototype>
+        <funcdef>void <function>sd_device_unrefp</function></funcdef>
+        <paramdef>sd_device **<parameter>device</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+
+    <para><function>sd_device_ref()</function> increases the internal reference counter of
+    <parameter>device</parameter> by one.</para>
+
+    <para><function>sd_device_unref()</function> decreases the internal reference counter of
+    <parameter>device</parameter> by one. Once the reference count has dropped to zero,
+    <parameter>device</parameter> is destroyed and cannot be used anymore, so further calls to
+    <function>sd_device_ref()</function> or <function>sd_device_unref()</function> are illegal.</para>
+
+    <para><function>sd_device_unrefp()</function> is similar to <function>sd_device_unref()</function> but
+    takes a pointer to a pointer to an <type>sd_device</type> object. This call is useful in conjunction with
+    GCC's and LLVM's <ulink url="https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html">Clean-up
+    Variable Attribute</ulink>. Note that this function is defined as an inline function. Use a declaration
+    like the following, in order to allocate a device object that is freed automatically as the code block is
+    left:</para>
+
+    <programlisting>{
+  __attribute__((cleanup(sd_device_unrefp))) sd_device *device = NULL;
+  int r;
+  …
+  r = sd_device_new_from_syspath(&amp;device, "…");
+  if (r &lt; 0)
+    fprintf(stderr, "Failed to allocate device: %s\n", strerror(-r));
+  …
+}</programlisting>
+
+    <para><function>sd_device_ref()</function> and <function>sd_device_unref()</function> execute no
+    operation if the argument is <constant>NULL</constant>. <function>sd_device_unrefp()</function> will
+    first dereference its argument, which must not be <constant>NULL</constant>, and will execute no
+    operation if <emphasis>that</emphasis> is <constant>NULL</constant>.</para>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Return Value</title>
+
+    <para><function>sd_device_ref()</function> always returns the argument, and
+    <function>sd_device_unref()</function> always returns <constant>NULL</constant>.
+    </para>
+  </refsect1>
+</refentry>
index a7699e354782a8e0e7ee87604e4a34b435185913..b626e4cf4a7d25f0661092a3ed5d42c16764f12e 100644 (file)
   <refsect1>
     <title>Description</title>
 
-    <para><function>sd_event_source_unref()</function> may be used to
-    decrement by one the reference counter of the event source object
-    specified as <parameter>source</parameter>. The reference counter
-    is initially set to one, when the event source is created with calls
-    such as
-    <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>
-    or
+    <para><function>sd_event_source_unref()</function> may be used to decrement by one the internal reference
+    counter of the event source object specified as <parameter>source</parameter>. The reference counter is
+    initially set to one, when the event source is created with calls such as
+    <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry> or
     <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>. When
-    the reference counter reaches zero it is removed from its event loop
-    object and destroyed.</para>
+    the reference counter reaches zero, the object is detached from the event loop object and destroyed.
+    </para>
 
     <para><function>sd_event_source_unrefp()</function> is similar to
     <function>sd_event_source_unref()</function> but takes a pointer to a
@@ -78,9 +75,8 @@
     Variable Attribute</ulink>. Note that this function is defined as
     inline function.</para>
 
-    <para><function>sd_event_source_ref()</function> may be used
-    to increase by one the reference counter of the event source object
-    specified as <parameter>source</parameter>.</para>
+    <para><function>sd_event_source_ref()</function> may be used to increase by one the internal reference
+    counter of the event source object specified as <parameter>source</parameter>.</para>
 
     <para><function>sd_event_source_unref()</function>,
     <function>sd_bus_creds_unrefp()</function> and
index abbd47f7782a65178863326cfd751b5c22184cfd..7aa7acaf600f45346bbbc0b0ab3a37fdb177d557 100644 (file)
@@ -4,6 +4,9 @@
 <!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
 
 <tbody>
+  <!-- note: units also use the following deprecated specifiers that are not documented:
+       %c, %r, %R. Do not reuse. -->
+
   <row id='a'>
     <entry><literal>%a</literal></entry>
     <entry>Architecture</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='R'>
-    <entry><literal>%R</literal></entry>
-    <entry>Pretty host name</entry>
-    <entry>The pretty hostname of the running system, as read from the <varname>PRETTY_HOSTNAME=</varname> field of <filename>/etc/machine-info</filename>. If not set, resolves to the short hostname. See <citerefentry><refentrytitle>machine-info</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
-  </row>
   <row id='m'>
     <entry><literal>%m</literal></entry>
     <entry>Machine ID</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='q'>
+    <entry><literal>%q</literal></entry>
+    <entry>Pretty host name</entry>
+    <entry>The pretty hostname of the running system, as read from the <varname>PRETTY_HOSTNAME=</varname> field of <filename>/etc/machine-info</filename>. If not set, resolves to the short hostname. See <citerefentry><refentrytitle>machine-info</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
+  </row>
   <row id='T'>
     <entry><literal>%T</literal></entry>
     <entry>Directory for temporary files</entry>
index 02f932edfba47f43482f92166ff019b4a223236c..3b235fd9c93e637d7cefb43b699d98d492688d9a 100644 (file)
         its configuration. The lockout mechanism is a global property of the TPM,
         <command>systemd-cryptenroll</command> does not control or configure the lockout mechanism. You may
         use tpm2-tss tools to inspect or configure the dictionary attack lockout, with
-        <citerefentry><refentrytitle>tpm2_getcap</refentrytitle><manvolnum>1</manvolnum></citerefentry> and
-        <citerefentry><refentrytitle>tpm2_dictionarylockout</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+        <citerefentry project='mankier'><refentrytitle>tpm2_getcap</refentrytitle><manvolnum>1</manvolnum></citerefentry> and
+        <citerefentry project='mankier'><refentrytitle>tpm2_dictionarylockout</refentrytitle><manvolnum>1</manvolnum></citerefentry>
         commands, respectively.</para></listitem>
       </varlistentry>
 
index ade5663c283643872156f0982129688f7b9a4142..a47ee4af1a39d6f2d1a812bf3a37e17fa88caa04 100644 (file)
@@ -33,8 +33,9 @@
     protected block devices. It should be instantiated for each device that requires integrity
     protection.</para>
 
-    <para>At early boot and when the system manager configuration is reloaded, entries from /etc/integritytab are converted into
-    <filename>systemd-integritysetup@.service</filename> units by
+    <para>At early boot and when the system manager configuration is reloaded, entries from
+    <citerefentry><refentrytitle>integritytab</refentrytitle><manvolnum>5</manvolnum></citerefentry> are
+    converted into <filename>systemd-integritysetup@.service</filename> units by
     <citerefentry><refentrytitle>systemd-integritysetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
 
     <para><filename>systemd-integritysetup@.service</filename> calls <command>systemd-integritysetup</command>.</para>
@@ -57,7 +58,7 @@
 
         <listitem><para>Create a block device <replaceable>volume</replaceable> using
         <replaceable>device</replaceable>. See
-        <citerefentry><refentrytitle>systemd-integritytab</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+        <citerefentry><refentrytitle>integritytab</refentrytitle><manvolnum>5</manvolnum></citerefentry>
         and
         <ulink url="https://www.kernel.org/doc/html/latest/admin-guide/device-mapper/dm-integrity.html">
           Kernel dm-integrity</ulink> documentation for details.
index 66ac26c5f871fecb32aef5e3dbe5986d35f69bfe..ab1fb8256718f1a3390c167b0723c08a15137193 100644 (file)
@@ -479,7 +479,7 @@ Dec 08 20:44:48 container systemd[1]: Started /bin/touch /tmp/foo.</programlisti
     <example>
       <title>Allowing access to the tty</title>
 
-      <para>The following command invokes <citerefentry><refentrytitle>bash</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+      <para>The following command invokes <citerefentry project='die-net'><refentrytitle>bash</refentrytitle><manvolnum>1</manvolnum></citerefentry>
       as a service passing its standard input, output and error to the calling TTY.</para>
 
       <programlisting># systemd-run -t --send-sighup bash</programlisting>
index f2d3b91e20f38bfc96b13da0fb5d609f0e371ade..3a8fc925d7f190f848569ec909551c722f388f6d 100644 (file)
     <title>Assembling Kernel Images</title>
 
     <para>In order to assemble an UEFI PE kernel image from various components as described above, use an
-    <citerefentry><refentrytitle>objcopy</refentrytitle><manvolnum>1</manvolnum></citerefentry> command line
+    <citerefentry project='man-pages'><refentrytitle>objcopy</refentrytitle><manvolnum>1</manvolnum></citerefentry> command line
     like this:</para>
 
     <programlisting>objcopy \
     UEFI boot stub.</para>
 
     <para>To then sign the resulting image for UEFI SecureBoot use an
-    <citerefentry><refentrytitle>sbsign</refentrytitle><manvolnum>1</manvolnum></citerefentry> command like
+    <citerefentry project='archlinux'><refentrytitle>sbsign</refentrytitle><manvolnum>1</manvolnum></citerefentry> command like
     the following:</para>
 
     <programlisting>sbsign \
       <citerefentry><refentrytitle>systemd-sysext</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
       <ulink url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink>,
       <ulink url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader Interface</ulink>,
-      <citerefentry><refentrytitle>objcopy</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
-      <citerefentry><refentrytitle>sbsign</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+      <citerefentry project='man-pages'><refentrytitle>objcopy</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+      <citerefentry project='archlinux'><refentrytitle>sbsign</refentrytitle><manvolnum>1</manvolnum></citerefentry>
     </para>
   </refsect1>
 </refentry>
index 3ad8135dcd8ba4f4cade54ff6455c6586ad961b5..7da7b18dcf95fac696693036c8c36cf24528f0e0 100644 (file)
     for the first time, it may not be used for changing the password or shell of an account that already
     exists.</para>
 
-    <para>Use <citerefentry><refentrytitle>mkpasswd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+    <para>Use <citerefentry project='man-pages'><refentrytitle>mkpasswd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
     for generating UNIX password hashes from the command line.</para>
   </refsect1>
 
       <citerefentry><refentrytitle>sysusers.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
       <ulink url="https://systemd.io/UIDS-GIDS">Users, Groups, UIDs and GIDs on systemd systems</ulink>,
       <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
-      <citerefentry><refentrytitle>mkpasswd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+      <citerefentry project='man-pages'><refentrytitle>mkpasswd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
     </para>
   </refsect1>
 
index fb521726e35cde2086f1ce0080fc926ff76906b6..1f916ac65eb11cdfadfd466e9d6822c31386abf9 100644 (file)
     directories listed above.
     <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry> will execute
     these binaries very early at bootup and at configuration reload time — before unit files are
-    loaded. Their main purpose is to convert configuration that is not native to the service manager into
-    dynamically generated unit files, symlinks or unit file drop-ins, so that they can extend the unit file
-    hierarchy the service manager subsequently loads and operates on.</para>
-
-    <para>Each generator is called with three directory paths that are to be used for
-    generator output. In these three directories, generators may dynamically generate
-    unit files (regular ones, instances, as well as templates), unit file
-    <filename>.d/</filename> drop-ins, and create symbolic links to unit files to add
-    additional dependencies, create aliases, or instantiate existing templates. Those
-    directories are included in the unit load path of
-    <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
-    allowing generated configuration to extend or override existing
-    definitions.</para>
-
-    <para>Directory paths for generator output differ by priority:
-    <filename>…/generator.early</filename> has priority higher than the admin
-    configuration in <filename>/etc/</filename>, while
-    <filename>…/generator</filename> has lower priority than
-    <filename>/etc/</filename> but higher than vendor configuration in
-    <filename>/usr/</filename>, and <filename>…/generator.late</filename> has priority
-    lower than all other configuration. See the next section and the discussion of
-    unit load paths and unit overriding in
+    loaded. Their main purpose is to convert configuration and execution context parameters that are not
+    native to the service manager into dynamically generated unit files, symlinks or unit file drop-ins, so
+    that they can extend the unit file hierarchy the service manager subsequently loads and operates
+    on.</para>
+
+    <para>Each generator is called with three directory paths that are to be used for generator output. In
+    these three directories, generators may dynamically generate unit files (regular ones, instances, as well
+    as templates), unit file <filename>.d/</filename> drop-ins, and create symbolic links to unit files to
+    add additional dependencies, create aliases, or instantiate existing templates. Those directories are
+    included in the unit load path of
+    <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, allowing
+    generated configuration to extend or override existing definitions.</para>
+
+    <para>Directory paths for generator output differ by priority: <filename>…/generator.early</filename> has
+    priority higher than the admin configuration in <filename>/etc/</filename>, while
+    <filename>…/generator</filename> has lower priority than <filename>/etc/</filename> but higher than
+    vendor configuration in <filename>/usr/</filename>, and <filename>…/generator.late</filename> has
+    priority lower than all other configuration. See the next section and the discussion of unit load paths
+    and unit overriding in
     <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
     </para>
 
-    <para>Generators are loaded from a set of paths determined during
-    compilation, as listed above. System and user generators are loaded
-    from directories with names ending in
-    <filename>system-generators/</filename> and
-    <filename>user-generators/</filename>, respectively. Generators
-    found in directories listed earlier override the ones with the
-    same name in directories lower in the list. A symlink to
-    <filename>/dev/null</filename> or an empty file can be used to
-    mask a generator, thereby preventing it from running. Please note
-    that the order of the two directories with the highest priority is
-    reversed with respect to the unit load path, and generators in
-    <filename>/run/</filename> overwrite those in
-    <filename>/etc/</filename>.</para>
-
-    <para>After installing new generators or updating the
-    configuration, <command>systemctl daemon-reload</command> may be
-    executed. This will delete the previous configuration created by
-    generators, re-run all generators, and cause
-    <command>systemd</command> to reload units from disk. See
-    <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
-    for more information.
+    <para>Generators are loaded from a set of paths determined during compilation, as listed above. System
+    and user generators are loaded from directories with names ending in
+    <filename>system-generators/</filename> and <filename>user-generators/</filename>,
+    respectively. Generators found in directories listed earlier override the ones with the same name in
+    directories lower in the list. A symlink to <filename>/dev/null</filename> or an empty file can be used
+    to mask a generator, thereby preventing it from running. Please note that the order of the two
+    directories with the highest priority is reversed with respect to the unit load path, and generators in
+    <filename>/run/</filename> overwrite those in <filename>/etc/</filename>.</para>
+
+    <para>After installing new generators or updating the configuration, <command>systemctl
+    daemon-reload</command> may be executed. This will delete the previous configuration created by
+    generators, re-run all generators, and cause <command>systemd</command> to reload units from disk. See
+    <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> for more
+    information.
     </para>
   </refsect1>
 
   <refsect1>
     <title>Output directories</title>
 
-    <para>Generators are invoked with three arguments: paths to directories where
-    generators can place their generated unit files or symlinks. By default those
-    paths are runtime directories that are included in the search path of
-    <command>systemd</command>, but a generator may be called with different paths
-    for debugging purposes.</para>
+    <para>Generators are invoked with three arguments: paths to directories where generators can place their
+    generated unit files or symlinks. By default those paths are runtime directories that are included in the
+    search path of <command>systemd</command>, but a generator may be called with different paths for
+    debugging purposes.</para>
 
     <orderedlist>
       <listitem>
         <para><parameter>normal-dir</parameter></para>
-        <para>In normal use this is <filename>/run/systemd/generator</filename> in
-        case of the system generators and
-        <filename>$XDG_RUNTIME_DIR/generator</filename> in case of the user
-        generators. Unit files placed in this directory take precedence over vendor
-        unit configuration but not over native user/administrator unit configuration.
+        <para>In normal use this is <filename>/run/systemd/generator</filename> in case of the system
+        generators and <filename>$XDG_RUNTIME_DIR/generator</filename> in case of the user generators. Unit
+        files placed in this directory take precedence over vendor unit configuration but not over native
+        user/administrator unit configuration.
         </para>
       </listitem>
 
       <listitem>
         <para><parameter>early-dir</parameter></para>
-        <para>In normal use this is <filename>/run/systemd/generator.early</filename>
-        in case of the system generators and
-        <filename>$XDG_RUNTIME_DIR/generator.early</filename> in case of the user
-        generators. Unit files placed in this directory override unit files in
-        <filename>/usr/</filename>, <filename>/run/</filename> and
-        <filename>/etc/</filename>. This means that unit files placed in this
-        directory take precedence over all normal configuration, both vendor and
-        user/administrator.</para>
+        <para>In normal use this is <filename>/run/systemd/generator.early</filename> in case of the system
+        generators and <filename>$XDG_RUNTIME_DIR/generator.early</filename> in case of the user
+        generators. Unit files placed in this directory override unit files in <filename>/usr/</filename>,
+        <filename>/run/</filename> and <filename>/etc/</filename>. This means that unit files placed in this
+        directory take precedence over all normal configuration, both vendor and user/administrator.</para>
       </listitem>
 
       <listitem>
         <para><parameter>late-dir</parameter></para>
-        <para>In normal use this is <filename>/run/systemd/generator.late</filename>
-        in case of the system generators and
-        <filename>$XDG_RUNTIME_DIR/generator.late</filename> in case of the user
-        generators. This directory may be used to extend the unit file tree without
-        overriding any other unit files. Any native configuration files supplied by
-        the vendor or user/administrator take precedence.</para>
+        <para>In normal use this is <filename>/run/systemd/generator.late</filename> in case of the system
+        generators and <filename>$XDG_RUNTIME_DIR/generator.late</filename> in case of the user
+        generators. This directory may be used to extend the unit file tree without overriding any other unit
+        files. Any native configuration files supplied by the vendor or user/administrator take
+        precedence.</para>
       </listitem>
     </orderedlist>
   </refsect1>
 
+  <refsect1>
+    <title>Environment</title>
+
+    <para>The service manager sets a number of environment variables when invoking generator
+    executables. They carry information about the execution context of the generator, in order to simplify
+    conditionalizing generators to specific environments. The following environment variables are set:</para>
+
+    <variablelist class='environment-variables'>
+      <varlistentry>
+        <term><varname>$SYSTEMD_SCOPE</varname></term>
+
+        <listitem><para>If the generator is invoked from the system service manager this variable is set to
+        <literal>system</literal>; if invoked from the per-user service manager it is set to
+        <literal>user</literal>.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>$SYSTEMD_IN_INITRD</varname></term>
+
+        <listitem><para>If the generator is run as part of an initial RAM file system (initrd) this is set to
+        <literal>1</literal>. If it is run from the regular host (i.e. after the transition from initrd to
+        host) it is set to <literal>0</literal>. This environment variable is only set for system
+        generators.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>$SYSTEMD_FIRST_BOOT</varname></term>
+
+        <listitem><para>If this boot-up cycle is considered a "first boot", this is set to
+        <literal>1</literal>; if it is a subsequent, regular boot it is set to <literal>0</literal>. For
+        details see the documentation of <varname>ConditionFirstBoot=</varname> in
+        <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>. This
+        environment variable is only set for system generators.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>$SYSTEMD_VIRTUALIZATION</varname></term>
+
+        <listitem><para>If the service manager is run in a virtualized environment,
+        <varname>$SYSTEMD_VIRTUALIZATION</varname> is set to a pair of strings, separated by a colon. The
+        first string is either <literal>vm</literal> or <literal>container</literal>, categorizing the type
+        of virtualization. The second string identifies the implementation of the virtualization
+        technology. If no virtualization is detected this variable will not be set. This data is identical to
+        what
+        <citerefentry><refentrytitle>systemd-detect-virt</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+        detects and reports, and uses the same vocabulary of virtualization implementation
+        identifiers.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>$SYSTEMD_ARCHITECTURE</varname></term>
+
+        <listitem><para>This variable is set to a short identifier of the reported architecture of the
+        system. For details about defined values, see documentation of
+        <varname>ConditionArchitecture=</varname> in
+        <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
   <refsect1>
     <title>Notes about writing generators</title>
 
     <itemizedlist>
       <listitem>
-        <para>All generators are executed in parallel. That means all executables are
-        started at the very same time and need to be able to cope with this
-        parallelism.
+        <para>All generators are executed in parallel. That means all executables are started at the very
+        same time and need to be able to cope with this parallelism.
         </para>
       </listitem>
 
       </listitem>
 
       <listitem>
-        <para>Units written by generators are removed when the configuration is
-        reloaded. That means the lifetime of the generated units is closely bound to
-        the reload cycles of <command>systemd</command> itself.</para>
+        <para>Units written by generators are removed when the configuration is reloaded. That means the
+        lifetime of the generated units is closely bound to the reload cycles of <command>systemd</command>
+        itself.</para>
       </listitem>
 
       <listitem>
         <para>Since
         <citerefentry project='man-pages'><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>
 
-        is not available (see above), log messages have to be written to
-        <filename>/dev/kmsg</filename> instead.</para>
+        is not available (see above), log messages have to be written to <filename>/dev/kmsg</filename>
+        instead.</para>
       </listitem>
 
       <listitem>
       </listitem>
 
       <listitem>
-        <para>Generators may write out dynamic unit files or just hook unit files
-        into other units with the usual <filename>.wants/</filename> or
-        <filename>.requires/</filename> symlinks. Often, it is nicer to simply
-        instantiate a template unit file from <filename>/usr/</filename> with a
-        generator instead of writing out entirely dynamic unit files. Of course, this
-        works only if a single parameter is to be used.</para>
+        <para>Generators may write out dynamic unit files or just hook unit files into other units with the
+        usual <filename>.wants/</filename> or <filename>.requires/</filename> symlinks. Often, it is nicer to
+        simply instantiate a template unit file from <filename>/usr/</filename> with a generator instead of
+        writing out entirely dynamic unit files. Of course, this works only if a single parameter is to be
+        used.</para>
       </listitem>
 
       <listitem>
-        <para>If you are careful, you can implement generators in shell scripts. We
-        do recommend C code however, since generators are executed synchronously and
-        hence delay the entire boot if they are slow.</para>
+        <para>If you are careful, you can implement generators in shell scripts. We do recommend C code
+        however, since generators are executed synchronously and hence delay the entire boot if they are
+        slow.</para>
       </listitem>
 
       <listitem>
-        <para>Regarding overriding semantics: there are two rules we try to follow
-        when thinking about the overriding semantics:</para>
+        <para>Regarding overriding semantics: there are two rules we try to follow when thinking about the
+        overriding semantics:</para>
 
         <orderedlist numeration="lowerroman">
           <listitem>
-            <para>User configuration should override vendor configuration. This
-            (mostly) means that stuff from <filename>/etc/</filename> should override
-            stuff from <filename>/usr/</filename>.</para>
+            <para>User configuration should override vendor configuration. This (mostly) means that stuff
+            from <filename>/etc/</filename> should override stuff from <filename>/usr/</filename>.</para>
           </listitem>
 
           <listitem>
-            <para>Native configuration should override non-native configuration. This
-            (mostly) means that stuff you generate should never override native unit
-            files for the same purpose.</para>
+            <para>Native configuration should override non-native configuration. This (mostly) means that
+            stuff you generate should never override native unit files for the same purpose.</para>
           </listitem>
         </orderedlist>
 
-        <para>Of these two rules the first rule is probably the more important one
-        and breaks the second one sometimes. Hence, when deciding whether to use
-        argv[1], argv[2], or argv[3], your default choice should probably be
-        argv[1].</para>
+        <para>Of these two rules the first rule is probably the more important one and breaks the second one
+        sometimes. Hence, when deciding whether to use argv[1], argv[2], or argv[3], your default choice
+        should probably be argv[1].</para>
       </listitem>
 
       <listitem>
-        <para>Instead of heading off now and writing all kind of generators for
-        legacy configuration file formats, please think twice! It is often a better
-        idea to just deprecate old stuff instead of keeping it artificially alive.
+        <para>Instead of heading off now and writing all kind of generators for legacy configuration file
+        formats, please think twice! It is often a better idea to just deprecate old stuff instead of keeping
+        it artificially alive.
         </para>
       </listitem>
     </itemizedlist>
       <title>systemd-fstab-generator</title>
 
       <para><citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-      converts <filename>/etc/fstab</filename> into native mount units. It uses
-      argv[1] as location to place the generated unit files in order to allow the
-      user to override <filename>/etc/fstab</filename> with their own native unit
-      files, but also to ensure that <filename>/etc/fstab</filename> overrides any
+      converts <filename>/etc/fstab</filename> into native mount units. It uses argv[1] as location to place
+      the generated unit files in order to allow the user to override <filename>/etc/fstab</filename> with
+      their own native unit files, but also to ensure that <filename>/etc/fstab</filename> overrides any
       vendor default from <filename>/usr/</filename>.</para>
 
-      <para>After editing <filename>/etc/fstab</filename>, the user should invoke
-      <command>systemctl daemon-reload</command>. This will re-run all generators and
-      cause <command>systemd</command> to reload units from disk. To actually mount
-      new directories added to <filename>fstab</filename>, <command>systemctl start
-      <replaceable>/path/to/mountpoint</replaceable></command> or <command>systemctl
+      <para>After editing <filename>/etc/fstab</filename>, the user should invoke <command>systemctl
+      daemon-reload</command>. This will re-run all generators and cause <command>systemd</command> to reload
+      units from disk. To actually mount new directories added to <filename>fstab</filename>,
+      <command>systemctl start <replaceable>/path/to/mountpoint</replaceable></command> or <command>systemctl
       start local-fs.target</command> may be used.</para>
     </example>
 
       <title>systemd-system-update-generator</title>
 
       <para><citerefentry><refentrytitle>systemd-system-update-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-      temporarily redirects <filename>default.target</filename> to
-      <filename>system-update.target</filename>, if a system update is
-      scheduled. Since this needs to override the default user configuration for
-      <filename>default.target</filename>, it uses argv[2]. For details about this
-      logic, see
+      temporarily redirects <filename>default.target</filename> to <filename>system-update.target</filename>,
+      if a system update is scheduled. Since this needs to override the default user configuration for
+      <filename>default.target</filename>, it uses argv[2]. For details about this logic, see
       <citerefentry><refentrytitle>systemd.offline-updates</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
       </para>
     </example>
index 0ba3c8552175b0d52629f9b1a361c1148653bce5..ace1dc63367d6f812abc3228031a15f400a6b693 100644 (file)
         <term><varname>RoutingAlgorithm=</varname></term>
         <listitem>
           <para>This can be either <literal>batman-v</literal> or <literal>batman-iv</literal> and describes which routing_algo
-          of <citerefentry><refentrytitle>batctl</refentrytitle><manvolnum>8</manvolnum></citerefentry> to use. The algorithm
+          of <citerefentry project='mankier'><refentrytitle>batctl</refentrytitle><manvolnum>8</manvolnum></citerefentry> to use. The algorithm
           cannot be changed after interface creation. Defaults to <literal>batman-v</literal>.
           </para>
         </listitem>
index 7a611dc93f791ad0c3bc4274b851ec63ec242eb6..cd033ac52e198ff0863c4397ac907f01a37dade3 100644 (file)
@@ -2097,7 +2097,7 @@ Note that this setting is <emphasis>not</emphasis> influenced by the <varname>Us
           <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>%R</literal></entry>
+            <entry><literal>%q</literal></entry>
             <entry>Pretty host name</entry>
             <entry>The pretty hostname of the running system at the point in time the unit configuration is loaded, as read from the <varname>PRETTY_HOSTNAME=</varname> field of <filename>/etc/machine-info</filename>. If not set, resolves to the short hostname. See <citerefentry><refentrytitle>machine-info</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
           </row>
index 5994abde8eae60619c176a05bc30a3ad83a40f11..edb1fccc0c3c61ca4e32a806b1d23184e2080026 100644 (file)
             along the chain, up to the root of sysfs that can be used in udev rules.</para>
           </listitem>
         </varlistentry>
+        <varlistentry>
+          <term><option>-t</option></term>
+          <term><option>--tree</option></term>
+          <listitem>
+            <para>Display a sysfs tree. This recursively iterates through the sysfs hierarchy and displays it
+            in a tree structure. If a path is specified only the subtree below that directory is
+            shown. This will show both device and subsystem items.</para>
+          </listitem>
+        </varlistentry>
         <varlistentry>
           <term><option>-x</option></term>
           <term><option>--export</option></term>
       does not probe a block device while changes are made to it, for example partitions created or file
       systems formatted. Note that many tools that interface with block devices natively support taking
       relevant locks, see for example
-      <citerefentry><refentrytitle>sfdisk</refentrytitle><manvolnum>8</manvolnum></citerefentry>'s
+      <citerefentry project='man-pages'><refentrytitle>sfdisk</refentrytitle><manvolnum>8</manvolnum></citerefentry>'s
       <option>--lock</option> switch.</para>
 
       <para>The command expects at least one block device specified via <option>--device=</option> or
index 69dce9c87fcaeb3a9aa3360ee0ea0fa6e421c57a..458370e83df5d42a8b9551cb11af3f32b643f2b3 100644 (file)
@@ -47,9 +47,6 @@ fuzzer_build = want_ossfuzz or want_libfuzzer
 # More items are added later after they have been detected.
 summary({'build mode' : get_option('mode')})
 
-# GCOV doesn't define any macro when compiled with, so let's define it ourselves
-conf.set10('BUILT_WITH_COVERAGE', get_option('b_coverage'))
-
 #####################################################################
 
 # Try to install the git pre-commit hook
@@ -1823,6 +1820,12 @@ export_dbus_interfaces_py = find_program('tools/dbus_exporter.py')
 
 ############################################################
 
+if get_option('b_coverage')
+        add_project_arguments('-include', 'src/basic/coverage.h', language : 'c')
+endif
+
+############################################################
+
 config_h = configure_file(
         output : 'config.h',
         configuration : conf)
@@ -4230,6 +4233,7 @@ foreach tuple : [
         ['link-boot-shared',      get_option('link-boot-shared')],
         ['fexecve'],
         ['standalone-binaries',   get_option('standalone-binaries')],
+        ['coverage',              get_option('b_coverage')],
 ]
 
         if tuple.length() >= 2
index 61f8b3351be7667f3ae72928a492db913f5103d4..e93419d63595dfa5c0dd5a2168fd707ec815f775 100644 (file)
@@ -24,7 +24,7 @@ bool unsafe_transition(const struct stat *a, const struct stat *b) {
         return a->st_uid != b->st_uid; /* Otherwise we need to stay within the same UID */
 }
 
-static int log_unsafe_transition(int a, int b, const char *path, unsigned flags) {
+static int log_unsafe_transition(int a, int b, const char *path, ChaseSymlinksFlags flags) {
         _cleanup_free_ char *n1 = NULL, *n2 = NULL, *user_a = NULL, *user_b = NULL;
         struct stat st;
 
@@ -44,7 +44,7 @@ static int log_unsafe_transition(int a, int b, const char *path, unsigned flags)
                                  strna(n1), strna(user_a), special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), strna(n2), strna(user_b), path);
 }
 
-static int log_autofs_mount_point(int fd, const char *path, unsigned flags) {
+static int log_autofs_mount_point(int fd, const char *path, ChaseSymlinksFlags flags) {
         _cleanup_free_ char *n1 = NULL;
 
         if (!FLAGS_SET(flags, CHASE_WARN))
@@ -57,7 +57,13 @@ static int log_autofs_mount_point(int fd, const char *path, unsigned flags) {
                                  strna(n1), path);
 }
 
-int chase_symlinks(const char *path, const char *original_root, unsigned flags, char **ret_path, int *ret_fd) {
+int chase_symlinks(
+                const char *path,
+                const char *original_root,
+                ChaseSymlinksFlags flags,
+                char **ret_path,
+                int *ret_fd) {
+
         _cleanup_free_ char *buffer = NULL, *done = NULL, *root = NULL;
         _cleanup_close_ int fd = -1;
         unsigned max_follow = CHASE_SYMLINKS_MAX; /* how many symlinks to follow before giving up and returning ELOOP */
@@ -78,6 +84,10 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
         if (isempty(path))
                 return -EINVAL;
 
+        /* We don't support relative paths in combination with a root directory */
+        if (FLAGS_SET(flags, CHASE_PREFIX_ROOT) && !path_is_absolute(path))
+                return -EINVAL;
+
         /* This is a lot like canonicalize_file_name(), but takes an additional "root" parameter, that allows following
          * symlinks relative to a root directory, instead of the root of the host.
          *
@@ -155,19 +165,19 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
                 path_simplify(root);
 
                 if (flags & CHASE_PREFIX_ROOT) {
-                        /* We don't support relative paths in combination with a root directory */
-                        if (!path_is_absolute(path))
-                                return -EINVAL;
-
-                        path = prefix_roota(root, path);
+                        buffer = path_join(root, path);
+                        if (!buffer)
+                                return -ENOMEM;
                 }
         }
 
-        r = path_make_absolute_cwd(path, &buffer);
-        if (r < 0)
-                return r;
+        if (!buffer) {
+                r = path_make_absolute_cwd(path, &buffer);
+                if (r < 0)
+                        return r;
+        }
 
-        fd = open(root ?: "/", O_CLOEXEC|O_DIRECTORY|O_PATH);
+        fd = open(empty_to_root(root), O_CLOEXEC|O_DIRECTORY|O_PATH);
         if (fd < 0)
                 return -errno;
 
@@ -193,6 +203,8 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
                 todo = buffer;
                 done = strdup("/");
         }
+        if (!done)
+                return -ENOMEM;
 
         for (;;) {
                 _cleanup_free_ char *first = NULL;
@@ -200,7 +212,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
                 struct stat st;
                 const char *e;
 
-                r = path_find_first_component(&todo, true, &e);
+                r = path_find_first_component(&todo, /* accept_dot_dot= */ true, &e);
                 if (r < 0)
                         return r;
                 if (r == 0) { /* We reached the end. */
@@ -224,9 +236,9 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
                         if (empty_or_root(done))
                                 continue;
 
-                        parent = dirname_malloc(done);
-                        if (!parent)
-                                return -ENOMEM;
+                        r = path_extract_directory(done, &parent);
+                        if (r < 0)
+                                return r;
 
                         /* Don't allow this to leave the root dir.  */
                         if (root &&
@@ -311,7 +323,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
                                  * directory as base. */
 
                                 safe_close(fd);
-                                fd = open(root ?: "/", O_CLOEXEC|O_DIRECTORY|O_PATH);
+                                fd = open(empty_to_root(root), O_CLOEXEC|O_DIRECTORY|O_PATH);
                                 if (fd < 0)
                                         return -errno;
 
@@ -375,7 +387,7 @@ chased_one:
                 const char *e;
 
                 /* todo may contain slashes at the beginning. */
-                r = path_find_first_component(&todo, true, &e);
+                r = path_find_first_component(&todo, /* accept_dot_dot= */ true, &e);
                 if (r < 0)
                         return r;
                 if (r == 0)
@@ -397,7 +409,7 @@ chased_one:
 int chase_symlinks_and_open(
                 const char *path,
                 const char *root,
-                unsigned chase_flags,
+                ChaseSymlinksFlags chase_flags,
                 int open_flags,
                 char **ret_path) {
 
@@ -435,7 +447,7 @@ int chase_symlinks_and_open(
 int chase_symlinks_and_opendir(
                 const char *path,
                 const char *root,
-                unsigned chase_flags,
+                ChaseSymlinksFlags chase_flags,
                 char **ret_path,
                 DIR **ret_dir) {
 
@@ -478,7 +490,7 @@ int chase_symlinks_and_opendir(
 int chase_symlinks_and_stat(
                 const char *path,
                 const char *root,
-                unsigned chase_flags,
+                ChaseSymlinksFlags chase_flags,
                 char **ret_path,
                 struct stat *ret_stat,
                 int *ret_fd) {
@@ -520,7 +532,7 @@ int chase_symlinks_and_stat(
 int chase_symlinks_and_fopen_unlocked(
                 const char *path,
                 const char *root,
-                unsigned chase_flags,
+                ChaseSymlinksFlags chase_flags,
                 const char *open_flags,
                 char **ret_path,
                 FILE **ret_file) {
index e2b22fe0412ee22c4c74de859dbcaeac65ae4bf4..491138a698bf24c8dfb4cfda8592dbad41fcaeea 100644 (file)
@@ -6,7 +6,7 @@
 
 #include "stat-util.h"
 
-enum {
+typedef enum ChaseSymlinksFlags {
         CHASE_PREFIX_ROOT = 1 << 0, /* The specified path will be prefixed by the specified root before beginning the iteration */
         CHASE_NONEXISTENT = 1 << 1, /* It's OK if the path doesn't actually exist. */
         CHASE_NO_AUTOFS   = 1 << 2, /* Return -EREMOTE if autofs mount point found */
@@ -16,17 +16,17 @@ enum {
         CHASE_NOFOLLOW    = 1 << 6, /* Do not follow the path's right-most component. With ret_fd, when the path's
                                      * right-most component refers to symlink, return O_PATH fd of the symlink. */
         CHASE_WARN        = 1 << 7, /* Emit an appropriate warning when an error is encountered */
-};
+} ChaseSymlinksFlags;
 
 bool unsafe_transition(const struct stat *a, const struct stat *b);
 
 /* How many iterations to execute before returning -ELOOP */
 #define CHASE_SYMLINKS_MAX 32
 
-int chase_symlinks(const char *path_with_prefix, const char *root, unsigned flags, char **ret_path, int *ret_fd);
+int chase_symlinks(const char *path_with_prefix, const char *root, ChaseSymlinksFlags chase_flags, char **ret_path, int *ret_fd);
 
-int chase_symlinks_and_open(const char *path, const char *root, unsigned chase_flags, int open_flags, char **ret_path);
-int chase_symlinks_and_opendir(const char *path, const char *root, unsigned chase_flags, char **ret_path, DIR **ret_dir);
-int chase_symlinks_and_stat(const char *path, const char *root, unsigned chase_flags, char **ret_path, struct stat *ret_stat, int *ret_fd);
+int chase_symlinks_and_open(const char *path, const char *root, ChaseSymlinksFlags chase_flags, int open_flags, char **ret_path);
+int chase_symlinks_and_opendir(const char *path, const char *root, ChaseSymlinksFlags chase_flags, char **ret_path, DIR **ret_dir);
+int chase_symlinks_and_stat(const char *path, const char *root, ChaseSymlinksFlags chase_flags, char **ret_path, struct stat *ret_stat, int *ret_fd);
 
-int chase_symlinks_and_fopen_unlocked(const char *path, const char *root, unsigned chase_flags, const char *open_flags, char **ret_path, FILE **ret_file);
+int chase_symlinks_and_fopen_unlocked(const char *path, const char *root, ChaseSymlinksFlags chase_flags, const char *open_flags, char **ret_path, FILE **ret_file);
diff --git a/src/basic/coverage.h b/src/basic/coverage.h
new file mode 100644 (file)
index 0000000..3ef02cf
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+/* When built with --coverage (gcov) we need to explicitly call __gcov_dump()
+ * in places where we use _exit(), since _exit() skips at-exit hooks resulting
+ * in lost coverage.
+ *
+ * To make sure we don't miss any _exit() calls, this header file is included
+ * explicitly on the compiler command line via the -include directive (only
+ * when built with -Db_coverage=true)
+ * */
+extern void _exit(int);
+extern void __gcov_dump(void);
+
+static inline void _coverage__exit(int status) {
+        __gcov_dump();
+        _exit(status);
+}
+#define _exit(x) _coverage__exit(x)
diff --git a/src/basic/devnum-util.c b/src/basic/devnum-util.c
new file mode 100644 (file)
index 0000000..70c0731
--- /dev/null
@@ -0,0 +1,135 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <string.h>
+#include <sys/stat.h>
+
+#include "chase-symlinks.h"
+#include "devnum-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "string-util.h"
+
+int parse_devnum(const char *s, dev_t *ret) {
+        const char *major;
+        unsigned x, y;
+        size_t n;
+        int r;
+
+        n = strspn(s, DIGITS);
+        if (n == 0)
+                return -EINVAL;
+        if (n > DECIMAL_STR_MAX(dev_t))
+                return -EINVAL;
+        if (s[n] != ':')
+                return -EINVAL;
+
+        major = strndupa_safe(s, n);
+        r = safe_atou(major, &x);
+        if (r < 0)
+                return r;
+
+        r = safe_atou(s + n + 1, &y);
+        if (r < 0)
+                return r;
+
+        if (!DEVICE_MAJOR_VALID(x) || !DEVICE_MINOR_VALID(y))
+                return -ERANGE;
+
+        *ret = makedev(x, y);
+        return 0;
+}
+
+int device_path_make_major_minor(mode_t mode, dev_t devnum, char **ret) {
+        const char *t;
+
+        /* Generates the /dev/{char|block}/MAJOR:MINOR path for a dev_t */
+
+        if (S_ISCHR(mode))
+                t = "char";
+        else if (S_ISBLK(mode))
+                t = "block";
+        else
+                return -ENODEV;
+
+        if (asprintf(ret, "/dev/%s/" DEVNUM_FORMAT_STR, t, DEVNUM_FORMAT_VAL(devnum)) < 0)
+                return -ENOMEM;
+
+        return 0;
+}
+
+int device_path_make_canonical(mode_t mode, dev_t devnum, char **ret) {
+        _cleanup_free_ char *p = NULL;
+        int r;
+
+        /* Finds the canonical path for a device, i.e. resolves the /dev/{char|block}/MAJOR:MINOR path to the end. */
+
+        assert(ret);
+
+        if (major(devnum) == 0 && minor(devnum) == 0) {
+                char *s;
+
+                /* A special hack to make sure our 'inaccessible' device nodes work. They won't have symlinks in
+                 * /dev/block/ and /dev/char/, hence we handle them specially here. */
+
+                if (S_ISCHR(mode))
+                        s = strdup("/run/systemd/inaccessible/chr");
+                else if (S_ISBLK(mode))
+                        s = strdup("/run/systemd/inaccessible/blk");
+                else
+                        return -ENODEV;
+
+                if (!s)
+                        return -ENOMEM;
+
+                *ret = s;
+                return 0;
+        }
+
+        r = device_path_make_major_minor(mode, devnum, &p);
+        if (r < 0)
+                return r;
+
+        return chase_symlinks(p, NULL, 0, ret, NULL);
+}
+
+int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devnum) {
+        mode_t mode;
+        dev_t devnum;
+        int r;
+
+        /* Tries to extract the major/minor directly from the device path if we can. Handles /dev/block/ and /dev/char/
+         * paths, as well out synthetic inaccessible device nodes. Never goes to disk. Returns -ENODEV if the device
+         * path cannot be parsed like this.  */
+
+        if (path_equal(path, "/run/systemd/inaccessible/chr")) {
+                mode = S_IFCHR;
+                devnum = makedev(0, 0);
+        } else if (path_equal(path, "/run/systemd/inaccessible/blk")) {
+                mode = S_IFBLK;
+                devnum = makedev(0, 0);
+        } else {
+                const char *w;
+
+                w = path_startswith(path, "/dev/block/");
+                if (w)
+                        mode = S_IFBLK;
+                else {
+                        w = path_startswith(path, "/dev/char/");
+                        if (!w)
+                                return -ENODEV;
+
+                        mode = S_IFCHR;
+                }
+
+                r = parse_devnum(w, &devnum);
+                if (r < 0)
+                        return r;
+        }
+
+        if (ret_mode)
+                *ret_mode = mode;
+        if (ret_devnum)
+                *ret_devnum = devnum;
+
+        return 0;
+}
diff --git a/src/basic/devnum-util.h b/src/basic/devnum-util.h
new file mode 100644 (file)
index 0000000..3f1894b
--- /dev/null
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+#include "stdio-util.h"
+
+int parse_devnum(const char *s, dev_t *ret);
+
+/* glibc and the Linux kernel have different ideas about the major/minor size. These calls will check whether the
+ * specified major is valid by the Linux kernel's standards, not by glibc's. Linux has 20bits of minor, and 12 bits of
+ * major space. See MINORBITS in linux/kdev_t.h in the kernel sources. (If you wonder why we define _y here, instead of
+ * comparing directly >= 0: it's to trick out -Wtype-limits, which would otherwise complain if the type is unsigned, as
+ * such a test would be pointless in such a case.) */
+
+#define DEVICE_MAJOR_VALID(x)                                           \
+        ({                                                              \
+                typeof(x) _x = (x), _y = 0;                             \
+                _x >= _y && _x < (UINT32_C(1) << 12);                   \
+                                                                        \
+        })
+
+#define DEVICE_MINOR_VALID(x)                                           \
+        ({                                                              \
+                typeof(x) _x = (x), _y = 0;                             \
+                _x >= _y && _x < (UINT32_C(1) << 20);                   \
+        })
+
+int device_path_make_major_minor(mode_t mode, dev_t devnum, char **ret);
+int device_path_make_canonical(mode_t mode, dev_t devnum, char **ret);
+int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devnum);
+
+static inline bool devnum_set_and_equal(dev_t a, dev_t b) {
+        /* Returns true if a and b definitely refer to the same device. If either is zero, this means "don't
+         * know" and we'll return false */
+        return a == b && a != 0;
+}
+
+/* Maximum string length for a major:minor string. (Note that DECIMAL_STR_MAX includes space for a trailing NUL) */
+#define DEVNUM_STR_MAX (DECIMAL_STR_MAX(dev_t)-1+1+DECIMAL_STR_MAX(dev_t))
+
+#define DEVNUM_FORMAT_STR "%u:%u"
+#define DEVNUM_FORMAT_VAL(d) major(d), minor(d)
+
+static inline char *format_devnum(dev_t d, char buf[static DEVNUM_STR_MAX]) {
+        return ASSERT_PTR(snprintf_ok(buf, DEVNUM_STR_MAX, DEVNUM_FORMAT_STR, DEVNUM_FORMAT_VAL(d)));
+}
+
+#define FORMAT_DEVNUM(d) format_devnum((d), (char[DEVNUM_STR_MAX]) {})
index cfa7d041e7bc2f3e85f96b1d6366af297f457f48..1bba139bfcabe89a503d051967997734d32465a5 100644 (file)
@@ -40,6 +40,7 @@ const char *special_glyph(SpecialGlyph code) {
                         [SPECIAL_GLYPH_TREE_RIGHT]              = "`-",
                         [SPECIAL_GLYPH_TREE_SPACE]              = "  ",
                         [SPECIAL_GLYPH_TREE_TOP]                = ",-",
+                        [SPECIAL_GLYPH_VERTICAL_DOTTED]         = ":",
                         [SPECIAL_GLYPH_TRIANGULAR_BULLET]       = ">",
                         [SPECIAL_GLYPH_BLACK_CIRCLE]            = "*",
                         [SPECIAL_GLYPH_WHITE_CIRCLE]            = "*",
@@ -81,6 +82,7 @@ const char *special_glyph(SpecialGlyph code) {
                         [SPECIAL_GLYPH_TREE_TOP]                = u8"┌─",
 
                         /* Single glyphs in both cases */
+                        [SPECIAL_GLYPH_VERTICAL_DOTTED]         = u8"┆",
                         [SPECIAL_GLYPH_TRIANGULAR_BULLET]       = u8"‣",
                         [SPECIAL_GLYPH_BLACK_CIRCLE]            = u8"●",
                         [SPECIAL_GLYPH_WHITE_CIRCLE]            = u8"○",
index 7e0a73842a80e2643be45d418318c377cd8fdb62..065dde8a62b69186cd9d0a119ab96664a1451e2a 100644 (file)
@@ -12,6 +12,7 @@ typedef enum SpecialGlyph {
         SPECIAL_GLYPH_TREE_RIGHT,
         SPECIAL_GLYPH_TREE_SPACE,
         SPECIAL_GLYPH_TREE_TOP,
+        SPECIAL_GLYPH_VERTICAL_DOTTED,
         SPECIAL_GLYPH_TRIANGULAR_BULLET,
         SPECIAL_GLYPH_BLACK_CIRCLE,
         SPECIAL_GLYPH_WHITE_CIRCLE,
index 685de7344931e0fb67fa3252197aae1c86d42d28..68d8b062e87330983304a1ed875014d37d65ea00 100644 (file)
 #define _alignptr_ __attribute__((__aligned__(sizeof(void*))))
 #define _warn_unused_result_ __attribute__((__warn_unused_result__))
 
-#if defined(BUILT_WITH_COVERAGE) && BUILT_WITH_COVERAGE
-/* We need to explicitly call __gcov_dump() in places where we use _exit(), since
- * _exit() skips at-exit hooks resulting in lost coverage */
-#  include <unistd.h>
-extern void __gcov_dump(void);
-
-_noreturn_ static inline void _coverage__exit(int status) {
-        __gcov_dump();
-        _exit(status);
-}
-#  define _exit(x) _coverage__exit(x)
-#endif
-
 #if !defined(HAS_FEATURE_MEMORY_SANITIZER)
 #  if defined(__has_feature)
 #    if __has_feature(memory_sanitizer)
index 92a4df20177608f16d2775c60153448aab005a9a..501fcf147faff11328d614e46254df0952568734 100644 (file)
@@ -32,6 +32,8 @@ basic_sources = files(
         'conf-files.c',
         'conf-files.h',
         'def.h',
+        'devnum-util.c',
+        'devnum-util.h',
         'dirent-util.c',
         'dirent-util.h',
         'dns-def.h',
index d078bf70df3d460e904e2b735dab065b67818a5d..88df92db611cd07b9e8a1ab6a4a6fc28323cb265 100644 (file)
@@ -4,6 +4,7 @@
  * Use 'ninja -C build update-syscall-tables' to download new syscall tables,
  * and 'ninja -C build update-syscall-header' to regenerate this file.
  */
+#pragma once
 
 /* Note: if this code looks strange, this is because it is derived from the same
  * template as the per-syscall blocks below. */
index 2694e83b988941f174f0a70a588f35a70684c7c3..83199bb1d755382406141937f23786abb1ecfe0b 100644 (file)
@@ -142,6 +142,7 @@ def print_syscall_defs(syscalls, tables, out):
  * Use 'ninja -C build update-syscall-tables' to download new syscall tables,
  * and 'ninja -C build update-syscall-header' to regenerate this file.
  */
+#pragma once
 ''',
           file=out)
     print(ARCH_CHECK, file=out)
index b9120a5ed0e688bd36802e8f5bb94e9f36a7236b..4da9cb4cae7ef806db04d17444841a7a7a9c63ca 100644 (file)
@@ -213,7 +213,7 @@ int userns_acquire(const char *uid_map, const char *gid_map) {
 
         r = namespace_open(pid, NULL, NULL, NULL, &userns_fd, NULL);
         if (r < 0)
-                return log_error_errno(r, "Failed to open netns fd: %m");
+                return log_error_errno(r, "Failed to open userns fd: %m");
 
         return TAKE_FD(userns_fd);
 
index 222b2304cd05d353b346564507293d297b8001e0..35fbb5ec6adc7b4988aec5546c8f0352dee51f9e 100644 (file)
@@ -692,34 +692,6 @@ int parse_ip_prefix_length(const char *s, int *ret) {
         return 0;
 }
 
-int parse_dev(const char *s, dev_t *ret) {
-        const char *major;
-        unsigned x, y;
-        size_t n;
-        int r;
-
-        n = strspn(s, DIGITS);
-        if (n == 0)
-                return -EINVAL;
-        if (s[n] != ':')
-                return -EINVAL;
-
-        major = strndupa_safe(s, n);
-        r = safe_atou(major, &x);
-        if (r < 0)
-                return r;
-
-        r = safe_atou(s + n + 1, &y);
-        if (r < 0)
-                return r;
-
-        if (!DEVICE_MAJOR_VALID(x) || !DEVICE_MINOR_VALID(y))
-                return -ERANGE;
-
-        *ret = makedev(x, y);
-        return 0;
-}
-
 int parse_oom_score_adjust(const char *s, int *ret) {
         int r, v;
 
index 8273124626f2082f766687afee444ad5a82a6972..f2222dcffb09d86356345e772ae54fbfb90be26d 100644 (file)
@@ -12,7 +12,6 @@
 typedef unsigned long loadavg_t;
 
 int parse_boolean(const char *v) _pure_;
-int parse_dev(const char *s, dev_t *ret);
 int parse_pid(const char *s, pid_t* ret_pid);
 int parse_mode(const char *s, mode_t *ret);
 int parse_ifindex(const char *s);
index 5d93e107a78af899b360170bc82a468dcb557858..94527eff4caa48fb3f954cc09a60f920d6c115c5 100644 (file)
 #include "extract-word.h"
 #include "fd-util.h"
 #include "fs-util.h"
-#include "glob-util.h"
 #include "log.h"
 #include "macro.h"
-#include "nulstr-util.h"
-#include "parse-util.h"
 #include "path-util.h"
 #include "stat-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "time-util.h"
-#include "utf8.h"
 
 int path_split_and_make_absolute(const char *p, char ***ret) {
         char **l;
@@ -376,52 +372,6 @@ char *path_simplify(char *path) {
         return path;
 }
 
-int path_simplify_and_warn(
-                char *path,
-                unsigned flag,
-                const char *unit,
-                const char *filename,
-                unsigned line,
-                const char *lvalue) {
-
-        bool fatal = flag & PATH_CHECK_FATAL;
-
-        assert(!FLAGS_SET(flag, PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE));
-
-        if (!utf8_is_valid(path))
-                return log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, path);
-
-        if (flag & (PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE)) {
-                bool absolute;
-
-                absolute = path_is_absolute(path);
-
-                if (!absolute && (flag & PATH_CHECK_ABSOLUTE))
-                        return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
-                                          "%s= path is not absolute%s: %s",
-                                          lvalue, fatal ? "" : ", ignoring", path);
-
-                if (absolute && (flag & PATH_CHECK_RELATIVE))
-                        return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
-                                          "%s= path is absolute%s: %s",
-                                          lvalue, fatal ? "" : ", ignoring", path);
-        }
-
-        path_simplify(path);
-
-        if (!path_is_valid(path))
-                return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
-                                  "%s= path has invalid length (%zu bytes)%s.",
-                                  lvalue, strlen(path), fatal ? "" : ", ignoring");
-
-        if (!path_is_normalized(path))
-                return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
-                                  "%s= path is not normalized%s: %s",
-                                  lvalue, fatal ? "" : ", ignoring", path);
-
-        return 0;
-}
-
 char *path_startswith_full(const char *path, const char *prefix, bool accept_dot_dot) {
         assert(path);
         assert(prefix);
@@ -1314,74 +1264,6 @@ bool valid_device_allow_pattern(const char *path) {
         return valid_device_node_path(path);
 }
 
-int systemd_installation_has_version(const char *root, unsigned minimal_version) {
-        const char *pattern;
-        int r;
-
-        /* Try to guess if systemd installation is later than the specified version. This
-         * is hacky and likely to yield false negatives, particularly if the installation
-         * is non-standard. False positives should be relatively rare.
-         */
-
-        NULSTR_FOREACH(pattern,
-                       /* /lib works for systems without usr-merge, and for systems with a sane
-                        * usr-merge, where /lib is a symlink to /usr/lib. /usr/lib is necessary
-                        * for Gentoo which does a merge without making /lib a symlink.
-                        */
-                       "lib/systemd/libsystemd-shared-*.so\0"
-                       "lib64/systemd/libsystemd-shared-*.so\0"
-                       "usr/lib/systemd/libsystemd-shared-*.so\0"
-                       "usr/lib64/systemd/libsystemd-shared-*.so\0") {
-
-                _cleanup_strv_free_ char **names = NULL;
-                _cleanup_free_ char *path = NULL;
-                char *c;
-
-                path = path_join(root, pattern);
-                if (!path)
-                        return -ENOMEM;
-
-                r = glob_extend(&names, path, 0);
-                if (r == -ENOENT)
-                        continue;
-                if (r < 0)
-                        return r;
-
-                assert_se(c = endswith(path, "*.so"));
-                *c = '\0'; /* truncate the glob part */
-
-                STRV_FOREACH(name, names) {
-                        /* This is most likely to run only once, hence let's not optimize anything. */
-                        char *t, *t2;
-                        unsigned version;
-
-                        t = startswith(*name, path);
-                        if (!t)
-                                continue;
-
-                        t2 = endswith(t, ".so");
-                        if (!t2)
-                                continue;
-
-                        t2[0] = '\0'; /* truncate the suffix */
-
-                        r = safe_atou(t, &version);
-                        if (r < 0) {
-                                log_debug_errno(r, "Found libsystemd shared at \"%s.so\", but failed to parse version: %m", *name);
-                                continue;
-                        }
-
-                        log_debug("Found libsystemd shared at \"%s.so\", version %u (%s).",
-                                  *name, version,
-                                  version >= minimal_version ? "OK" : "too old");
-                        if (version >= minimal_version)
-                                return true;
-                }
-        }
-
-        return false;
-}
-
 bool dot_or_dot_dot(const char *path) {
         if (!path)
                 return false;
index 518f3340bf2ebf94fbbbd4469ca9b1715060cb87..553aa4fb58631db69e7740634267feb838b96832 100644 (file)
@@ -77,14 +77,6 @@ char* path_extend_internal(char **x, ...);
 
 char* path_simplify(char *path);
 
-enum {
-        PATH_CHECK_FATAL    = 1 << 0,  /* If not set, then error message is appended with 'ignoring'. */
-        PATH_CHECK_ABSOLUTE = 1 << 1,
-        PATH_CHECK_RELATIVE = 1 << 2,
-};
-
-int path_simplify_and_warn(char *path, unsigned flag, const char *unit, const char *filename, unsigned line, const char *lvalue);
-
 static inline bool path_equal_ptr(const char *a, const char *b) {
         return !!a == !!b && (!a || path_equal(a, b));
 }
@@ -181,8 +173,6 @@ bool is_device_path(const char *path);
 bool valid_device_node_path(const char *path);
 bool valid_device_allow_pattern(const char *path);
 
-int systemd_installation_has_version(const char *root, unsigned minimal_version);
-
 bool dot_or_dot_dot(const char *path);
 
 static inline const char *skip_dev_prefix(const char *p) {
index b25cabc6b48bc7597b4fa8036cbed2f10259fd2c..c7293db6989b04de9d41ebd5675ea6daf8c1396d 100644 (file)
@@ -314,101 +314,6 @@ int fd_verify_directory(int fd) {
         return stat_verify_directory(&st);
 }
 
-int device_path_make_major_minor(mode_t mode, dev_t devno, char **ret) {
-        const char *t;
-
-        /* Generates the /dev/{char|block}/MAJOR:MINOR path for a dev_t */
-
-        if (S_ISCHR(mode))
-                t = "char";
-        else if (S_ISBLK(mode))
-                t = "block";
-        else
-                return -ENODEV;
-
-        if (asprintf(ret, "/dev/%s/%u:%u", t, major(devno), minor(devno)) < 0)
-                return -ENOMEM;
-
-        return 0;
-}
-
-int device_path_make_canonical(mode_t mode, dev_t devno, char **ret) {
-        _cleanup_free_ char *p = NULL;
-        int r;
-
-        /* Finds the canonical path for a device, i.e. resolves the /dev/{char|block}/MAJOR:MINOR path to the end. */
-
-        assert(ret);
-
-        if (major(devno) == 0 && minor(devno) == 0) {
-                char *s;
-
-                /* A special hack to make sure our 'inaccessible' device nodes work. They won't have symlinks in
-                 * /dev/block/ and /dev/char/, hence we handle them specially here. */
-
-                if (S_ISCHR(mode))
-                        s = strdup("/run/systemd/inaccessible/chr");
-                else if (S_ISBLK(mode))
-                        s = strdup("/run/systemd/inaccessible/blk");
-                else
-                        return -ENODEV;
-
-                if (!s)
-                        return -ENOMEM;
-
-                *ret = s;
-                return 0;
-        }
-
-        r = device_path_make_major_minor(mode, devno, &p);
-        if (r < 0)
-                return r;
-
-        return chase_symlinks(p, NULL, 0, ret, NULL);
-}
-
-int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devno) {
-        mode_t mode;
-        dev_t devno;
-        int r;
-
-        /* Tries to extract the major/minor directly from the device path if we can. Handles /dev/block/ and /dev/char/
-         * paths, as well out synthetic inaccessible device nodes. Never goes to disk. Returns -ENODEV if the device
-         * path cannot be parsed like this.  */
-
-        if (path_equal(path, "/run/systemd/inaccessible/chr")) {
-                mode = S_IFCHR;
-                devno = makedev(0, 0);
-        } else if (path_equal(path, "/run/systemd/inaccessible/blk")) {
-                mode = S_IFBLK;
-                devno = makedev(0, 0);
-        } else {
-                const char *w;
-
-                w = path_startswith(path, "/dev/block/");
-                if (w)
-                        mode = S_IFBLK;
-                else {
-                        w = path_startswith(path, "/dev/char/");
-                        if (!w)
-                                return -ENODEV;
-
-                        mode = S_IFCHR;
-                }
-
-                r = parse_dev(w, &devno);
-                if (r < 0)
-                        return r;
-        }
-
-        if (ret_mode)
-                *ret_mode = mode;
-        if (ret_devno)
-                *ret_devno = devno;
-
-        return 0;
-}
-
 int proc_mounted(void) {
         int r;
 
index 37513a43e77b7b0e4f8b5fb95905a2e1d684fe87..4483ceb7de7665f7f751e4ca046b47082d9ea18b 100644 (file)
@@ -71,29 +71,6 @@ int fd_verify_regular(int fd);
 int stat_verify_directory(const struct stat *st);
 int fd_verify_directory(int fd);
 
-/* glibc and the Linux kernel have different ideas about the major/minor size. These calls will check whether the
- * specified major is valid by the Linux kernel's standards, not by glibc's. Linux has 20bits of minor, and 12 bits of
- * major space. See MINORBITS in linux/kdev_t.h in the kernel sources. (If you wonder why we define _y here, instead of
- * comparing directly >= 0: it's to trick out -Wtype-limits, which would otherwise complain if the type is unsigned, as
- * such a test would be pointless in such a case.) */
-
-#define DEVICE_MAJOR_VALID(x)                                           \
-        ({                                                              \
-                typeof(x) _x = (x), _y = 0;                             \
-                _x >= _y && _x < (UINT32_C(1) << 12);                   \
-                                                                        \
-        })
-
-#define DEVICE_MINOR_VALID(x)                                           \
-        ({                                                              \
-                typeof(x) _x = (x), _y = 0;                             \
-                _x >= _y && _x < (UINT32_C(1) << 20);                   \
-        })
-
-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_same(const struct stat *a, const struct stat *b);
@@ -119,9 +96,3 @@ int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct s
                 struct new_statx nsx;           \
         } var
 #endif
-
-static inline bool devid_set_and_equal(dev_t a, dev_t b) {
-        /* Returns true if a and b definitely refer to the same device. If either is zero, this means "don't
-         * know" and we'll return false */
-        return a == b && a != 0;
-}
index 4e70907adefa389be85e12ffd85617eb87b9c99d..fbc5566a651de8a046c4404c720569be3d363b0d 100644 (file)
@@ -473,6 +473,7 @@ sendmmsg
 sendmsg
 sendto
 set_mempolicy
+set_mempolicy_home_node
 set_robust_list
 set_thread_area
 set_tid_address
index 5aef86b09e0244603769945e26f9b3e46848588a..38988407fcb0258dc4b821809a060a21f03a7b0b 100644 (file)
@@ -473,6 +473,7 @@ sendmmsg    503
 sendmsg        114
 sendto 133
 set_mempolicy  431
+set_mempolicy_home_node        560
 set_robust_list        466
 set_thread_area
 set_tid_address        411
index f275f104bfe5bd614f635b0a1dd8da3b50132b05..801f551c258513952ff38d50659f7fed011da18b 100644 (file)
@@ -473,6 +473,7 @@ sendmmsg    269
 sendmsg        211
 sendto 206
 set_mempolicy  237
+set_mempolicy_home_node        450
 set_robust_list        99
 set_thread_area
 set_tid_address        96
index 9037b283842c4d10becd932a60021b99d486bff2..94bbcbf7036a408dd2d4e96d2af07eb7f457c6e5 100644 (file)
@@ -473,6 +473,7 @@ sendmmsg    374
 sendmsg        296
 sendto 290
 set_mempolicy  321
+set_mempolicy_home_node        450
 set_robust_list        338
 set_thread_area
 set_tid_address        256
index e91d7cfca46a2426cdbd5e4342859bb6a30b248f..207c43937e56551dfb9dc68f83c1a1b171016a8f 100644 (file)
@@ -473,6 +473,7 @@ sendmmsg    269
 sendmsg        211
 sendto 206
 set_mempolicy  237
+set_mempolicy_home_node        450
 set_robust_list        99
 set_thread_area
 set_tid_address        96
index 6b57d6f05d85e435fd7ae303a5184f27b13829a8..4c0c99368ef0ff984eccee8aeab9afb3770590ed 100644 (file)
@@ -473,6 +473,7 @@ sendmmsg    345
 sendmsg        370
 sendto 369
 set_mempolicy  276
+set_mempolicy_home_node        450
 set_robust_list        311
 set_thread_area        243
 set_tid_address        258
index 3d646f6d1758e044b7bb791eb4ce4f9eb734153d..9346b2e0d15862752dca4ad386b039f3cc0123b7 100644 (file)
@@ -473,6 +473,7 @@ sendmmsg    1331
 sendmsg        1205
 sendto 1199
 set_mempolicy  1261
+set_mempolicy_home_node        1474
 set_robust_list        1298
 set_thread_area
 set_tid_address        1233
index 8b10af64db0dd7f76bf98fe2336c1c6618d86beb..848e9e90aae876023ac774f0a92f2bf903762726 100644 (file)
@@ -473,6 +473,7 @@ sendmmsg    269
 sendmsg        211
 sendto 206
 set_mempolicy  237
+set_mempolicy_home_node        450
 set_robust_list        99
 set_thread_area
 set_tid_address        96
index ef7295db2f62b70ecee0d6ad82b812b503a46d92..f5a95685f6d76d54572b9d56e8ec2d151676a179 100644 (file)
@@ -473,6 +473,7 @@ sendmmsg    372
 sendmsg        367
 sendto 366
 set_mempolicy  270
+set_mempolicy_home_node        450
 set_robust_list        304
 set_thread_area        334
 set_tid_address        253
index 1f7ff567be3a041e0093d4acbf5e1cb2f25d0571..7d0b9976b066533ef5f7d8c8a7991f3c15fe990c 100644 (file)
@@ -473,6 +473,7 @@ sendmmsg    5302
 sendmsg        5045
 sendto 5043
 set_mempolicy  5229
+set_mempolicy_home_node        5450
 set_robust_list        5268
 set_thread_area        5242
 set_tid_address        5212
index 7e1ad9637dc1af8c21cce87fa0826836a7a0ee2d..2e15c66124fdb0db7743a9c453ecc4dc7a4bee55 100644 (file)
@@ -473,6 +473,7 @@ sendmmsg    6307
 sendmsg        6045
 sendto 6043
 set_mempolicy  6233
+set_mempolicy_home_node        6450
 set_robust_list        6272
 set_thread_area        6246
 set_tid_address        6213
index c0c262fd1ab9e34a4f9b1851b274eea32f56c53e..a8d95e3e3559fcb3f1e5c89f157321882f7df245 100644 (file)
@@ -473,6 +473,7 @@ sendmmsg    4343
 sendmsg        4179
 sendto 4180
 set_mempolicy  4270
+set_mempolicy_home_node        4450
 set_robust_list        4309
 set_thread_area        4283
 set_tid_address        4252
index 2f085161e1abae8ff976fc0acbf1147905aeaf6e..ad68616e250f2a35096428a7ed78cda12965e3d4 100644 (file)
@@ -473,6 +473,7 @@ sendmmsg    349
 sendmsg        341
 sendto 335
 set_mempolicy  261
+set_mempolicy_home_node        450
 set_robust_list        300
 set_thread_area
 set_tid_address        232
index 85e53422eeb10c094c0439685d71a4899ccfab08..9e8dc6dd8cc5f0ee3c464b9e30fb300ac4b2e0e1 100644 (file)
@@ -473,6 +473,7 @@ sendmmsg    349
 sendmsg        341
 sendto 335
 set_mempolicy  261
+set_mempolicy_home_node        450
 set_robust_list        300
 set_thread_area
 set_tid_address        232
index 013e38189b67281fd01e40af1afae465ef721116..2a4aceff949eb86256a1486d31c45fdcd6f084b1 100644 (file)
@@ -473,6 +473,7 @@ sendmmsg    269
 sendmsg        211
 sendto 206
 set_mempolicy  237
+set_mempolicy_home_node        450
 set_robust_list        99
 set_thread_area
 set_tid_address        96
index 104a2d9dfa9e0bef4f39a7bb5867cc87466ec7f5..07d1d4253ac066b7f9d8e7795081222987ce0988 100644 (file)
@@ -473,6 +473,7 @@ sendmmsg    269
 sendmsg        211
 sendto 206
 set_mempolicy  237
+set_mempolicy_home_node        450
 set_robust_list        99
 set_thread_area
 set_tid_address        96
index a25093c7be3ff4c600038db939f9cb850d6ac63a..bbc824c005965cf8f029eaea6ad449c59672621f 100644 (file)
@@ -473,6 +473,7 @@ sendmmsg    358
 sendmsg        370
 sendto 369
 set_mempolicy  270
+set_mempolicy_home_node        450
 set_robust_list        304
 set_thread_area
 set_tid_address        252
index b4b798f9df0b8f93b6cf0ef69bf8d4e8171cef23..bc385eabadf823e744cf886b7c3b703ff7c9985f 100644 (file)
@@ -473,6 +473,7 @@ sendmmsg    358
 sendmsg        370
 sendto 369
 set_mempolicy  270
+set_mempolicy_home_node        450
 set_robust_list        304
 set_thread_area
 set_tid_address        252
index a382e75c24b23942d686c864980e1f7394cdcd3f..6c39ad86f4fe9c2f660582a52a634a78cf4beae7 100644 (file)
@@ -473,6 +473,7 @@ sendmmsg    336
 sendmsg        114
 sendto 133
 set_mempolicy  305
+set_mempolicy_home_node        450
 set_robust_list        300
 set_thread_area
 set_tid_address        166
index 5bc9c58a2aa2d46326e6dc4cfdbf0497720c6d20..2942c2e489cdc6efc0fe38452f205f4524ba58e7 100644 (file)
@@ -473,6 +473,7 @@ sendmmsg    307
 sendmsg        46
 sendto 44
 set_mempolicy  238
+set_mempolicy_home_node        450
 set_robust_list        273
 set_thread_area        205
 set_tid_address        218
index 6119f21c1b117f33a0c26658a5bcef8fd503c4e7..7cf74e97d0a7f5f15460c179d0feaf25079a11a2 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "alloc-util.h"
 #include "def.h"
+#include "devnum-util.h"
 #include "env-util.h"
 #include "fd-util.h"
 #include "fileio.h"
index c8bc205d1b03dae8aae232f65c5f01b2f081eb5f..d9c901d73bb2cc8eae76c949a948415725f85108 100644 (file)
@@ -5,6 +5,7 @@
 
 #include "alloc-util.h"
 #include "bootspec.h"
+#include "devnum-util.h"
 #include "efi-api.h"
 #include "efi-loader.h"
 #include "efivars.h"
@@ -16,7 +17,6 @@
 #include "parse-util.h"
 #include "path-util.h"
 #include "pretty-print.h"
-#include "stat-util.h"
 #include "sync-util.h"
 #include "terminal-util.h"
 #include "util.h"
@@ -121,7 +121,7 @@ static int acquire_path(void) {
                                        "Couldn't find $BOOT partition. It is recommended to mount it to /boot.\n"
                                        "Alternatively, use --path= to specify path to mount point.");
 
-        if (esp_path && xbootldr_path && !devid_set_and_equal(esp_devid, xbootldr_devid)) /* in case the two paths refer to the same inode, suppress one */
+        if (esp_path && xbootldr_path && !devnum_set_and_equal(esp_devid, xbootldr_devid)) /* in case the two paths refer to the same inode, suppress one */
                 a = strv_new(esp_path, xbootldr_path);
         else if (esp_path)
                 a = strv_new(esp_path);
index a393370f8d413021b5e2122ac2480458fd6e0f25..eac071bcc637bf5f371971dd2c4646138c43126d 100644 (file)
@@ -16,6 +16,7 @@
 #include "blkid-util.h"
 #include "bootspec.h"
 #include "copy.h"
+#include "devnum-util.h"
 #include "dirent-util.h"
 #include "efi-api.h"
 #include "efi-loader.h"
@@ -595,7 +596,7 @@ static int boot_config_load_and_select(
 
         /* If XBOOTLDR and ESP actually refer to the same block device, suppress XBOOTLDR, since it would
          * find the same entries twice. */
-        bool same = esp_path && xbootldr_path && devid_set_and_equal(esp_devid, xbootldr_devid);
+        bool same = esp_path && xbootldr_path && devnum_set_and_equal(esp_devid, xbootldr_devid);
 
         r = boot_config_load(config, esp_path, same ? NULL : xbootldr_path);
         if (r < 0)
index 4cb370af29cb64ad2b0a6f3b6197980b0af2acdf..205ce71edf09284d11cede746274ecf69ac59c93 100644 (file)
@@ -1,4 +1,5 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
 
 #include <efi.h>
 
index 46996d28f4e7054384d98b5ab8e4ff62501e353f..3af9e78a1e32f5e9f2987d115da3002cb0b77d92 100644 (file)
@@ -5,12 +5,12 @@
 
 #include "bpf-devices.h"
 #include "bpf-program.h"
+#include "devnum-util.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "nulstr-util.h"
 #include "parse-util.h"
 #include "path-util.h"
-#include "stat-util.h"
 #include "stdio-util.h"
 #include "string-util.h"
 
index 2e2dfcb2aab2953c4ef216003de570ebdcdaf94a..9282b1ff200c2cf7cd02331c98f17753017a9c91 100644 (file)
@@ -16,6 +16,7 @@
 #include "cgroup-setup.h"
 #include "cgroup-util.h"
 #include "cgroup.h"
+#include "devnum-util.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "in-addr-prefix-util.h"
@@ -31,7 +32,6 @@
 #include "procfs-util.h"
 #include "restrict-ifaces.h"
 #include "special.h"
-#include "stat-util.h"
 #include "stdio-util.h"
 #include "string-table.h"
 #include "string-util.h"
@@ -1084,7 +1084,7 @@ static int set_bfq_weight(Unit *u, const char *controller, dev_t dev, uint64_t i
         bfq_weight = BFQ_WEIGHT(io_weight);
 
         if (major(dev) > 0)
-                xsprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), bfq_weight);
+                xsprintf(buf, DEVNUM_FORMAT_STR " %" PRIu64 "\n", DEVNUM_FORMAT_VAL(dev), bfq_weight);
         else
                 xsprintf(buf, "%" PRIu64 "\n", bfq_weight);
 
@@ -1117,7 +1117,7 @@ static void cgroup_apply_io_device_weight(Unit *u, const char *dev_path, uint64_
 
         r1 = set_bfq_weight(u, "io", dev, io_weight);
 
-        xsprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), io_weight);
+        xsprintf(buf, DEVNUM_FORMAT_STR " %" PRIu64 "\n", DEVNUM_FORMAT_VAL(dev), io_weight);
         r2 = cg_set_attribute("io", u->cgroup_path, "io.weight", buf);
 
         /* Look at the configured device, when both fail, prefer io.weight errno. */
@@ -1138,7 +1138,7 @@ static void cgroup_apply_blkio_device_weight(Unit *u, const char *dev_path, uint
         if (r < 0)
                 return;
 
-        xsprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), blkio_weight);
+        xsprintf(buf, DEVNUM_FORMAT_STR " %" PRIu64 "\n", DEVNUM_FORMAT_VAL(dev), blkio_weight);
         (void) set_attribute_and_warn(u, "blkio", "blkio.weight_device", buf);
 }
 
@@ -1152,9 +1152,9 @@ static void cgroup_apply_io_device_latency(Unit *u, const char *dev_path, usec_t
                 return;
 
         if (target != USEC_INFINITY)
-                xsprintf(buf, "%u:%u target=%" PRIu64 "\n", major(dev), minor(dev), target);
+                xsprintf(buf, DEVNUM_FORMAT_STR " target=%" PRIu64 "\n", DEVNUM_FORMAT_VAL(dev), target);
         else
-                xsprintf(buf, "%u:%u target=max\n", major(dev), minor(dev));
+                xsprintf(buf, DEVNUM_FORMAT_STR " target=max\n", DEVNUM_FORMAT_VAL(dev));
 
         (void) set_attribute_and_warn(u, "io", "io.latency", buf);
 }
@@ -1173,7 +1173,7 @@ static void cgroup_apply_io_device_limit(Unit *u, const char *dev_path, uint64_t
                 else
                         xsprintf(limit_bufs[type], "%s", limits[type] == CGROUP_LIMIT_MAX ? "max" : "0");
 
-        xsprintf(buf, "%u:%u rbps=%s wbps=%s riops=%s wiops=%s\n", major(dev), minor(dev),
+        xsprintf(buf, DEVNUM_FORMAT_STR " rbps=%s wbps=%s riops=%s wiops=%s\n", DEVNUM_FORMAT_VAL(dev),
                  limit_bufs[CGROUP_IO_RBPS_MAX], limit_bufs[CGROUP_IO_WBPS_MAX],
                  limit_bufs[CGROUP_IO_RIOPS_MAX], limit_bufs[CGROUP_IO_WIOPS_MAX]);
         (void) set_attribute_and_warn(u, "io", "io.max", buf);
@@ -1186,10 +1186,10 @@ static void cgroup_apply_blkio_device_limit(Unit *u, const char *dev_path, uint6
         if (lookup_block_device(dev_path, &dev) < 0)
                 return;
 
-        sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), rbps);
+        sprintf(buf, DEVNUM_FORMAT_STR " %" PRIu64 "\n", DEVNUM_FORMAT_VAL(dev), rbps);
         (void) set_attribute_and_warn(u, "blkio", "blkio.throttle.read_bps_device", buf);
 
-        sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), wbps);
+        sprintf(buf, DEVNUM_FORMAT_STR " %" PRIu64 "\n", DEVNUM_FORMAT_VAL(dev), wbps);
         (void) set_attribute_and_warn(u, "blkio", "blkio.throttle.write_bps_device", buf);
 }
 
index 156071f168158d5928701f994da0c95371c5261d..a6b2ea288664dacbef751a4a440964b2604be8bb 100644 (file)
@@ -2839,261 +2839,171 @@ const sd_bus_vtable bus_manager_vtable[] = {
         SD_BUS_PROPERTY("DefaultOOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("CtrlAltDelBurstAction", "s", bus_property_get_emergency_action, offsetof(Manager, cad_burst_action), SD_BUS_VTABLE_PROPERTY_CONST),
 
-        SD_BUS_METHOD_WITH_NAMES("GetUnit",
-                                 "s",
-                                 SD_BUS_PARAM(name),
-                                 "o",
-                                 SD_BUS_PARAM(unit),
-                                 method_get_unit,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("GetUnitByPID",
-                                 "u",
-                                 SD_BUS_PARAM(pid),
-                                 "o",
-                                 SD_BUS_PARAM(unit),
-                                 method_get_unit_by_pid,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("GetUnitByInvocationID",
-                                 "ay",
-                                 SD_BUS_PARAM(invocation_id),
-                                 "o",
-                                 SD_BUS_PARAM(unit),
-                                 method_get_unit_by_invocation_id,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("GetUnitByControlGroup",
-                                 "s",
-                                 SD_BUS_PARAM(cgroup),
-                                 "o",
-                                 SD_BUS_PARAM(unit),
-                                 method_get_unit_by_control_group,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("LoadUnit",
-                                 "s",
-                                 SD_BUS_PARAM(name),
-                                 "o",
-                                 SD_BUS_PARAM(unit),
-                                 method_load_unit,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("StartUnit",
-                                 "ss",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(mode),
-                                 "o",
-                                 SD_BUS_PARAM(job),
-                                 method_start_unit,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("StartUnitWithFlags",
-                                 "sst",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(mode)
-                                 SD_BUS_PARAM(flags),
-                                 "o",
-                                 SD_BUS_PARAM(job),
-                                 method_start_unit,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("StartUnitReplace",
-                                 "sss",
-                                 SD_BUS_PARAM(old_unit)
-                                 SD_BUS_PARAM(new_unit)
-                                 SD_BUS_PARAM(mode),
-                                 "o",
-                                 SD_BUS_PARAM(job),
-                                 method_start_unit_replace,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("StopUnit",
-                                 "ss",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(mode),
-                                 "o",
-                                 SD_BUS_PARAM(job),
-                                 method_stop_unit,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("ReloadUnit",
-                                 "ss",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(mode),
-                                 "o",
-                                 SD_BUS_PARAM(job),
-                                 method_reload_unit,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("RestartUnit",
-                                 "ss",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(mode),
-                                 "o",
-                                 SD_BUS_PARAM(job),
-                                 method_restart_unit,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("TryRestartUnit",
-                                 "ss",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(mode),
-                                 "o",
-                                 SD_BUS_PARAM(job),
-                                 method_try_restart_unit,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("ReloadOrRestartUnit",
-                                 "ss",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(mode),
-                                 "o",
-                                 SD_BUS_PARAM(job),
-                                 method_reload_or_restart_unit,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("ReloadOrTryRestartUnit",
-                                 "ss",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(mode),
-                                 "o",
-                                 SD_BUS_PARAM(job),
-                                 method_reload_or_try_restart_unit,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("EnqueueUnitJob",
-                                 "sss",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(job_type)
-                                 SD_BUS_PARAM(job_mode),
-                                 "uososa(uosos)",
-                                 SD_BUS_PARAM(job_id)
-                                 SD_BUS_PARAM(job_path)
-                                 SD_BUS_PARAM(unit_id)
-                                 SD_BUS_PARAM(unit_path)
-                                 SD_BUS_PARAM(job_type)
-                                 SD_BUS_PARAM(affected_jobs),
-                                 method_enqueue_unit_job,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("KillUnit",
-                                 "ssi",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(whom)
-                                 SD_BUS_PARAM(signal),
-                                 NULL,,
-                                 method_kill_unit,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("CleanUnit",
-                                 "sas",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(mask),
-                                 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),
-                                 NULL,,
-                                 method_reset_failed_unit,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetUnitProperties",
-                                 "sba(sv)",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(runtime)
-                                 SD_BUS_PARAM(properties),
-                                 NULL,,
-                                 method_set_unit_properties,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("BindMountUnit",
-                                 "sssbb",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(source)
-                                 SD_BUS_PARAM(destination)
-                                 SD_BUS_PARAM(read_only)
-                                 SD_BUS_PARAM(mkdir),
-                                 NULL,,
-                                 method_bind_mount_unit,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("MountImageUnit",
-                                 "sssbba(ss)",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(source)
-                                 SD_BUS_PARAM(destination)
-                                 SD_BUS_PARAM(read_only)
-                                 SD_BUS_PARAM(mkdir)
-                                 SD_BUS_PARAM(options),
-                                 NULL,,
-                                 method_mount_image_unit,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("RefUnit",
-                                 "s",
-                                 SD_BUS_PARAM(name),
-                                 NULL,,
-                                 method_ref_unit,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("UnrefUnit",
-                                 "s",
-                                 SD_BUS_PARAM(name),
-                                 NULL,,
-                                 method_unref_unit,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("StartTransientUnit",
-                                 "ssa(sv)a(sa(sv))",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(mode)
-                                 SD_BUS_PARAM(properties)
-                                 SD_BUS_PARAM(aux),
-                                 "o",
-                                 SD_BUS_PARAM(job),
-                                 method_start_transient_unit,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("GetUnitProcesses",
-                                 "s",
-                                 SD_BUS_PARAM(name),
-                                 "a(sus)",
-                                 SD_BUS_PARAM(processes),
-                                 method_get_unit_processes,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("AttachProcessesToUnit",
-                                 "ssau",
-                                 SD_BUS_PARAM(unit_name)
-                                 SD_BUS_PARAM(subcgroup)
-                                 SD_BUS_PARAM(pids),
-                                 NULL,,
-                                 method_attach_processes_to_unit,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("AbandonScope",
-                                 "s",
-                                 SD_BUS_PARAM(name),
-                                 NULL,,
-                                 method_abandon_scope,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("GetJob",
-                                 "u",
-                                 SD_BUS_PARAM(id),
-                                 "o",
-                                 SD_BUS_PARAM(job),
-                                 method_get_job,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("GetJobAfter",
-                                 "u",
-                                 SD_BUS_PARAM(id),
-                                 "a(usssoo)",
-                                 SD_BUS_PARAM(jobs),
-                                 method_get_job_waiting,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("GetJobBefore",
-                                 "u",
-                                 SD_BUS_PARAM(id),
-                                 "a(usssoo)",
-                                 SD_BUS_PARAM(jobs),
-                                 method_get_job_waiting,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("CancelJob",
-                                 "u",
-                                 SD_BUS_PARAM(id),
-                                 NULL,,
-                                 method_cancel_job,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetUnit",
+                                SD_BUS_ARGS("s", name),
+                                SD_BUS_RESULT("o", unit),
+                                method_get_unit,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetUnitByPID",
+                                SD_BUS_ARGS("u", pid),
+                                SD_BUS_RESULT("o", unit),
+                                method_get_unit_by_pid,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetUnitByInvocationID",
+                                SD_BUS_ARGS("ay", invocation_id),
+                                SD_BUS_RESULT("o", unit),
+                                method_get_unit_by_invocation_id,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetUnitByControlGroup",
+                                SD_BUS_ARGS("s", cgroup),
+                                SD_BUS_RESULT("o", unit),
+                                method_get_unit_by_control_group,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("LoadUnit",
+                                SD_BUS_ARGS("s", name),
+                                SD_BUS_RESULT("o", unit),
+                                method_load_unit,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("StartUnit",
+                                SD_BUS_ARGS("s", name, "s", mode),
+                                SD_BUS_RESULT("o", job),
+                                method_start_unit,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("StartUnitWithFlags",
+                                SD_BUS_ARGS("s", name, "s", mode, "t", flags),
+                                SD_BUS_RESULT("o", job),
+                                method_start_unit,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("StartUnitReplace",
+                                SD_BUS_ARGS("s", old_unit, "s", new_unit, "s", mode),
+                                SD_BUS_RESULT("o", job),
+                                method_start_unit_replace,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("StopUnit",
+                                SD_BUS_ARGS("s", name, "s", mode),
+                                SD_BUS_RESULT("o", job),
+                                method_stop_unit,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ReloadUnit",
+                                SD_BUS_ARGS("s", name, "s", mode),
+                                SD_BUS_RESULT("o", job),
+                                method_reload_unit,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("RestartUnit",
+                                SD_BUS_ARGS("s", name, "s", mode),
+                                SD_BUS_RESULT("o", job),
+                                method_restart_unit,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("TryRestartUnit",
+                                SD_BUS_ARGS("s", name, "s", mode),
+                                SD_BUS_RESULT("o", job),
+                                method_try_restart_unit,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ReloadOrRestartUnit",
+                                SD_BUS_ARGS("s", name, "s", mode),
+                                SD_BUS_RESULT("o", job),
+                                method_reload_or_restart_unit,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ReloadOrTryRestartUnit",
+                                SD_BUS_ARGS("s", name, "s", mode),
+                                SD_BUS_RESULT("o", job),
+                                method_reload_or_try_restart_unit,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("EnqueueUnitJob",
+                                SD_BUS_ARGS("s", name, "s", job_type, "s", job_mode),
+                                SD_BUS_RESULT("u", job_id, "o", job_path, "s", unit_id, "o", unit_path, "s", job_type, "a(uosos)", affected_jobs),
+                                method_enqueue_unit_job,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("KillUnit",
+                                SD_BUS_ARGS("s", name, "s", whom, "i", signal),
+                                SD_BUS_NO_RESULT,
+                                method_kill_unit,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("CleanUnit",
+                                SD_BUS_ARGS("s", name, "as", mask),
+                                SD_BUS_NO_RESULT,
+                                method_clean_unit,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("FreezeUnit",
+                                SD_BUS_ARGS("s", name),
+                                SD_BUS_NO_RESULT,
+                                method_freeze_unit,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ThawUnit",
+                                SD_BUS_ARGS("s", name),
+                                SD_BUS_NO_RESULT,
+                                method_thaw_unit,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ResetFailedUnit",
+                                SD_BUS_ARGS("s", name),
+                                SD_BUS_NO_RESULT,
+                                method_reset_failed_unit,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetUnitProperties",
+                                SD_BUS_ARGS("s", name, "b", runtime, "a(sv)", properties),
+                                SD_BUS_NO_RESULT,
+                                method_set_unit_properties,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("BindMountUnit",
+                                SD_BUS_ARGS("s", name, "s", source, "s", destination, "b", read_only, "b", mkdir),
+                                SD_BUS_NO_RESULT,
+                                method_bind_mount_unit,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("MountImageUnit",
+                                SD_BUS_ARGS("s", name, "s", source, "s", destination, "b", read_only, "b", mkdir, "a(ss)", options),
+                                SD_BUS_NO_RESULT,
+                                method_mount_image_unit,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("RefUnit",
+                                SD_BUS_ARGS("s", name),
+                                SD_BUS_NO_RESULT,
+                                method_ref_unit,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("UnrefUnit",
+                                SD_BUS_ARGS("s", name),
+                                SD_BUS_NO_RESULT,
+                                method_unref_unit,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("StartTransientUnit",
+                                SD_BUS_ARGS("s", name, "s", mode, "a(sv)", properties, "a(sa(sv))", aux),
+                                SD_BUS_RESULT("o", job),
+                                method_start_transient_unit,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetUnitProcesses",
+                                SD_BUS_ARGS("s", name),
+                                SD_BUS_RESULT("a(sus)", processes),
+                                method_get_unit_processes,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("AttachProcessesToUnit",
+                                SD_BUS_ARGS("s", unit_name, "s", subcgroup, "au", pids),
+                                SD_BUS_NO_RESULT,
+                                method_attach_processes_to_unit,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("AbandonScope",
+                                SD_BUS_ARGS("s", name),
+                                SD_BUS_NO_RESULT,
+                                method_abandon_scope,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetJob",
+                                SD_BUS_ARGS("u", id),
+                                SD_BUS_RESULT("o", job),
+                                method_get_job,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetJobAfter",
+                                SD_BUS_ARGS("u", id),
+                                SD_BUS_RESULT("a(usssoo)", jobs),
+                                method_get_job_waiting,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetJobBefore",
+                                SD_BUS_ARGS("u", id),
+                                SD_BUS_RESULT("a(usssoo)", jobs),
+                                method_get_job_waiting,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("CancelJob",
+                                SD_BUS_ARGS("u", id),
+                                SD_BUS_NO_RESULT,
+                                method_cancel_job,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ClearJobs",
                       NULL,
                       NULL,
@@ -3104,46 +3014,36 @@ const sd_bus_vtable bus_manager_vtable[] = {
                       NULL,
                       method_reset_failed,
                       SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetShowStatus",
-                                 "s",
-                                 SD_BUS_PARAM(mode),
-                                 NULL,,
-                                 method_set_show_status,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("ListUnits",
-                                 NULL,,
-                                 "a(ssssssouso)",
-                                 SD_BUS_PARAM(units),
-                                 method_list_units,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("ListUnitsFiltered",
-                                 "as",
-                                 SD_BUS_PARAM(states),
-                                 "a(ssssssouso)",
-                                 SD_BUS_PARAM(units),
-                                 method_list_units_filtered,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("ListUnitsByPatterns",
-                                 "asas",
-                                 SD_BUS_PARAM(states)
-                                 SD_BUS_PARAM(patterns),
-                                 "a(ssssssouso)",
-                                 SD_BUS_PARAM(units),
-                                 method_list_units_by_patterns,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("ListUnitsByNames",
-                                 "as",
-                                 SD_BUS_PARAM(names),
-                                 "a(ssssssouso)",
-                                 SD_BUS_PARAM(units),
-                                 method_list_units_by_names,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("ListJobs",
-                                 NULL,,
-                                 "a(usssoo)",
-                                 SD_BUS_PARAM(jobs),
-                                 method_list_jobs,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetShowStatus",
+                                SD_BUS_ARGS("s", mode),
+                                SD_BUS_NO_RESULT,
+                                method_set_show_status,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ListUnits",
+                                SD_BUS_NO_ARGS,
+                                SD_BUS_RESULT("a(ssssssouso)", units),
+                                method_list_units,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ListUnitsFiltered",
+                                SD_BUS_ARGS("as", states),
+                                SD_BUS_RESULT("a(ssssssouso)", units),
+                                method_list_units_filtered,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ListUnitsByPatterns",
+                                SD_BUS_ARGS("as", states, "as", patterns),
+                                SD_BUS_RESULT("a(ssssssouso)", units),
+                                method_list_units_by_patterns,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ListUnitsByNames",
+                                SD_BUS_ARGS("as", names),
+                                SD_BUS_RESULT("a(ssssssouso)", units),
+                                method_list_units_by_names,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ListJobs",
+                                SD_BUS_NO_ARGS,
+                                SD_BUS_RESULT("a(usssoo)", jobs),
+                                method_list_jobs,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Subscribe",
                       NULL,
                       NULL,
@@ -3154,32 +3054,26 @@ const sd_bus_vtable bus_manager_vtable[] = {
                       NULL,
                       method_unsubscribe,
                       SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("Dump",
-                                 NULL,,
-                                 "s",
-                                 SD_BUS_PARAM(output),
-                                 method_dump,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("DumpByFileDescriptor",
-                                 NULL,,
-                                 "h",
-                                 SD_BUS_PARAM(fd),
-                                 method_dump_by_fd,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("CreateSnapshot",
-                                 "sb",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(cleanup),
-                                 "o",
-                                 SD_BUS_PARAM(unit),
-                                 method_refuse_snapshot,
-                                 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_HIDDEN),
-        SD_BUS_METHOD_WITH_NAMES("RemoveSnapshot",
-                                 "s",
-                                 SD_BUS_PARAM(name),
-                                 NULL,,
-                                 method_refuse_snapshot,
-                                 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_HIDDEN),
+        SD_BUS_METHOD_WITH_ARGS("Dump",
+                                SD_BUS_NO_ARGS,
+                                SD_BUS_RESULT("s", output),
+                                method_dump,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("DumpByFileDescriptor",
+                                SD_BUS_NO_ARGS,
+                                SD_BUS_RESULT("h", fd),
+                                method_dump_by_fd,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("CreateSnapshot",
+                                SD_BUS_ARGS("s", name, "b", cleanup),
+                                SD_BUS_RESULT("o", unit),
+                                method_refuse_snapshot,
+                                SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_HIDDEN),
+        SD_BUS_METHOD_WITH_ARGS("RemoveSnapshot",
+                                SD_BUS_ARGS("s", name),
+                                SD_BUS_NO_RESULT,
+                                method_refuse_snapshot,
+                                SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_HIDDEN),
         SD_BUS_METHOD("Reload",
                       NULL,
                       NULL,
@@ -3215,264 +3109,166 @@ const sd_bus_vtable bus_manager_vtable[] = {
                       NULL,
                       method_kexec,
                       SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)),
-        SD_BUS_METHOD_WITH_NAMES("SwitchRoot",
-                                 "ss",
-                                 SD_BUS_PARAM(new_root)
-                                 SD_BUS_PARAM(init),
-                                 NULL,,
-                                 method_switch_root,
-                                 SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)),
-        SD_BUS_METHOD_WITH_NAMES("SetEnvironment",
-                                 "as",
-                                 SD_BUS_PARAM(assignments),
-                                 NULL,,
-                                 method_set_environment,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("UnsetEnvironment",
-                                 "as",
-                                 SD_BUS_PARAM(names),
-                                 NULL,,
-                                 method_unset_environment,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("UnsetAndSetEnvironment",
-                                 "asas",
-                                 SD_BUS_PARAM(names)
-                                 SD_BUS_PARAM(assignments),
-                                 NULL,,
-                                 method_unset_and_set_environment,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("EnqueueMarkedJobs",
-                                 NULL,,
-                                 "ao",
-                                 SD_BUS_PARAM(jobs),
-                                 method_enqueue_marked_jobs,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("ListUnitFiles",
-                                 NULL,,
-                                 "a(ss)",
-                                 SD_BUS_PARAM(unit_files),
-                                 method_list_unit_files,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("ListUnitFilesByPatterns",
-                                 "asas",
-                                 SD_BUS_PARAM(states)
-                                 SD_BUS_PARAM(patterns),
-                                 "a(ss)",
-                                 SD_BUS_PARAM(unit_files),
-                                 method_list_unit_files_by_patterns,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("GetUnitFileState",
-                                 "s",
-                                 SD_BUS_PARAM(file),
-                                 "s",
-                                 SD_BUS_PARAM(state),
-                                 method_get_unit_file_state,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("EnableUnitFiles",
-                                 "asbb",
-                                 SD_BUS_PARAM(files)
-                                 SD_BUS_PARAM(runtime)
-                                 SD_BUS_PARAM(force),
-                                 "ba(sss)",
-                                 SD_BUS_PARAM(carries_install_info)
-                                 SD_BUS_PARAM(changes),
-                                 method_enable_unit_files,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("DisableUnitFiles",
-                                 "asb",
-                                 SD_BUS_PARAM(files)
-                                 SD_BUS_PARAM(runtime),
-                                 "a(sss)",
-                                 SD_BUS_PARAM(changes),
-                                 method_disable_unit_files,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("EnableUnitFilesWithFlags",
-                                 "ast",
-                                 SD_BUS_PARAM(files)
-                                 SD_BUS_PARAM(flags),
-                                 "ba(sss)",
-                                 SD_BUS_PARAM(carries_install_info)
-                                 SD_BUS_PARAM(changes),
-                                 method_enable_unit_files_with_flags,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("DisableUnitFilesWithFlags",
-                                 "ast",
-                                 SD_BUS_PARAM(files)
-                                 SD_BUS_PARAM(flags),
-                                 "a(sss)",
-                                 SD_BUS_PARAM(changes),
-                                 method_disable_unit_files_with_flags,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("ReenableUnitFiles",
-                                 "asbb",
-                                 SD_BUS_PARAM(files)
-                                 SD_BUS_PARAM(runtime)
-                                 SD_BUS_PARAM(force),
-                                 "ba(sss)",
-                                 SD_BUS_PARAM(carries_install_info)
-                                 SD_BUS_PARAM(changes),
-                                 method_reenable_unit_files,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("LinkUnitFiles",
-                                 "asbb",
-                                 SD_BUS_PARAM(files)
-                                 SD_BUS_PARAM(runtime)
-                                 SD_BUS_PARAM(force),
-                                 "a(sss)",
-                                 SD_BUS_PARAM(changes),
-                                 method_link_unit_files,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("PresetUnitFiles",
-                                 "asbb",
-                                 SD_BUS_PARAM(files)
-                                 SD_BUS_PARAM(runtime)
-                                 SD_BUS_PARAM(force),
-                                 "ba(sss)",
-                                 SD_BUS_PARAM(carries_install_info)
-                                 SD_BUS_PARAM(changes),
-                                 method_preset_unit_files,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("PresetUnitFilesWithMode",
-                                 "assbb",
-                                 SD_BUS_PARAM(files)
-                                 SD_BUS_PARAM(mode)
-                                 SD_BUS_PARAM(runtime)
-                                 SD_BUS_PARAM(force),
-                                 "ba(sss)",
-                                 SD_BUS_PARAM(carries_install_info)
-                                 SD_BUS_PARAM(changes),
-                                 method_preset_unit_files_with_mode,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("MaskUnitFiles",
-                                 "asbb",
-                                 SD_BUS_PARAM(files)
-                                 SD_BUS_PARAM(runtime)
-                                 SD_BUS_PARAM(force),
-                                 "a(sss)",
-                                 SD_BUS_PARAM(changes),
-                                 method_mask_unit_files,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("UnmaskUnitFiles",
-                                 "asb",
-                                 SD_BUS_PARAM(files)
-                                 SD_BUS_PARAM(runtime),
-                                 "a(sss)",
-                                 SD_BUS_PARAM(changes),
-                                 method_unmask_unit_files,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("RevertUnitFiles",
-                                 "as",
-                                 SD_BUS_PARAM(files),
-                                 "a(sss)",
-                                 SD_BUS_PARAM(changes),
-                                 method_revert_unit_files,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetDefaultTarget",
-                                 "sb",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(force),
-                                 "a(sss)",
-                                 SD_BUS_PARAM(changes),
-                                 method_set_default_target,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("GetDefaultTarget",
-                                 NULL,,
-                                 "s",
-                                 SD_BUS_PARAM(name),
-                                 method_get_default_target,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("PresetAllUnitFiles",
-                                 "sbb",
-                                 SD_BUS_PARAM(mode)
-                                 SD_BUS_PARAM(runtime)
-                                 SD_BUS_PARAM(force),
-                                 "a(sss)",
-                                 SD_BUS_PARAM(changes),
-                                 method_preset_all_unit_files,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("AddDependencyUnitFiles",
-                                 "asssbb",
-                                 SD_BUS_PARAM(files)
-                                 SD_BUS_PARAM(target)
-                                 SD_BUS_PARAM(type)
-                                 SD_BUS_PARAM(runtime)
-                                 SD_BUS_PARAM(force),
-                                 "a(sss)",
-                                 SD_BUS_PARAM(changes),
-                                 method_add_dependency_unit_files,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("GetUnitFileLinks",
-                                 "sb",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(runtime),
-                                 "as",
-                                 SD_BUS_PARAM(links),
-                                 method_get_unit_file_links,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetExitCode",
-                                 "y",
-                                 SD_BUS_PARAM(number),
-                                 NULL,,
-                                 method_set_exit_code,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("LookupDynamicUserByName",
-                                 "s",
-                                 SD_BUS_PARAM(name),
-                                 "u",
-                                 SD_BUS_PARAM(uid),
-                                 method_lookup_dynamic_user_by_name,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("LookupDynamicUserByUID",
-                                 "u",
-                                 SD_BUS_PARAM(uid),
-                                 "s",
-                                 SD_BUS_PARAM(name),
-                                 method_lookup_dynamic_user_by_uid,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("GetDynamicUsers",
-                                 NULL,,
-                                 "a(us)",
-                                 SD_BUS_PARAM(users),
-                                 method_get_dynamic_users,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-
-        SD_BUS_SIGNAL_WITH_NAMES("UnitNew",
-                                 "so",
-                                 SD_BUS_PARAM(id)
-                                 SD_BUS_PARAM(unit),
-                                 0),
-        SD_BUS_SIGNAL_WITH_NAMES("UnitRemoved",
-                                 "so",
-                                 SD_BUS_PARAM(id)
-                                 SD_BUS_PARAM(unit),
-                                 0),
-        SD_BUS_SIGNAL_WITH_NAMES("JobNew",
-                                 "uos",
-                                 SD_BUS_PARAM(id)
-                                 SD_BUS_PARAM(job)
-                                 SD_BUS_PARAM(unit),
-                                 0),
-        SD_BUS_SIGNAL_WITH_NAMES("JobRemoved",
-                                 "uoss",
-                                 SD_BUS_PARAM(id)
-                                 SD_BUS_PARAM(job)
-                                 SD_BUS_PARAM(unit)
-                                 SD_BUS_PARAM(result),
-                                 0),
-        SD_BUS_SIGNAL_WITH_NAMES("StartupFinished",
-                                 "tttttt",
-                                 SD_BUS_PARAM(firmware)
-                                 SD_BUS_PARAM(loader)
-                                 SD_BUS_PARAM(kernel)
-                                 SD_BUS_PARAM(initrd)
-                                 SD_BUS_PARAM(userspace)
-                                 SD_BUS_PARAM(total),
-                                 0),
+        SD_BUS_METHOD_WITH_ARGS("SwitchRoot",
+                                SD_BUS_ARGS("s", new_root, "s", init),
+                                SD_BUS_NO_RESULT,
+                                method_switch_root,
+                                SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)),
+        SD_BUS_METHOD_WITH_ARGS("SetEnvironment",
+                                SD_BUS_ARGS("as", assignments),
+                                SD_BUS_NO_RESULT,
+                                method_set_environment,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("UnsetEnvironment",
+                                SD_BUS_ARGS("as", names),
+                                SD_BUS_NO_RESULT,
+                                method_unset_environment,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("UnsetAndSetEnvironment",
+                                SD_BUS_ARGS("as", names, "as", assignments),
+                                SD_BUS_NO_RESULT,
+                                method_unset_and_set_environment,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("EnqueueMarkedJobs",
+                                SD_BUS_NO_ARGS,
+                                SD_BUS_RESULT("ao", jobs),
+                                method_enqueue_marked_jobs,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ListUnitFiles",
+                                SD_BUS_NO_ARGS,
+                                SD_BUS_RESULT("a(ss)", unit_files),
+                                method_list_unit_files,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ListUnitFilesByPatterns",
+                                SD_BUS_ARGS("as", states, "as", patterns),
+                                SD_BUS_RESULT("a(ss)", unit_files),
+                                method_list_unit_files_by_patterns,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetUnitFileState",
+                                SD_BUS_ARGS("s", file),
+                                SD_BUS_RESULT("s", state),
+                                method_get_unit_file_state,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("EnableUnitFiles",
+                                SD_BUS_ARGS("as", files, "b", runtime, "b", force),
+                                SD_BUS_RESULT("b", carries_install_info, "a(sss)", changes),
+                                method_enable_unit_files,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("DisableUnitFiles",
+                                SD_BUS_ARGS("as", files, "b", runtime),
+                                SD_BUS_RESULT("a(sss)", changes),
+                                method_disable_unit_files,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("EnableUnitFilesWithFlags",
+                                SD_BUS_ARGS("as", files, "t", flags),
+                                SD_BUS_RESULT("b", carries_install_info, "a(sss)", changes),
+                                method_enable_unit_files_with_flags,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("DisableUnitFilesWithFlags",
+                                SD_BUS_ARGS("as", files, "t", flags),
+                                SD_BUS_RESULT("a(sss)", changes),
+                                method_disable_unit_files_with_flags,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ReenableUnitFiles",
+                                SD_BUS_ARGS("as", files, "b", runtime, "b", force),
+                                SD_BUS_RESULT("b", carries_install_info, "a(sss)", changes),
+                                method_reenable_unit_files,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("LinkUnitFiles",
+                                SD_BUS_ARGS("as", files, "b", runtime, "b", force),
+                                SD_BUS_RESULT("a(sss)", changes),
+                                method_link_unit_files,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("PresetUnitFiles",
+                                SD_BUS_ARGS("as", files, "b", runtime, "b", force),
+                                SD_BUS_RESULT("b", carries_install_info, "a(sss)", changes),
+                                method_preset_unit_files,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("PresetUnitFilesWithMode",
+                                SD_BUS_ARGS("as", files, "s", mode, "b", runtime, "b", force),
+                                SD_BUS_RESULT("b", carries_install_info, "a(sss)", changes),
+                                method_preset_unit_files_with_mode,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("MaskUnitFiles",
+                                SD_BUS_ARGS("as", files, "b", runtime, "b", force),
+                                SD_BUS_RESULT("a(sss)", changes),
+                                method_mask_unit_files,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("UnmaskUnitFiles",
+                                SD_BUS_ARGS("as", files, "b", runtime),
+                                SD_BUS_RESULT("a(sss)", changes),
+                                method_unmask_unit_files,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("RevertUnitFiles",
+                                SD_BUS_ARGS("as", files),
+                                SD_BUS_RESULT("a(sss)", changes),
+                                method_revert_unit_files,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetDefaultTarget",
+                                SD_BUS_ARGS("s", name, "b", force),
+                                SD_BUS_RESULT("a(sss)", changes),
+                                method_set_default_target,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetDefaultTarget",
+                                SD_BUS_NO_ARGS,
+                                SD_BUS_RESULT("s", name),
+                                method_get_default_target,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("PresetAllUnitFiles",
+                                SD_BUS_ARGS("s", mode, "b", runtime, "b", force),
+                                SD_BUS_RESULT("a(sss)", changes),
+                                method_preset_all_unit_files,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("AddDependencyUnitFiles",
+                                SD_BUS_ARGS("as", files, "s", target, "s", type, "b", runtime, "b", force),
+                                SD_BUS_RESULT("a(sss)", changes),
+                                method_add_dependency_unit_files,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetUnitFileLinks",
+                                SD_BUS_ARGS("s", name, "b", runtime),
+                                SD_BUS_RESULT("as", links),
+                                method_get_unit_file_links,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetExitCode",
+                                SD_BUS_ARGS("y", number),
+                                SD_BUS_NO_RESULT,
+                                method_set_exit_code,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("LookupDynamicUserByName",
+                                SD_BUS_ARGS("s", name),
+                                SD_BUS_RESULT("u", uid),
+                                method_lookup_dynamic_user_by_name,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("LookupDynamicUserByUID",
+                                SD_BUS_ARGS("u", uid),
+                                SD_BUS_RESULT("s", name),
+                                method_lookup_dynamic_user_by_uid,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetDynamicUsers",
+                                SD_BUS_NO_ARGS,
+                                SD_BUS_RESULT("a(us)", users),
+                                method_get_dynamic_users,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+
+        SD_BUS_SIGNAL_WITH_ARGS("UnitNew",
+                                SD_BUS_ARGS("s", id, "o", unit),
+                                0),
+        SD_BUS_SIGNAL_WITH_ARGS("UnitRemoved",
+                                SD_BUS_ARGS("s", id, "o", unit),
+                                0),
+        SD_BUS_SIGNAL_WITH_ARGS("JobNew",
+                                SD_BUS_ARGS("u", id, "o", job, "s", unit),
+                                0),
+        SD_BUS_SIGNAL_WITH_ARGS("JobRemoved",
+                                SD_BUS_ARGS("u", id, "o", job, "s", unit, "s", result),
+                                0),
+        SD_BUS_SIGNAL_WITH_ARGS("StartupFinished",
+                                SD_BUS_ARGS("t", firmware, "t", loader, "t", kernel, "t", initrd, "t", userspace, "t", total),
+                                0),
         SD_BUS_SIGNAL("UnitFilesChanged", NULL, 0),
-        SD_BUS_SIGNAL_WITH_NAMES("Reloading",
-                                 "b",
-                                 SD_BUS_PARAM(active),
-                                 0),
+        SD_BUS_SIGNAL_WITH_ARGS("Reloading",
+                                SD_BUS_ARGS("b", active),
+                                0),
 
         SD_BUS_VTABLE_END
 };
index e90fe4f596b0a03672bc77a98d2e111348bfff6e..9c7da5a3514b91a84d055fc0f8ec690e5f054d97 100644 (file)
@@ -247,24 +247,15 @@ const sd_bus_vtable bus_service_vtable[] = {
         BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPost", offsetof(Service, exec_command[SERVICE_EXEC_STOP_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
         BUS_EXEC_EX_COMMAND_LIST_VTABLE("ExecStopPostEx", offsetof(Service, exec_command[SERVICE_EXEC_STOP_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
 
-        SD_BUS_METHOD_WITH_NAMES("BindMount",
-                                 "ssbb",
-                                 SD_BUS_PARAM(source)
-                                 SD_BUS_PARAM(destination)
-                                 SD_BUS_PARAM(read_only)
-                                 SD_BUS_PARAM(mkdir),
-                                 NULL,,
-                                 bus_service_method_bind_mount,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-
-        SD_BUS_METHOD_WITH_NAMES("MountImage",
-                                 "ssbba(ss)",
-                                 SD_BUS_PARAM(source)
-                                 SD_BUS_PARAM(destination)
-                                 SD_BUS_PARAM(read_only)
-                                 SD_BUS_PARAM(mkdir)
-                                 SD_BUS_PARAM(options),
-                                 NULL,,
+        SD_BUS_METHOD_WITH_ARGS("BindMount",
+                                SD_BUS_ARGS("s", source, "s", destination, "b", read_only, "b", mkdir),
+                                SD_BUS_NO_RESULT,
+                                bus_service_method_bind_mount,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+
+        SD_BUS_METHOD_WITH_ARGS("MountImage",
+                                 SD_BUS_ARGS("s", source, "s", destination, "b", read_only, "b", mkdir, "a(ss)", options),
+                                 SD_BUS_NO_RESULT,
                                  bus_service_method_mount_image,
                                  SD_BUS_VTABLE_UNPRIVILEGED),
 
index 9c4e0fee5a035a49eba13fbb7dd88e9d98d5ebfd..34608fc0915f4a6ac2d94038865326dfc74008bf 100644 (file)
@@ -951,87 +951,61 @@ const sd_bus_vtable bus_unit_vtable[] = {
         SD_BUS_PROPERTY("CollectMode", "s", property_get_collect_mode, offsetof(Unit, collect_mode), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("Refs", "as", property_get_refs, 0, 0),
 
-        SD_BUS_METHOD_WITH_NAMES("Start",
-                                 "s",
-                                 SD_BUS_PARAM(mode),
-                                 "o",
-                                 SD_BUS_PARAM(job),
-                                 bus_unit_method_start,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("Stop",
-                                 "s",
-                                 SD_BUS_PARAM(mode),
-                                 "o",
-                                 SD_BUS_PARAM(job),
-                                 bus_unit_method_stop,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("Reload",
-                                 "s",
-                                 SD_BUS_PARAM(mode),
-                                 "o",
-                                 SD_BUS_PARAM(job),
-                                 bus_unit_method_reload,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("Restart",
-                                 "s",
-                                 SD_BUS_PARAM(mode),
-                                 "o",
-                                 SD_BUS_PARAM(job),
-                                 bus_unit_method_restart,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("TryRestart",
-                                 "s",
-                                 SD_BUS_PARAM(mode),
-                                 "o",
-                                 SD_BUS_PARAM(job),
-                                 bus_unit_method_try_restart,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("ReloadOrRestart",
-                                 "s",
-                                 SD_BUS_PARAM(mode),
-                                 "o",
-                                 SD_BUS_PARAM(job),
-                                 bus_unit_method_reload_or_restart,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("ReloadOrTryRestart",
-                                 "s",
-                                 SD_BUS_PARAM(mode),
-                                 "o",
-                                 SD_BUS_PARAM(job),
-                                 bus_unit_method_reload_or_try_restart,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("EnqueueJob",
-                                 "ss",
-                                 SD_BUS_PARAM(job_type)
-                                 SD_BUS_PARAM(job_mode),
-                                 "uososa(uosos)",
-                                 SD_BUS_PARAM(job_id)
-                                 SD_BUS_PARAM(job_path)
-                                 SD_BUS_PARAM(unit_id)
-                                 SD_BUS_PARAM(unit_path)
-                                 SD_BUS_PARAM(job_type)
-                                 SD_BUS_PARAM(affected_jobs),
-                                 bus_unit_method_enqueue_job,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("Kill",
-                                 "si",
-                                 SD_BUS_PARAM(whom)
-                                 SD_BUS_PARAM(signal),
-                                 NULL,,
-                                 bus_unit_method_kill,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("Start",
+                                SD_BUS_ARGS("s", mode),
+                                SD_BUS_RESULT("o", job),
+                                bus_unit_method_start,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("Stop",
+                                SD_BUS_ARGS("s", mode),
+                                SD_BUS_RESULT("o", job),
+                                bus_unit_method_stop,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("Reload",
+                                SD_BUS_ARGS("s", mode),
+                                SD_BUS_RESULT("o", job),
+                                bus_unit_method_reload,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("Restart",
+                                SD_BUS_ARGS("s", mode),
+                                SD_BUS_RESULT("o", job),
+                                bus_unit_method_restart,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("TryRestart",
+                                SD_BUS_ARGS("s", mode),
+                                SD_BUS_RESULT("o", job),
+                                bus_unit_method_try_restart,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ReloadOrRestart",
+                                SD_BUS_ARGS("s", mode),
+                                SD_BUS_RESULT("o", job),
+                                bus_unit_method_reload_or_restart,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ReloadOrTryRestart",
+                                SD_BUS_ARGS("s", mode),
+                                SD_BUS_RESULT("o", job),
+                                bus_unit_method_reload_or_try_restart,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("EnqueueJob",
+                                SD_BUS_ARGS("s", job_type, "s", job_mode),
+                                SD_BUS_RESULT("u", job_id, "o", job_path, "s", unit_id, "o", unit_path, "s", job_type, "a(uosos)", affected_jobs),
+                                bus_unit_method_enqueue_job,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("Kill",
+                                SD_BUS_ARGS("s", whom, "i", signal),
+                                SD_BUS_NO_RESULT,
+                                bus_unit_method_kill,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ResetFailed",
                       NULL,
                       NULL,
                       bus_unit_method_reset_failed,
                       SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetProperties",
-                                 "ba(sv)",
-                                 SD_BUS_PARAM(runtime)
-                                 SD_BUS_PARAM(properties),
-                                 NULL,,
-                                 bus_unit_method_set_properties,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetProperties",
+                                SD_BUS_ARGS("b", runtime, "a(sv)", properties),
+                                SD_BUS_NO_RESULT,
+                                bus_unit_method_set_properties,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Ref",
                       NULL,
                       NULL,
@@ -1042,12 +1016,11 @@ const sd_bus_vtable bus_unit_vtable[] = {
                       NULL,
                       bus_unit_method_unref,
                       SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("Clean",
-                                 "as",
-                                 SD_BUS_PARAM(mask),
-                                 NULL,,
-                                 bus_unit_method_clean,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("Clean",
+                                SD_BUS_ARGS("as", mask),
+                                SD_BUS_NO_RESULT,
+                                bus_unit_method_clean,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Freeze",
                       NULL,
                       NULL,
@@ -1600,18 +1573,15 @@ const sd_bus_vtable bus_unit_cgroup_vtable[] = {
         SD_BUS_PROPERTY("IOWriteBytes", "t", property_get_io_counter, 0, 0),
         SD_BUS_PROPERTY("IOWriteOperations", "t", property_get_io_counter, 0, 0),
 
-        SD_BUS_METHOD_WITH_NAMES("GetProcesses",
-                                 NULL,,
-                                 "a(sus)",
-                                 SD_BUS_PARAM(processes),
+        SD_BUS_METHOD_WITH_ARGS("GetProcesses",
+                                 SD_BUS_NO_ARGS,
+                                 SD_BUS_ARGS("a(sus)", processes),
                                  bus_unit_method_get_processes,
                                  SD_BUS_VTABLE_UNPRIVILEGED),
 
-        SD_BUS_METHOD_WITH_NAMES("AttachProcesses",
-                                 "sau",
-                                 SD_BUS_PARAM(subcgroup)
-                                 SD_BUS_PARAM(pids),
-                                 NULL,,
+        SD_BUS_METHOD_WITH_ARGS("AttachProcesses",
+                                 SD_BUS_ARGS("s", subcgroup, "au", pids),
+                                 SD_BUS_NO_RESULT,
                                  bus_unit_method_attach_processes,
                                  SD_BUS_VTABLE_UNPRIVILEGED),
 
index 66e0c01c2324f22765d9bc3019d0edf471683407..74c41335caefe5f00c48071c9022347a3e887e08 100644 (file)
@@ -49,7 +49,7 @@
 #include "missing_ioprio.h"
 #include "mountpoint-util.h"
 #include "nulstr-util.h"
-#include "parse-socket-bind-item.h"
+#include "parse-helpers.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "percent-util.h"
index 59ddb9c48758272306590383ed090effa3c333e8..716febbefa25e5b38cdede3dfc71e8b17bc2337d 100644 (file)
@@ -16,7 +16,6 @@
 int locale_setup(char ***environment) {
         _cleanup_(locale_variables_freep) char *variables[_VARIABLE_LC_MAX] = {};
         _cleanup_strv_free_ char **add = NULL;
-        LocaleVariable i;
         int r;
 
         r = proc_cmdline_get_key_many(PROC_CMDLINE_STRIP_RD_PREFIX,
@@ -58,7 +57,7 @@ int locale_setup(char ***environment) {
                         log_warning_errno(r, "Failed to read /etc/locale.conf: %m");
         }
 
-        for (i = 0; i < _VARIABLE_LC_MAX; i++) {
+        for (LocaleVariable i = 0; i < _VARIABLE_LC_MAX; i++) {
                 char *s;
 
                 if (!variables[i])
index c6e9e9b0342b54d77ed5fc709f761239bfd238a6..438405bda2739b6f9275949fb1f673515195c07b 100644 (file)
@@ -2051,7 +2051,7 @@ static void log_execution_mode(bool *ret_first_boot) {
                         }
                 }
 
-                assert(uname(&uts) >= 0);
+                assert_se(uname(&uts) >= 0);
 
                 if (strverscmp_improved(uts.release, KERNEL_BASELINE_VERSION) < 0)
                         log_warning("Warning! Reported kernel version %s is older than systemd's required baseline kernel version %s. "
index 2f60b141590d11bd5bb1133df8286b93357f1252..a68324affc5bcb2698978f55592d2a2e9ac87e2a 100644 (file)
@@ -3665,9 +3665,67 @@ static int manager_run_environment_generators(Manager *m) {
         return r;
 }
 
+static int build_generator_environment(Manager *m, char ***ret) {
+        _cleanup_strv_free_ char **nl = NULL;
+        Virtualization v;
+        int r;
+
+        assert(m);
+        assert(ret);
+
+        /* Generators oftentimes want to know some basic facts about the environment they run in, in order to
+         * adjust generated units to that. Let's pass down some bits of information that are easy for us to
+         * determine (but a bit harder for generator scripts to determine), as environment variables. */
+
+        nl = strv_copy(m->transient_environment);
+        if (!nl)
+                return -ENOMEM;
+
+        r = strv_env_assign(&nl, "SYSTEMD_SCOPE", MANAGER_IS_SYSTEM(m) ? "system" : "user");
+        if (r < 0)
+                return r;
+
+        if (MANAGER_IS_SYSTEM(m)) {
+                /* Note that $SYSTEMD_IN_INITRD may be used to override the initrd detection in much of our
+                 * codebase. This is hence more than purely informational. It will shortcut detection of the
+                 * initrd state if generators invoke our own tools. But that's OK, as it would come to the
+                 * same results (hopefully). */
+                r = strv_env_assign(&nl, "SYSTEMD_IN_INITRD", one_zero(in_initrd()));
+                if (r < 0)
+                        return r;
+
+                if (m->first_boot >= 0) {
+                        r = strv_env_assign(&nl, "SYSTEMD_FIRST_BOOT", one_zero(m->first_boot));
+                        if (r < 0)
+                                return r;
+                }
+        }
+
+        v = detect_virtualization();
+        if (v < 0)
+                log_debug_errno(v, "Failed to detect virtualization, ignoring: %m");
+        else if (v > 0) {
+                const char *s;
+
+                s = strjoina(VIRTUALIZATION_IS_VM(v) ? "vm:" :
+                             VIRTUALIZATION_IS_CONTAINER(v) ? "container:" : ":",
+                             virtualization_to_string(v));
+
+                r = strv_env_assign(&nl, "SYSTEMD_VIRTUALIZATION", s);
+                if (r < 0)
+                        return r;
+        }
+
+        r = strv_env_assign(&nl, "SYSTEMD_ARCHITECTURE", architecture_to_string(uname_architecture()));
+        if (r < 0)
+                return r;
+
+        *ret = TAKE_PTR(nl);
+        return 0;
+}
+
 static int manager_run_generators(Manager *m) {
-        _cleanup_strv_free_ char **paths = NULL;
-        const char *argv[5];
+        _cleanup_strv_free_ char **paths = NULL, **ge = NULL;
         int r;
 
         assert(m);
@@ -3688,16 +3746,28 @@ static int manager_run_generators(Manager *m) {
                 goto finish;
         }
 
-        argv[0] = NULL; /* Leave this empty, execute_directory() will fill something in */
-        argv[1] = m->lookup_paths.generator;
-        argv[2] = m->lookup_paths.generator_early;
-        argv[3] = m->lookup_paths.generator_late;
-        argv[4] = NULL;
+        const char *argv[] = {
+                NULL, /* Leave this empty, execute_directory() will fill something in */
+                m->lookup_paths.generator,
+                m->lookup_paths.generator_early,
+                m->lookup_paths.generator_late,
+                NULL,
+        };
+
+        r = build_generator_environment(m, &ge);
+        if (r < 0) {
+                log_error_errno(r, "Failed to build generator environment: %m");
+                goto finish;
+        }
 
         RUN_WITH_UMASK(0022)
-                (void) execute_directories((const char* const*) paths, DEFAULT_TIMEOUT_USEC, NULL, NULL,
-                                           (char**) argv, m->transient_environment,
-                                           EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS | EXEC_DIR_SET_SYSTEMD_EXEC_PID);
+                (void) execute_directories(
+                                (const char* const*) paths,
+                                DEFAULT_TIMEOUT_USEC,
+                                /* callbacks= */ NULL, /* callback_args= */ NULL,
+                                (char**) argv,
+                                ge,
+                                EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS | EXEC_DIR_SET_SYSTEMD_EXEC_PID);
 
         r = 0;
 
index e6aa7b6473eaa602abe1c609a800f94e1061b50a..926aa961741ae70fc5c5e3e923b95f448d548605 100644 (file)
@@ -12,6 +12,7 @@
 #include "base-filesystem.h"
 #include "chase-symlinks.h"
 #include "dev-setup.h"
+#include "devnum-util.h"
 #include "env-util.h"
 #include "escape.h"
 #include "extension-release.h"
@@ -885,10 +886,10 @@ add_symlink:
                 return 0;
 
         /* Create symlinks like /dev/char/1:9 → ../urandom */
-        if (asprintf(&sl, "%s/dev/%s/%u:%u",
+        if (asprintf(&sl, "%s/dev/%s/" DEVNUM_FORMAT_STR,
                      temporary_mount,
                      S_ISCHR(st.st_mode) ? "char" : "block",
-                     major(st.st_rdev), minor(st.st_rdev)) < 0)
+                     DEVNUM_FORMAT_VAL(st.st_rdev)) < 0)
                 return log_oom();
 
         (void) mkdir_parents(sl, 0755);
@@ -2055,6 +2056,12 @@ int setup_namespace(
                 if (r < 0)
                         return log_debug_errno(r, "Failed to create loop device for root image: %m");
 
+                /* Make sure udevd won't issue BLKRRPART (which might flush out the loaded partition table)
+                 * while we are still trying to mount things */
+                r = loop_device_flock(loop_device, LOCK_SH);
+                if (r < 0)
+                        return log_debug_errno(r, "Failed to lock loopback device with LOCK_SH: %m");
+
                 r = dissect_image(
                                 loop_device->fd,
                                 &verity,
@@ -2403,6 +2410,14 @@ int setup_namespace(
                         goto finish;
                 }
 
+                /* Now release the block device lock, so that udevd is free to call BLKRRPART on the device
+                 * if it likes. */
+                r = loop_device_flock(loop_device, LOCK_UN);
+                if (r < 0) {
+                        log_debug_errno(r, "Failed to release lock on loopback block device: %m");
+                        goto finish;
+                }
+
                 if (decrypted_image) {
                         r = decrypted_image_relinquish(decrypted_image);
                         if (r < 0) {
index 0cdfcd6efdb60d250c063e1234e38e7589863d31..e454df0405306a58b597120413c295b7abe9eb74 100644 (file)
@@ -195,8 +195,8 @@ int unit_name_printf(const Unit *u, const char* format, char **ret) {
 }
 
 int unit_full_printf_full(const Unit *u, const char *format, size_t max_length, char **ret) {
-        /* This is similar to unit_name_printf() but also supports unescaping. Also, adds a couple of additional codes
-         * (which are likely not suitable for unescaped inclusion in unit names):
+        /* This is similar to unit_name_printf() but also supports unescaping. Also, adds a couple of
+         * additional codes (which are likely not suitable for unescaped inclusion in unit names):
          *
          * %f: the unescaped instance if set, otherwise the id unescaped as path
          *
@@ -214,9 +214,9 @@ int unit_full_printf_full(const Unit *u, const char *format, size_t max_length,
          * %h: the homedir of the running user
          * %s: the shell of the running user
          *
-         * NOTICE: When you add new entries here, please be careful: specifiers which depend on settings of the unit
-         * file itself are broken by design, as they would resolve differently depending on whether they are used
-         * before or after the relevant configuration setting. Hence: don't add them.
+         * NOTICE: When you add new entries here, please be careful: specifiers which depend on settings of
+         * the unit file itself are broken by design, as they would resolve differently depending on whether
+         * they are used before or after the relevant configuration setting. Hence: don't add them.
          */
 
         assert(u);
@@ -237,9 +237,9 @@ int unit_full_printf_full(const Unit *u, const char *format, size_t max_length,
                 { 'y', specifier_real_path,                u->fragment_path },
                 { 'Y', specifier_real_directory,           u->fragment_path },
 
-                { 'c', specifier_cgroup,                   NULL },
-                { 'r', specifier_cgroup_slice,             NULL },
-                { 'R', specifier_cgroup_root,              NULL },
+                { 'c', specifier_cgroup,                   NULL },  /* deprecated, see 1b89b0c499cd4bf0ff389caab4ecaae6e75f9d4e */
+                { 'r', specifier_cgroup_slice,             NULL },  /* deprecated, see 1b89b0c499cd4bf0ff389caab4ecaae6e75f9d4e */
+                { 'R', specifier_cgroup_root,              NULL },  /* deprecated, see 1b89b0c499cd4bf0ff389caab4ecaae6e75f9d4e */
 
                 { 'C', specifier_special_directory,        UINT_TO_PTR(EXEC_DIRECTORY_CACHE) },
                 { 'd', specifier_credentials_dir,          NULL },
index 2fd314ff37176decc95c99860ba5505175fe86b3..6e3441e5a0b1586d5c6974c5a3db59f6fd692360 100644 (file)
@@ -103,7 +103,7 @@ static int verb_list(int argc, char **argv, void *userdata) {
 
         r = open_credential_directory(&d);
         if (r == -ENXIO)
-                return log_error_errno(r, "No credentials received. (i.e. $CREDENTIALS_PATH not set or pointing to empty directory.)");
+                return log_error_errno(r, "No credentials received. (i.e. $CREDENTIALS_DIRECTORY not set or pointing to empty directory.)");
         if (r < 0)
                 return log_error_errno(r, "Failed to open credentials directory: %m");
 
index 1d78dc50858336413865342620eeab10a44e4ffb..51e3c4b83769ea59801390a4961f3c7654ac2e6a 100644 (file)
@@ -639,6 +639,10 @@ static int action_mount(DissectedImage *m, LoopDevice *d) {
         if (r < 0)
                 return r;
 
+        r = loop_device_flock(d, LOCK_UN);
+        if (r < 0)
+                return log_error_errno(r, "Failed to unlock loopback block device: %m");
+
         if (di) {
                 r = decrypted_image_relinquish(di);
                 if (r < 0)
@@ -687,6 +691,10 @@ static int action_copy(DissectedImage *m, LoopDevice *d) {
 
         mounted_dir = TAKE_PTR(created_dir);
 
+        r = loop_device_flock(d, LOCK_UN);
+        if (r < 0)
+                return log_error_errno(r, "Failed to unlock loopback block device: %m");
+
         if (di) {
                 r = decrypted_image_relinquish(di);
                 if (r < 0)
@@ -845,6 +853,12 @@ static int run(int argc, char *argv[]) {
         if (r < 0)
                 return log_error_errno(r, "Failed to set up loopback device for %s: %m", arg_image);
 
+        /* Make sure udevd doesn't issue BLKRRPART underneath us thus making devices disappear in the middle,
+         * that we assume already are there. */
+        r = loop_device_flock(d, LOCK_SH);
+        if (r < 0)
+                return log_error_errno(r, "Failed to lock loopback device: %m");
+
         r = dissect_image_and_warn(
                         d->fd,
                         arg_image,
index 28982a4c3471a3443387d38f5e03561d12988ae4..cd4b05c52d49eacc5e42c4e7b38f0e1bc31085c8 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <stdlib.h>
+#include <sys/file.h>
 #include <unistd.h>
 
 #include "sd-device.h"
@@ -11,6 +12,7 @@
 #include "blockdev-util.h"
 #include "btrfs-util.h"
 #include "device-util.h"
+#include "devnum-util.h"
 #include "dirent-util.h"
 #include "dissect-image.h"
 #include "dropin.h"
@@ -56,8 +58,8 @@ static int open_parent_block_device(dev_t devnum, int *ret_fd) {
         if (sd_device_get_devname(d, &name) < 0) {
                 r = sd_device_get_syspath(d, &name);
                 if (r < 0) {
-                        log_device_debug_errno(d, r, "Device %u:%u does not have a name, ignoring: %m",
-                                               major(devnum), minor(devnum));
+                        log_device_debug_errno(d, r, "Device " DEVNUM_FORMAT_STR " does not have a name, ignoring: %m",
+                                               DEVNUM_FORMAT_VAL(devnum));
                         return 0;
                 }
         }
@@ -696,6 +698,12 @@ static int enumerate_partitions(dev_t devnum) {
         if (r <= 0)
                 return r;
 
+        /* Let's take a LOCK_SH lock on the block device, in case udevd is already running. If we don't take
+         * the lock, udevd might end up issuing BLKRRPART in the middle, and we don't want that, since that
+         * might remove all partitions while we are operating on them. */
+        if (flock(fd, LOCK_SH) < 0)
+                return log_error_errno(errno, "Failed to lock root block device: %m");
+
         r = dissect_image(
                         fd,
                         NULL, NULL,
@@ -703,7 +711,6 @@ static int enumerate_partitions(dev_t devnum) {
                         UINT64_MAX,
                         USEC_INFINITY,
                         DISSECT_IMAGE_GPT_ONLY|
-                        DISSECT_IMAGE_NO_UDEV|
                         DISSECT_IMAGE_USR_NO_ROOT,
                         &m);
         if (r == -ENOPKG) {
index 58e35e403ebec5ca8b99f95804eb9583996fd9a2..1c7d9179d8eb8378d5d226a415e9c21f790c7065 100644 (file)
@@ -5,6 +5,7 @@
 #include <sys/stat.h>
 
 #include "alloc-util.h"
+#include "devnum-util.h"
 #include "fileio.h"
 #include "log.h"
 #include "util.h"
@@ -12,7 +13,6 @@
 int main(int argc, char *argv[]) {
         struct stat st;
         const char *device;
-        _cleanup_free_ char *major_minor = NULL;
         int r;
 
         if (argc != 2) {
@@ -40,14 +40,9 @@ int main(int argc, char *argv[]) {
                 return EXIT_FAILURE;
         }
 
-        if (asprintf(&major_minor, "%d:%d", major(st.st_rdev), minor(st.st_rdev)) < 0) {
-                log_oom();
-                return EXIT_FAILURE;
-        }
-
-        r = write_string_file("/sys/power/resume", major_minor, WRITE_STRING_FILE_DISABLE_BUFFER);
+        r = write_string_file("/sys/power/resume", FORMAT_DEVNUM(st.st_rdev), WRITE_STRING_FILE_DISABLE_BUFFER);
         if (r < 0) {
-                log_error_errno(r, "Failed to write '%s' to /sys/power/resume: %m", major_minor);
+                log_error_errno(r, "Failed to write '" DEVNUM_FORMAT_STR "' to /sys/power/resume: %m", DEVNUM_FORMAT_VAL(st.st_rdev));
                 return EXIT_FAILURE;
         }
 
@@ -58,6 +53,6 @@ int main(int argc, char *argv[]) {
          * no hibernation image).
          */
 
-        log_info("Could not resume from '%s' (%s).", device, major_minor);
+        log_info("Could not resume from '%s' (" DEVNUM_FORMAT_STR ").", device, DEVNUM_FORMAT_VAL(st.st_rdev));
         return EXIT_SUCCESS;
 }
index c2b9eb64f9bd0d23b6475e1d688842c74ef8ae0e..a0253c34c1d3a605edd335ecc537301206071164 100644 (file)
@@ -527,7 +527,7 @@ static int search_quota(uid_t uid, const char *exclude_quota_path) {
 
                 previous_devno = st.st_dev;
 
-                r = quotactl_devno(QCMD_FIXED(Q_GETQUOTA, USRQUOTA), st.st_dev, uid, &req);
+                r = quotactl_devnum(QCMD_FIXED(Q_GETQUOTA, USRQUOTA), st.st_dev, uid, &req);
                 if (r < 0) {
                         if (ERRNO_IS_NOT_SUPPORTED(r))
                                 log_debug_errno(r, "No UID quota support on %s, ignoring.", where);
index 5416d12fcf984e5456701794adfff80fb0958f7d..17c2f4f4e2ce386e56da74a1730c0bedb5e27e1e 100644 (file)
@@ -19,6 +19,7 @@
 #include "blockdev-util.h"
 #include "btrfs-util.h"
 #include "chattr-util.h"
+#include "devnum-util.h"
 #include "dm-util.h"
 #include "env-util.h"
 #include "errno-util.h"
@@ -46,7 +47,6 @@
 #include "process-util.h"
 #include "random-util.h"
 #include "resize-fs.h"
-#include "stat-util.h"
 #include "strv.h"
 #include "sync-util.h"
 #include "tmpfile-util.h"
@@ -1301,7 +1301,7 @@ int home_setup_luks(
                                 return log_error_errno(r, "Failed to stat block device %s: %m", n);
                         assert(S_ISBLK(st.st_mode));
 
-                        if (asprintf(&sysfs, "/sys/dev/block/%u:%u/partition", major(st.st_rdev), minor(st.st_rdev)) < 0)
+                        if (asprintf(&sysfs, "/sys/dev/block/" DEVNUM_FORMAT_STR "/partition", DEVNUM_FORMAT_VAL(st.st_rdev)) < 0)
                                 return log_oom();
 
                         if (access(sysfs, F_OK) < 0) {
@@ -1312,7 +1312,7 @@ int home_setup_luks(
                         } else {
                                 _cleanup_free_ char *buffer = NULL;
 
-                                if (asprintf(&sysfs, "/sys/dev/block/%u:%u/start", major(st.st_rdev), minor(st.st_rdev)) < 0)
+                                if (asprintf(&sysfs, "/sys/dev/block/" DEVNUM_FORMAT_STR "/start", DEVNUM_FORMAT_VAL(st.st_rdev)) < 0)
                                         return log_oom();
 
                                 r = read_one_line_file(sysfs, &buffer);
@@ -2205,7 +2205,7 @@ int home_create_luks(
                 if (!S_ISBLK(st.st_mode))
                         return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK), "Device is not a block device, refusing.");
 
-                if (asprintf(&sysfs, "/sys/dev/block/%u:%u/partition", major(st.st_rdev), minor(st.st_rdev)) < 0)
+                if (asprintf(&sysfs, "/sys/dev/block/" DEVNUM_FORMAT_STR "/partition", DEVNUM_FORMAT_VAL(st.st_rdev)) < 0)
                         return log_oom();
                 if (access(sysfs, F_OK) < 0) {
                         if (errno != ENOENT)
index 7001870dfb85ac9d1b9b1b9202b804336e988665..574d1556af18ea03298d4032ee61df99255894c9 100644 (file)
@@ -54,7 +54,7 @@ int home_update_quota_classic(UserRecord *h, const char *path) {
         if (devno == 0)
                 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system %s not backed by a block device.", path);
 
-        r = quotactl_devno(QCMD_FIXED(Q_GETQUOTA, USRQUOTA), devno, h->uid, &req);
+        r = quotactl_devnum(QCMD_FIXED(Q_GETQUOTA, USRQUOTA), devno, h->uid, &req);
         if (r < 0) {
                 if (ERRNO_IS_NOT_SUPPORTED(r))
                         return log_error_errno(r, "No UID quota support on %s.", path);
@@ -74,7 +74,7 @@ int home_update_quota_classic(UserRecord *h, const char *path) {
         req.dqb_valid = QIF_BLIMITS;
         req.dqb_bsoftlimit = req.dqb_bhardlimit = h->disk_size / QIF_DQBLKSIZE;
 
-        r = quotactl_devno(QCMD_FIXED(Q_SETQUOTA, USRQUOTA), devno, h->uid, &req);
+        r = quotactl_devnum(QCMD_FIXED(Q_SETQUOTA, USRQUOTA), devno, h->uid, &req);
         if (r < 0) {
                 if (r == -ESRCH)
                         return log_error_errno(SYNTHETIC_ERRNO(ENOTTY), "UID quota not available on %s.", path);
index db6cedfb163f5034817da7959994f9a5da1a74dc..2ad175c2483b4858c74f1b2a47b3d7b1c0f5368c 100644 (file)
@@ -23,8 +23,7 @@
 #include "main-func.h"
 #include "mkdir.h"
 #include "parse-argument.h"
-#include "parse-util.h"
-#include "path-util.h"
+#include "parse-helpers.h"
 #include "pretty-print.h"
 #include "process-util.h"
 #include "rlimit-util.h"
index 14794fb3af5393f07650c85fb8ce80321dbfdea1..97f4ee356c6b658a87c5e80b37425fb689913966 100644 (file)
@@ -547,7 +547,75 @@ static int match_initialized(sd_device_enumerator *enumerator, sd_device *device
         return (enumerator->match_initialized == MATCH_INITIALIZED_NO) == (r == 0);
 }
 
-static int enumerator_scan_dir_and_add_devices(sd_device_enumerator *enumerator, const char *basedir, const char *subdir1, const char *subdir2) {
+static int test_matches(
+                sd_device_enumerator *enumerator,
+                sd_device *device) {
+
+        int r;
+
+        assert(enumerator);
+        assert(device);
+
+        /* Checks all matches, except for the sysname match (which the caller should check beforehand) */
+
+        r = match_initialized(enumerator, device);
+        if (r <= 0)
+                return r;
+
+        if (!device_match_parent(device, enumerator->match_parent, NULL))
+                return false;
+
+        if (!match_tag(enumerator, device))
+                return false;
+
+        if (!match_property(enumerator, device))
+                return false;
+
+        if (!device_match_sysattr(device, enumerator->match_sysattr, enumerator->nomatch_sysattr))
+                return false;
+
+        return true;
+}
+
+static bool match_subsystem(sd_device_enumerator *enumerator, const char *subsystem) {
+        const char *subsystem_match;
+
+        assert(enumerator);
+
+        if (!subsystem)
+                return false;
+
+        SET_FOREACH(subsystem_match, enumerator->nomatch_subsystem)
+                if (fnmatch(subsystem_match, subsystem, 0) == 0)
+                        return false;
+
+        if (set_isempty(enumerator->match_subsystem))
+                return true;
+
+        SET_FOREACH(subsystem_match, enumerator->match_subsystem)
+                if (fnmatch(subsystem_match, subsystem, 0) == 0)
+                        return true;
+
+        return false;
+}
+
+static bool relevant_sysfs_subdir(const struct dirent *de) {
+        assert(de);
+
+        if (de->d_name[0] == '.')
+                return false;
+
+        /* Also filter out regular files and such, i.e. stuff that definitely isn't a kobject path. (Note
+         * that we rely on the fact that sysfs fills in d_type here, i.e. doesn't do DT_UNKNOWN) */
+        return IN_SET(de->d_type, DT_DIR, DT_LNK);
+}
+
+static int enumerator_scan_dir_and_add_devices(
+                sd_device_enumerator *enumerator,
+                const char *basedir,
+                const char *subdir1,
+                const char *subdir2) {
+
         _cleanup_closedir_ DIR *dir = NULL;
         char *path;
         int k, r = 0;
@@ -571,8 +639,9 @@ static int enumerator_scan_dir_and_add_devices(sd_device_enumerator *enumerator,
         FOREACH_DIRENT_ALL(de, dir, return -errno) {
                 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
                 char syspath[strlen(path) + 1 + strlen(de->d_name) + 1];
+                sd_device *upwards;
 
-                if (de->d_name[0] == '.')
+                if (!relevant_sysfs_subdir(de))
                         continue;
 
                 if (!match_sysname(enumerator, de->d_name))
@@ -589,56 +658,75 @@ static int enumerator_scan_dir_and_add_devices(sd_device_enumerator *enumerator,
                         continue;
                 }
 
-                k = match_initialized(enumerator, device);
+                k = test_matches(enumerator, device);
                 if (k <= 0) {
                         if (k < 0)
                                 r = k;
                         continue;
                 }
 
-                if (!device_match_parent(device, enumerator->match_parent, NULL))
-                        continue;
-
-                if (!match_tag(enumerator, device))
-                        continue;
-
-                if (!match_property(enumerator, device))
-                        continue;
-
-                if (!device_match_sysattr(device, enumerator->match_sysattr, enumerator->nomatch_sysattr))
-                        continue;
-
                 k = device_enumerator_add_device(enumerator, device);
                 if (k < 0)
                         r = k;
-        }
 
-        return r;
-}
+                /* Also include all potentially matching parent devices in the enumeration. These are things
+                 * like root busses — e.g. /sys/devices/pci0000:00/ or /sys/devices/pnp0/, which ar not
+                 * linked from /sys/class/ or /sys/bus/, hence pick them up explicitly here. */
+                upwards = device;
+                for (;;) {
+                        const char *ss, *usn;
 
-static bool match_subsystem(sd_device_enumerator *enumerator, const char *subsystem) {
-        const char *subsystem_match;
+                        k = sd_device_get_parent(upwards, &upwards);
+                        if (k == -ENOENT) /* Reached the top? */
+                                break;
+                        if (k < 0) {
+                                r = k;
+                                break;
+                        }
 
-        assert(enumerator);
+                        k = sd_device_get_subsystem(upwards, &ss);
+                        if (k == -ENOENT) /* Has no subsystem? */
+                                continue;
+                        if (k < 0) {
+                                r = k;
+                                break;
+                        }
 
-        if (!subsystem)
-                return false;
+                        if (!match_subsystem(enumerator, ss))
+                                continue;
 
-        SET_FOREACH(subsystem_match, enumerator->nomatch_subsystem)
-                if (fnmatch(subsystem_match, subsystem, 0) == 0)
-                        return false;
+                        k = sd_device_get_sysname(upwards, &usn);
+                        if (k < 0) {
+                                r = k;
+                                break;
+                        }
 
-        if (set_isempty(enumerator->match_subsystem))
-                return true;
+                        if (!match_sysname(enumerator, usn))
+                                continue;
 
-        SET_FOREACH(subsystem_match, enumerator->match_subsystem)
-                if (fnmatch(subsystem_match, subsystem, 0) == 0)
-                        return true;
+                        k = test_matches(enumerator, upwards);
+                        if (k < 0)
+                                break;
+                        if (k == 0)
+                                continue;
 
-        return false;
+                        k = device_enumerator_add_device(enumerator, upwards);
+                        if (k < 0)
+                                r = k;
+                        else if (k == 0) /* Exists already? Then no need to go further up. */
+                                break;
+                }
+        }
+
+        return r;
 }
 
-static int enumerator_scan_dir(sd_device_enumerator *enumerator, const char *basedir, const char *subdir, const char *subsystem) {
+static int enumerator_scan_dir(
+                sd_device_enumerator *enumerator,
+                const char *basedir,
+                const char *subdir,
+                const char *subsystem) {
+
         _cleanup_closedir_ DIR *dir = NULL;
         char *path;
         int r = 0;
@@ -654,7 +742,7 @@ static int enumerator_scan_dir(sd_device_enumerator *enumerator, const char *bas
         FOREACH_DIRENT_ALL(de, dir, return -errno) {
                 int k;
 
-                if (de->d_name[0] == '.')
+                if (!relevant_sysfs_subdir(de))
                         continue;
 
                 if (!match_subsystem(enumerator, subsystem ? : de->d_name))
@@ -997,7 +1085,7 @@ _public_ sd_device *sd_device_enumerator_get_subsystem_next(sd_device_enumerator
 }
 
 int device_enumerator_scan_devices_and_subsystems(sd_device_enumerator *enumerator) {
-        int r = 0, k;
+        int r;
 
         assert(enumerator);
 
@@ -1007,22 +1095,14 @@ int device_enumerator_scan_devices_and_subsystems(sd_device_enumerator *enumerat
 
         device_enumerator_unref_devices(enumerator);
 
-        if (!set_isempty(enumerator->match_tag)) {
-                k = enumerator_scan_devices_tags(enumerator);
-                if (k < 0)
-                        r = k;
-        } else if (enumerator->match_parent) {
-                k = enumerator_scan_devices_children(enumerator);
-                if (k < 0)
-                        r = k;
-        } else {
-                k = enumerator_scan_dir(enumerator, "class", NULL, NULL);
-                if (k < 0)
-                        r = log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/class: %m");
+        if (!set_isempty(enumerator->match_tag))
+                r = enumerator_scan_devices_tags(enumerator);
+        else if (enumerator->match_parent)
+                r = enumerator_scan_devices_children(enumerator);
+        else {
+                int k;
 
-                k = enumerator_scan_dir(enumerator, "bus", "devices", NULL);
-                if (k < 0)
-                        r = log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/bus: %m");
+                r = enumerator_scan_devices_all(enumerator);
 
                 if (match_subsystem(enumerator, "module")) {
                         k = enumerator_scan_dir_and_add_devices(enumerator, "module", NULL, NULL);
index 22200c0eea25f5374f6f6726b1cc73b96509db0f..bbd990bdb4b6a6accfcde49c51c77c08ed6e73fe 100644 (file)
@@ -12,7 +12,9 @@
 #include "device-internal.h"
 #include "device-private.h"
 #include "device-util.h"
+#include "devnum-util.h"
 #include "dirent-util.h"
+#include "env-util.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "format-util.h"
 #include "hashmap.h"
 #include "id128-util.h"
 #include "macro.h"
+#include "missing_magic.h"
 #include "netlink-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "set.h"
 #include "socket-util.h"
-#include "stat-util.h"
 #include "stdio-util.h"
 #include "string-util.h"
 #include "strv.h"
@@ -150,7 +152,9 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
                                        _syspath);
 
         if (verify) {
-                r = chase_symlinks(_syspath, NULL, 0, &syspath, NULL);
+                _cleanup_close_ int fd = -1;
+
+                r = chase_symlinks(_syspath, NULL, 0, &syspath, &fd);
                 if (r == -ENOENT)
                          /* the device does not exist (any more?) */
                         return log_debug_errno(SYNTHETIC_ERRNO(ENODEV),
@@ -181,36 +185,59 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
                         path_simplify(syspath);
                 }
 
-                if (path_startswith(syspath,  "/sys/devices/")) {
-                        char *path;
+                if (path_startswith(syspath, "/sys/devices/")) {
+                        /* For proper devices, stricter rules apply: they must have a 'uevent' file,
+                         * otherwise we won't allow them */
 
-                        /* all 'devices' require an 'uevent' file */
-                        path = strjoina(syspath, "/uevent");
-                        if (access(path, F_OK) < 0) {
+                        if (faccessat(fd, "uevent", F_OK, 0) < 0) {
                                 if (errno == ENOENT)
-                                        /* This is not a valid device.
-                                         * Note, this condition is quite often satisfied when
-                                         * enumerating devices or finding a parent device.
+                                        /* This is not a valid device.  Note, this condition is quite often
+                                         * satisfied when enumerating devices or finding a parent device.
                                          * Hence, use log_trace_errno() here. */
                                         return log_trace_errno(SYNTHETIC_ERRNO(ENODEV),
-                                                               "sd-device: the uevent file \"%s\" does not exist.", path);
+                                                               "sd-device: the uevent file \"%s/uevent\" does not exist.", syspath);
+                                if (errno == ENOTDIR)
+                                        /* Not actually a directory. */
+                                        return log_debug_errno(SYNTHETIC_ERRNO(ENODEV),
+                                                               "sd-device: the syspath \"%s\" is not a directory.", syspath);
 
-                                return log_debug_errno(errno, "sd-device: cannot access uevent file for %s: %m", syspath);
+                                return log_debug_errno(errno, "sd-device: cannot find uevent file for %s: %m", syspath);
                         }
                 } else {
-                        /* everything else just needs to be a directory */
-                        if (!is_dir(syspath, false))
+                        struct stat st;
+
+                        /* For everything else lax rules apply: they just need to be a directory */
+
+                        if (fstat(fd, &st) < 0)
+                                return log_debug_errno(errno, "sd-device: failed to check if syspath \"%s\" is a directory: %m", syspath);
+                        if (!S_ISDIR(st.st_mode))
                                 return log_debug_errno(SYNTHETIC_ERRNO(ENODEV),
                                                        "sd-device: the syspath \"%s\" is not a directory.", syspath);
                 }
+
+                /* Only operate on sysfs, i.e. refuse going down into /sys/fs/cgroup/ or similar places where
+                 * things are not arranged as kobjects in kernel, and hence don't necessarily have
+                 * kobject/attribute structure. */
+                r = getenv_bool_secure("SYSTEMD_DEVICE_VERIFY_SYSFS");
+                if (r < 0 && r != -ENXIO)
+                        log_debug_errno(r, "Failed to parse $SYSTEMD_DEVICE_VERIFY_SYSFS value: %m");
+                if (r != 0) {
+                        r = fd_is_fs_type(fd, SYSFS_MAGIC);
+                        if (r < 0)
+                                return log_debug_errno(r, "sd-device: failed to check if syspath \"%s\" is backed by sysfs.", syspath);
+                        if (r == 0)
+                                return log_debug_errno(SYNTHETIC_ERRNO(ENODEV),
+                                                       "sd-device: the syspath \"%s\" is outside of sysfs, refusing.", syspath);
+                }
         } else {
                 syspath = strdup(_syspath);
                 if (!syspath)
                         return log_oom_debug();
-        }
 
-        devpath = syspath + STRLEN("/sys");
+                path_simplify(syspath);
+        }
 
+        assert_se(devpath = startswith(syspath, "/sys"));
         if (devpath[0] != '/')
                 return log_debug_errno(SYNTHETIC_ERRNO(ENODEV), "sd-device: \"/sys\" alone is not a valid device path.");
 
@@ -234,7 +261,7 @@ _public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) {
         if (r < 0)
                 return r;
 
-        r = device_set_syspath(device, syspath, true);
+        r = device_set_syspath(device, syspath, /* verify= */ true);
         if (r < 0)
                 return r;
 
@@ -242,22 +269,55 @@ _public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) {
         return 0;
 }
 
-_public_ int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum) {
-        char id[DECIMAL_STR_MAX(unsigned) * 2 + 1], *syspath;
+static int device_new_from_mode_and_devnum(sd_device **ret, mode_t mode, dev_t devnum) {
+        _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
+        _cleanup_free_ char *syspath = NULL;
+        const char *t, *subsystem;
+        dev_t n;
+        int r;
 
-        assert_return(ret, -EINVAL);
-        assert_return(IN_SET(type, 'b', 'c'), -EINVAL);
+        assert(ret);
+
+        if (S_ISCHR(mode))
+                t = "char";
+        else if (S_ISBLK(mode))
+                t = "block";
+        else
+                return -ENOTTY;
 
-        if (devnum == 0)
-                return log_debug_errno(SYNTHETIC_ERRNO(ENODEV),
-                                       "sd-device: Attempted to allocate device by zero major/minor, refusing.");
+        if (major(devnum) == 0)
+                return -ENODEV;
 
-        /* use /sys/dev/{block,char}/<maj>:<min> link */
-        xsprintf(id, "%u:%u", major(devnum), minor(devnum));
+        if (asprintf(&syspath, "/sys/dev/%s/%u:%u", t, major(devnum), minor(devnum)) < 0)
+                return -ENOMEM;
 
-        syspath = strjoina("/sys/dev/", (type == 'b' ? "block" : "char"), "/", id);
+        r = sd_device_new_from_syspath(&dev, syspath);
+        if (r < 0)
+                return r;
 
-        return sd_device_new_from_syspath(ret, syspath);
+        r = sd_device_get_devnum(dev, &n);
+        if (r == -ENOENT)
+                return -ENXIO;
+        if (r < 0)
+                return r;
+        if (n != devnum)
+                return -ENXIO;
+
+        r = sd_device_get_subsystem(dev, &subsystem);
+        if (r < 0 && r != -ENOENT)
+                return r;
+        if (r >= 0 && streq(subsystem, "block") != !!S_ISBLK(mode))
+                return -ENXIO;
+
+        *ret = TAKE_PTR(dev);
+        return 0;
+}
+
+_public_ int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum) {
+        assert_return(ret, -EINVAL);
+        assert_return(IN_SET(type, 'b', 'c'), -EINVAL);
+
+        return device_new_from_mode_and_devnum(ret, type == 'b' ? S_IFBLK : S_IFCHR, devnum);
 }
 
 static int device_new_from_main_ifname(sd_device **ret, const char *ifname) {
@@ -295,7 +355,9 @@ _public_ int sd_device_new_from_ifname(sd_device **ret, const char *ifname) {
 }
 
 _public_ int sd_device_new_from_ifindex(sd_device **ret, int ifindex) {
+        _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
         char ifname[IF_NAMESIZE];
+        int r, i;
 
         assert_return(ret, -EINVAL);
         assert_return(ifindex > 0, -EINVAL);
@@ -303,7 +365,20 @@ _public_ int sd_device_new_from_ifindex(sd_device **ret, int ifindex) {
         if (format_ifname(ifindex, ifname) < 0)
                 return -ENODEV;
 
-        return device_new_from_main_ifname(ret, ifname);
+        r = device_new_from_main_ifname(&dev, ifname);
+        if (r < 0)
+                return r;
+
+        r = sd_device_get_ifindex(dev, &i);
+        if (r == -ENOENT)
+                return -ENXIO;
+        if (r < 0)
+                return r;
+        if (i != ifindex)
+                return -ENXIO;
+
+        *ret = TAKE_PTR(dev);
+        return 0;
 }
 
 static int device_strjoin_new(
@@ -364,7 +439,10 @@ _public_ int sd_device_new_from_subsystem_sysname(
                         const char *subsys = memdupa_suffix0(sysname, sep - sysname);
                         sep++;
 
-                        r = device_strjoin_new("/sys/bus/", subsys, "/drivers/", sep, ret);
+                        if (streq(sep, "drivers")) /* If the sysname is "drivers", then it's the drivers directory itself that is meant. */
+                                r = device_strjoin_new("/sys/bus/", subsys, "/drivers", NULL, ret);
+                        else
+                                r = device_strjoin_new("/sys/bus/", subsys, "/drivers/", sep, ret);
                         if (r < 0)
                                 return r;
                         if (r > 0)
@@ -400,23 +478,16 @@ _public_ int sd_device_new_from_subsystem_sysname(
 }
 
 _public_ int sd_device_new_from_stat_rdev(sd_device **ret, const struct stat *st) {
-        char type;
-
         assert_return(ret, -EINVAL);
         assert_return(st, -EINVAL);
 
-        if (S_ISBLK(st->st_mode))
-                type = 'b';
-        else if (S_ISCHR(st->st_mode))
-                type = 'c';
-        else
-                return -ENOTTY;
-
-        return sd_device_new_from_devnum(ret, type, st->st_rdev);
+        return device_new_from_mode_and_devnum(ret, st->st_mode, st->st_rdev);
 }
 
 _public_ int sd_device_new_from_devname(sd_device **ret, const char *devname) {
         struct stat st;
+        dev_t devnum;
+        mode_t mode;
 
         assert_return(ret, -EINVAL);
         assert_return(devname, -EINVAL);
@@ -428,16 +499,11 @@ _public_ int sd_device_new_from_devname(sd_device **ret, const char *devname) {
         if (isempty(path_startswith(devname, "/dev")))
                 return -EINVAL;
 
-        if (device_path_parse_major_minor(devname, NULL, NULL) >= 0) {
-                _cleanup_free_ char *syspath = NULL;
-
+        if (device_path_parse_major_minor(devname, &mode, &devnum) >= 0)
                 /* Let's shortcut when "/dev/block/maj:min" or "/dev/char/maj:min" is specified.
-                 * In that case, we directly convert the path to syspath, hence it is not necessary
+                 * In that case, we can directly convert the path to syspath, hence it is not necessary
                  * that the specified path exists. So, this works fine without udevd being running. */
-
-                syspath = path_join("/sys", devname);
-                return sd_device_new_from_syspath(ret, syspath);
-        }
+                return device_new_from_mode_and_devnum(ret, mode, devnum);
 
         if (stat(devname, &st) < 0)
                 return ERRNO_IS_DEVICE_ABSENT(errno) ? -ENODEV : -errno;
@@ -548,11 +614,15 @@ int device_set_devnum(sd_device *device, const char *major, const char *minor) {
                 return r;
         if (maj == 0)
                 return 0;
+        if (!DEVICE_MAJOR_VALID(maj))
+                return -EINVAL;
 
         if (minor) {
                 r = safe_atou(minor, &min);
                 if (r < 0)
                         return r;
+                if (!DEVICE_MINOR_VALID(min))
+                        return -EINVAL;
         }
 
         r = device_add_property_internal(device, "MAJOR", major);
@@ -598,7 +668,6 @@ static int handle_uevent_line(
                 const char *value,
                 const char **major,
                 const char **minor) {
-        int r;
 
         assert(device);
         assert(key);
@@ -606,35 +675,22 @@ static int handle_uevent_line(
         assert(major);
         assert(minor);
 
-        if (streq(key, "DEVTYPE")) {
-                r = device_set_devtype(device, value);
-                if (r < 0)
-                        return r;
-        } else if (streq(key, "IFINDEX")) {
-                r = device_set_ifindex(device, value);
-                if (r < 0)
-                        return r;
-        } else if (streq(key, "DEVNAME")) {
-                r = device_set_devname(device, value);
-                if (r < 0)
-                        return r;
-        } else if (streq(key, "DEVMODE")) {
-                r = device_set_devmode(device, value);
-                if (r < 0)
-                        return r;
-        } else if (streq(key, "DISKSEQ")) {
-                r = device_set_diskseq(device, value);
-                if (r < 0)
-                        return r;
-        } else if (streq(key, "MAJOR"))
+        if (streq(key, "DEVTYPE"))
+                return device_set_devtype(device, value);
+        if (streq(key, "IFINDEX"))
+                return device_set_ifindex(device, value);
+        if (streq(key, "DEVNAME"))
+                return device_set_devname(device, value);
+        if (streq(key, "DEVMODE"))
+                return device_set_devmode(device, value);
+        if (streq(key, "DISKSEQ"))
+                return device_set_diskseq(device, value);
+        if (streq(key, "MAJOR"))
                 *major = value;
         else if (streq(key, "MINOR"))
                 *minor = value;
-        else {
-                r = device_add_property_internal(device, key, value);
-                if (r < 0)
-                        return r;
-        }
+        else
+                return device_add_property_internal(device, key, value);
 
         return 0;
 }
@@ -721,7 +777,7 @@ int device_read_uevent_file(sd_device *device) {
         if (major) {
                 r = device_set_devnum(device, major, minor);
                 if (r < 0)
-                        log_device_debug_errno(device, r, "sd-device: Failed to set 'MAJOR=%s' or 'MINOR=%s' from '%s', ignoring: %m", major, minor, path);
+                        log_device_debug_errno(device, r, "sd-device: Failed to set 'MAJOR=%s' or 'MINOR=%s' from '%s', ignoring: %m", major, strna(minor), path);
         }
 
         return 0;
@@ -759,7 +815,7 @@ _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
                 if (isempty(id))
                         return -EINVAL;
 
-                r = parse_dev(id + 1, &devt);
+                r = parse_devnum(id + 1, &devt);
                 if (r < 0)
                         return r;
 
@@ -887,10 +943,13 @@ int device_set_drivers_subsystem(sd_device *device) {
                 return r;
 
         drivers = strstr(devpath, "/drivers/");
+        if (!drivers)
+                drivers = endswith(devpath, "/drivers");
         if (!drivers)
                 return -EINVAL;
 
-        r = path_find_last_component(devpath, false, &drivers, &p);
+        /* Find the path component immediately before the "/drivers/" string */
+        r = path_find_last_component(devpath, /* accept_dot_dot= */ false, &drivers, &p);
         if (r < 0)
                 return r;
         if (r == 0)
@@ -932,11 +991,11 @@ _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
                 if (subsystem)
                         r = device_set_subsystem(device, subsystem);
                 /* use implicit names */
-                else if (path_startswith(device->devpath, "/module/"))
+                else if (!isempty(path_startswith(device->devpath, "/module/")))
                         r = device_set_subsystem(device, "module");
-                else if (strstr(syspath, "/drivers/"))
+                else if (strstr(syspath, "/drivers/") || endswith(syspath, "/drivers"))
                         r = device_set_drivers_subsystem(device);
-                else if (PATH_STARTSWITH_SET(device->devpath, "/class/", "/bus/"))
+                else if (!isempty(PATH_STARTSWITH_SET(device->devpath, "/class/", "/bus/")))
                         r = device_set_subsystem(device, "subsystem");
                 else {
                         device->subsystem_set = true;
@@ -1334,7 +1393,6 @@ int device_set_usec_initialized(sd_device *device, usec_t when) {
 }
 
 static int handle_db_line(sd_device *device, char key, const char *value) {
-        char *path;
         int r;
 
         assert(device);
@@ -1343,24 +1401,17 @@ static int handle_db_line(sd_device *device, char key, const char *value) {
         switch (key) {
         case 'G': /* Any tag */
         case 'Q': /* Current tag */
-                r = device_add_tag(device, value, key == 'Q');
-                if (r < 0)
-                        return r;
+                return device_add_tag(device, value, key == 'Q');
 
-                break;
-        case 'S':
-                path = strjoina("/dev/", value);
-                r = device_add_devlink(device, path);
-                if (r < 0)
-                        return r;
+        case 'S': {
+                const char *path;
 
-                break;
+                path = strjoina("/dev/", value);
+                return device_add_devlink(device, path);
+        }
         case 'E':
-                r = device_add_property_internal_from_string(device, value);
-                if (r < 0)
-                        return r;
+                return device_add_property_internal_from_string(device, value);
 
-                break;
         case 'I': {
                 usec_t t;
 
@@ -1368,35 +1419,25 @@ static int handle_db_line(sd_device *device, char key, const char *value) {
                 if (r < 0)
                         return r;
 
-                r = device_set_usec_initialized(device, t);
-                if (r < 0)
-                        return r;
-
-                break;
+                return device_set_usec_initialized(device, t);
         }
         case 'L':
-                r = safe_atoi(value, &device->devlink_priority);
-                if (r < 0)
-                        return r;
+                return safe_atoi(value, &device->devlink_priority);
 
-                break;
         case 'W':
                 /* Deprecated. Previously, watch handle is both saved in database and /run/udev/watch.
                  * However, the handle saved in database may not be updated when the handle is updated
                  * or removed. Moreover, it is not necessary to store the handle within the database,
                  * as its value becomes meaningless when udevd is restarted. */
-                break;
+                return 0;
+
         case 'V':
-                r = safe_atou(value, &device->database_version);
-                if (r < 0)
-                        return r;
+                return safe_atou(value, &device->database_version);
 
-                break;
         default:
                 log_device_debug(device, "sd-device: Unknown key '%c' in device db, ignoring", key);
+                return 0;
         }
-
-        return 0;
 }
 
 int device_get_device_id(sd_device *device, const char **ret) {
index 4dbdf1987241a8b2829a91d4894d94e1109748a5..e5d370d4f3c1259c076f5fbf98e8948e4c23769c 100644 (file)
@@ -706,6 +706,9 @@ static void event_unmask_signal_data(sd_event *e, struct signal_data *d, int sig
                 return;
         }
 
+        if (event_pid_changed(e))
+                return;
+
         assert(d->fd >= 0);
 
         if (signalfd(d->fd, &d->sigset, SFD_NONBLOCK|SFD_CLOEXEC) < 0)
@@ -851,6 +854,9 @@ static void source_disconnect(sd_event_source *s) {
                 break;
 
         case SOURCE_CHILD:
+                if (event_pid_changed(s->event))
+                        s->child.process_owned = false;
+
                 if (s->child.pid > 0) {
                         if (event_source_is_online(s)) {
                                 assert(s->event->n_online_child_sources > 0);
@@ -1426,7 +1432,6 @@ _public_ int sd_event_add_child(
                 return -ENOMEM;
 
         s->wakeup = WAKEUP_EVENT_SOURCE;
-        s->child.pid = pid;
         s->child.options = options;
         s->child.callback = callback;
         s->userdata = userdata;
@@ -1436,7 +1441,7 @@ _public_ int sd_event_add_child(
          * pin the PID, and make regular waitid() handling race-free. */
 
         if (shall_use_pidfd()) {
-                s->child.pidfd = pidfd_open(s->child.pid, 0);
+                s->child.pidfd = pidfd_open(pid, 0);
                 if (s->child.pidfd < 0) {
                         /* Propagate errors unless the syscall is not supported or blocked */
                         if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
@@ -1446,10 +1451,6 @@ _public_ int sd_event_add_child(
         } else
                 s->child.pidfd = -1;
 
-        r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s);
-        if (r < 0)
-                return r;
-
         if (EVENT_SOURCE_WATCH_PIDFD(s)) {
                 /* We have a pidfd and we only want to watch for exit */
                 r = source_child_pidfd_register(s, s->enabled);
@@ -1465,6 +1466,12 @@ _public_ int sd_event_add_child(
                 e->need_process_child = true;
         }
 
+        r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s);
+        if (r < 0)
+                return r;
+
+        /* These must be done after everything succeeds. */
+        s->child.pid = pid;
         e->n_online_child_sources++;
 
         if (ret)
@@ -1691,7 +1698,8 @@ static void event_free_inotify_data(sd_event *e, struct inotify_data *d) {
         assert_se(hashmap_remove(e->inotify_data, &d->priority) == d);
 
         if (d->fd >= 0) {
-                if (epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, d->fd, NULL) < 0)
+                if (!event_pid_changed(e) &&
+                    epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, d->fd, NULL) < 0)
                         log_debug_errno(errno, "Failed to remove inotify fd from epoll, ignoring: %m");
 
                 safe_close(d->fd);
@@ -1801,7 +1809,7 @@ static void event_free_inode_data(
         if (d->inotify_data) {
 
                 if (d->wd >= 0) {
-                        if (d->inotify_data->fd >= 0) {
+                        if (d->inotify_data->fd >= 0 && !event_pid_changed(e)) {
                                 /* So here's a problem. At the time this runs the watch descriptor might already be
                                  * invalidated, because an IN_IGNORED event might be queued right the moment we enter
                                  * the syscall. Hence, whenever we get EINVAL, ignore it entirely, since it's a very
@@ -3218,23 +3226,16 @@ static int process_child(sd_event *e, int64_t threshold, int64_t *ret_min_priori
 
         e->need_process_child = false;
 
-        /*
-           So, this is ugly. We iteratively invoke waitid() with P_PID
-           + WNOHANG for each PID we wait for, instead of using
-           P_ALL. This is because we only want to get child
-           information of very specific child processes, and not all
-           of them. We might not have processed the SIGCHLD even of a
-           previous invocation and we don't want to maintain a
-           unbounded *per-child* event queue, hence we really don't
-           want anything flushed out of the kernel's queue that we
-           don't care about. Since this is O(n) this means that if you
-           have a lot of processes you probably want to handle SIGCHLD
-           yourself.
-
-           We do not reap the children here (by using WNOWAIT), this
-           is only done after the event source is dispatched so that
-           the callback still sees the process as a zombie.
-        */
+        /* So, this is ugly. We iteratively invoke waitid() with P_PID + WNOHANG for each PID we wait
+         * for, instead of using P_ALL. This is because we only want to get child information of very
+         * specific child processes, and not all of them. We might not have processed the SIGCHLD event
+         * of a previous invocation and we don't want to maintain a unbounded *per-child* event queue,
+         * hence we really don't want anything flushed out of the kernel's queue that we don't care
+         * about. Since this is O(n) this means that if you have a lot of processes you probably want
+         * to handle SIGCHLD yourself.
+         *
+         * We do not reap the children here (by using WNOWAIT), this is only done after the event
+         * source is dispatched so that the callback still sees the process as a zombie. */
 
         HASHMAP_FOREACH(s, e->child_sources) {
                 assert(s->type == SOURCE_CHILD);
@@ -3251,7 +3252,9 @@ static int process_child(sd_event *e, int64_t threshold, int64_t *ret_min_priori
                 if (s->child.exited)
                         continue;
 
-                if (EVENT_SOURCE_WATCH_PIDFD(s)) /* There's a usable pidfd known for this event source? then don't waitid() for it here */
+                if (EVENT_SOURCE_WATCH_PIDFD(s))
+                        /* There's a usable pidfd known for this event source? Then don't waitid() for
+                         * it here */
                         continue;
 
                 zero(s->child.siginfo);
@@ -3266,10 +3269,9 @@ static int process_child(sd_event *e, int64_t threshold, int64_t *ret_min_priori
                                 s->child.exited = true;
 
                         if (!zombie && (s->child.options & WEXITED)) {
-                                /* If the child isn't dead then let's
-                                 * immediately remove the state change
-                                 * from the queue, since there's no
-                                 * benefit in leaving it queued */
+                                /* If the child isn't dead then let's immediately remove the state
+                                 * change from the queue, since there's no benefit in leaving it
+                                 * queued. */
 
                                 assert(s->child.options & (WSTOPPED|WCONTINUED));
                                 (void) waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|(s->child.options & (WSTOPPED|WCONTINUED)));
@@ -3324,19 +3326,16 @@ static int process_signal(sd_event *e, struct signal_data *d, uint32_t events, i
         assert_return(events == EPOLLIN, -EIO);
         assert(min_priority);
 
-        /* If there's a signal queued on this priority and SIGCHLD is
-           on this priority too, then make sure to recheck the
-           children we watch. This is because we only ever dequeue
-           the first signal per priority, and if we dequeue one, and
-           SIGCHLD might be enqueued later we wouldn't know, but we
-           might have higher priority children we care about hence we
-           need to check that explicitly. */
+        /* If there's a signal queued on this priority and SIGCHLD is on this priority too, then make
+         * sure to recheck the children we watch. This is because we only ever dequeue the first signal
+         * per priority, and if we dequeue one, and SIGCHLD might be enqueued later we wouldn't know,
+         * but we might have higher priority children we care about hence we need to check that
+         * explicitly. */
 
         if (sigismember(&d->sigset, SIGCHLD))
                 e->need_process_child = true;
 
-        /* If there's already an event source pending for this
-         * priority we don't read another */
+        /* If there's already an event source pending for this priority we don't read another */
         if (d->current)
                 return 0;
 
index a9da1e773171ba238eeaafc4e38df82cce3b0373..914e56bd7765f486e044715c3ef5af0901cc05da 100644 (file)
@@ -2794,7 +2794,7 @@ static int property_get_reboot_to_boot_loader_menu(
 
         r = getenv_bool("SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU");
         if (r == -ENXIO) {
-                /* EFI case: returns the current value of LoaderConfigTimeoutOneShot. Three cases are distuingished:
+                /* EFI case: returns the current value of LoaderConfigTimeoutOneShot. Three cases are distinguished:
                  *
                  *     1. Variable not set, boot into boot loader menu is not enabled (we return UINT64_MAX to the user)
                  *     2. Variable set to "0", boot into boot loader menu is enabled with no timeout (we return 0 to the user)
index ff4cd0a631bf9fc19302f17011244ae1497d8932..7d46759822bf83b7baa8fdf8d8f09ff0d8ec9f90 100644 (file)
@@ -8,6 +8,7 @@
 #include "bus-label.h"
 #include "bus-polkit.h"
 #include "bus-util.h"
+#include "devnum-util.h"
 #include "fd-util.h"
 #include "logind-brightness.h"
 #include "logind-dbus.h"
@@ -21,7 +22,6 @@
 #include "missing_capability.h"
 #include "path-util.h"
 #include "signal-util.h"
-#include "stat-util.h"
 #include "strv.h"
 #include "user-util.h"
 #include "util.h"
index eef48c252753bd2d5c8ed7b81421df59366b9f0d..4995e5885aae24c9aace1254759f3534d28e557d 100644 (file)
@@ -15,6 +15,7 @@
 #include "audit-util.h"
 #include "bus-error.h"
 #include "bus-util.h"
+#include "devnum-util.h"
 #include "env-file.h"
 #include "escape.h"
 #include "fd-util.h"
@@ -377,7 +378,7 @@ static int session_load_devices(Session *s, const char *devices) {
                         break;
                 }
 
-                k = parse_dev(word, &dev);
+                k = parse_devnum(word, &dev);
                 if (k < 0) {
                         r = k;
                         continue;
index 7baca67f1b4de21d9f43f484a9d58a796cf237b0..293be0bf8ba892f543175ed95439fb8daf23a097 100644 (file)
@@ -1278,85 +1278,61 @@ static const sd_bus_vtable machine_vtable[] = {
                       NULL,
                       bus_machine_method_terminate,
                       SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("Kill",
-                                 "si",
-                                 SD_BUS_PARAM(who)
-                                 SD_BUS_PARAM(signal),
-                                 NULL,,
-                                 bus_machine_method_kill,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("GetAddresses",
-                                 NULL,,
-                                 "a(iay)",
-                                 SD_BUS_PARAM(addresses),
-                                 bus_machine_method_get_addresses,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("GetOSRelease",
-                                 NULL,,
-                                 "a{ss}",
-                                 SD_BUS_PARAM(fields),
-                                 bus_machine_method_get_os_release,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("GetUIDShift",
-                                 NULL,,
-                                 "u",
-                                 SD_BUS_PARAM(shift),
-                                 bus_machine_method_get_uid_shift,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("OpenPTY",
-                                 NULL,,
-                                 "hs",
-                                 SD_BUS_PARAM(pty)
-                                 SD_BUS_PARAM(pty_path),
-                                 bus_machine_method_open_pty,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("OpenLogin",
-                                 NULL,,
-                                 "hs",
-                                 SD_BUS_PARAM(pty)
-                                 SD_BUS_PARAM(pty_path),
-                                 bus_machine_method_open_login,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("OpenShell",
-                                 "ssasas",
-                                 SD_BUS_PARAM(user)
-                                 SD_BUS_PARAM(path)
-                                 SD_BUS_PARAM(args)
-                                 SD_BUS_PARAM(environment),
-                                 "hs",
-                                 SD_BUS_PARAM(pty)
-                                 SD_BUS_PARAM(pty_path),
-                                 bus_machine_method_open_shell,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("BindMount",
-                                 "ssbb",
-                                 SD_BUS_PARAM(source)
-                                 SD_BUS_PARAM(destination)
-                                 SD_BUS_PARAM(read_only)
-                                 SD_BUS_PARAM(mkdir),
-                                 NULL,,
-                                 bus_machine_method_bind_mount,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("CopyFrom",
-                                 "ss",
-                                 SD_BUS_PARAM(source)
-                                 SD_BUS_PARAM(destination),
-                                 NULL,,
-                                 bus_machine_method_copy,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("CopyTo",
-                                 "ss",
-                                 SD_BUS_PARAM(source)
-                                 SD_BUS_PARAM(destination),
-                                 NULL,,
-                                 bus_machine_method_copy,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("OpenRootDirectory",
-                                 NULL,,
-                                 "h",
-                                 SD_BUS_PARAM(fd),
-                                 bus_machine_method_open_root_directory,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("Kill",
+                                SD_BUS_ARGS("s", who, "i", signal),
+                                SD_BUS_NO_RESULT,
+                                bus_machine_method_kill,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetAddresses",
+                                SD_BUS_NO_ARGS,
+                                SD_BUS_RESULT("a(iay)", addresses),
+                                bus_machine_method_get_addresses,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetOSRelease",
+                                SD_BUS_NO_ARGS,
+                                SD_BUS_RESULT("a{ss}", fields),
+                                bus_machine_method_get_os_release,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetUIDShift",
+                                SD_BUS_NO_ARGS,
+                                SD_BUS_RESULT("u", shift),
+                                bus_machine_method_get_uid_shift,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("OpenPTY",
+                                SD_BUS_NO_ARGS,
+                                SD_BUS_RESULT("h", pty, "s", pty_path),
+                                bus_machine_method_open_pty,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("OpenLogin",
+                                SD_BUS_NO_ARGS,
+                                SD_BUS_RESULT("h", pty, "s", pty_path),
+                                bus_machine_method_open_login,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("OpenShell",
+                                SD_BUS_ARGS("s", user, "s", path, "as", args, "as", environment),
+                                SD_BUS_RESULT("h", pty, "s", pty_path),
+                                bus_machine_method_open_shell,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("BindMount",
+                                SD_BUS_ARGS("s", source, "s", destination, "b", read_only, "b", mkdir),
+                                SD_BUS_NO_RESULT,
+                                bus_machine_method_bind_mount,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("CopyFrom",
+                                SD_BUS_ARGS("s", source, "s", destination),
+                                SD_BUS_NO_RESULT,
+                                bus_machine_method_copy,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("CopyTo",
+                                SD_BUS_ARGS("s", source, "s", destination),
+                                SD_BUS_NO_RESULT,
+                                bus_machine_method_copy,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("OpenRootDirectory",
+                                SD_BUS_NO_ARGS,
+                                SD_BUS_RESULT("h", fd),
+                                bus_machine_method_open_root_directory,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
 
         SD_BUS_VTABLE_END
 };
index ee9ad99255342655fb2546fdf35bc44ac2f844bb..865d8400e8dd0e4af9cbe4d818a0b4ef045139b0 100644 (file)
@@ -1014,310 +1014,194 @@ const sd_bus_vtable manager_vtable[] = {
         SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage, 0, 0),
         SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit, 0, 0),
 
-        SD_BUS_METHOD_WITH_NAMES("GetMachine",
-                                 "s",
-                                 SD_BUS_PARAM(name),
-                                 "o",
-                                 SD_BUS_PARAM(machine),
-                                 method_get_machine,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("GetImage",
-                                 "s",
-                                 SD_BUS_PARAM(name),
-                                 "o",
-                                 SD_BUS_PARAM(image),
-                                 method_get_image,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("GetMachineByPID",
-                                 "u",
-                                 SD_BUS_PARAM(pid),
-                                 "o",
-                                 SD_BUS_PARAM(machine),
-                                 method_get_machine_by_pid,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("ListMachines",
-                                 NULL,,
-                                 "a(ssso)",
-                                 SD_BUS_PARAM(machines),
-                                 method_list_machines,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("ListImages",
-                                 NULL,,
-                                 "a(ssbttto)",
-                                 SD_BUS_PARAM(images),
-                                 method_list_images,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("CreateMachine",
-                                 "sayssusa(sv)",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(id)
-                                 SD_BUS_PARAM(service)
-                                 SD_BUS_PARAM(class)
-                                 SD_BUS_PARAM(leader)
-                                 SD_BUS_PARAM(root_directory)
-                                 SD_BUS_PARAM(scope_properties),
-                                 "o",
-                                 SD_BUS_PARAM(path),
-                                 method_create_machine, 0),
-        SD_BUS_METHOD_WITH_NAMES("CreateMachineWithNetwork",
-                                 "sayssusaia(sv)",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(id)
-                                 SD_BUS_PARAM(service)
-                                 SD_BUS_PARAM(class)
-                                 SD_BUS_PARAM(leader)
-                                 SD_BUS_PARAM(root_directory)
-                                 SD_BUS_PARAM(ifindices)
-                                 SD_BUS_PARAM(scope_properties),
-                                 "o",
-                                 SD_BUS_PARAM(path),
-                                 method_create_machine_with_network, 0),
-        SD_BUS_METHOD_WITH_NAMES("RegisterMachine",
-                                 "sayssus",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(id)
-                                 SD_BUS_PARAM(service)
-                                 SD_BUS_PARAM(class)
-                                 SD_BUS_PARAM(leader)
-                                 SD_BUS_PARAM(root_directory),
-                                 "o",
-                                 SD_BUS_PARAM(path),
-                                 method_register_machine, 0),
-        SD_BUS_METHOD_WITH_NAMES("RegisterMachineWithNetwork",
-                                 "sayssusai",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(id)
-                                 SD_BUS_PARAM(service)
-                                 SD_BUS_PARAM(class)
-                                 SD_BUS_PARAM(leader)
-                                 SD_BUS_PARAM(root_directory)
-                                 SD_BUS_PARAM(ifindices),
-                                 "o",
-                                 SD_BUS_PARAM(path),
-                                 method_register_machine_with_network, 0),
-        SD_BUS_METHOD_WITH_NAMES("UnregisterMachine",
-                                 "s",
-                                 SD_BUS_PARAM(name),
-                                 NULL,,
-                                 method_unregister_machine,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("TerminateMachine",
-                                 "s",
-                                 SD_BUS_PARAM(id),
-                                 NULL,,
-                                 method_terminate_machine,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("KillMachine",
-                                 "ssi",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(who)
-                                 SD_BUS_PARAM(signal),
-                                 NULL,,
-                                 method_kill_machine,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("GetMachineAddresses",
-                                 "s",
-                                 SD_BUS_PARAM(name),
-                                 "a(iay)",
-                                 SD_BUS_PARAM(addresses),
-                                 method_get_machine_addresses,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("GetMachineOSRelease",
-                                 "s",
-                                 SD_BUS_PARAM(name),
-                                 "a{ss}",
-                                 SD_BUS_PARAM(fields),
-                                 method_get_machine_os_release,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("OpenMachinePTY",
-                                 "s",
-                                 SD_BUS_PARAM(name),
-                                 "hs",
-                                 SD_BUS_PARAM(pty)
-                                 SD_BUS_PARAM(pty_path),
-                                 method_open_machine_pty,
-                                 0),
-        SD_BUS_METHOD_WITH_NAMES("OpenMachineLogin",
-                                 "s",
-                                 SD_BUS_PARAM(name),
-                                 "hs",
-                                 SD_BUS_PARAM(pty)
-                                 SD_BUS_PARAM(pty_path),
-                                 method_open_machine_login,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("OpenMachineShell",
-                                 "sssasas",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(user)
-                                 SD_BUS_PARAM(path)
-                                 SD_BUS_PARAM(args)
-                                 SD_BUS_PARAM(environment),
-                                 "hs",
-                                 SD_BUS_PARAM(pty)
-                                 SD_BUS_PARAM(pty_path),
-                                 method_open_machine_shell,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("BindMountMachine",
-                                 "sssbb",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(source)
-                                 SD_BUS_PARAM(destination)
-                                 SD_BUS_PARAM(read_only)
-                                 SD_BUS_PARAM(mkdir),
-                                 NULL,,
-                                 method_bind_mount_machine,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("CopyFromMachine",
-                                 "sss",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(source)
-                                 SD_BUS_PARAM(destination),
-                                 NULL,,
-                                 method_copy_machine,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("CopyToMachine",
-                                 "sss",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(source)
-                                 SD_BUS_PARAM(destination),
-                                 NULL,,
-                                 method_copy_machine,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("OpenMachineRootDirectory",
-                                 "s",
-                                 SD_BUS_PARAM(name),
-                                 "h",
-                                 SD_BUS_PARAM(fd),
-                                 method_open_machine_root_directory,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("GetMachineUIDShift",
-                                 "s",
-                                 SD_BUS_PARAM(name),
-                                 "u",
-                                 SD_BUS_PARAM(shift),
-                                 method_get_machine_uid_shift,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("RemoveImage",
-                                 "s",
-                                 SD_BUS_PARAM(name),
-                                 NULL,,
-                                 method_remove_image,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("RenameImage",
-                                 "ss",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(new_name),
-                                 NULL,,
-                                 method_rename_image,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("CloneImage",
-                                 "ssb",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(new_name)
-                                 SD_BUS_PARAM(read_only),
-                                 NULL,,
-                                 method_clone_image,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("MarkImageReadOnly",
-                                 "sb",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(read_only),
-                                 NULL,,
-                                 method_mark_image_read_only,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("GetImageHostname",
-                                 "s",
-                                 SD_BUS_PARAM(name),
-                                 "s",
-                                 SD_BUS_PARAM(hostname),
-                                 method_get_image_hostname,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("GetImageMachineID",
-                                 "s",
-                                 SD_BUS_PARAM(name),
-                                 "ay",
-                                 SD_BUS_PARAM(id),
-                                 method_get_image_machine_id,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("GetImageMachineInfo",
-                                 "s",
-                                 SD_BUS_PARAM(name),
-                                 "a{ss}",
-                                 SD_BUS_PARAM(machine_info),
-                                 method_get_image_machine_info,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("GetImageOSRelease",
-                                 "s",
-                                 SD_BUS_PARAM(name),
-                                 "a{ss}",
-                                 SD_BUS_PARAM(os_release),
-                                 method_get_image_os_release,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetPoolLimit",
-                                 "t",
-                                 SD_BUS_PARAM(size),
-                                 NULL,,
-                                 method_set_pool_limit,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetImageLimit",
-                                 "st",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(size),
-                                 NULL,,
-                                 method_set_image_limit,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("CleanPool",
-                                 "s",
-                                 SD_BUS_PARAM(mode),
-                                 "a(st)",
-                                 SD_BUS_PARAM(images),
-                                 method_clean_pool,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("MapFromMachineUser",
-                                 "su",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(uid_inner),
-                                 "u",
-                                 SD_BUS_PARAM(uid_outer),
-                                 method_map_from_machine_user,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("MapToMachineUser",
-                                 "u",
-                                 SD_BUS_PARAM(uid_outer),
-                                 "sou",
-                                 SD_BUS_PARAM(machine_name)
-                                 SD_BUS_PARAM(machine_path)
-                                 SD_BUS_PARAM(uid_inner),
-                                 method_map_to_machine_user,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("MapFromMachineGroup",
-                                 "su",
-                                 SD_BUS_PARAM(name)
-                                 SD_BUS_PARAM(gid_inner),
-                                 "u",
-                                 SD_BUS_PARAM(gid_outer),
-                                 method_map_from_machine_group,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("MapToMachineGroup",
-                                 "u",
-                                 SD_BUS_PARAM(gid_outer),
-                                 "sou",
-                                 SD_BUS_PARAM(machine_name)
-                                 SD_BUS_PARAM(machine_path)
-                                 SD_BUS_PARAM(gid_inner),
-                                 method_map_to_machine_group,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-
-        SD_BUS_SIGNAL_WITH_NAMES("MachineNew",
-                                 "so",
-                                 SD_BUS_PARAM(machine)
-                                 SD_BUS_PARAM(path),
-                                 0),
-        SD_BUS_SIGNAL_WITH_NAMES("MachineRemoved",
-                                 "so",
-                                 SD_BUS_PARAM(machine)
-                                 SD_BUS_PARAM(path),
-                                 0),
+        SD_BUS_METHOD_WITH_ARGS("GetMachine",
+                                SD_BUS_ARGS("s", name),
+                                SD_BUS_RESULT("o", machine),
+                                method_get_machine,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetImage",
+                                SD_BUS_ARGS("s", name),
+                                SD_BUS_RESULT("o", image),
+                                method_get_image,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetMachineByPID",
+                                SD_BUS_ARGS("u", pid),
+                                SD_BUS_RESULT("o", machine),
+                                method_get_machine_by_pid,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ListMachines",
+                                SD_BUS_NO_ARGS,
+                                SD_BUS_RESULT("a(ssso)", machines),
+                                method_list_machines,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ListImages",
+                                SD_BUS_NO_ARGS,
+                                SD_BUS_RESULT("a(ssbttto)", images),
+                                method_list_images,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("CreateMachine",
+                                SD_BUS_ARGS("s", name, "ay", id, "s", service, "s", class, "u", leader, "s", root_directory, "a(sv)", scope_properties),
+                                SD_BUS_RESULT("o", path),
+                                method_create_machine, 0),
+        SD_BUS_METHOD_WITH_ARGS("CreateMachineWithNetwork",
+                                SD_BUS_ARGS("s", name, "ay", id, "s", service, "s", class, "u", leader, "s", root_directory, "ai", ifindices, "a(sv)", scope_properties),
+                                SD_BUS_RESULT("o", path),
+                                method_create_machine_with_network, 0),
+        SD_BUS_METHOD_WITH_ARGS("RegisterMachine",
+                                SD_BUS_ARGS("s", name, "ay", id, "s", service, "s", class, "u", leader, "s", root_directory),
+                                SD_BUS_RESULT("o", path),
+                                method_register_machine, 0),
+        SD_BUS_METHOD_WITH_ARGS("RegisterMachineWithNetwork",
+                                SD_BUS_ARGS("s", name, "ay", id, "s", service, "s", class, "u", leader, "s", root_directory, "ai", ifindices),
+                                SD_BUS_RESULT("o", path),
+                                method_register_machine_with_network, 0),
+        SD_BUS_METHOD_WITH_ARGS("UnregisterMachine",
+                                SD_BUS_ARGS("s", name),
+                                SD_BUS_NO_RESULT,
+                                method_unregister_machine,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("TerminateMachine",
+                                SD_BUS_ARGS("s", id),
+                                SD_BUS_NO_RESULT,
+                                method_terminate_machine,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("KillMachine",
+                                SD_BUS_ARGS("s", name, "s", who, "i", signal),
+                                SD_BUS_NO_RESULT,
+                                method_kill_machine,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetMachineAddresses",
+                                SD_BUS_ARGS("s", name),
+                                SD_BUS_RESULT("a(iay)", addresses),
+                                method_get_machine_addresses,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetMachineOSRelease",
+                                SD_BUS_ARGS("s", name),
+                                SD_BUS_RESULT("a{ss}", fields),
+                                method_get_machine_os_release,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("OpenMachinePTY",
+                                SD_BUS_ARGS("s", name),
+                                SD_BUS_RESULT("h", pty, "s", pty_path),
+                                method_open_machine_pty,
+                                0),
+        SD_BUS_METHOD_WITH_ARGS("OpenMachineLogin",
+                                SD_BUS_ARGS("s", name),
+                                SD_BUS_RESULT("h", pty, "s", pty_path),
+                                method_open_machine_login,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("OpenMachineShell",
+                                SD_BUS_ARGS("s", name, "s", user, "s", path, "as", args, "as", environment),
+                                SD_BUS_RESULT("h", pty, "s", pty_path),
+                                method_open_machine_shell,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("BindMountMachine",
+                                SD_BUS_ARGS("s", name, "s", source, "s", destination, "b", read_only, "b", mkdir),
+                                SD_BUS_NO_RESULT,
+                                method_bind_mount_machine,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("CopyFromMachine",
+                                SD_BUS_ARGS("s", name, "s", source, "s", destination),
+                                SD_BUS_NO_RESULT,
+                                method_copy_machine,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("CopyToMachine",
+                                SD_BUS_ARGS("s", name, "s", source, "s", destination),
+                                SD_BUS_NO_RESULT,
+                                method_copy_machine,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("OpenMachineRootDirectory",
+                                SD_BUS_ARGS("s", name),
+                                SD_BUS_RESULT("h", fd),
+                                method_open_machine_root_directory,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetMachineUIDShift",
+                                SD_BUS_ARGS("s", name),
+                                SD_BUS_RESULT("u", shift),
+                                method_get_machine_uid_shift,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("RemoveImage",
+                                SD_BUS_ARGS("s", name),
+                                SD_BUS_NO_RESULT,
+                                method_remove_image,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("RenameImage",
+                                SD_BUS_ARGS("s", name, "s", new_name),
+                                SD_BUS_NO_RESULT,
+                                method_rename_image,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("CloneImage",
+                                SD_BUS_ARGS("s", name, "s", new_name, "b", read_only),
+                                SD_BUS_NO_RESULT,
+                                method_clone_image,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("MarkImageReadOnly",
+                                SD_BUS_ARGS("s", name, "b", read_only),
+                                SD_BUS_NO_RESULT,
+                                method_mark_image_read_only,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetImageHostname",
+                                SD_BUS_ARGS("s", name),
+                                SD_BUS_RESULT("s", hostname),
+                                method_get_image_hostname,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetImageMachineID",
+                                SD_BUS_ARGS("s", name),
+                                SD_BUS_RESULT("ay", id),
+                                method_get_image_machine_id,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetImageMachineInfo",
+                                SD_BUS_ARGS("s", name),
+                                SD_BUS_RESULT("a{ss}", machine_info),
+                                method_get_image_machine_info,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetImageOSRelease",
+                                SD_BUS_ARGS("s", name),
+                                SD_BUS_RESULT("a{ss}", os_release),
+                                method_get_image_os_release,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetPoolLimit",
+                                SD_BUS_ARGS("t", size),
+                                SD_BUS_NO_RESULT,
+                                method_set_pool_limit,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetImageLimit",
+                                SD_BUS_ARGS("s", name, "t", size),
+                                SD_BUS_NO_RESULT,
+                                method_set_image_limit,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("CleanPool",
+                                SD_BUS_ARGS("s", mode),
+                                SD_BUS_RESULT("a(st)",images),
+                                method_clean_pool,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("MapFromMachineUser",
+                                SD_BUS_ARGS("s", name, "u", uid_inner),
+                                SD_BUS_RESULT("u", uid_outer),
+                                method_map_from_machine_user,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("MapToMachineUser",
+                                SD_BUS_ARGS("u", uid_outer),
+                                SD_BUS_RESULT("s", machine_name, "o", machine_path, "u", uid_inner),
+                                method_map_to_machine_user,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("MapFromMachineGroup",
+                                SD_BUS_ARGS("s", name, "u", gid_inner),
+                                SD_BUS_RESULT("u", gid_outer),
+                                method_map_from_machine_group,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("MapToMachineGroup",
+                                SD_BUS_ARGS("u", gid_outer),
+                                SD_BUS_RESULT("s", machine_name, "o", machine_path, "u", gid_inner),
+                                method_map_to_machine_group,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+
+        SD_BUS_SIGNAL_WITH_ARGS("MachineNew",
+                                SD_BUS_ARGS("s", machine, "o", path),
+                                0),
+        SD_BUS_SIGNAL_WITH_ARGS("MachineRemoved",
+                                SD_BUS_ARGS("s", machine, "o", path),
+                                0),
 
         SD_BUS_VTABLE_END
 };
index ac626495bc1f327f57c24310cbb0d1dfb570ff76..03ac92daaf17f2b0cd7286ea76de470ebc60fd10 100644 (file)
@@ -14,7 +14,7 @@
 #include "memory-util.h"
 #include "netlink-util.h"
 #include "networkd-manager.h"
-#include "path-util.h"
+#include "parse-helpers.h"
 #include "socket-util.h"
 #include "string-table.h"
 #include "string-util.h"
index 32525e6200c7c9799b4319400663048dd5c4acbb..fc2c6288ae95b0d316cf5acd283cc3414ae90677 100644 (file)
@@ -23,8 +23,8 @@
 #include "networkd-route-util.h"
 #include "networkd-route.h"
 #include "networkd-util.h"
+#include "parse-helpers.h"
 #include "parse-util.h"
-#include "path-util.h"
 #include "random-util.h"
 #include "resolve-private.h"
 #include "string-util.h"
index 2453c33259db409534c456acd56ca1f2efe39732..4a708ebfe3c5ff1bfff78f4b8c5efa0574f2ba76 100644 (file)
@@ -863,11 +863,15 @@ int manager_enumerate(Manager *m) {
                 return log_error_errno(r, "Could not enumerate links: %m");
 
         r = manager_enumerate_qdisc(m);
-        if (r < 0)
+        if (r == -EOPNOTSUPP)
+                log_debug_errno(r, "Could not enumerate QDiscs, ignoring: %m");
+        else if (r < 0)
                 return log_error_errno(r, "Could not enumerate QDisc: %m");
 
         r = manager_enumerate_tclass(m);
-        if (r < 0)
+        if (r == -EOPNOTSUPP)
+                log_debug_errno(r, "Could not enumerate TClasses, ignoring: %m");
+        else if (r < 0)
                 return log_error_errno(r, "Could not enumerate TClass: %m");
 
         r = manager_enumerate_addresses(m);
index 072a7e5fdd5652119fc03c9468fb3635fb0942f5..b40354704be3c52dd3f7f8690dad3c2c017c1f8c 100644 (file)
@@ -1,4 +1,5 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
 
 #include <inttypes.h>
 
index a42e16dd99df863d1e4ac2d2d953d886dc527f64..f6cca7099bdddcc1e5f5097a9e7391112664a980 100644 (file)
@@ -28,6 +28,8 @@ libnspawn_core_sources = files(
         'nspawn-setuid.h',
         'nspawn-stub-pid1.c',
         'nspawn-stub-pid1.h',
+        'nspawn-util.c',
+        'nspawn-util.h',
         'nspawn.h',
 )
 
@@ -58,6 +60,11 @@ tests += [
           libshared],
          [libseccomp]],
 
+        [files('test-nspawn-util.c'),
+         [libnspawn_core,
+          libshared],
+         [libseccomp]],
+
         [files('test-patch-uid.c'),
          [libnspawn_core,
           libshared],
index 44564ba61959e2f25d0280cc916222ba97fb6032..86c014d25e7aae82d6e29e4ee434300139870feb 100644 (file)
@@ -8,6 +8,7 @@
 #include "bus-util.h"
 #include "cap-list.h"
 #include "cpu-set-util.h"
+#include "devnum-util.h"
 #include "env-util.h"
 #include "format-util.h"
 #include "fs-util.h"
@@ -20,7 +21,6 @@
 #if HAVE_SECCOMP
 #include "seccomp-util.h"
 #endif
-#include "stat-util.h"
 #include "stdio-util.h"
 #include "string-util.h"
 #include "strv.h"
diff --git a/src/nspawn/nspawn-util.c b/src/nspawn/nspawn-util.c
new file mode 100644 (file)
index 0000000..402554f
--- /dev/null
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "alloc-util.h"
+#include "glob-util.h"
+#include "log.h"
+#include "nspawn-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "string-util.h"
+
+int systemd_installation_has_version(const char *root, const char *minimal_version) {
+        int r;
+
+        /* Try to guess if systemd installation is later than the specified version. This
+         * is hacky and likely to yield false negatives, particularly if the installation
+         * is non-standard. False positives should be relatively rare.
+         */
+
+        FOREACH_STRING(pattern,
+                       /* /lib works for systems without usr-merge, and for systems with a sane
+                        * usr-merge, where /lib is a symlink to /usr/lib. /usr/lib is necessary
+                        * for Gentoo which does a merge without making /lib a symlink.
+                        */
+                       "/lib/systemd/libsystemd-shared-*.so",
+                       "/lib64/systemd/libsystemd-shared-*.so",
+                       "/usr/lib/systemd/libsystemd-shared-*.so",
+                       "/usr/lib64/systemd/libsystemd-shared-*.so") {
+
+                _cleanup_strv_free_ char **names = NULL;
+                _cleanup_free_ char *path = NULL;
+                char *c;
+
+                path = path_join(root, pattern);
+                if (!path)
+                        return -ENOMEM;
+
+                r = glob_extend(&names, path, 0);
+                if (r == -ENOENT)
+                        continue;
+                if (r < 0)
+                        return r;
+
+                assert_se(c = endswith(path, "*.so"));
+                *c = '\0'; /* truncate the glob part */
+
+                STRV_FOREACH(name, names) {
+                        /* This is most likely to run only once, hence let's not optimize anything. */
+                        char *t, *t2;
+
+                        t = startswith(*name, path);
+                        if (!t)
+                                continue;
+
+                        t2 = endswith(t, ".so");
+                        if (!t2)
+                                continue;
+                        *t2 = '\0';
+
+                        r = strverscmp_improved(t, minimal_version);
+                        log_debug("Found libsystemd shared at \"%s.so\", version %s (%s).",
+                                  *name, t,
+                                  r >= 0 ? "OK" : "too old");
+                        if (r >= 0)
+                                return true;
+                }
+        }
+
+        return false;
+}
diff --git a/src/nspawn/nspawn-util.h b/src/nspawn/nspawn-util.h
new file mode 100644 (file)
index 0000000..e83cd56
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+int systemd_installation_has_version(const char *root, const char *minimal_version);
index aa7367c5c93439a3d9693ee2f7185b55e34c1227..807c6669807d299f3c41e1bd122ba4f716dad67b 100644 (file)
 #include "nspawn-settings.h"
 #include "nspawn-setuid.h"
 #include "nspawn-stub-pid1.h"
+#include "nspawn-util.h"
 #include "nspawn.h"
 #include "nulstr-util.h"
 #include "os-util.h"
 #include "pager.h"
 #include "parse-argument.h"
 #include "parse-util.h"
-#include "path-util.h"
 #include "pretty-print.h"
 #include "process-util.h"
 #include "ptyfwd.h"
@@ -509,7 +509,7 @@ static int detect_unified_cgroup_hierarchy_from_image(const char *directory) {
         if (r > 0) {
                 /* Unified cgroup hierarchy support was added in 230. Unfortunately the detection
                  * routine only detects 231, so we'll have a false negative here for 230. */
-                r = systemd_installation_has_version(directory, 230);
+                r = systemd_installation_has_version(directory, "230");
                 if (r < 0)
                         return log_error_errno(r, "Failed to determine systemd version in container: %m");
                 if (r > 0)
@@ -518,7 +518,7 @@ static int detect_unified_cgroup_hierarchy_from_image(const char *directory) {
                         arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_NONE;
         } else if (cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER) > 0) {
                 /* Mixed cgroup hierarchy support was added in 233 */
-                r = systemd_installation_has_version(directory, 233);
+                r = systemd_installation_has_version(directory, "233");
                 if (r < 0)
                         return log_error_errno(r, "Failed to determine systemd version in container: %m");
                 if (r > 0)
@@ -5737,6 +5737,13 @@ static int run(int argc, char *argv[]) {
                         goto finish;
                 }
 
+                /* Take a LOCK_SH lock on the device, so that udevd doesn't issue BLKRRPART in our back */
+                r = loop_device_flock(loop, LOCK_SH);
+                if (r < 0) {
+                        log_error_errno(r, "Failed to take lock on loopback block device: %m");
+                        goto finish;
+                }
+
                 r = dissect_image_and_warn(
                                 loop->fd,
                                 arg_image,
diff --git a/src/nspawn/test-nspawn-util.c b/src/nspawn/test-nspawn-util.c
new file mode 100644 (file)
index 0000000..08c8050
--- /dev/null
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "nspawn-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "tests.h"
+
+TEST(systemd_installation_has_version) {
+        int r;
+
+        FOREACH_STRING(version, "0", "231", STRINGIFY(PROJECT_VERSION), "999") {
+                r = systemd_installation_has_version(saved_argv[1], version);
+                assert_se(r >= 0);
+                log_info("%s has systemd >= %s: %s",
+                         saved_argv[1] ?: "Current installation", version, yes_no(r));
+        }
+}
+
+/* This program can be called with a path to an installation root.
+ * For example: build/test-nspawn-util /var/lib/machines/rawhide
+ */
+DEFINE_TEST_MAIN(LOG_DEBUG);
index 0d1da2773f065815b91f2b83fc509fc1a53eb8fc..31dcf0ffdf14f47c3f00bc85d816789e66994c32 100644 (file)
@@ -14,6 +14,7 @@
 #include "btrfs-util.h"
 #include "cryptsetup-util.h"
 #include "device-nodes.h"
+#include "devnum-util.h"
 #include "dissect-image.h"
 #include "escape.h"
 #include "fd-util.h"
index 118ab6c7d08bf21c898283529c6d694029d4e9c1..051242e836c5e5a575c361b8bf7090371dfcfd91 100644 (file)
@@ -12,6 +12,7 @@
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 
+#include "sd-device.h"
 #include "sd-id128.h"
 
 #include "alloc-util.h"
@@ -23,6 +24,7 @@
 #include "conf-parser.h"
 #include "cryptsetup-util.h"
 #include "def.h"
+#include "devnum-util.h"
 #include "dirent-util.h"
 #include "efivars.h"
 #include "errno-util.h"
@@ -46,8 +48,7 @@
 #include "mount-util.h"
 #include "mountpoint-util.h"
 #include "parse-argument.h"
-#include "parse-util.h"
-#include "path-util.h"
+#include "parse-helpers.h"
 #include "pretty-print.h"
 #include "proc-cmdline.h"
 #include "process-util.h"
@@ -55,7 +56,6 @@
 #include "resize-fs.h"
 #include "sort-util.h"
 #include "specifier.h"
-#include "stat-util.h"
 #include "stdio-util.h"
 #include "string-table.h"
 #include "string-util.h"
@@ -3644,14 +3644,13 @@ static int resolve_copy_blocks_auto_candidate(
                 sd_id128_t *ret_uuid) {
 
         _cleanup_(blkid_free_probep) blkid_probe b = NULL;
-        _cleanup_free_ char *p = NULL;
+        _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
         _cleanup_close_ int fd = -1;
-        const char *pttype, *t;
+        const char *pttype, *t, *p;
         sd_id128_t pt_parsed, u;
         blkid_partition pp;
         dev_t whole_devno;
         blkid_partlist pl;
-        struct stat st;
         int r;
 
         /* Checks if the specified partition has the specified GPT type UUID, and is located on the specified
@@ -3674,21 +3673,19 @@ static int resolve_copy_blocks_auto_candidate(
                                 major(partition_devno), minor(partition_devno),
                                 major(restrict_devno), minor(restrict_devno));
 
-        r = device_path_make_major_minor(S_IFBLK, whole_devno, &p);
+        r = sd_device_new_from_devnum(&dev, 'b', whole_devno);
         if (r < 0)
-                return log_error_errno(r, "Failed to convert block device to device node path: %m");
-
-        fd = open(p, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
-        if (fd < 0)
-                return log_error_errno(r, "Failed to open '%s': %m", p);
+                return log_error_errno(r, "Failed to create sd-device for block device %u:%u: %m",
+                                       major(whole_devno), minor(whole_devno));
 
-        if (fstat(fd, &st) < 0)
-                return log_error_errno(r, "Failed to stat '%s': %m", p);
+        r = sd_device_get_devname(dev, &p);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get name of block device %u:%u: %m",
+                                       major(whole_devno), minor(whole_devno));
 
-        if (!S_ISBLK(st.st_mode) || st.st_rdev != whole_devno)
-                return log_error_errno(
-                                SYNTHETIC_ERRNO(EPERM),
-                                "Opened and determined block device don't match, refusing.");
+        fd = sd_device_open(dev, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
+        if (fd < 0)
+                return log_error_errno(fd, "Failed to open block device %s: %m", p);
 
         b = blkid_new_probe();
         if (!b)
@@ -3806,7 +3803,7 @@ static int resolve_copy_blocks_auto(
                 sd_id128_t type_uuid,
                 const char *root,
                 dev_t restrict_devno,
-                char **ret_path,
+                dev_t *ret_devno,
                 sd_id128_t *ret_uuid) {
 
         const char *try1 = NULL, *try2 = NULL;
@@ -3816,8 +3813,6 @@ static int resolve_copy_blocks_auto(
         dev_t devno, found = 0;
         int r;
 
-        assert(ret_path);
-
         /* Enforce some security restrictions: CopyBlocks=auto should not be an avenue to get outside of the
          * --root=/--image= confinement. Specifically, refuse CopyBlocks= in combination with --root= at all,
          * and restrict block device references in the --image= case to loopback block device we set up.
@@ -3890,7 +3885,7 @@ static int resolve_copy_blocks_auto(
                         if (r < 0)
                                 return log_error_errno(r, "Failed to read %s: %m", q);
 
-                        r = parse_dev(t, &sl);
+                        r = parse_devnum(t, &sl);
                         if (r < 0) {
                                 log_debug_errno(r, "Failed to parse %s, ignoring: %m", q);
                                 continue;
@@ -3927,9 +3922,8 @@ static int resolve_copy_blocks_auto(
                 return log_error_errno(SYNTHETIC_ERRNO(ENXIO),
                                        "Unable to automatically discover suitable partition to copy blocks from.");
 
-        r = device_path_make_major_minor(S_IFBLK, found, ret_path);
-        if (r < 0)
-                return log_error_errno(r, "Failed to convert dev_t to device node path: %m");
+        if (ret_devno)
+                *ret_devno = found;
 
         if (ret_uuid)
                 *ret_uuid = found_uuid;
@@ -3973,32 +3967,43 @@ static int context_open_copy_block_paths(
                                                        "Copying from block device node is not permitted in --image=/--root= mode, refusing.");
 
                 } else if (p->copy_blocks_auto) {
+                        _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
+                        const char *devname;
+                        dev_t devno;
 
-                        r = resolve_copy_blocks_auto(p->type_uuid, root, restrict_devno, &opened, &uuid);
+                        r = resolve_copy_blocks_auto(p->type_uuid, root, restrict_devno, &devno, &uuid);
                         if (r < 0)
                                 return r;
 
-                        source_fd = open(opened, O_RDONLY|O_CLOEXEC|O_NOCTTY);
+                        r = sd_device_new_from_devnum(&dev, 'b', devno);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to create sd-device object for device %u:%u: %m", major(devno), minor(devno));
+
+                        r = sd_device_get_devname(dev, &devname);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to get device name of %u:%u: %m", major(devno), minor(devno));
+
+                        opened = strdup(devname);
+                        if (!opened)
+                                return log_oom();
+
+                        source_fd = sd_device_open(dev, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
                         if (source_fd < 0)
-                                return log_error_errno(errno, "Failed to open automatically determined source block copy device '%s': %m", opened);
+                                return log_error_errno(source_fd, "Failed to open automatically determined source block copy device '%s': %m", opened);
 
                         if (fstat(source_fd, &st) < 0)
                                 return log_error_errno(errno, "Failed to stat block copy file '%s': %m", opened);
-
-                        /* If we found it automatically, it must be a block device, let's enforce that */
-                        if (!S_ISBLK(st.st_mode))
-                                return log_error_errno(SYNTHETIC_ERRNO(EBADF),
-                                                       "Automatically detected source block copy device '%s' is not a block device, refusing: %m", opened);
-                }  else
+                } else
                         continue;
 
                 if (S_ISDIR(st.st_mode)) {
-                        _cleanup_free_ char *bdev = NULL;
+                        _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
+                        const char *bdev;
 
                         /* If the file is a directory, automatically find the backing block device */
 
                         if (major(st.st_dev) != 0)
-                                r = device_path_make_major_minor(S_IFBLK, st.st_dev, &bdev);
+                                r = sd_device_new_from_devnum(&dev, 'b', st.st_dev);
                         else {
                                 dev_t devt;
 
@@ -4010,22 +4015,23 @@ static int context_open_copy_block_paths(
                                 if (r < 0)
                                         return log_error_errno(r, "Unable to determine backing block device of '%s': %m", opened);
 
-                                r = device_path_make_major_minor(S_IFBLK, devt, &bdev);
+                                r = sd_device_new_from_devnum(&dev, 'b', devt);
                         }
                         if (r < 0)
-                                return log_error_errno(r, "Failed to determine block device path for block device backing '%s': %m", opened);
+                                return log_error_errno(r, "Failed to create sd-device object for block device backing '%s': %m", opened);
+
+                        r = sd_device_get_devpath(dev, &bdev);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to get device name for block device backing '%s': %m", opened);
 
                         safe_close(source_fd);
 
-                        source_fd = open(bdev, O_RDONLY|O_CLOEXEC|O_NOCTTY);
+                        source_fd = sd_device_open(dev, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
                         if (source_fd < 0)
-                                return log_error_errno(errno, "Failed to open block device '%s': %m", bdev);
+                                return log_error_errno(source_fd, "Failed to open block device '%s': %m", bdev);
 
                         if (fstat(source_fd, &st) < 0)
                                 return log_error_errno(errno, "Failed to stat block device '%s': %m", bdev);
-
-                        if (!S_ISBLK(st.st_mode))
-                                return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK), "Block device '%s' is not actually a block device, refusing.", bdev);
                 }
 
                 if (S_ISREG(st.st_mode))
index 89f626653915fba6314e41069043260ce213670d..2b9bebbe8ccc5fbe1986986399c027860ae4f06a 100755 (executable)
@@ -22,7 +22,7 @@ SEED=e2a40bf9-73f1-4278-9160-49c031e7aef8
 
 echo "### Testing systemd-repart --empty=create ###"
 
-"$repart" "$D/zzz" --empty=create --size=1G --seed="$SEED"
+"$repart" "$D/zzz" --empty=create --size=1G --seed="$SEED" --no-pager
 
 sfdisk -d "$D/zzz" | grep -v -e 'sector-size' -e '^$' >"$D/empty"
 
@@ -58,7 +58,7 @@ SizeMaxBytes=64M
 PaddingMinBytes=92M
 EOF
 
-"$repart" "$D/zzz" --dry-run=no --seed="$SEED" --definitions="$D/definitions"
+"$repart" "$D/zzz" --dry-run=no --seed="$SEED" --definitions="$D/definitions" --no-pager
 
 sfdisk -d "$D/zzz" | grep -v -e 'sector-size' -e '^$' >"$D/populated"
 
@@ -93,7 +93,7 @@ EOF
 echo "Label=ignored_label" >>"$D/definitions/home.conf"
 echo "UUID=b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" >>"$D/definitions/home.conf"
 
-"$repart" "$D/zzz" --dry-run=no --seed="$SEED" --definitions="$D/definitions"
+"$repart" "$D/zzz" --dry-run=no --seed="$SEED" --definitions="$D/definitions" --no-pager
 
 sfdisk -d "$D/zzz" | grep -v -e 'sector-size' -e '^$' >"$D/populated2"
 
@@ -113,7 +113,7 @@ EOF
 
 echo "### Resizing to 2G ###"
 
-"$repart" "$D/zzz" --size=2G --dry-run=no --seed="$SEED" --definitions="$D/definitions"
+"$repart" "$D/zzz" --size=2G --dry-run=no --seed="$SEED" --definitions="$D/definitions" --no-pager
 
 sfdisk -d "$D/zzz" | grep -v -e 'sector-size' -e '^$' >"$D/populated3"
 
@@ -143,7 +143,7 @@ UUID=2a1d97e1d0a346cca26eadc643926617
 CopyBlocks=$D/block-copy
 EOF
 
-"$repart" "$D/zzz" --size=3G --dry-run=no --seed="$SEED" --definitions="$D/definitions"
+"$repart" "$D/zzz" --size=3G --dry-run=no --seed="$SEED" --definitions="$D/definitions" --no-pager
 
 sfdisk -d "$D/zzz" | grep -v -e 'sector-size' -e '^$' >"$D/populated4"
 
@@ -180,7 +180,7 @@ CopyFiles=$D/definitions:/def
 SizeMinBytes=48M
 EOF
 
-    "$repart" "$D/zzz" --size=auto --dry-run=no --seed="$SEED" --definitions="$D/definitions"
+    "$repart" "$D/zzz" --size=auto --dry-run=no --seed="$SEED" --definitions="$D/definitions" --no-pager
 
     sfdisk -d "$D/zzz" | grep -v -e 'sector-size' -e '^$' >"$D/populated5"
 
index 0c10b161f01a000cf599d327c66cd8409515adf3..7bba7b47e42a6d36a216d8c1c50705167e0f3d06 100644 (file)
@@ -359,6 +359,10 @@ static int portable_extract_by_path(
                 /* We now have a loopback block device, let's fork off a child in its own mount namespace, mount it
                  * there, and extract the metadata we need. The metadata is sent from the child back to us. */
 
+                r = loop_device_flock(d, LOCK_SH);
+                if (r < 0)
+                        return log_debug_errno(r, "Failed to acquire lock on loopback block device: %m");
+
                 BLOCK_SIGNALS(SIGCHLD);
 
                 r = mkdtemp_malloc("/tmp/inspect-XXXXXX", &tmpdir);
index 930313b84420513d1eb906ae515e5898be0d81de..a25dffae630ae074c292c8c6bc356a351a02a8c7 100644 (file)
@@ -225,7 +225,7 @@ int config_parse_dnssd_service_name(
                 { 'a', specifier_architecture,    NULL },
                 { 'b', specifier_boot_id,         NULL },
                 { 'B', specifier_os_build_id,     NULL },
-                { 'H', specifier_host_name,       NULL }, /* We will use specifier_dnssd_host_name(). */
+                { 'H', specifier_hostname,        NULL }, /* We will use specifier_dnssd_hostname(). */
                 { 'm', specifier_machine_id,      NULL },
                 { 'o', specifier_os_id,           NULL },
                 { 'v', specifier_kernel_release,  NULL },
index 0cc50d64783e5f5a4622fe61194d055c6cb44af2..bcbb2754d78df263851f0e84c069f5a197267c04 100644 (file)
@@ -166,7 +166,7 @@ bool dns_search_domain_unlink_marked(DnsSearchDomain *first) {
         } else
                 changed = false;
 
-        return changed || dns_search_domain_unlink_marked(next);
+        return dns_search_domain_unlink_marked(next) || changed;
 }
 
 void dns_search_domain_mark_all(DnsSearchDomain *first) {
index 6d77aa817e41550dce9b9e40744d27b91e3c61ea..443760ab7078fcf95adf290c6ff0aab34ca0e8bf 100644 (file)
@@ -135,7 +135,7 @@ static int dnssd_service_load(Manager *manager, const char *filename) {
         return 0;
 }
 
-static int specifier_dnssd_host_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
+static int specifier_dnssd_hostname(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
         DnssdService *s  = (DnssdService *) userdata;
         char *n;
 
@@ -153,15 +153,15 @@ static int specifier_dnssd_host_name(char specifier, const void *data, const cha
 
 int dnssd_render_instance_name(DnssdService *s, char **ret_name) {
         static const Specifier specifier_table[] = {
-                { 'a', specifier_architecture,    NULL },
-                { 'b', specifier_boot_id,         NULL },
-                { 'B', specifier_os_build_id,     NULL },
-                { 'H', specifier_dnssd_host_name, NULL },
-                { 'm', specifier_machine_id,      NULL },
-                { 'o', specifier_os_id,           NULL },
-                { 'v', specifier_kernel_release,  NULL },
-                { 'w', specifier_os_version_id,   NULL },
-                { 'W', specifier_os_variant_id,   NULL },
+                { 'a', specifier_architecture,   NULL },
+                { 'b', specifier_boot_id,        NULL },
+                { 'B', specifier_os_build_id,    NULL },
+                { 'H', specifier_dnssd_hostname, NULL },
+                { 'm', specifier_machine_id,     NULL },
+                { 'o', specifier_os_id,          NULL },
+                { 'v', specifier_kernel_release, NULL },
+                { 'w', specifier_os_version_id,  NULL },
+                { 'W', specifier_os_variant_id,  NULL },
                 {}
         };
         _cleanup_free_ char *name = NULL;
index a0c60be26e95ed398882410f16cd4d0083ee12ea..c3b90bb22734a664526f38a58ac6ef723a1336f9 100644 (file)
@@ -6,12 +6,12 @@
 #include "alloc-util.h"
 #include "blockdev-util.h"
 #include "btrfs-util.h"
+#include "devnum-util.h"
 #include "dirent-util.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "missing_magic.h"
 #include "parse-util.h"
-#include "stat-util.h"
 
 int block_get_whole_disk(dev_t d, dev_t *ret) {
         char p[SYS_BLOCK_PATH_MAX("/partition")];
@@ -44,7 +44,7 @@ int block_get_whole_disk(dev_t d, dev_t *ret) {
         if (r < 0)
                 return r;
 
-        r = parse_dev(s, &devt);
+        r = parse_devnum(s, &devt);
         if (r < 0)
                 return r;
 
@@ -170,7 +170,7 @@ int block_get_originating(dev_t dt, dev_t *ret) {
         if (r < 0)
                 return r;
 
-        r = parse_dev(t, &devt);
+        r = parse_devnum(t, &devt);
         if (r < 0)
                 return -EINVAL;
 
index 7016f3840e138defd3a2423553779ab38dbdb78a..91cb605fb1ce011aaa81bf4aa9a584d84a096e45 100644 (file)
@@ -5,6 +5,7 @@
 #include "bootspec.h"
 #include "bootspec-fundamental.h"
 #include "conf-files.h"
+#include "devnum-util.h"
 #include "dirent-util.h"
 #include "efi-loader.h"
 #include "env-file.h"
@@ -15,7 +16,6 @@
 #include "pe-header.h"
 #include "recurse-dir.h"
 #include "sort-util.h"
-#include "stat-util.h"
 #include "strv.h"
 #include "unaligned.h"
 
@@ -918,7 +918,7 @@ int boot_config_load_auto(
                 return r; /* It's fine if the XBOOTLDR partition doesn't exist, hence we ignore ENOKEY here */
 
         /* If both paths actually refer to the same inode, suppress the xbootldr path */
-        if (esp_where && xbootldr_where && devid_set_and_equal(esp_devid, xbootldr_devid))
+        if (esp_where && xbootldr_where && devnum_set_and_equal(esp_devid, xbootldr_devid))
                 xbootldr_where = mfree(xbootldr_where);
 
         return boot_config_load(config, esp_where, xbootldr_where);
index ec5951b52f6f25741ed45c24ad7763977b71bb02..5e3bcbb6e4164ea1f8d4d7bce27007000123d52b 100644 (file)
@@ -659,7 +659,7 @@ int btrfs_subvol_find_subtree_qgroup(int fd, uint64_t subvol_id, uint64_t *ret)
          * prepared with btrfs_subvol_auto_qgroup_fd() with
          * insert_intermediary_qgroup=true (or equivalent). For others
          * it will return the leaf qgroup instead. The two cases may
-         * be distuingished via the return value, which is 1 in case
+         * be distinguished via the return value, which is 1 in case
          * an appropriate "subtree" qgroup was found, and 0
          * otherwise. */
 
index 95ef3230b4a9675f4b7f6116d54054b703aaa45b..4f02c2c373062a8dd19a957a93b22a3595f9f718 100644 (file)
@@ -29,7 +29,7 @@
 #include "mountpoint-util.h"
 #include "nsflags.h"
 #include "numa-util.h"
-#include "parse-socket-bind-item.h"
+#include "parse-helpers.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "percent-util.h"
index aeea0a02d52d62407751330479117cee912c7553..6c105e7fd27fd21b096ff178259e317e55f6879a 100644 (file)
@@ -24,6 +24,7 @@
 #include "macro.h"
 #include "missing_network.h"
 #include "nulstr-util.h"
+#include "parse-helpers.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "percent-util.h"
index 3f1644ea859949fb7e9a7f8ab6ea35233ccb0262..ea0afb81a5042c5c6ca8ab5d60bd0aa8c4167c18 100644 (file)
@@ -1196,6 +1196,12 @@ int image_read_metadata(Image *i) {
                 if (r < 0)
                         return r;
 
+                /* Make sure udevd doesn't issue BLKRRPART in the background which might make our partitions
+                 * disappear temporarily. */
+                r = loop_device_flock(d, LOCK_SH);
+                if (r < 0)
+                        return r;
+
                 r = dissect_image(
                                 d->fd,
                                 NULL, NULL,
index 2cf031cdeb0aad60038ecf14861221c7fd4d3897..25fed4cf508ea0ca8d6dd8fabf574cf788cf86cc 100644 (file)
@@ -4,6 +4,7 @@
 #include <valgrind/memcheck.h>
 #endif
 
+#include <linux/blkpg.h>
 #include <linux/dm-ioctl.h>
 #include <linux/loop.h>
 #include <sys/mount.h>
@@ -125,389 +126,6 @@ not_found:
 }
 
 #if HAVE_BLKID
-static int enumerator_for_parent(sd_device *d, sd_device_enumerator **ret) {
-        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
-        int r;
-
-        assert(d);
-        assert(ret);
-
-        r = sd_device_enumerator_new(&e);
-        if (r < 0)
-                return r;
-
-        r = sd_device_enumerator_add_match_subsystem(e, "block", true);
-        if (r < 0)
-                return r;
-
-        r = sd_device_enumerator_add_match_parent(e, d);
-        if (r < 0)
-                return r;
-
-        r = sd_device_enumerator_add_match_sysattr(e, "partition", NULL, true);
-        if (r < 0)
-                return r;
-
-        *ret = TAKE_PTR(e);
-        return 0;
-}
-
-static int device_is_partition(
-                sd_device *d,
-                sd_device *expected_parent,
-                blkid_partition pp) {
-
-        const char *v, *parent_syspath, *expected_parent_syspath;
-        blkid_loff_t bsize, bstart;
-        uint64_t size, start;
-        int partno, bpartno, r;
-        sd_device *parent;
-
-        assert(d);
-        assert(expected_parent);
-        assert(pp);
-
-        r = sd_device_get_subsystem(d, &v);
-        if (r < 0)
-                return r;
-        if (!streq(v, "block"))
-                return false;
-
-        if (sd_device_get_devtype(d, &v) < 0 || !streq(v, "partition"))
-                return false;
-
-        r = sd_device_get_parent(d, &parent);
-        if (r < 0)
-                return false; /* Doesn't have a parent? No relevant to us */
-
-        r = sd_device_get_syspath(parent, &parent_syspath); /* Check parent of device of this action */
-        if (r < 0)
-                return r;
-
-        r = sd_device_get_syspath(expected_parent, &expected_parent_syspath); /* Check parent of device we are looking for */
-        if (r < 0)
-                return r;
-
-        if (!path_equal(parent_syspath, expected_parent_syspath))
-                return false; /* Has a different parent than what we need, not interesting to us */
-
-        /* On kernel uevents we may find the partition number in the PARTN= field. Let's use that preferably,
-         * since it's cheaper and more importantly: the sysfs attribute "partition" appears to become
-         * available late, hence let's use the property instead, which is available at the moment we see the
-         * uevent. */
-        r = sd_device_get_property_value(d, "PARTN", &v);
-        if (r == -ENOENT)
-                r = sd_device_get_sysattr_value(d, "partition", &v);
-        if (r < 0)
-                return r;
-
-        r = safe_atoi(v, &partno);
-        if (r < 0)
-                return r;
-
-        errno = 0;
-        bpartno = blkid_partition_get_partno(pp);
-        if (bpartno < 0)
-                return errno_or_else(EIO);
-
-        if (partno != bpartno)
-                return false;
-
-        r = sd_device_get_sysattr_value(d, "start", &v);
-        if (r < 0)
-                return r;
-        r = safe_atou64(v, &start);
-        if (r < 0)
-                return r;
-
-        errno = 0;
-        bstart = blkid_partition_get_start(pp);
-        if (bstart < 0)
-                return errno_or_else(EIO);
-
-        if (start != (uint64_t) bstart)
-                return false;
-
-        r = sd_device_get_sysattr_value(d, "size", &v);
-        if (r < 0)
-                return r;
-        r = safe_atou64(v, &size);
-        if (r < 0)
-                return r;
-
-        errno = 0;
-        bsize = blkid_partition_get_size(pp);
-        if (bsize < 0)
-                return errno_or_else(EIO);
-
-        if (size != (uint64_t) bsize)
-                return false;
-
-        return true;
-}
-
-static int find_partition(
-                sd_device *parent,
-                blkid_partition pp,
-                usec_t timestamp_not_before,
-                DissectImageFlags flags,
-                sd_device **ret) {
-
-        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
-        sd_device *q;
-        int r;
-
-        assert(parent);
-        assert(pp);
-        assert(ret);
-
-        r = enumerator_for_parent(parent, &e);
-        if (r < 0)
-                return r;
-
-        FOREACH_DEVICE(e, q) {
-                uint64_t usec;
-
-                if (!FLAGS_SET(flags, DISSECT_IMAGE_NO_UDEV)) {
-                        r = sd_device_get_usec_initialized(q, &usec);
-                        if (r == -EBUSY) /* Not initialized yet */
-                                continue;
-                        if (r < 0)
-                                return r;
-
-                        if (timestamp_not_before != USEC_INFINITY &&
-                            usec < timestamp_not_before) /* udev database entry older than our attachment? Then it's not ours */
-                                continue;
-                }
-
-                r = device_is_partition(q, parent, pp);
-                if (r < 0)
-                        return r;
-                if (r > 0) {
-                        *ret = sd_device_ref(q);
-                        return 0;
-                }
-        }
-
-        return -ENXIO;
-}
-
-struct wait_data {
-        sd_device *parent_device;
-        blkid_partition blkidp;
-        sd_device *found;
-        uint64_t diskseq;
-        uint64_t uevent_seqnum_not_before;
-        usec_t timestamp_not_before;
-        DissectImageFlags flags;
-};
-
-static inline void wait_data_done(struct wait_data *d) {
-        sd_device_unref(d->found);
-}
-
-static int device_monitor_handler(sd_device_monitor *monitor, sd_device *device, void *userdata) {
-        struct wait_data *w = userdata;
-        int r;
-
-        assert(w);
-
-        if (device_for_action(device, SD_DEVICE_REMOVE))
-                return 0;
-
-        if (w->diskseq != 0) {
-                uint64_t diskseq;
-
-                /* If w->diskseq is non-zero, then we must have a disk seqnum */
-                r = sd_device_get_diskseq(device, &diskseq);
-                if (r < 0) {
-                        log_debug_errno(r, "Dropping event because it has no diskseq, but waiting for %" PRIu64, w->diskseq);
-                        return 0;
-                }
-                if (diskseq < w->diskseq) {
-                        log_debug("Dropping event because diskseq too old (%" PRIu64 " < %" PRIu64 ")",
-                                  diskseq, w->diskseq);
-                        return 0;
-                }
-                if (diskseq > w->diskseq) {
-                        r = -EBUSY;
-                        goto finish; /* Newer than what we were expecting, so we missed it, stop waiting */
-                }
-        } else if (w->uevent_seqnum_not_before != UINT64_MAX) {
-                uint64_t seqnum;
-
-                r = sd_device_get_seqnum(device, &seqnum);
-                if (r < 0)
-                        goto finish;
-
-                if (seqnum <= w->uevent_seqnum_not_before) { /* From an older use of this loop device */
-                        log_debug("Dropping event because seqnum too old (%" PRIu64 " <= %" PRIu64 ")",
-                                  seqnum, w->uevent_seqnum_not_before);
-                        return 0;
-                }
-        }
-
-        r = device_is_partition(device, w->parent_device, w->blkidp);
-        if (r < 0)
-                goto finish;
-        if (r == 0) /* Not the one we need */
-                return 0;
-
-        /* It's the one we need! Yay! */
-        assert(!w->found);
-        w->found = sd_device_ref(device);
-        r = 0;
-
-finish:
-        return sd_event_exit(sd_device_monitor_get_event(monitor), r);
-}
-
-static int timeout_handler(sd_event_source *s, uint64_t usec, void *userdata) {
-        struct wait_data *w = userdata;
-        int r;
-
-        assert(w);
-
-        /* Why partition not appeared within the timeout? We may lost some uevent, as some properties
-         * were not ready when we received uevent... Not sure, but anyway, let's try to find the
-         * partition again before give up. */
-
-        r = find_partition(w->parent_device, w->blkidp, w->timestamp_not_before, w->flags, &w->found);
-        if (r == -ENXIO)
-                return log_debug_errno(SYNTHETIC_ERRNO(ETIMEDOUT),
-                                       "Partition still not appeared after timeout reached.");
-        if (r < 0)
-                return log_debug_errno(r, "Failed to find partition: %m");
-
-        log_debug("Partition appeared after timeout reached.");
-        return sd_event_exit(sd_event_source_get_event(s), 0);
-}
-
-static int retry_handler(sd_event_source *s, uint64_t usec, void *userdata) {
-        struct wait_data *w = userdata;
-        int r;
-
-        assert(w);
-
-        r = find_partition(w->parent_device, w->blkidp, w->timestamp_not_before, w->flags, &w->found);
-        if (r != -ENXIO) {
-                if (r < 0)
-                        return log_debug_errno(r, "Failed to find partition: %m");
-
-                log_debug("Partition found by a periodic search.");
-                return sd_event_exit(sd_event_source_get_event(s), 0);
-        }
-
-        r = sd_event_source_set_time_relative(s, 500 * USEC_PER_MSEC);
-        if (r < 0)
-                return r;
-
-        return sd_event_source_set_enabled(s, SD_EVENT_ONESHOT);
-}
-
-static int wait_for_partition_device(
-                sd_device *parent,
-                blkid_partition pp,
-                usec_t deadline,
-                uint64_t diskseq,
-                uint64_t uevent_seqnum_not_before,
-                usec_t timestamp_not_before,
-                DissectImageFlags flags,
-                sd_device **ret) {
-
-        _cleanup_(sd_event_source_unrefp) sd_event_source *timeout_source = NULL, *retry_source = NULL;
-        _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL;
-        _cleanup_(sd_event_unrefp) sd_event *event = NULL;
-        int r;
-
-        assert(parent);
-        assert(pp);
-        assert(ret);
-
-        r = find_partition(parent, pp, timestamp_not_before, flags, ret);
-        if (r != -ENXIO)
-                return r;
-
-        r = sd_event_new(&event);
-        if (r < 0)
-                return r;
-
-        r = sd_device_monitor_new(&monitor);
-        if (r < 0)
-                return r;
-
-        r = sd_device_monitor_filter_add_match_subsystem_devtype(monitor, "block", "partition");
-        if (r < 0)
-                return r;
-
-        r = sd_device_monitor_filter_add_match_parent(monitor, parent, true);
-        if (r < 0)
-                return r;
-
-        r = sd_device_monitor_filter_add_match_sysattr(monitor, "partition", NULL, true);
-        if (r < 0)
-                return r;
-
-        r = sd_device_monitor_attach_event(monitor, event);
-        if (r < 0)
-                return r;
-
-        _cleanup_(wait_data_done) struct wait_data w = {
-                .parent_device = parent,
-                .blkidp = pp,
-                .diskseq = diskseq,
-                .uevent_seqnum_not_before = uevent_seqnum_not_before,
-                .timestamp_not_before = timestamp_not_before,
-                .flags = flags,
-        };
-
-        r = sd_device_monitor_start(monitor, device_monitor_handler, &w);
-        if (r < 0)
-                return r;
-
-        /* Check again, the partition might have appeared in the meantime */
-        r = find_partition(parent, pp, timestamp_not_before, flags, ret);
-        if (r != -ENXIO)
-                return r;
-
-        if (deadline != USEC_INFINITY) {
-                r = sd_event_add_time(
-                                event, &timeout_source,
-                                CLOCK_MONOTONIC, deadline, 0,
-                                timeout_handler, &w);
-                if (r < 0)
-                        return r;
-
-                r = sd_event_source_set_exit_on_failure(timeout_source, true);
-                if (r < 0)
-                        return r;
-        }
-
-        /* If we don't have a disk sequence number then we cannot do exact matching,
-         * and we cannot know if we missed it or if it has not been sent yet, so set
-         * up additional retries to increase the chances of receiving the event. */
-        if (diskseq == 0) {
-                r = sd_event_add_time_relative(
-                                event, &retry_source,
-                                CLOCK_MONOTONIC, 500 * USEC_PER_MSEC, 0,
-                                retry_handler, &w);
-                if (r < 0)
-                        return r;
-
-                r = sd_event_source_set_exit_on_failure(retry_source, true);
-                if (r < 0)
-                        return r;
-        }
-
-        r = sd_event_loop(event);
-        if (r < 0)
-                return r;
-
-        assert(w.found);
-        *ret = TAKE_PTR(w.found);
-        return 0;
-}
-
 static void check_partition_flags(
                 const char *node,
                 unsigned long long pflags,
@@ -530,92 +148,79 @@ static void check_partition_flags(
                 log_debug("Unexpected partition flag %llu set on %s!", bit, node);
         }
 }
+#endif
 
-static int device_wait_for_initialization_harder(
-                sd_device *device,
-                const char *subsystem,
-                usec_t deadline,
-                sd_device **ret) {
-
-        usec_t start, left, retrigger_timeout;
-        int r;
-
-        start = now(CLOCK_MONOTONIC);
-        left = usec_sub_unsigned(deadline, start);
+static void dissected_partition_done(DissectedPartition *p) {
+        assert(p);
 
-        if (DEBUG_LOGGING) {
-                const char *sn = NULL;
+        free(p->fstype);
+        free(p->node);
+        free(p->label);
+        free(p->decrypted_fstype);
+        free(p->decrypted_node);
+        free(p->mount_options);
 
-                (void) sd_device_get_sysname(device, &sn);
-                log_device_debug(device,
-                                 "Will wait up to %s for '%s' to initialize…", FORMAT_TIMESPAN(left, 0), strna(sn));
-        }
+        *p = (DissectedPartition) {
+                .partno = -1,
+                .architecture = _ARCHITECTURE_INVALID,
+        };
+}
 
-        if (left != USEC_INFINITY)
-                retrigger_timeout = CLAMP(left / 4, 1 * USEC_PER_SEC, 5 * USEC_PER_SEC); /* A fourth of the total timeout, but let's clamp to 1s…5s range */
-        else
-                retrigger_timeout = 2 * USEC_PER_SEC;
+#if HAVE_BLKID
+static int ioctl_partition_add(
+                int fd,
+                const char *name,
+                int nr,
+                uint64_t start,
+                uint64_t size) {
 
-        for (;;) {
-                usec_t local_deadline, n;
-                bool last_try;
+        assert(fd >= 0);
+        assert(name);
+        assert(nr > 0);
 
-                n = now(CLOCK_MONOTONIC);
-                assert(n >= start);
+        struct blkpg_partition bp = {
+                .pno = nr,
+                .start = start,
+                .length = size,
+        };
 
-                /* Find next deadline, when we'll retrigger */
-                local_deadline = start +
-                        DIV_ROUND_UP(n - start, retrigger_timeout) * retrigger_timeout;
+        struct blkpg_ioctl_arg ba = {
+                .op = BLKPG_ADD_PARTITION,
+                .data = &bp,
+                .datalen = sizeof(bp),
+        };
 
-                if (deadline != USEC_INFINITY && deadline <= local_deadline) {
-                        local_deadline = deadline;
-                        last_try = true;
-                } else
-                        last_try = false;
+        if (strlen(name) >= sizeof(bp.devname))
+                return -EINVAL;
 
-                r = device_wait_for_initialization(device, subsystem, local_deadline, ret);
-                if (r >= 0 && DEBUG_LOGGING) {
-                        const char *sn = NULL;
+        strcpy(bp.devname, name);
 
-                        (void) sd_device_get_sysname(device, &sn);
-                        log_device_debug(device,
-                                         "Successfully waited for device '%s' to initialize for %s.",
-                                         strna(sn),
-                                         FORMAT_TIMESPAN(usec_sub_unsigned(now(CLOCK_MONOTONIC), start), 0));
+        return RET_NERRNO(ioctl(fd, BLKPG, &ba));
+}
 
-                }
-                if (r != -ETIMEDOUT || last_try)
-                        return r;
+static int make_partition_devname(
+                const char *whole_devname,
+                int nr,
+                char **ret) {
 
-                if (DEBUG_LOGGING)
-                        log_device_debug(device,
-                                         "Device didn't initialize within %s, assuming lost event. Retriggering device.",
-                                         FORMAT_TIMESPAN(usec_sub_unsigned(now(CLOCK_MONOTONIC), start), 0));
+        bool need_p;
 
-                r = sd_device_trigger(device, SD_DEVICE_CHANGE);
-                if (r < 0)
-                        return r;
-        }
-}
-#endif
+        assert(whole_devname);
+        assert(nr > 0);
 
-#define DEVICE_TIMEOUT_USEC (45 * USEC_PER_SEC)
+        /* Given a whole block device node name (e.g. /dev/sda or /dev/loop7) generate a partition device
+         * name (e.g. /dev/sda7 or /dev/loop7p5). The rule the kernel uses is simple: if whole block device
+         * node name ends in a digit, then suffix a 'p', followed by the partition number. Otherwise, just
+         * suffix the partition number without any 'p'. */
 
-static void dissected_partition_done(DissectedPartition *p) {
-        assert(p);
+        if (isempty(whole_devname)) /* Make sure there *is* a last char */
+                return -EINVAL;
 
-        free(p->fstype);
-        free(p->node);
-        free(p->label);
-        free(p->decrypted_fstype);
-        free(p->decrypted_node);
-        free(p->mount_options);
+        need_p = strchr(DIGITS, whole_devname[strlen(whole_devname)-1]); /* Last char a digit? */
 
-        *p = (DissectedPartition) {
-                .partno = -1,
-                .architecture = _ARCHITECTURE_INVALID,
-        };
+        return asprintf(ret, "%s%s%i", whole_devname, need_p ? "p" : "", nr);
 }
+#endif
 
 int dissect_image(
                 int fd,
@@ -638,11 +243,10 @@ int dissect_image(
         _cleanup_(blkid_free_probep) blkid_probe b = NULL;
         _cleanup_free_ char *generic_node = NULL;
         sd_id128_t generic_uuid = SD_ID128_NULL;
-        const char *pttype = NULL, *sysname = NULL;
+        const char *pttype = NULL, *sysname = NULL, *devname = NULL;
         blkid_partlist pl;
         int r, generic_nr = -1, n_partitions;
         struct stat st;
-        usec_t deadline;
 
         assert(fd >= 0);
         assert(ret);
@@ -698,23 +302,6 @@ int dissect_image(
         if (r < 0)
                 return r;
 
-        if (!FLAGS_SET(flags, DISSECT_IMAGE_NO_UDEV)) {
-                _cleanup_(sd_device_unrefp) sd_device *initialized = NULL;
-
-                /* If udev support is enabled, then let's wait for the device to be initialized before we doing anything. */
-
-                r = device_wait_for_initialization_harder(
-                                d,
-                                "block",
-                                usec_add(now(CLOCK_MONOTONIC), DEVICE_TIMEOUT_USEC),
-                                &initialized);
-                if (r < 0)
-                        return r;
-
-                sd_device_unref(d);
-                d = TAKE_PTR(initialized);
-        }
-
         b = blkid_new_probe();
         if (!b)
                 return -ENOMEM;
@@ -770,6 +357,9 @@ int dissect_image(
                 if (r < 0)
                         return r;
         }
+        r = sd_device_get_devname(d, &devname);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to get device devname: %m");
 
         if (!image_name_is_valid(m->image_name)) {
                 log_debug("Image name %s is not valid, ignoring", strempty(m->image_name));
@@ -785,8 +375,8 @@ int dissect_image(
 
                 (void) blkid_probe_lookup_value(b, "USAGE", &usage, NULL);
                 if (STRPTR_IN_SET(usage, "filesystem", "crypto")) {
-                        const char *fstype = NULL, *options = NULL, *devname = NULL;
                         _cleanup_free_ char *t = NULL, *n = NULL, *o = NULL;
+                        const char *fstype = NULL, *options = NULL;
 
                         /* OK, we have found a file system, that's our root partition then. */
                         (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
@@ -797,10 +387,6 @@ int dissect_image(
                                         return -ENOMEM;
                         }
 
-                        r = sd_device_get_devname(d, &devname);
-                        if (r < 0)
-                                return r;
-
                         n = strdup(devname);
                         if (!n)
                                 return -ENOMEM;
@@ -873,13 +459,11 @@ int dissect_image(
         if (n_partitions < 0)
                 return errno_or_else(EIO);
 
-        deadline = usec_add(now(CLOCK_MONOTONIC), DEVICE_TIMEOUT_USEC);
         for (int i = 0; i < n_partitions; i++) {
-                _cleanup_(sd_device_unrefp) sd_device *q = NULL;
+                _cleanup_free_ char *node = NULL;
                 unsigned long long pflags;
                 blkid_loff_t start, size;
                 blkid_partition pp;
-                const char *node;
                 int nr;
 
                 errno = 0;
@@ -887,14 +471,6 @@ int dissect_image(
                 if (!pp)
                         return errno_or_else(EIO);
 
-                r = wait_for_partition_device(d, pp, deadline, diskseq, uevent_seqnum_not_before, timestamp_not_before, flags, &q);
-                if (r < 0)
-                        return r;
-
-                r = sd_device_get_devname(q, &node);
-                if (r < 0)
-                        return r;
-
                 pflags = blkid_partition_get_flags(pp);
 
                 errno = 0;
@@ -916,6 +492,31 @@ int dissect_image(
 
                 assert((uint64_t) size < UINT64_MAX/512);
 
+                r = make_partition_devname(devname, nr, &node);
+                if (r < 0)
+                        return r;
+
+                /* So here's the thing: after the main ("whole") block device popped up it might take a while
+                 * before the kernel fully probed the partition table. Waiting for that to finish is icky in
+                 * userspace. So here's what we do instead. We issue the BLKPG_ADD_PARTITION ioctl to add the
+                 * partition ourselves, racing against the kernel. Good thing is: if this call fails with
+                 * EBUSY then the kernel was quicker than us, and that's totally OK, the outcome is good for
+                 * us: the device node will exist. If OTOH our call was successful we won the race. Which is
+                 * also good as the outcome is the same: the partition block device exists, and we can use
+                 * it.
+                 *
+                 * Kernel returns EBUSY if there's already a partition by that number or an overlapping
+                 * partition already existent. */
+
+                r = ioctl_partition_add(fd, node, nr, (uint64_t) start * 512, (uint64_t) size * 512);
+                if (r < 0) {
+                        if (r != -EBUSY)
+                                return log_debug_errno(r, "BLKPG_ADD_PARTITION failed: %m");
+
+                        log_debug_errno(r, "Kernel was quicker than us in adding partition %i.", nr);
+                } else
+                        log_debug("We were quicker than kernel in adding partition %i.", nr);
+
                 if (is_gpt) {
                         PartitionDesignator designator = _PARTITION_DESIGNATOR_INVALID;
                         Architecture architecture = _ARCHITECTURE_INVALID;
@@ -1447,7 +1048,7 @@ int dissect_image(
             (flags & DISSECT_IMAGE_GENERIC_ROOT) &&
             (!verity || !verity->root_hash || verity->designator != PARTITION_USR)) {
 
-                /* OK, we found nothing usable, then check if there's a single generic one distro, and use
+                /* OK, we found nothing usable, then check if there's a single generic partition, and use
                  * that. If the root hash was set however, then we won't fall back to a generic node, because
                  * the root hash decides. */
 
@@ -3379,6 +2980,11 @@ int mount_image_privately_interactively(
         if (r < 0)
                 return log_error_errno(r, "Failed to set up loopback device for %s: %m", image);
 
+        /* Make sure udevd doesn't issue BLKRRPART behind our backs */
+        r = loop_device_flock(d, LOCK_SH);
+        if (r < 0)
+                return r;
+
         r = dissect_image_and_warn(d->fd, image, &verity, NULL, d->diskseq, d->uevent_seqnum_not_before, d->timestamp_not_before, flags, &dissected_image);
         if (r < 0)
                 return r;
@@ -3405,6 +3011,10 @@ int mount_image_privately_interactively(
         if (r < 0)
                 return r;
 
+        r = loop_device_flock(d, LOCK_UN);
+        if (r < 0)
+                return r;
+
         if (decrypted_image) {
                 r = decrypted_image_relinquish(decrypted_image);
                 if (r < 0)
@@ -3485,6 +3095,10 @@ int verity_dissect_and_mount(
         if (r < 0)
                 return log_debug_errno(r, "Failed to create loop device for image: %m");
 
+        r = loop_device_flock(loop_device, LOCK_SH);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to lock loop device: %m");
+
         r = dissect_image(
                         loop_device->fd,
                         &verity,
@@ -3532,6 +3146,10 @@ int verity_dissect_and_mount(
         if (r < 0)
                 return log_debug_errno(r, "Failed to mount image: %m");
 
+        r = loop_device_flock(loop_device, LOCK_UN);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to unlock loopback device: %m");
+
         /* If we got os-release values from the caller, then we need to match them with the image's
          * extension-release.d/ content. Return -EINVAL if there's any mismatch.
          * First, check the distro ID. If that matches, then check the new SYSEXT_LEVEL value if
index 1bc8d2ef9a3eb069212c494f5d3c37baf12851b4..55bb8a1dadc27ccc61370774a051476078881617 100644 (file)
@@ -188,19 +188,18 @@ typedef enum DissectImageFlags {
         DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY = 1 << 7,  /* Mount only the non-root and non-/usr partitions */
         DISSECT_IMAGE_VALIDATE_OS         = 1 << 8,  /* Refuse mounting images that aren't identifiable as OS images */
         DISSECT_IMAGE_VALIDATE_OS_EXT     = 1 << 9,  /* Refuse mounting images that aren't identifiable as OS extension images */
-        DISSECT_IMAGE_NO_UDEV             = 1 << 10, /* Don't wait for udev initializing things */
-        DISSECT_IMAGE_RELAX_VAR_CHECK     = 1 << 11, /* Don't insist that the UUID of /var is hashed from /etc/machine-id */
-        DISSECT_IMAGE_FSCK                = 1 << 12, /* File system check the partition before mounting (no effect when combined with DISSECT_IMAGE_READ_ONLY) */
-        DISSECT_IMAGE_NO_PARTITION_TABLE  = 1 << 13, /* Only recognize single file system images */
-        DISSECT_IMAGE_VERITY_SHARE        = 1 << 14, /* When activating a verity device, reuse existing one if already open */
-        DISSECT_IMAGE_MKDIR               = 1 << 15, /* Make top-level directory to mount right before mounting, if missing */
-        DISSECT_IMAGE_USR_NO_ROOT         = 1 << 16, /* If no root fs is in the image, but /usr is, then allow this (so that we can mount the rootfs as tmpfs or so */
-        DISSECT_IMAGE_REQUIRE_ROOT        = 1 << 17, /* Don't accept disks without root partition (or at least /usr partition if DISSECT_IMAGE_USR_NO_ROOT is set) */
-        DISSECT_IMAGE_MOUNT_READ_ONLY     = 1 << 18, /* Make mounts read-only */
+        DISSECT_IMAGE_RELAX_VAR_CHECK     = 1 << 10, /* Don't insist that the UUID of /var is hashed from /etc/machine-id */
+        DISSECT_IMAGE_FSCK                = 1 << 11, /* File system check the partition before mounting (no effect when combined with DISSECT_IMAGE_READ_ONLY) */
+        DISSECT_IMAGE_NO_PARTITION_TABLE  = 1 << 12, /* Only recognize single file system images */
+        DISSECT_IMAGE_VERITY_SHARE        = 1 << 13, /* When activating a verity device, reuse existing one if already open */
+        DISSECT_IMAGE_MKDIR               = 1 << 14, /* Make top-level directory to mount right before mounting, if missing */
+        DISSECT_IMAGE_USR_NO_ROOT         = 1 << 15, /* If no root fs is in the image, but /usr is, then allow this (so that we can mount the rootfs as tmpfs or so */
+        DISSECT_IMAGE_REQUIRE_ROOT        = 1 << 16, /* Don't accept disks without root partition (or at least /usr partition if DISSECT_IMAGE_USR_NO_ROOT is set) */
+        DISSECT_IMAGE_MOUNT_READ_ONLY     = 1 << 17, /* Make mounts read-only */
         DISSECT_IMAGE_READ_ONLY           = DISSECT_IMAGE_DEVICE_READ_ONLY |
                                             DISSECT_IMAGE_MOUNT_READ_ONLY,
-        DISSECT_IMAGE_GROWFS              = 1 << 19, /* Grow file systems in partitions marked for that to the size of the partitions after mount */
-        DISSECT_IMAGE_MOUNT_IDMAPPED      = 1 << 20, /* Mount mounts with kernel 5.12-style userns ID mapping, if file system type doesn't support uid=/gid= */
+        DISSECT_IMAGE_GROWFS              = 1 << 18, /* Grow file systems in partitions marked for that to the size of the partitions after mount */
+        DISSECT_IMAGE_MOUNT_IDMAPPED      = 1 << 19, /* Mount mounts with kernel 5.12-style userns ID mapping, if file system type doesn't support uid=/gid= */
 } DissectImageFlags;
 
 struct DissectedImage {
index fca24329d4dcbdf93c812fc093072a540f3708c3..75e639dd99f5cf1693ed1997eeb1d633a4aa13a8 100644 (file)
@@ -1,11 +1,13 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <linux/magic.h>
+#include <sys/vfs.h>
 
 #include "sd-device.h"
 
 #include "alloc-util.h"
 #include "blkid-util.h"
+#include "devnum-util.h"
 #include "env-util.h"
 #include "errno-util.h"
 #include "find-esp.h"
index 39a9a766c010c52d240deaffec0d8996a799542b..530688fc97f0255eddc942b77e8793f4a4190142 100644 (file)
@@ -18,6 +18,7 @@
 #include "alloc-util.h"
 #include "blockdev-util.h"
 #include "device-util.h"
+#include "devnum-util.h"
 #include "env-util.h"
 #include "errno-util.h"
 #include "fd-util.h"
@@ -876,7 +877,7 @@ static int resize_partition(int partition_fd, uint64_t offset, uint64_t size) {
         r = read_one_line_file(sysfs, &buffer);
         if (r < 0)
                 return r;
-        r = parse_dev(buffer, &devno);
+        r = parse_devnum(buffer, &devno);
         if (r < 0)
                 return r;
 
index 4333c9a0a90b5f6f0c662e9e5079cff5063a5b52..1d4e4a07c04a53039f45b265281e469165838461 100644 (file)
@@ -245,8 +245,8 @@ shared_sources = files(
         'pager.h',
         'parse-argument.c',
         'parse-argument.h',
-        'parse-socket-bind-item.c',
-        'parse-socket-bind-item.h',
+        'parse-helpers.c',
+        'parse-helpers.h',
         'pcre2-dlopen.c',
         'pcre2-dlopen.h',
         'pe-header.h',
similarity index 66%
rename from src/shared/parse-socket-bind-item.c
rename to src/shared/parse-helpers.c
index 3c924676321ceb92352f931ad57f9390e8f79f84..a9bb58715edcc33442812c02cd961347ff7a5cc5 100644 (file)
@@ -3,8 +3,57 @@
 #include "af-list.h"
 #include "extract-word.h"
 #include "ip-protocol-list.h"
-#include "parse-socket-bind-item.h"
+#include "log.h"
+#include "parse-helpers.h"
 #include "parse-util.h"
+#include "path-util.h"
+#include "utf8.h"
+
+int path_simplify_and_warn(
+                char *path,
+                unsigned flag,
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *lvalue) {
+
+        bool fatal = flag & PATH_CHECK_FATAL;
+
+        assert(!FLAGS_SET(flag, PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE));
+
+        if (!utf8_is_valid(path))
+                return log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, path);
+
+        if (flag & (PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE)) {
+                bool absolute;
+
+                absolute = path_is_absolute(path);
+
+                if (!absolute && (flag & PATH_CHECK_ABSOLUTE))
+                        return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
+                                          "%s= path is not absolute%s: %s",
+                                          lvalue, fatal ? "" : ", ignoring", path);
+
+                if (absolute && (flag & PATH_CHECK_RELATIVE))
+                        return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
+                                          "%s= path is absolute%s: %s",
+                                          lvalue, fatal ? "" : ", ignoring", path);
+        }
+
+        path_simplify(path);
+
+        if (!path_is_valid(path))
+                return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
+                                  "%s= path has invalid length (%zu bytes)%s.",
+                                  lvalue, strlen(path), fatal ? "" : ", ignoring");
+
+        if (!path_is_normalized(path))
+                return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
+                                  "%s= path is not normalized%s: %s",
+                                  lvalue, fatal ? "" : ", ignoring", path);
+
+        return 0;
+}
 
 static int parse_af_token(
                 const char *token,
diff --git a/src/shared/parse-helpers.h b/src/shared/parse-helpers.h
new file mode 100644 (file)
index 0000000..49da281
--- /dev/null
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <stdint.h>
+
+enum {
+        PATH_CHECK_FATAL    = 1 << 0,  /* If not set, then error message is appended with 'ignoring'. */
+        PATH_CHECK_ABSOLUTE = 1 << 1,
+        PATH_CHECK_RELATIVE = 1 << 2,
+};
+
+int path_simplify_and_warn(
+                char *path,
+                unsigned flag,
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *lvalue);
+
+int parse_socket_bind_item(
+        const char *str,
+        int *address_family,
+        int *ip_protocol,
+        uint16_t *nr_ports,
+        uint16_t *port_min);
diff --git a/src/shared/parse-socket-bind-item.h b/src/shared/parse-socket-bind-item.h
deleted file mode 100644 (file)
index c8cff8d..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#pragma once
-
-#include <stdint.h>
-
-int parse_socket_bind_item(
-        const char *str,
-        int *address_family,
-        int *ip_protocol,
-        uint16_t *nr_ports,
-        uint16_t *port_min);
index fbf8ee50644cf91b2b23fec18fa6ff2248eb5f25..7aacad12048279335a9ef53a4fd4f3ad92c2af26 100644 (file)
@@ -1,20 +1,21 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <sys/quota.h>
+#include <sys/stat.h>
 
 #include "alloc-util.h"
 #include "blockdev-util.h"
+#include "devnum-util.h"
 #include "quota-util.h"
-#include "stat-util.h"
 
-int quotactl_devno(int cmd, dev_t devno, int id, void *addr) {
+int quotactl_devnum(int cmd, dev_t devnum, int id, void *addr) {
         _cleanup_free_ char *devnode = NULL;
         int r;
 
         /* Like quotactl() but takes a dev_t instead of a path to a device node, and fixes caddr_t → void*,
          * like we should, today */
 
-        r = device_path_make_major_minor(S_IFBLK, devno, &devnode);
+        r = device_path_make_major_minor(S_IFBLK, devnum, &devnode);
         if (r < 0)
                 return r;
 
@@ -37,5 +38,5 @@ int quotactl_path(int cmd, const char *path, int id, void *addr) {
         if (devno == 0) /* Doesn't have a block device */
                 return -ENODEV;
 
-        return quotactl_devno(cmd, devno, id, addr);
+        return quotactl_devnum(cmd, devno, id, addr);
 }
index a61bdcbae60ebffdd37714bf1dffcf84cbac99c1..fc395221ae68e448b4bfbe0303d0d1251adf7012 100644 (file)
@@ -15,5 +15,5 @@ static inline int QCMD_FIXED(uint32_t cmd, uint32_t type) {
         return (int) QCMD(cmd, type);
 }
 
-int quotactl_devno(int cmd, dev_t devno, int id, void *addr);
+int quotactl_devnum(int cmd, dev_t devnum, int id, void *addr);
 int quotactl_path(int cmd, const char *path, int id, void *addr);
index 8ec3d09a58314428a7e4531ae6e2d65613ae4772..a56f2ff618271cb3f6a507c6861553cb60792ef0 100644 (file)
 #include "btrfs-util.h"
 #include "conf-parser.h"
 #include "def.h"
+#include "devnum-util.h"
 #include "env-util.h"
 #include "errno-util.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "log.h"
 #include "macro.h"
-#include "parse-util.h"
 #include "path-util.h"
 #include "sleep-config.h"
 #include "stat-util.h"
@@ -274,7 +274,7 @@ static int read_resume_files(dev_t *ret_resume, uint64_t *ret_resume_offset) {
         if (r < 0)
                 return log_debug_errno(r, "Error reading /sys/power/resume: %m");
 
-        r = parse_dev(resume_str, &resume);
+        r = parse_devnum(resume_str, &resume);
         if (r < 0)
                 return log_debug_errno(r, "Error parsing /sys/power/resume device: %s: %m", resume_str);
 
index 16eb8830dc4865a34ba04015dab8ded2af993ec1..0742fae39ed67d46226e12a80654d0ffcd571d72 100644 (file)
@@ -199,7 +199,7 @@ int specifier_boot_id(char specifier, const void *data, const char *root, const
         return 0;
 }
 
-int specifier_host_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
+int specifier_hostname(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
         char *n;
 
         assert(ret);
@@ -212,7 +212,7 @@ int specifier_host_name(char specifier, const void *data, const char *root, cons
         return 0;
 }
 
-int specifier_short_host_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
+int specifier_short_hostname(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
         char *n;
 
         assert(ret);
@@ -225,7 +225,7 @@ int specifier_short_host_name(char specifier, const void *data, const char *root
         return 0;
 }
 
-int specifier_pretty_host_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
+int specifier_pretty_hostname(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
         char *n = NULL;
 
         assert(ret);
@@ -276,12 +276,18 @@ int specifier_architecture(char specifier, const void *data, const char *root, c
  * installation. */
 
 static int parse_os_release_specifier(const char *root, const char *id, char **ret) {
+        char *v = NULL;
         int r;
 
         assert(ret);
 
+        r = parse_os_release(root, id, &v);
+        if (r >= 0)
+                /* parse_os_release() calls parse_env_file() which only sets the return value for
+                 * entries found. Let's make sure we set the return value in all cases. */
+                *ret = v;
+
         /* Translate error for missing os-release file to EUNATCH. */
-        r = parse_os_release(root, id, ret);
         return r == -ENOENT ? -EUNATCH : r;
 }
 
index 78b10f846717258e77b01d1f5e1ac128a3a3a92d..abde3d9ad2b3738b741015c8d845513e08cf14a2 100644 (file)
@@ -19,9 +19,9 @@ int specifier_real_directory(char specifier, const void *data, const char *root,
 
 int specifier_machine_id(char specifier, const void *data, const char *root, const void *userdata, char **ret);
 int specifier_boot_id(char specifier, const void *data, const char *root, const void *userdata, char **ret);
-int specifier_host_name(char specifier, const void *data, const char *root, const void *userdata, char **ret);
-int specifier_short_host_name(char specifier, const void *data, const char *root, const void *userdata, char **ret);
-int specifier_pretty_host_name(char specifier, const void *data, const char *root, const void *userdata, char **ret);
+int specifier_hostname(char specifier, const void *data, const char *root, const void *userdata, char **ret);
+int specifier_short_hostname(char specifier, const void *data, const char *root, const void *userdata, char **ret);
+int specifier_pretty_hostname(char specifier, const void *data, const char *root, const void *userdata, char **ret);
 int specifier_kernel_release(char specifier, const void *data, const char *root, const void *userdata, char **ret);
 int specifier_architecture(char specifier, const void *data, const char *root, const void *userdata, char **ret);
 int specifier_os_id(char specifier, const void *data, const char *root, const void *userdata, char **ret);
@@ -51,6 +51,7 @@ int specifier_var_tmp_dir(char specifier, const void *data, const char *root, co
  * %B: the OS build ID, according to /etc/os-release
  * %H: the hostname of the running system
  * %l: the short hostname of the running system
+ * %q: the 'pretty' hostname as per /etc/machine-info
  * %m: the machine ID of the running system
  * %M: the OS image ID, according to /etc/os-release
  * %o: the OS ID according to /etc/os-release
@@ -69,30 +70,30 @@ int specifier_var_tmp_dir(char specifier, const void *data, const char *root, co
  * %V: the temporary directory for large, persistent stuff (e.g. /var/tmp, or $TMPDIR, $TEMP, $TMP)
  */
 
-#define COMMON_SYSTEM_SPECIFIERS                  \
-        { 'a', specifier_architecture,    NULL }, \
-        { 'A', specifier_os_image_version,NULL }, \
-        { 'b', specifier_boot_id,         NULL }, \
-        { 'B', specifier_os_build_id,     NULL }, \
-        { 'H', specifier_host_name,       NULL }, \
-        { 'l', specifier_short_host_name, NULL }, \
-        { 'R', specifier_pretty_host_name,NULL }, \
-        { 'm', specifier_machine_id,      NULL }, \
-        { 'M', specifier_os_image_id,     NULL }, \
-        { 'o', specifier_os_id,           NULL }, \
-        { 'v', specifier_kernel_release,  NULL }, \
-        { 'w', specifier_os_version_id,   NULL }, \
-        { 'W', specifier_os_variant_id,   NULL }
+#define COMMON_SYSTEM_SPECIFIERS                   \
+        { 'a', specifier_architecture,     NULL }, \
+        { 'A', specifier_os_image_version, NULL }, \
+        { 'b', specifier_boot_id,          NULL }, \
+        { 'B', specifier_os_build_id,      NULL }, \
+        { 'H', specifier_hostname,         NULL }, \
+        { 'l', specifier_short_hostname,   NULL }, \
+        { 'q', specifier_pretty_hostname,  NULL }, \
+        { 'm', specifier_machine_id,       NULL }, \
+        { 'M', specifier_os_image_id,      NULL }, \
+        { 'o', specifier_os_id,            NULL }, \
+        { 'v', specifier_kernel_release,   NULL }, \
+        { 'w', specifier_os_version_id,    NULL }, \
+        { 'W', specifier_os_variant_id,    NULL }
 
-#define COMMON_CREDS_SPECIFIERS(scope)                          \
-        { 'g', specifier_group_name,      INT_TO_PTR(scope) },  \
-        { 'G', specifier_group_id,        INT_TO_PTR(scope) },  \
-        { 'u', specifier_user_name,       INT_TO_PTR(scope) },  \
-        { 'U', specifier_user_id,         INT_TO_PTR(scope) }
+#define COMMON_CREDS_SPECIFIERS(scope)                           \
+        { 'g', specifier_group_name,       INT_TO_PTR(scope) },  \
+        { 'G', specifier_group_id,         INT_TO_PTR(scope) },  \
+        { 'u', specifier_user_name,        INT_TO_PTR(scope) },  \
+        { 'U', specifier_user_id,          INT_TO_PTR(scope) }
 
-#define COMMON_TMP_SPECIFIERS                     \
-        { 'T', specifier_tmp_dir,         NULL }, \
-        { 'V', specifier_var_tmp_dir,     NULL }
+#define COMMON_TMP_SPECIFIERS                      \
+        { 'T', specifier_tmp_dir,          NULL }, \
+        { 'V', specifier_var_tmp_dir,      NULL }
 
 static inline char* specifier_escape(const char *string) {
         return strreplace(string, "%", "%%");
index 6d4df0afd27f75495716f638794317b2f3558ac6..20fbb916e9b48c22772f6f2fcf715f98b872fe30 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "capability-util.h"
 #include "chase-symlinks.h"
+#include "devnum-util.h"
 #include "discover-image.h"
 #include "dissect-image.h"
 #include "env-util.h"
@@ -31,7 +32,6 @@
 #include "pretty-print.h"
 #include "process-util.h"
 #include "sort-util.h"
-#include "stat-util.h"
 #include "terminal-util.h"
 #include "user-util.h"
 #include "verbs.h"
@@ -84,7 +84,7 @@ static int is_our_mount_point(const char *p) {
         if (r < 0)
                 return log_error_errno(r, "Failed to determine whether hierarchy '%s' contains '.systemd-sysext/dev': %m", p);
 
-        r = parse_dev(buf, &dev);
+        r = parse_devnum(buf, &dev);
         if (r < 0)
                 return log_error_errno(r, "Failed to parse device major/minor stored in '.systemd-sysext/dev' file on '%s': %m", p);
 
@@ -533,6 +533,10 @@ static int merge_subprocess(Hashmap *images, const char *workspace) {
                         if (r < 0)
                                 return log_error_errno(r, "Failed to set up loopback device for %s: %m", img->path);
 
+                        r = loop_device_flock(d, LOCK_SH);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to lock loopback device: %m");
+
                         r = dissect_image_and_warn(
                                         d->fd,
                                         img->path,
index 3df34cf7fb2db565709bd3266a9a306c1590ea08..edc524cc7596ae8593f0296a63e356cdcda45ab7 100644 (file)
@@ -7,6 +7,7 @@
 #include "alloc-util.h"
 #include "blockdev-util.h"
 #include "chase-symlinks.h"
+#include "devnum-util.h"
 #include "dirent-util.h"
 #include "env-util.h"
 #include "fd-util.h"
@@ -18,7 +19,6 @@
 #include "macro.h"
 #include "process-util.h"
 #include "sort-util.h"
-#include "stat-util.h"
 #include "string-table.h"
 #include "sysupdate-cache.h"
 #include "sysupdate-instance.h"
index a9fceed601197ad486bac9c390dd6509b8a2f4ff..e5bbbadc162f68fd7b793d237b9c5c9cb018c7d1 100644 (file)
@@ -12,8 +12,8 @@
 #include "gpt.h"
 #include "hexdecoct.h"
 #include "install-file.h"
+#include "parse-helpers.h"
 #include "parse-util.h"
-#include "path-util.h"
 #include "process-util.h"
 #include "rm-rf.h"
 #include "specifier.h"
index 11517c990b5f9d9efcdfdc5619bda3ba72f506f3..c47dd71d197cb81c5dc02141905c7ad21102569a 100644 (file)
@@ -244,6 +244,8 @@ tests += [
 
         [files('test-stat-util.c')],
 
+        [files('test-devnum-util.c')],
+
         [files('test-os-util.c')],
 
         [files('test-libcrypt-util.c'),
@@ -261,7 +263,7 @@ tests += [
 
         [files('test-parse-argument.c')],
 
-        [files('test-parse-socket-bind-item.c')],
+        [files('test-parse-helpers.c')],
 
         [files('test-parse-util.c')],
 
diff --git a/src/test/test-devnum-util.c b/src/test/test-devnum-util.c
new file mode 100644 (file)
index 0000000..66f4ac9
--- /dev/null
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <sys/stat.h>
+
+#include "devnum-util.h"
+#include "path-util.h"
+#include "stat-util.h"
+#include "tests.h"
+
+TEST(parse_devnum) {
+        dev_t dev;
+
+        assert_se(parse_devnum("", &dev) == -EINVAL);
+        assert_se(parse_devnum("junk", &dev) == -EINVAL);
+        assert_se(parse_devnum("0", &dev) == -EINVAL);
+        assert_se(parse_devnum("5", &dev) == -EINVAL);
+        assert_se(parse_devnum("5:", &dev) == -EINVAL);
+        assert_se(parse_devnum(":5", &dev) == -EINVAL);
+        assert_se(parse_devnum("-1:-1", &dev) == -EINVAL);
+#if SIZEOF_DEV_T < 8
+        assert_se(parse_devnum("4294967295:4294967295", &dev) == -EINVAL);
+#endif
+        assert_se(parse_devnum("8:11", &dev) >= 0 && major(dev) == 8 && minor(dev) == 11);
+        assert_se(parse_devnum("0:0", &dev) >= 0 && major(dev) == 0 && minor(dev) == 0);
+}
+
+TEST(device_major_minor_valid) {
+        /* on glibc dev_t is 64bit, even though in the kernel it is only 32bit */
+        assert_cc(sizeof(dev_t) == sizeof(uint64_t));
+
+        assert_se(DEVICE_MAJOR_VALID(0U));
+        assert_se(DEVICE_MINOR_VALID(0U));
+
+        assert_se(DEVICE_MAJOR_VALID(1U));
+        assert_se(DEVICE_MINOR_VALID(1U));
+
+        assert_se(!DEVICE_MAJOR_VALID(-1U));
+        assert_se(!DEVICE_MINOR_VALID(-1U));
+
+        assert_se(DEVICE_MAJOR_VALID(1U << 10));
+        assert_se(DEVICE_MINOR_VALID(1U << 10));
+
+        assert_se(DEVICE_MAJOR_VALID((1U << 12) - 1));
+        assert_se(DEVICE_MINOR_VALID((1U << 20) - 1));
+
+        assert_se(!DEVICE_MAJOR_VALID((1U << 12)));
+        assert_se(!DEVICE_MINOR_VALID((1U << 20)));
+
+        assert_se(!DEVICE_MAJOR_VALID(1U << 25));
+        assert_se(!DEVICE_MINOR_VALID(1U << 25));
+
+        assert_se(!DEVICE_MAJOR_VALID(UINT32_MAX));
+        assert_se(!DEVICE_MINOR_VALID(UINT32_MAX));
+
+        assert_se(!DEVICE_MAJOR_VALID(UINT64_MAX));
+        assert_se(!DEVICE_MINOR_VALID(UINT64_MAX));
+
+        assert_se(DEVICE_MAJOR_VALID(major(0)));
+        assert_se(DEVICE_MINOR_VALID(minor(0)));
+}
+
+static void test_device_path_make_canonical_one(const char *path) {
+        _cleanup_free_ char *resolved = NULL, *raw = NULL;
+        struct stat st;
+        dev_t devno;
+        mode_t mode;
+        int r;
+
+        log_debug("> %s", path);
+
+        if (stat(path, &st) < 0) {
+                assert_se(errno == ENOENT);
+                log_notice("Path %s not found, skipping test", path);
+                return;
+        }
+
+        r = device_path_make_canonical(st.st_mode, st.st_rdev, &resolved);
+        if (r == -ENOENT) {
+                /* maybe /dev/char/x:y and /dev/block/x:y are missing in this test environment, because we
+                 * run in a container or so? */
+                log_notice("Device %s cannot be resolved, skipping test", path);
+                return;
+        }
+
+        assert_se(r >= 0);
+        assert_se(path_equal(path, resolved));
+
+        assert_se(device_path_make_major_minor(st.st_mode, st.st_rdev, &raw) >= 0);
+        assert_se(device_path_parse_major_minor(raw, &mode, &devno) >= 0);
+
+        assert_se(st.st_rdev == devno);
+        assert_se((st.st_mode & S_IFMT) == (mode & S_IFMT));
+}
+
+TEST(device_path_make_canonical) {
+        test_device_path_make_canonical_one("/dev/null");
+        test_device_path_make_canonical_one("/dev/zero");
+        test_device_path_make_canonical_one("/dev/full");
+        test_device_path_make_canonical_one("/dev/random");
+        test_device_path_make_canonical_one("/dev/urandom");
+        test_device_path_make_canonical_one("/dev/tty");
+
+        if (is_device_node("/run/systemd/inaccessible/blk") > 0) {
+                test_device_path_make_canonical_one("/run/systemd/inaccessible/chr");
+                test_device_path_make_canonical_one("/run/systemd/inaccessible/blk");
+        }
+}
+
+static void test_devnum_format_str_one(dev_t devnum, const char *s) {
+        dev_t x;
+
+        assert_se(streq(FORMAT_DEVNUM(devnum), s));
+        assert_se(parse_devnum(s, &x) >= 0);
+        assert_se(x == devnum);
+}
+
+TEST(devnum_format_str) {
+        test_devnum_format_str_one(makedev(0, 0), "0:0");
+        test_devnum_format_str_one(makedev(1, 2), "1:2");
+        test_devnum_format_str_one(makedev(99, 100), "99:100");
+        test_devnum_format_str_one(makedev(4095, 1048575), "4095:1048575");
+}
+
+DEFINE_TEST_MAIN(LOG_INFO);
index 6ec3f7f00bdc0a73e248856ff4ceb0f7e959efff..e58e1638e7466f4cce5d3bb78a9979a64bf5914b 100644 (file)
@@ -92,6 +92,7 @@ TEST(dump_special_glyphs) {
         dump_glyph(SPECIAL_GLYPH_TREE_RIGHT);
         dump_glyph(SPECIAL_GLYPH_TREE_SPACE);
         dump_glyph(SPECIAL_GLYPH_TREE_TOP);
+        dump_glyph(SPECIAL_GLYPH_VERTICAL_DOTTED);
         dump_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET);
         dump_glyph(SPECIAL_GLYPH_BLACK_CIRCLE);
         dump_glyph(SPECIAL_GLYPH_WHITE_CIRCLE);
index 2f3c3745e2031fc9990304ea5ce29363e6b0cfe1..d1793222f0ee07f8e8b72d06f135a687a488ddab 100644 (file)
@@ -55,6 +55,9 @@ static void* thread_func(void *ptr) {
 
                 log_notice("Acquired loop device %s, will mount on %s", loop->node, mounted);
 
+                /* Let's make sure udev doesn't call BLKRRPART in the background, while we try to mount the device. */
+                assert_se(loop_device_flock(loop, LOCK_SH) >= 0);
+
                 r = dissect_image(loop->fd, NULL, NULL, loop->diskseq, loop->uevent_seqnum_not_before, loop->timestamp_not_before, DISSECT_IMAGE_READ_ONLY, &dissected);
                 if (r < 0)
                         log_error_errno(r, "Failed dissect loopback device %s: %m", loop->node);
@@ -85,6 +88,10 @@ static void* thread_func(void *ptr) {
                 log_notice_errno(r, "Mounted %s → %s: %m", loop->node, mounted);
                 assert_se(r >= 0);
 
+                /* Now the block device is mounted, we don't need no manual lock anymore, the devices are now
+                 * pinned by the mounts. */
+                assert_se(loop_device_flock(loop, LOCK_UN) >= 0);
+
                 log_notice("Unmounting %s", mounted);
                 mounted = umount_and_rmdir_and_free(mounted);
 
@@ -158,12 +165,6 @@ static int run(int argc, char *argv[]) {
                 return EXIT_TEST_SKIP;
         }
 
-        if (strstr_ptr(ci_environment(), "autopkgtest") || strstr_ptr(ci_environment(), "github-actions")) {
-                // FIXME: we should reenable this one day
-                log_tests_skipped("Skipping test on Ubuntu autopkgtest CI/GH Actions, test too slow and installed udev too flakey.");
-                return EXIT_TEST_SKIP;
-        }
-
         /* This is a test for the loopback block device setup code and it's use by the image dissection
          * logic: since the kernel APIs are hard use and prone to races, let's test this in a heavy duty
          * test: we open a bunch of threads and repeatedly allocate and deallocate loopback block devices in
@@ -221,6 +222,11 @@ static int run(int argc, char *argv[]) {
         pthread_t threads[arg_n_threads];
         sd_id128_t id;
 
+        /* Take an explicit lock while we format the file systems, in accordance with
+         * https://systemd.io/BLOCK_DEVICE_LOCKING/. We don't want udev to interfere and probe while we write
+         * or even issue BLKRRPART or similar while we are working on this. */
+        assert_se(loop_device_flock(loop, LOCK_EX) >= 0);
+
         assert_se(dissect_image(loop->fd, NULL, NULL, loop->diskseq, loop->uevent_seqnum_not_before, loop->timestamp_not_before, 0, &dissected) >= 0);
 
         assert_se(dissected->partitions[PARTITION_ESP].found);
@@ -249,9 +255,21 @@ static int run(int argc, char *argv[]) {
 
         assert_se(mkdtemp_malloc(NULL, &mounted) >= 0);
 
+        /* We are particularly correct here, and now downgrade LOCK → LOCK_SH. That's because we are done
+         * with formatting the file systems, so we don't need the exclusive lock anymore. From now on a
+         * shared one is fine. This way udev can now probe the device if it wants, but still won't call
+         * BLKRRPART on it, and that's good, because that would destroy our partition table while we are at
+         * it. */
+        assert_se(loop_device_flock(loop, LOCK_SH) >= 0);
+
         /* This first (writable) mount will initialize the mount point dirs, so that the subsequent read-only ones can work */
         assert_se(dissected_image_mount(dissected, mounted, UID_INVALID, UID_INVALID, 0) >= 0);
 
+        /* Now we mounted everything, the partitions are pinned. Now it's fine to release the lock
+         * fully. This means udev could now issue BLKRRPART again, but that's OK given this will fail because
+         * we now mounted the device. */
+        assert_se(loop_device_flock(loop, LOCK_UN) >= 0);
+
         assert_se(umount_recursive(mounted, 0) >= 0);
         loop = loop_device_unref(loop);
 
similarity index 99%
rename from src/test/test-parse-socket-bind-item.c
rename to src/test/test-parse-helpers.c
index 6bca27265c0724c7e777fb0782dc5ee82f7e2fc1..052e2514f43849374fa4b13df21a40a65137a94b 100644 (file)
@@ -5,7 +5,7 @@
 #include <stdio.h>
 
 #include "macro.h"
-#include "parse-socket-bind-item.h"
+#include "parse-helpers.h"
 #include "tests.h"
 
 static void test_valid_item(
index daa547c793b9d510a7a096b5fe549bfc4c2ddd34..388d0fe3f7ef7c120289e8c4c02ed80432ef716e 100644 (file)
@@ -812,23 +812,6 @@ TEST(parse_nice) {
         assert_se(parse_nice("+20", &n) == -ERANGE);
 }
 
-TEST(parse_dev) {
-        dev_t dev;
-
-        assert_se(parse_dev("", &dev) == -EINVAL);
-        assert_se(parse_dev("junk", &dev) == -EINVAL);
-        assert_se(parse_dev("0", &dev) == -EINVAL);
-        assert_se(parse_dev("5", &dev) == -EINVAL);
-        assert_se(parse_dev("5:", &dev) == -EINVAL);
-        assert_se(parse_dev(":5", &dev) == -EINVAL);
-        assert_se(parse_dev("-1:-1", &dev) == -EINVAL);
-#if SIZEOF_DEV_T < 8
-        assert_se(parse_dev("4294967295:4294967295", &dev) == -EINVAL);
-#endif
-        assert_se(parse_dev("8:11", &dev) >= 0 && major(dev) == 8 && minor(dev) == 11);
-        assert_se(parse_dev("0:0", &dev) >= 0 && major(dev) == 0 && minor(dev) == 0);
-}
-
 TEST(parse_errno) {
         assert_se(parse_errno("EILSEQ") == EILSEQ);
         assert_se(parse_errno("EINVAL") == EINVAL);
index d40febef5f726ad0eab083601bdc28cf91454f5e..4c56a7d52008a7b0f29bb7d7b9b808ae9a4534b2 100644 (file)
@@ -960,21 +960,6 @@ TEST(hidden_or_backup_file) {
         assert_se(!hidden_or_backup_file("test.dpkg-old.foo"));
 }
 
-TEST(systemd_installation_has_version) {
-        int r;
-        const unsigned versions[] = {0, 231, PROJECT_VERSION, 999};
-        unsigned i;
-
-        log_info("/* %s */", __func__);
-
-        for (i = 0; i < ELEMENTSOF(versions); i++) {
-                r = systemd_installation_has_version(saved_argv[1], versions[i]);
-                assert_se(r >= 0);
-                log_info("%s has systemd >= %u: %s",
-                         saved_argv[1] ?: "Current installation", versions[i], yes_no(r));
-        }
-}
-
 TEST(skip_dev_prefix) {
         assert_se(streq(skip_dev_prefix("/"), "/"));
         assert_se(streq(skip_dev_prefix("/dev"), ""));
index 49b4f5a2a33e2a6d50877e985ef5d320591171ad..516502032a78dc0e58499a7b34fe3ab7b8d1d600 100644 (file)
@@ -74,7 +74,7 @@ TEST(specifier_printf) {
         assert_se(streq(w, "xxx a=AAAA b=BBBB e= yyy"));
 
         free(w);
-        r = specifier_printf("machine=%m, boot=%b, host=%H, pretty=%R, version=%v, arch=%a, empty=%e", SIZE_MAX, table, NULL, NULL, &w);
+        r = specifier_printf("machine=%m, boot=%b, host=%H, pretty=%q, version=%v, arch=%a, empty=%e", SIZE_MAX, table, NULL, NULL, &w);
         assert_se(r >= 0);
         assert_se(w);
         puts(w);
index 9975a1848d254f1c4efbe11b95e84b00a38f0c7d..c5afde02d0c642df504699fb75ee03eb4d5a205a 100644 (file)
@@ -149,88 +149,6 @@ TEST(fd_is_ns) {
         assert_se(IN_SET(fd_is_ns(fd, CLONE_NEWNET), 1, -EUCLEAN));
 }
 
-TEST(device_major_minor_valid) {
-        /* on glibc dev_t is 64bit, even though in the kernel it is only 32bit */
-        assert_cc(sizeof(dev_t) == sizeof(uint64_t));
-
-        assert_se(DEVICE_MAJOR_VALID(0U));
-        assert_se(DEVICE_MINOR_VALID(0U));
-
-        assert_se(DEVICE_MAJOR_VALID(1U));
-        assert_se(DEVICE_MINOR_VALID(1U));
-
-        assert_se(!DEVICE_MAJOR_VALID(-1U));
-        assert_se(!DEVICE_MINOR_VALID(-1U));
-
-        assert_se(DEVICE_MAJOR_VALID(1U << 10));
-        assert_se(DEVICE_MINOR_VALID(1U << 10));
-
-        assert_se(DEVICE_MAJOR_VALID((1U << 12) - 1));
-        assert_se(DEVICE_MINOR_VALID((1U << 20) - 1));
-
-        assert_se(!DEVICE_MAJOR_VALID((1U << 12)));
-        assert_se(!DEVICE_MINOR_VALID((1U << 20)));
-
-        assert_se(!DEVICE_MAJOR_VALID(1U << 25));
-        assert_se(!DEVICE_MINOR_VALID(1U << 25));
-
-        assert_se(!DEVICE_MAJOR_VALID(UINT32_MAX));
-        assert_se(!DEVICE_MINOR_VALID(UINT32_MAX));
-
-        assert_se(!DEVICE_MAJOR_VALID(UINT64_MAX));
-        assert_se(!DEVICE_MINOR_VALID(UINT64_MAX));
-
-        assert_se(DEVICE_MAJOR_VALID(major(0)));
-        assert_se(DEVICE_MINOR_VALID(minor(0)));
-}
-
-static void test_device_path_make_canonical_one(const char *path) {
-        _cleanup_free_ char *resolved = NULL, *raw = NULL;
-        struct stat st;
-        dev_t devno;
-        mode_t mode;
-        int r;
-
-        log_debug("> %s", path);
-
-        if (stat(path, &st) < 0) {
-                assert_se(errno == ENOENT);
-                log_notice("Path %s not found, skipping test", path);
-                return;
-        }
-
-        r = device_path_make_canonical(st.st_mode, st.st_rdev, &resolved);
-        if (r == -ENOENT) {
-                /* maybe /dev/char/x:y and /dev/block/x:y are missing in this test environment, because we
-                 * run in a container or so? */
-                log_notice("Device %s cannot be resolved, skipping test", path);
-                return;
-        }
-
-        assert_se(r >= 0);
-        assert_se(path_equal(path, resolved));
-
-        assert_se(device_path_make_major_minor(st.st_mode, st.st_rdev, &raw) >= 0);
-        assert_se(device_path_parse_major_minor(raw, &mode, &devno) >= 0);
-
-        assert_se(st.st_rdev == devno);
-        assert_se((st.st_mode & S_IFMT) == (mode & S_IFMT));
-}
-
-TEST(device_path_make_canonical) {
-        test_device_path_make_canonical_one("/dev/null");
-        test_device_path_make_canonical_one("/dev/zero");
-        test_device_path_make_canonical_one("/dev/full");
-        test_device_path_make_canonical_one("/dev/random");
-        test_device_path_make_canonical_one("/dev/urandom");
-        test_device_path_make_canonical_one("/dev/tty");
-
-        if (is_device_node("/run/systemd/inaccessible/blk") > 0) {
-                test_device_path_make_canonical_one("/run/systemd/inaccessible/chr");
-                test_device_path_make_canonical_one("/run/systemd/inaccessible/blk");
-        }
-}
-
 TEST(dir_is_empty) {
         _cleanup_(rm_rf_physical_and_freep) char *empty_dir = NULL;
         _cleanup_free_ char *j = NULL, *jj = NULL;
index 90539f108f54fd11f40a8b7617764b3657dbf91c..c2f631417fd4ce0e5ba90c6e5b7dc3993638a25d 100644 (file)
@@ -16,6 +16,7 @@
 #include "specifier.h"
 #include "string-util.h"
 #include "tests.h"
+#include "tmpfile-util.h"
 #include "unit-def.h"
 #include "unit-name.h"
 #include "unit-printf.h"
@@ -233,42 +234,75 @@ TEST(unit_name_mangle) {
 }
 
 TEST_RET(unit_printf, .sd_booted = true) {
-        _cleanup_free_ char *mid = NULL, *bid = NULL, *host = NULL, *gid = NULL, *group = NULL, *uid = NULL, *user = NULL, *shell = NULL, *home = NULL;
+        _cleanup_free_ char
+                *architecture, *os_image_version, *boot_id, *os_build_id,
+                *hostname, *short_hostname, *pretty_hostname,
+                *machine_id, *os_image_id, *os_id, *os_version_id, *os_variant_id,
+                *user, *group, *uid, *gid, *home, *shell,
+                *tmp_dir, *var_tmp_dir;
         _cleanup_(manager_freep) Manager *m = NULL;
         Unit *u;
         int r;
 
-        assert_se(specifier_machine_id('m', NULL, NULL, NULL, &mid) >= 0 && mid);
-        assert_se(specifier_boot_id('b', NULL, NULL, NULL, &bid) >= 0 && bid);
-        assert_se(host = gethostname_malloc());
+        _cleanup_(unlink_tempfilep) char filename[] = "/tmp/test-unit_printf.XXXXXX";
+        assert_se(mkostemp_safe(filename) >= 0);
+
+        /* Using the specifier functions is admittedly a bit circular, but we don't want to reimplement the
+         * logic a second time. We're at least testing that the hookup works. */
+        assert_se(specifier_architecture('a', NULL, NULL, NULL, &architecture) >= 0);
+        assert_se(architecture);
+        assert_se(specifier_os_image_version('A', NULL, NULL, NULL, &os_image_version) >= 0);
+        assert_se(specifier_boot_id('b', NULL, NULL, NULL, &boot_id) >= 0);
+        assert_se(boot_id);
+        assert_se(specifier_os_build_id('B', NULL, NULL, NULL, &os_build_id) >= 0);
+        assert_se(hostname = gethostname_malloc());
+        assert_se(specifier_short_hostname('l', NULL, NULL, NULL, &short_hostname) == 0);
+        assert_se(short_hostname);
+        assert_se(specifier_pretty_hostname('q', NULL, NULL, NULL, &pretty_hostname) == 0);
+        assert_se(pretty_hostname);
+        assert_se(specifier_machine_id('m', NULL, NULL, NULL, &machine_id) >= 0);
+        assert_se(machine_id);
+        assert_se(specifier_os_image_id('M', NULL, NULL, NULL, &os_image_id) >= 0);
+        assert_se(specifier_os_id('o', NULL, NULL, NULL, &os_id) >= 0);
+        assert_se(specifier_os_version_id('w', NULL, NULL, NULL, &os_version_id) >= 0);
+        assert_se(specifier_os_variant_id('W', NULL, NULL, NULL, &os_variant_id) >= 0);
         assert_se(user = uid_to_name(getuid()));
         assert_se(group = gid_to_name(getgid()));
         assert_se(asprintf(&uid, UID_FMT, getuid()));
         assert_se(asprintf(&gid, UID_FMT, getgid()));
         assert_se(get_home_dir(&home) >= 0);
         assert_se(get_shell(&shell) >= 0);
+        assert_se(specifier_tmp_dir('T', NULL, NULL, NULL, &tmp_dir) >= 0);
+        assert_se(tmp_dir);
+        assert_se(specifier_var_tmp_dir('V', NULL, NULL, NULL, &var_tmp_dir) >= 0);
+        assert_se(var_tmp_dir);
 
         r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
         if (manager_errno_skip_test(r))
                 return log_tests_skipped_errno(r, "manager_new");
         assert_se(r == 0);
 
-#define expect(unit, pattern, expected)                                 \
+        assert_se(free_and_strdup(&m->cgroup_root, "/cgroup-root") == 1);
+
+#define expect(unit, pattern, _expected)                                \
         {                                                               \
-                char *e;                                                \
                 _cleanup_free_ char *t = NULL;                          \
                 assert_se(unit_full_printf(unit, pattern, &t) >= 0);    \
-                printf("result: %s\nexpect: %s\n", t, expected);        \
-                if ((e = endswith(expected, "*")))                      \
-                        assert_se(strncmp(t, e, e-expected));              \
-                else                                                    \
-                        assert_se(streq(t, expected));                     \
+                const char *expected = strempty(_expected);             \
+                printf("%s: result: %s\n    expect: %s\n", pattern, t, expected); \
+                assert_se(fnmatch(expected, t, FNM_NOESCAPE) == 0);     \
         }
 
         assert_se(u = unit_new(m, sizeof(Service)));
         assert_se(unit_add_name(u, "blah.service") == 0);
         assert_se(unit_add_name(u, "blah.service") == 0);
 
+        /* We need *a* file that exists, but it doesn't even need to have the right suffix. */
+        assert_se(free_and_strdup(&u->fragment_path, filename) == 1);
+
+        /* This sets the slice to /app.slice. */
+        assert_se(unit_set_default_slice(u) == 1);
+
         /* general tests */
         expect(u, "%%", "%");
         expect(u, "%%s", "%s");
@@ -276,62 +310,103 @@ TEST_RET(unit_printf, .sd_booted = true) {
         expect(u, "%", "%");
 
         /* normal unit */
-        expect(u, "%n", "blah.service");
-        expect(u, "%f", "/blah");
-        expect(u, "%N", "blah");
-        expect(u, "%p", "blah");
-        expect(u, "%P", "blah");
-        expect(u, "%i", "");
-        expect(u, "%I", "");
-        expect(u, "%j", "blah");
-        expect(u, "%J", "blah");
+        expect(u, "%a", architecture);
+        expect(u, "%A", os_image_version);
+        expect(u, "%b", boot_id);
+        expect(u, "%B", os_build_id);
+        expect(u, "%H", hostname);
+        expect(u, "%l", short_hostname);
+        expect(u, "%q", pretty_hostname);
+        expect(u, "%m", machine_id);
+        expect(u, "%M", os_image_id);
+        expect(u, "%o", os_id);
+        expect(u, "%w", os_version_id);
+        expect(u, "%W", os_variant_id);
         expect(u, "%g", group);
         expect(u, "%G", gid);
         expect(u, "%u", user);
         expect(u, "%U", uid);
+        expect(u, "%T", tmp_dir);
+        expect(u, "%V", var_tmp_dir);
+
+        expect(u, "%i", "");
+        expect(u, "%I", "");
+        expect(u, "%j", "blah");
+        expect(u, "%J", "blah");
+        expect(u, "%n", "blah.service");
+        expect(u, "%N", "blah");
+        expect(u, "%p", "blah");
+        expect(u, "%P", "blah");
+        expect(u, "%f", "/blah");
+        expect(u, "%y", filename);
+        expect(u, "%Y", "/tmp");
+        expect(u, "%C", m->prefix[EXEC_DIRECTORY_CACHE]);
+        expect(u, "%d", "*/credentials/blah.service");
+        expect(u, "%E", m->prefix[EXEC_DIRECTORY_CONFIGURATION]);
+        expect(u, "%L", m->prefix[EXEC_DIRECTORY_LOGS]);
+        expect(u, "%S", m->prefix[EXEC_DIRECTORY_STATE]);
+        expect(u, "%t", m->prefix[EXEC_DIRECTORY_RUNTIME]);
         expect(u, "%h", home);
-        expect(u, "%m", mid);
-        expect(u, "%b", bid);
-        expect(u, "%H", host);
-        expect(u, "%t", "/run/user/*");
+        expect(u, "%s", shell);
+
+        /* deprecated */
+        expect(u, "%c", "/cgroup-root/app.slice/blah.service");
+        expect(u, "%r", "/cgroup-root/app.slice");
+        expect(u, "%R", "/cgroup-root");
 
         /* templated */
         assert_se(u = unit_new(m, sizeof(Service)));
         assert_se(unit_add_name(u, "blah@foo-foo.service") == 0);
         assert_se(unit_add_name(u, "blah@foo-foo.service") == 0);
 
-        expect(u, "%n", "blah@foo-foo.service");
-        expect(u, "%N", "blah@foo-foo");
-        expect(u, "%f", "/foo/foo");
-        expect(u, "%p", "blah");
-        expect(u, "%P", "blah");
+        assert_se(free_and_strdup(&u->fragment_path, filename) == 1);
+
+        /* This sets the slice to /app.slice/app-blah.slice. */
+        assert_se(unit_set_default_slice(u) == 1);
+
         expect(u, "%i", "foo-foo");
         expect(u, "%I", "foo/foo");
         expect(u, "%j", "blah");
         expect(u, "%J", "blah");
-        expect(u, "%g", group);
-        expect(u, "%G", gid);
-        expect(u, "%u", user);
-        expect(u, "%U", uid);
+        expect(u, "%n", "blah@foo-foo.service");
+        expect(u, "%N", "blah@foo-foo");
+        expect(u, "%p", "blah");
+        expect(u, "%P", "blah");
+        expect(u, "%f", "/foo/foo");
+        expect(u, "%y", filename);
+        expect(u, "%Y", "/tmp");
+        expect(u, "%C", m->prefix[EXEC_DIRECTORY_CACHE]);
+        expect(u, "%d", "*/credentials/blah@foo-foo.service");
+        expect(u, "%E", m->prefix[EXEC_DIRECTORY_CONFIGURATION]);
+        expect(u, "%L", m->prefix[EXEC_DIRECTORY_LOGS]);
+        expect(u, "%S", m->prefix[EXEC_DIRECTORY_STATE]);
+        expect(u, "%t", m->prefix[EXEC_DIRECTORY_RUNTIME]);
         expect(u, "%h", home);
-        expect(u, "%m", mid);
-        expect(u, "%b", bid);
-        expect(u, "%H", host);
-        expect(u, "%t", "/run/user/*");
+        expect(u, "%s", shell);
+
+        /* deprecated */
+        expect(u, "%c", "/cgroup-root/app.slice/app-blah.slice/blah@foo-foo.service");
+        expect(u, "%r", "/cgroup-root/app.slice/app-blah.slice");
+        expect(u, "%R", "/cgroup-root");
 
         /* templated with components */
         assert_se(u = unit_new(m, sizeof(Slice)));
         assert_se(unit_add_name(u, "blah-blah\\x2d.slice") == 0);
 
-        expect(u, "%n", "blah-blah\\x2d.slice");
-        expect(u, "%N", "blah-blah\\x2d");
-        expect(u, "%f", "/blah/blah-");
-        expect(u, "%p", "blah-blah\\x2d");
-        expect(u, "%P", "blah/blah-");
         expect(u, "%i", "");
         expect(u, "%I", "");
         expect(u, "%j", "blah\\x2d");
         expect(u, "%J", "blah-");
+        expect(u, "%n", "blah-blah\\x2d.slice");
+        expect(u, "%N", "blah-blah\\x2d");
+        expect(u, "%p", "blah-blah\\x2d");
+        expect(u, "%P", "blah/blah-");
+        expect(u, "%f", "/blah/blah-");
+
+        /* deprecated */
+        expect(u, "%c", "/cgroup-root/blah-blah\\x2d.slice");
+        expect(u, "%r", "/cgroup-root");
+        expect(u, "%R", "/cgroup-root");
 
 #undef expect
 
index c28615cf5e634826160af70b16deb528c2f80c0d..9ca5d37b75ef507e667ec92f855a1a7b53bd914c 100644 (file)
@@ -1049,42 +1049,31 @@ static const sd_bus_vtable timedate_vtable[] = {
         SD_BUS_PROPERTY("TimeUSec", "t", property_get_time, 0, 0),
         SD_BUS_PROPERTY("RTCTimeUSec", "t", property_get_rtc_time, 0, 0),
 
-        SD_BUS_METHOD_WITH_NAMES("SetTime",
-                                 "xbb",
-                                 SD_BUS_PARAM(usec_utc)
-                                 SD_BUS_PARAM(relative)
-                                 SD_BUS_PARAM(interactive),
-                                 NULL,,
-                                 method_set_time,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetTimezone",
-                                 "sb",
-                                 SD_BUS_PARAM(timezone)
-                                 SD_BUS_PARAM(interactive),
-                                 NULL,,
-                                 method_set_timezone,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetLocalRTC",
-                                 "bbb",
-                                 SD_BUS_PARAM(local_rtc)
-                                 SD_BUS_PARAM(fix_system)
-                                 SD_BUS_PARAM(interactive),
-                                 NULL,,
-                                 method_set_local_rtc,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("SetNTP",
-                                 "bb",
-                                 SD_BUS_PARAM(use_ntp)
-                                 SD_BUS_PARAM(interactive),
-                                 NULL,,
-                                 method_set_ntp,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("ListTimezones",
-                                 NULL,,
-                                 "as",
-                                 SD_BUS_PARAM(timezones),
-                                 method_list_timezones,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetTime",
+                                SD_BUS_ARGS("x", usec_utc, "b", relative, "b", interactive),
+                                SD_BUS_NO_RESULT,
+                                method_set_time,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetTimezone",
+                                SD_BUS_ARGS("s", timezone, "b", interactive),
+                                SD_BUS_NO_RESULT,
+                                method_set_timezone,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetLocalRTC",
+                                SD_BUS_ARGS("b", local_rtc, "b", fix_system, "b", interactive),
+                                SD_BUS_NO_RESULT,
+                                method_set_local_rtc,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetNTP",
+                                SD_BUS_ARGS("b", use_ntp, "b", interactive),
+                                SD_BUS_NO_RESULT,
+                                method_set_ntp,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ListTimezones",
+                                SD_BUS_NO_ARGS,
+                                SD_BUS_RESULT("as", timezones),
+                                method_list_timezones,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
 
         SD_BUS_VTABLE_END,
 };
index 35467026a84f7086748dfab883d7889e4adb2351..15ca7d2fd5a3d8b61b71110bd70102fafc1ed008 100644 (file)
@@ -50,6 +50,8 @@ if conf.get('ENABLE_TIMESYNCD') == 1
                      install_dir : dbussystemservicedir)
         install_data('80-systemd-timesync.list',
                      install_dir : ntpservicelistdir)
+        install_data('org.freedesktop.timesync1.policy',
+                     install_dir : polkitpolicydir)
 endif
 
 ############################################################
index eccdbec7189e4db4dfb1f8fefca4539be649ef18..8c74b36d6e16ae6930a2addbbefa923621bcee9b 100644 (file)
                        send_interface="org.freedesktop.DBus.Properties"
                        send_member="GetAll"/>
 
+                <allow send_destination="org.freedesktop.timesync1"
+                       send_interface="org.freedesktop.timesync1.Manager"
+                       send_member="SetRuntimeNTPServers"/>
+
                 <allow receive_sender="org.freedesktop.timesync1"/>
         </policy>
 
diff --git a/src/timesync/org.freedesktop.timesync1.policy b/src/timesync/org.freedesktop.timesync1.policy
new file mode 100644 (file)
index 0000000..e13e8df
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?> <!--*-nxml-*-->
+<!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
+        "http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
+
+<!--
+  SPDX-License-Identifier: LGPL-2.1-or-later
+
+  This file is part of systemd.
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+-->
+
+<policyconfig>
+
+        <vendor>The systemd Project</vendor>
+        <vendor_url>https://systemd.io</vendor_url>
+
+        <action id="org.freedesktop.timesync1.set-runtime-servers">
+                <description gettext-domain="systemd">Set runtime NTP servers</description>
+                <message gettext-domain="systemd">Authentication is required to set runtime NTP servers.</message>
+                <defaults>
+                        <allow_any>auth_admin</allow_any>
+                        <allow_inactive>auth_admin</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+                <annotate key="org.freedesktop.policykit.owner">unix-user:systemd-timesync</annotate>
+        </action>
+
+</policyconfig>
index b738dfd3cc2a38fc0ab2310143c9874a34879e40..0eb61a380842d02c737297f7d0bd2183855cee7e 100644 (file)
@@ -1,18 +1,24 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
+#include <sys/capability.h>
+
 #include "sd-bus.h"
 
 #include "alloc-util.h"
 #include "bus-get-properties.h"
 #include "bus-internal.h"
 #include "bus-log-control-api.h"
+#include "bus-polkit.h"
 #include "bus-protocol.h"
 #include "bus-util.h"
+#include "dns-domain.h"
 #include "in-addr-util.h"
 #include "log.h"
 #include "macro.h"
+#include "strv.h"
 #include "time-util.h"
 #include "timesyncd-bus.h"
+#include "user-util.h"
 
 static int property_get_servers(
                 sd_bus *bus,
@@ -43,6 +49,54 @@ static int property_get_servers(
         return sd_bus_message_close_container(reply);
 }
 
+static int method_set_runtime_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        _cleanup_strv_free_ char **msg_names = NULL;
+        Manager *m = userdata;
+        int r;
+
+        assert(m);
+        assert(message);
+
+        r = sd_bus_message_read_strv(message, &msg_names);
+        if (r < 0)
+                return r;
+
+        STRV_FOREACH(name, msg_names) {
+                r = dns_name_is_valid_or_address(*name);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to check validity of NTP server name or address '%s': %m", *name);
+                if (r == 0)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid NTP server name or address, refusing: %s", *name);
+        }
+
+        r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
+                                    "org.freedesktop.timesync1.set-runtime-servers",
+                                    NULL, true, UID_INVALID,
+                                    &m->polkit_registry, error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                /* Polkit will call us back */
+                return 1;
+
+        manager_flush_runtime_servers(m);
+
+        STRV_FOREACH(name, msg_names) {
+                r = server_name_new(m, NULL, SERVER_RUNTIME, *name);
+                if (r < 0) {
+                        manager_flush_runtime_servers(m);
+
+                        return log_error_errno(r, "Failed to add runtime server '%s': %m", *name);
+                }
+        }
+
+        m->exhausted_servers = true;
+        manager_set_server_name(m, NULL);
+        (void) manager_connect(m);
+
+        return sd_bus_reply_method_return(message, NULL);
+}
+
 static int property_get_current_server_name(
                 sd_bus *bus,
                 const char *path,
@@ -162,6 +216,7 @@ static const sd_bus_vtable manager_vtable[] = {
 
         SD_BUS_PROPERTY("LinkNTPServers", "as", property_get_servers, offsetof(Manager, link_servers), 0),
         SD_BUS_PROPERTY("SystemNTPServers", "as", property_get_servers, offsetof(Manager, system_servers), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("RuntimeNTPServers", "as", property_get_servers, offsetof(Manager, runtime_servers), 0),
         SD_BUS_PROPERTY("FallbackNTPServers", "as", property_get_servers, offsetof(Manager, fallback_servers), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("ServerName", "s", property_get_current_server_name, offsetof(Manager, current_server_name), 0),
         SD_BUS_PROPERTY("ServerAddress", "(iay)", property_get_current_server_address, offsetof(Manager, current_server_address), 0),
@@ -172,6 +227,12 @@ static const sd_bus_vtable manager_vtable[] = {
         SD_BUS_PROPERTY("NTPMessage", "(uuuuittayttttbtt)", property_get_ntp_message, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("Frequency", "x", NULL, offsetof(Manager, drift_freq), 0),
 
+        SD_BUS_METHOD_WITH_ARGS("SetRuntimeNTPServers",
+                                SD_BUS_ARGS("as", runtime_servers),
+                                SD_BUS_NO_RESULT,
+                                method_set_runtime_servers,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+
         SD_BUS_VTABLE_END
 };
 
index ae906a631dee98fc65b5ddcb827ca1dbd00c2bd2..78b9cb99321fced9edd5ffbc0866541a10c8d9f5 100644 (file)
@@ -14,6 +14,7 @@
 #include "sd-messages.h"
 
 #include "alloc-util.h"
+#include "bus-polkit.h"
 #include "dns-domain.h"
 #include "event-util.h"
 #include "fd-util.h"
@@ -825,22 +826,25 @@ int manager_connect(Manager *m) {
                         bool restart = true;
 
                         /* Our current server name list is exhausted,
-                         * let's find the next one to iterate. First
-                         * we try the system list, then the link list.
-                         * After having processed the link list we
-                         * jump back to the system list. However, if
-                         * both lists are empty, we change to the
-                         * fallback list. */
+                         * let's find the next one to iterate. First we try the runtime list, then the system list,
+                         * then the link list. After having processed the link list we jump back to the system list
+                         * if no runtime server list.
+                         * However, if all lists are empty, we change to the fallback list. */
                         if (!m->current_server_name || m->current_server_name->type == SERVER_LINK) {
-                                f = m->system_servers;
+                                f = m->runtime_servers;
+                                if (!f)
+                                        f = m->system_servers;
                                 if (!f)
                                         f = m->link_servers;
                         } else {
                                 f = m->link_servers;
-                                if (!f)
-                                        f = m->system_servers;
-                                else
+                                if (f)
                                         restart = false;
+                                else {
+                                        f = m->runtime_servers;
+                                        if (!f)
+                                                f = m->system_servers;
+                                }
                         }
 
                         if (!f)
@@ -852,7 +856,7 @@ int manager_connect(Manager *m) {
                                 return 0;
                         }
 
-                        if (restart && !m->exhausted_servers && m->poll_interval_usec) {
+                        if (restart && !m->exhausted_servers && m->poll_interval_usec > 0) {
                                 log_debug("Waiting after exhausting servers.");
                                 r = sd_event_add_time_relative(m->event, &m->event_retry, CLOCK_BOOTTIME, m->poll_interval_usec, 0, manager_retry_connect, m);
                                 if (r < 0)
@@ -925,6 +929,16 @@ void manager_flush_server_names(Manager  *m, ServerType t) {
         if (t == SERVER_FALLBACK)
                 while (m->fallback_servers)
                         server_name_free(m->fallback_servers);
+
+        if (t == SERVER_RUNTIME)
+                manager_flush_runtime_servers(m);
+}
+
+void manager_flush_runtime_servers(Manager *m) {
+        assert(m);
+
+        while (m->runtime_servers)
+                server_name_free(m->runtime_servers);
 }
 
 Manager* manager_free(Manager *m) {
@@ -934,6 +948,7 @@ Manager* manager_free(Manager *m) {
         manager_disconnect(m);
         manager_flush_server_names(m, SERVER_SYSTEM);
         manager_flush_server_names(m, SERVER_LINK);
+        manager_flush_server_names(m, SERVER_RUNTIME);
         manager_flush_server_names(m, SERVER_FALLBACK);
 
         sd_event_source_unref(m->event_retry);
@@ -948,6 +963,8 @@ Manager* manager_free(Manager *m) {
 
         sd_bus_flush_close_unref(m->bus);
 
+        bus_verify_polkit_async_registry_free(m->polkit_registry);
+
         return mfree(m);
 }
 
@@ -1013,7 +1030,9 @@ clear:
         return r;
 }
 
-static bool manager_is_connected(Manager *m) {
+bool manager_is_connected(Manager *m) {
+        assert(m);
+
         /* Return true when the manager is sending a request, resolving a server name, or
          * in a poll interval. */
         return m->server_socket >= 0 || m->resolve_query || m->event_timer;
index 74917aa0ee409bbf6b6dc4c793bb8d31271ab2e4..e595c7ddfc1f04579104b77f68e514c2e3879c38 100644 (file)
@@ -8,6 +8,7 @@
 #include "sd-network.h"
 #include "sd-resolve.h"
 
+#include "hashmap.h"
 #include "list.h"
 #include "ratelimit.h"
 #include "time-util.h"
@@ -41,6 +42,7 @@ struct Manager {
 
         LIST_HEAD(ServerName, system_servers);
         LIST_HEAD(ServerName, link_servers);
+        LIST_HEAD(ServerName, runtime_servers);
         LIST_HEAD(ServerName, fallback_servers);
 
         bool have_fallbacks:1;
@@ -63,6 +65,9 @@ struct Manager {
         sd_event_source *event_timeout;
         bool talking;
 
+        /* PolicyKit */
+        Hashmap *polkit_registry;
+
         /* last sent packet */
         struct timespec trans_time_mon;
         struct timespec trans_time;
@@ -121,8 +126,10 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
 void manager_set_server_name(Manager *m, ServerName *n);
 void manager_set_server_address(Manager *m, ServerAddress *a);
 void manager_flush_server_names(Manager *m, ServerType t);
+void manager_flush_runtime_servers(Manager *m);
 
 int manager_connect(Manager *m);
 void manager_disconnect(Manager *m);
+bool manager_is_connected(Manager *m);
 
 int manager_setup_save_time_event(Manager *m);
index dd168917341ef43399221831c848304bed660f66..3b7d79323fee443e8892f43aea087d815009c2bc 100644 (file)
@@ -1,8 +1,18 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "alloc-util.h"
+#include "string-table.h"
 #include "timesyncd-server.h"
 
+static const char * const server_type_table[_SERVER_TYPE_MAX] = {
+        [SERVER_SYSTEM]   = "system",
+        [SERVER_FALLBACK] = "fallback",
+        [SERVER_LINK]     = "link",
+        [SERVER_RUNTIME]  = "runtime",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(server_type, ServerType);
+
 int server_address_new(
                 ServerName *n,
                 ServerAddress **ret,
@@ -56,7 +66,7 @@ int server_name_new(
                 ServerType type,
                 const char *string) {
 
-        ServerName *n, *tail;
+        ServerName *n;
 
         assert(m);
         assert(string);
@@ -76,24 +86,29 @@ int server_name_new(
                 return -ENOMEM;
         }
 
-        if (type == SERVER_SYSTEM) {
-                LIST_FIND_TAIL(names, m->system_servers, tail);
-                LIST_INSERT_AFTER(names, m->system_servers, tail, n);
-        } else if (type == SERVER_LINK) {
-                LIST_FIND_TAIL(names, m->link_servers, tail);
-                LIST_INSERT_AFTER(names, m->link_servers, tail, n);
-        } else if (type == SERVER_FALLBACK) {
-                LIST_FIND_TAIL(names, m->fallback_servers, tail);
-                LIST_INSERT_AFTER(names, m->fallback_servers, tail, n);
-        } else
+        switch (type) {
+        case SERVER_SYSTEM:
+                LIST_APPEND(names, m->system_servers, n);
+                break;
+        case SERVER_LINK:
+                LIST_APPEND(names, m->link_servers, n);
+                break;
+        case SERVER_FALLBACK:
+                LIST_APPEND(names, m->fallback_servers, n);
+                break;
+        case SERVER_RUNTIME:
+                LIST_APPEND(names, m->runtime_servers, n);
+                break;
+        default:
                 assert_not_reached();
+        }
 
         if (type != SERVER_FALLBACK &&
             m->current_server_name &&
             m->current_server_name->type == SERVER_FALLBACK)
                 manager_set_server_name(m, NULL);
 
-        log_debug("Added new server %s.", string);
+        log_debug("Added new %s server %s.", server_type_to_string(type), string);
 
         if (ret)
                 *ret = n;
@@ -114,6 +129,8 @@ ServerName *server_name_free(ServerName *n) {
                         LIST_REMOVE(names, n->manager->link_servers, n);
                 else if (n->type == SERVER_FALLBACK)
                         LIST_REMOVE(names, n->manager->fallback_servers, n);
+                else if (n->type == SERVER_RUNTIME)
+                        LIST_REMOVE(names, n->manager->runtime_servers, n);
                 else
                         assert_not_reached();
 
index 8e9e408eccb09781f09f5df42af1a596a8907507..e22917aa12914fa0f7826ab4a88c1cef10a958c4 100644 (file)
@@ -11,6 +11,9 @@ typedef enum ServerType {
         SERVER_SYSTEM,
         SERVER_FALLBACK,
         SERVER_LINK,
+        SERVER_RUNTIME,
+        _SERVER_TYPE_MAX,
+        _SERVER_TYPE_INVALID = -EINVAL,
 } ServerType;
 
 #include "timesyncd-manager.h"
index 023207bc6017ccd1123182a0ba9d7a049d2e85d9..0842d67d8557914cbf92ae2a5f44b126a1f6f9a7 100644 (file)
@@ -26,6 +26,7 @@
 #include "conf-files.h"
 #include "copy.h"
 #include "def.h"
+#include "devnum-util.h"
 #include "dirent-util.h"
 #include "dissect-image.h"
 #include "env-util.h"
@@ -58,7 +59,6 @@
 #include "set.h"
 #include "sort-util.h"
 #include "specifier.h"
-#include "stat-util.h"
 #include "stdio-util.h"
 #include "string-table.h"
 #include "string-util.h"
@@ -2923,8 +2923,8 @@ static int parse_line(
                 { 'a', specifier_architecture,    NULL },
                 { 'b', specifier_boot_id,         NULL },
                 { 'B', specifier_os_build_id,     NULL },
-                { 'H', specifier_host_name,       NULL },
-                { 'l', specifier_short_host_name, NULL },
+                { 'H', specifier_hostname,        NULL },
+                { 'l', specifier_short_hostname,  NULL },
                 { 'm', specifier_machine_id_safe, NULL },
                 { 'o', specifier_os_id,           NULL },
                 { 'v', specifier_kernel_release,  NULL },
@@ -3084,7 +3084,7 @@ static int parse_line(
                         return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG), "Device file requires argument.");
                 }
 
-                r = parse_dev(i.argument, &i.major_minor);
+                r = parse_devnum(i.argument, &i.major_minor);
                 if (r < 0) {
                         *invalid_config = true;
                         return log_syntax(NULL, LOG_ERR, fname, line, r, "Can't parse device file major/minor '%s'.", i.argument);
index 95d15224af7b0fac8049e8795787e571477be5d2..2de172a67a74623bdfaacb01ca98d5e60f2b674a 100644 (file)
@@ -39,7 +39,6 @@
 struct LinkConfigContext {
         LIST_HEAD(LinkConfig, configs);
         int ethtool_fd;
-        bool enable_name_policy;
         usec_t network_dirs_ts_usec;
 };
 
@@ -97,7 +96,6 @@ int link_config_ctx_new(LinkConfigContext **ret) {
 
         *ctx = (LinkConfigContext) {
                 .ethtool_fd = -1,
-                .enable_name_policy = true,
         };
 
         *ret = TAKE_PTR(ctx);
@@ -298,12 +296,6 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) {
         return 0;
 }
 
-static bool enable_name_policy(void) {
-        bool b;
-
-        return proc_cmdline_get_bool("net.ifnames", &b) <= 0 || b;
-}
-
 static int device_unsigned_attribute(sd_device *device, const char *attr, unsigned *type) {
         const char *s;
         int r;
@@ -326,11 +318,6 @@ int link_config_load(LinkConfigContext *ctx) {
 
         link_configs_free(ctx);
 
-        if (!enable_name_policy()) {
-                ctx->enable_name_policy = false;
-                log_info("Network interface NamePolicy= disabled on kernel command line, ignoring.");
-        }
-
         /* update timestamp */
         paths_check_timestamp(NETWORK_DIRS, &ctx->network_dirs_ts_usec, true);
 
@@ -686,7 +673,27 @@ static int link_apply_rtnl_settings(Link *link, sd_netlink **rtnl) {
         return 0;
 }
 
-static int link_generate_new_name(Link *link, bool enable_name_policy) {
+static bool enable_name_policy(void) {
+        static int cached = -1;
+        bool b;
+        int r;
+
+        if (cached >= 0)
+                return cached;
+
+        r = proc_cmdline_get_bool("net.ifnames", &b);
+        if (r < 0)
+                log_warning_errno(r, "Failed to parse net.ifnames= kernel command line option, ignoring: %m");
+        if (r <= 0)
+                return (cached = true);
+
+        if (!b)
+                log_info("Network interface NamePolicy= disabled on kernel command line.");
+
+        return (cached = b);
+}
+
+static int link_generate_new_name(Link *link) {
         LinkConfig *config;
         sd_device *device;
 
@@ -709,7 +716,7 @@ static int link_generate_new_name(Link *link, bool enable_name_policy) {
                 goto no_rename;
         }
 
-        if (enable_name_policy && config->name_policy)
+        if (enable_name_policy() && config->name_policy)
                 for (NamePolicy *policy = config->name_policy; *policy != _NAMEPOLICY_INVALID; policy++) {
                         const char *new_name = NULL;
 
@@ -931,7 +938,7 @@ int link_apply_config(LinkConfigContext *ctx, sd_netlink **rtnl, Link *link) {
         if (r < 0)
                 return r;
 
-        r = link_generate_new_name(link, ctx->enable_name_policy);
+        r = link_generate_new_name(link);
         if (r < 0)
                 return r;
 
index 55f7d3f44ddf98f2ae1ebc2a5eec9cc7a1ed1c8d..f04e29b8f8980f1546e82a5aa23eb0e8c73b3b97 100644 (file)
@@ -156,7 +156,8 @@ static bool test_pointers(sd_device *dev,
         bool has_abs_coordinates = false;
         bool has_rel_coordinates = false;
         bool has_mt_coordinates = false;
-        bool has_joystick_axes_or_buttons = false;
+        size_t num_joystick_axes = 0;
+        size_t num_joystick_buttons = 0;
         bool has_pad_buttons = false;
         bool is_direct = false;
         bool has_touch = false;
@@ -214,15 +215,19 @@ static bool test_pointers(sd_device *dev,
          * Catz Mad Catz M.M.O.TE). Skip those.
          */
         if (!test_bit(BTN_JOYSTICK - 1, bitmask_key)) {
-                for (int button = BTN_JOYSTICK; button < BTN_DIGI && !has_joystick_axes_or_buttons; button++)
-                        has_joystick_axes_or_buttons = test_bit(button, bitmask_key);
-                for (int button = BTN_TRIGGER_HAPPY1; button <= BTN_TRIGGER_HAPPY40 && !has_joystick_axes_or_buttons; button++)
-                        has_joystick_axes_or_buttons = test_bit(button, bitmask_key);
-                for (int button = BTN_DPAD_UP; button <= BTN_DPAD_RIGHT && !has_joystick_axes_or_buttons; button++)
-                        has_joystick_axes_or_buttons = test_bit(button, bitmask_key);
+                for (int button = BTN_JOYSTICK; button < BTN_DIGI; button++)
+                        if (test_bit(button, bitmask_key))
+                                num_joystick_buttons++;
+                for (int button = BTN_TRIGGER_HAPPY1; button <= BTN_TRIGGER_HAPPY40; button++)
+                        if (test_bit(button, bitmask_key))
+                                num_joystick_buttons++;
+                for (int button = BTN_DPAD_UP; button <= BTN_DPAD_RIGHT; button++)
+                        if (test_bit(button, bitmask_key))
+                                num_joystick_buttons++;
         }
-        for (int axis = ABS_RX; axis < ABS_PRESSURE && !has_joystick_axes_or_buttons; axis++)
-                has_joystick_axes_or_buttons = test_bit(axis, bitmask_abs);
+        for (int axis = ABS_RX; axis < ABS_PRESSURE; axis++)
+                if (test_bit(axis, bitmask_abs))
+                        num_joystick_axes++;
 
         if (has_abs_coordinates) {
                 if (has_stylus || has_pen)
@@ -235,9 +240,9 @@ static bool test_pointers(sd_device *dev,
                         is_abs_mouse = true;
                 else if (has_touch || is_direct)
                         is_touchscreen = true;
-                else if (has_joystick_axes_or_buttons)
+                else if (num_joystick_buttons > 0 || num_joystick_axes > 0)
                         is_joystick = true;
-        } else if (has_joystick_axes_or_buttons)
+        } else if (num_joystick_buttons > 0 || num_joystick_axes > 0)
                 is_joystick = true;
 
         if (has_mt_coordinates) {
@@ -262,6 +267,34 @@ static bool test_pointers(sd_device *dev,
         if (is_mouse && id->bustype == BUS_I2C)
                 is_pointing_stick = true;
 
+        /* Joystick un-detection. Some keyboards have random joystick buttons
+         * set. Avoid those being labeled as ID_INPUT_JOYSTICK with some heuristics.
+         * The well-known keys represent a (randomly picked) set of key groups.
+         * A joystick may have one of those but probably not several. And a joystick with less than 2 buttons
+         * or axes is not a joystick either.
+         * libinput uses similar heuristics, any changes here should be added to libinput too.
+         */
+        if (is_joystick) {
+                static const unsigned int well_known_keyboard_keys[] = {
+                        KEY_LEFTCTRL, KEY_CAPSLOCK, KEY_NUMLOCK, KEY_INSERT,
+                        KEY_MUTE, KEY_CALC, KEY_FILE, KEY_MAIL, KEY_PLAYPAUSE,
+                        KEY_BRIGHTNESSDOWN,
+                };
+                size_t num_well_known_keys = 0;
+
+                if (has_keys)
+                        for (size_t i = 0; i < ELEMENTSOF(well_known_keyboard_keys); i++)
+                                if (test_bit(well_known_keyboard_keys[i], bitmask_key))
+                                        num_well_known_keys++;
+
+                if (num_well_known_keys >= 4 || num_joystick_buttons + num_joystick_axes < 2) {
+                        log_device_debug(dev, "Input device has %zd joystick buttons and %zd axes but also %zd keyboard key sets, "
+                                         "assuming this is a keyboard, not a joystick.",
+                                         num_joystick_buttons, num_joystick_axes, num_well_known_keys);
+                        is_joystick = false;
+                }
+        }
+
         if (is_pointing_stick)
                 udev_builtin_add_property(dev, test, "ID_INPUT_POINTINGSTICK", "1");
         if (is_mouse || is_abs_mouse)
index 114fda663ee2139808af516c23251e6a85a2b362..f2ea2a7cd51390bc3906c8880a826a9ce5974e9d 100644 (file)
@@ -400,11 +400,11 @@ static int dev_pci_slot(sd_device *dev, const LinkInfo *info, NetNames *names) {
         /* ACPI _SUN — slot user number */
         r = sd_device_new_from_subsystem_sysname(&pci, "subsystem", "pci");
         if (r < 0)
-                return log_debug_errno(r, "sd_device_new_from_subsystem_sysname failed: %m");
+                return log_debug_errno(r, "sd_device_new_from_subsystem_sysname() failed: %m");
 
         r = sd_device_get_syspath(pci, &syspath);
         if (r < 0)
-                return log_device_debug_errno(pci, r, "sd_device_get_syspath failed: %m");
+                return log_device_debug_errno(pci, r, "sd_device_get_syspath() failed: %m");
 
         if (!snprintf_ok(slots, sizeof slots, "%s/slots", syspath))
                 return log_device_debug_errno(dev, SYNTHETIC_ERRNO(ENAMETOOLONG),
@@ -504,11 +504,11 @@ static int names_vio(sd_device *dev, NetNames *names) {
         /* check if our direct parent is a VIO device with no other bus in-between */
         r = sd_device_get_parent(dev, &parent);
         if (r < 0)
-                return log_device_debug_errno(dev, r, "sd_device_get_parent failed: %m");
+                return log_device_debug_errno(dev, r, "sd_device_get_parent() failed: %m");
 
         r = sd_device_get_subsystem(parent, &subsystem);
         if (r < 0)
-                return log_device_debug_errno(parent, r, "sd_device_get_subsystem failed: %m");
+                return log_device_debug_errno(parent, r, "sd_device_get_subsystem() failed: %m");
         if (!streq("vio", subsystem))
                 return -ENOENT;
         log_device_debug(dev, "Parent device is in the vio subsystem.");
@@ -519,7 +519,7 @@ static int names_vio(sd_device *dev, NetNames *names) {
          * there should only ever be one bus, and then remove leading zeros. */
         r = sd_device_get_syspath(dev, &syspath);
         if (r < 0)
-                return log_device_debug_errno(dev, r, "sd_device_get_syspath failed: %m");
+                return log_device_debug_errno(dev, r, "sd_device_get_syspath() failed: %m");
 
         r = sscanf(syspath, "/sys/devices/vio/%4x%4x/net/eth%u", &busid, &slotid, &ethid);
         log_device_debug(dev, "Parsing vio slot information from syspath \"%s\": %s",
@@ -547,11 +547,11 @@ static int names_platform(sd_device *dev, NetNames *names, bool test) {
         /* check if our direct parent is a platform device with no other bus in-between */
         r = sd_device_get_parent(dev, &parent);
         if (r < 0)
-                return log_device_debug_errno(dev, r, "sd_device_get_parent failed: %m");
+                return log_device_debug_errno(dev, r, "sd_device_get_parent() failed: %m");
 
         r = sd_device_get_subsystem(parent, &subsystem);
         if (r < 0)
-                return log_device_debug_errno(parent, r, "sd_device_get_subsystem failed: %m");
+                return log_device_debug_errno(parent, r, "sd_device_get_subsystem() failed: %m");
 
         if (!streq("platform", subsystem))
                  return -ENOENT;
@@ -559,7 +559,7 @@ static int names_platform(sd_device *dev, NetNames *names, bool test) {
 
         r = sd_device_get_syspath(dev, &syspath);
         if (r < 0)
-                return log_device_debug_errno(dev, r, "sd_device_get_syspath failed: %m");
+                return log_device_debug_errno(dev, r, "sd_device_get_syspath() failed: %m");
 
         /* syspath is too short, to have a valid ACPI instance */
         if (strlen(syspath) < STRLEN(PLATFORM_TEST) + 1)
@@ -1138,8 +1138,15 @@ static int builtin_net_id(sd_device *dev, sd_netlink **rtnl, int argc, char *arg
         return 0;
 }
 
+static int builtin_net_id_init(void) {
+        /* Load naming scheme here to suppress log messages in workers. */
+        naming_scheme();
+        return 0;
+}
+
 const UdevBuiltin udev_builtin_net_id = {
         .name = "net_id",
         .cmd = builtin_net_id,
+        .init = builtin_net_id_init,
         .help = "Network device properties",
 };
index a9095969bdcc0db579d0c67c9af7e88d40f4ebeb..bf827097719af7f2d259250324dc37c5fb77f7ac 100644 (file)
@@ -32,12 +32,10 @@ static const UdevBuiltin *const builtins[_UDEV_BUILTIN_MAX] = {
 };
 
 void udev_builtin_init(void) {
-        unsigned i;
-
         if (initialized)
                 return;
 
-        for (i = 0; i < _UDEV_BUILTIN_MAX; i++)
+        for (UdevBuiltinCommand i = 0; i < _UDEV_BUILTIN_MAX; i++)
                 if (builtins[i] && builtins[i]->init)
                         builtins[i]->init();
 
@@ -45,12 +43,10 @@ void udev_builtin_init(void) {
 }
 
 void udev_builtin_exit(void) {
-        unsigned i;
-
         if (!initialized)
                 return;
 
-        for (i = 0; i < _UDEV_BUILTIN_MAX; i++)
+        for (UdevBuiltinCommand i = 0; i < _UDEV_BUILTIN_MAX; i++)
                 if (builtins[i] && builtins[i]->exit)
                         builtins[i]->exit();
 
@@ -58,18 +54,14 @@ void udev_builtin_exit(void) {
 }
 
 bool udev_builtin_validate(void) {
-        unsigned i;
-
-        for (i = 0; i < _UDEV_BUILTIN_MAX; i++)
+        for (UdevBuiltinCommand i = 0; i < _UDEV_BUILTIN_MAX; i++)
                 if (builtins[i] && builtins[i]->validate && builtins[i]->validate())
                         return true;
         return false;
 }
 
 void udev_builtin_list(void) {
-        unsigned i;
-
-        for (i = 0; i < _UDEV_BUILTIN_MAX; i++)
+        for (UdevBuiltinCommand i = 0; i < _UDEV_BUILTIN_MAX; i++)
                 if (builtins[i])
                         fprintf(stderr, "  %-14s  %s\n", builtins[i]->name, builtins[i]->help);
 }
@@ -93,14 +85,13 @@ bool udev_builtin_run_once(UdevBuiltinCommand cmd) {
 }
 
 UdevBuiltinCommand udev_builtin_lookup(const char *command) {
-        UdevBuiltinCommand i;
         size_t n;
 
         assert(command);
 
         command += strspn(command, WHITESPACE);
         n = strcspn(command, WHITESPACE);
-        for (i = 0; i < _UDEV_BUILTIN_MAX; i++)
+        for (UdevBuiltinCommand i = 0; i < _UDEV_BUILTIN_MAX; i++)
                 if (builtins[i] && strneq(builtins[i]->name, command, n))
                         return i;
 
index abfed2c181d9cb0bee2ff30984ac991bfc64fabd..b0f2f919a9ab193c7023026023cb81fc8062c6df 100644 (file)
@@ -6,7 +6,7 @@
 #include "sd-device.h"
 #include "sd-netlink.h"
 
-typedef enum {
+typedef enum UdevBuiltinCommand {
 #if HAVE_BLKID
         UDEV_BUILTIN_BLKID,
 #endif
index deacbc31c56ab301d1f18625c8d27a49803591f0..c9f58e8c29bf29e6abab5e8d64cef7f6de5acdb7 100644 (file)
@@ -12,6 +12,7 @@
 #include "alloc-util.h"
 #include "device-private.h"
 #include "device-util.h"
+#include "devnum-util.h"
 #include "dirent-util.h"
 #include "escape.h"
 #include "fd-util.h"
index 12a1769bd86e5fe08ebffb61e5de4dee2944ccb2..4ee15592cbd968ad02ac5f13a4e66351679393ff 100644 (file)
@@ -18,6 +18,9 @@
 #include "dirent-util.h"
 #include "errno-util.h"
 #include "fd-util.h"
+#include "fileio.h"
+#include "glyph-util.h"
+#include "pager.h"
 #include "sort-util.h"
 #include "static-destruct.h"
 #include "string-table.h"
@@ -31,6 +34,7 @@ typedef enum ActionType {
         ACTION_QUERY,
         ACTION_ATTRIBUTE_WALK,
         ACTION_DEVICE_ID_FILE,
+        ACTION_TREE,
 } ActionType;
 
 typedef enum QueryType {
@@ -48,6 +52,9 @@ static bool arg_value = false;
 static const char *arg_export_prefix = NULL;
 static usec_t arg_wait_for_initialization_timeout = 0;
 
+/* Put a limit on --tree descent level to not exhaust our stack */
+#define TREE_DEPTH_MAX 64
+
 static bool skip_attribute(const char *name) {
         assert(name);
 
@@ -171,7 +178,7 @@ static int print_device_chain(sd_device *device) {
         return 0;
 }
 
-static int print_record(sd_device *device) {
+static int print_record(sd_device *device, const char *prefix) {
         const char *str, *val, *subsys;
         dev_t devnum;
         uint64_t q;
@@ -179,6 +186,8 @@ static int print_record(sd_device *device) {
 
         assert(device);
 
+        prefix = strempty(prefix);
+
         /* We don't show syspath here, because it's identical to devpath (modulo the "/sys" prefix).
          *
          * We don't show action/seqnum here because that only makes sense for records synthesized from
@@ -197,52 +206,54 @@ static int print_record(sd_device *device) {
          *     • no color for regular properties */
 
         assert_se(sd_device_get_devpath(device, &str) >= 0);
-        printf("P: %s%s%s\n", ansi_highlight_white(), str, ansi_normal());
+        printf("%sP: %s%s%s\n", prefix, ansi_highlight_white(), str, ansi_normal());
 
         if (sd_device_get_sysname(device, &str) >= 0)
-                printf("M: %s%s%s\n", ansi_highlight_white(), str, ansi_normal());
+                printf("%sM: %s%s%s\n", prefix, ansi_highlight_white(), str, ansi_normal());
 
         if (sd_device_get_sysnum(device, &str) >= 0)
-                printf("R: %s%s%s\n", ansi_highlight_white(), str, ansi_normal());
+                printf("%sR: %s%s%s\n", prefix, ansi_highlight_white(), str, ansi_normal());
 
         if (sd_device_get_subsystem(device, &subsys) >= 0)
-                printf("U: %s%s%s\n", ansi_highlight_green(), subsys, ansi_normal());
+                printf("%sU: %s%s%s\n", prefix, ansi_highlight_green(), subsys, ansi_normal());
 
         if (sd_device_get_devtype(device, &str) >= 0)
-                printf("T: %s%s%s\n", ansi_highlight_green(), str, ansi_normal());
+                printf("%sT: %s%s%s\n", prefix, ansi_highlight_green(), str, ansi_normal());
 
         if (sd_device_get_devnum(device, &devnum) >= 0)
-                printf("D: %s%c %u:%u%s\n",
+                printf("%sD: %s%c %u:%u%s\n",
+                       prefix,
                        ansi_highlight_cyan(),
                        streq_ptr(subsys, "block") ? 'b' : 'c', major(devnum), minor(devnum),
                        ansi_normal());
 
         if (sd_device_get_ifindex(device, &ifi) >= 0)
-                printf("I: %s%i%s\n", ansi_highlight_cyan(), ifi, ansi_normal());
+                printf("%sI: %s%i%s\n", prefix, ansi_highlight_cyan(), ifi, ansi_normal());
 
         if (sd_device_get_devname(device, &str) >= 0) {
                 assert_se(val = path_startswith(str, "/dev/"));
-                printf("N: %s%s%s\n", ansi_highlight_cyan(), val, ansi_normal());
+                printf("%sN: %s%s%s\n", prefix, ansi_highlight_cyan(), val, ansi_normal());
 
                 if (device_get_devlink_priority(device, &i) >= 0)
-                        printf("L: %s%i%s\n", ansi_highlight_cyan(), i, ansi_normal());
+                        printf("%sL: %s%i%s\n", prefix, ansi_highlight_cyan(), i, ansi_normal());
 
                 FOREACH_DEVICE_DEVLINK(device, str) {
                         assert_se(val = path_startswith(str, "/dev/"));
-                        printf("S: %s%s%s\n", ansi_highlight_cyan(), val, ansi_normal());
+                        printf("%sS: %s%s%s\n", prefix, ansi_highlight_cyan(), val, ansi_normal());
                 }
         }
 
         if (sd_device_get_diskseq(device, &q) >= 0)
-                printf("Q: %s%" PRIu64 "%s\n", ansi_highlight_magenta(), q, ansi_normal());
+                printf("%sQ: %s%" PRIu64 "%s\n", prefix, ansi_highlight_magenta(), q, ansi_normal());
 
         if (sd_device_get_driver(device, &str) >= 0)
-                printf("V: %s%s%s\n", ansi_highlight_yellow4(), str, ansi_normal());
+                printf("%sV: %s%s%s\n", prefix, ansi_highlight_yellow4(), str, ansi_normal());
 
         FOREACH_DEVICE_PROPERTY(device, str, val)
-                printf("E: %s=%s\n", str, val);
+                printf("%sE: %s=%s\n", prefix, str, val);
 
-        puts("");
+        if (isempty(prefix))
+                puts("");
         return 0;
 }
 
@@ -284,7 +295,7 @@ static int export_devices(void) {
                 return log_error_errno(r, "Failed to scan devices: %m");
 
         FOREACH_DEVICE_AND_SUBSYSTEM(e, d)
-                (void) print_record(d);
+                (void) print_record(d, NULL);
 
         return 0;
 }
@@ -305,11 +316,13 @@ static void cleanup_dir(DIR *dir, mode_t mask, int depth) {
                 if ((stats.st_mode & mask) != 0)
                         continue;
                 if (S_ISDIR(stats.st_mode)) {
-                        _cleanup_closedir_ DIR *dir2 = NULL;
+                        _cleanup_closedir_ DIR *subdir = NULL;
 
-                        dir2 = fdopendir(openat(dirfd(dir), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
-                        if (dir2)
-                                cleanup_dir(dir2, mask, depth-1);
+                        subdir = xopendirat(dirfd(dir), dent->d_name, O_NOFOLLOW);
+                        if (!subdir)
+                                log_debug_errno(errno, "Failed to open subdirectory '%s', ignoring: %m", dent->d_name);
+                        else
+                                cleanup_dir(subdir, mask, depth-1);
 
                         (void) unlinkat(dirfd(dir), dent->d_name, AT_REMOVEDIR);
                 } else
@@ -352,11 +365,13 @@ static void cleanup_dirs_after_db_cleanup(DIR *dir, DIR *datadir) {
                 if (fstatat(dirfd(dir), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) < 0)
                         continue;
                 if (S_ISDIR(stats.st_mode)) {
-                        _cleanup_closedir_ DIR *dir2 = NULL;
+                        _cleanup_closedir_ DIR *subdir = NULL;
 
-                        dir2 = fdopendir(openat(dirfd(dir), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
-                        if (dir2)
-                                cleanup_dir_after_db_cleanup(dir2, datadir);
+                        subdir = xopendirat(dirfd(dir), dent->d_name, O_NOFOLLOW);
+                        if (!subdir)
+                                log_debug_errno(errno, "Failed to open subdirectory '%s', ignoring: %m", dent->d_name);
+                        else
+                                cleanup_dir_after_db_cleanup(subdir, datadir);
 
                         (void) unlinkat(dirfd(dir), dent->d_name, AT_REMOVEDIR);
                 } else
@@ -449,7 +464,7 @@ static int query_device(QueryType query, sd_device* device) {
         }
 
         case QUERY_ALL:
-                return print_record(device);
+                return print_record(device, NULL);
 
         default:
                 assert_not_reached();
@@ -474,6 +489,7 @@ static int help(void) {
                "  -r --root                   Prepend dev directory to path names\n"
                "  -a --attribute-walk         Print all key matches walking along the chain\n"
                "                              of parent devices\n"
+               "  -t --tree                   Show tree of devices\n"
                "  -d --device-id-of-file=FILE Print major:minor of device containing this file\n"
                "  -x --export                 Export key/value pairs\n"
                "  -P --export-prefix          Export the key name with a prefix\n"
@@ -486,6 +502,156 @@ static int help(void) {
         return 0;
 }
 
+static int draw_tree(
+                sd_device *parent,
+                sd_device *const array[], size_t n,
+                const char *prefix,
+                unsigned level);
+
+static int output_tree_device(
+                sd_device *device,
+                const char *str,
+                const char *prefix,
+                bool more,
+                sd_device *const array[], size_t n,
+                unsigned level) {
+
+        _cleanup_free_ char *subprefix = NULL, *subsubprefix = NULL;
+
+        assert(device);
+        assert(str);
+
+        prefix = strempty(prefix);
+
+        printf("%s%s%s\n", prefix, special_glyph(more ? SPECIAL_GLYPH_TREE_BRANCH : SPECIAL_GLYPH_TREE_RIGHT), str);
+
+        subprefix = strjoin(prefix, special_glyph(more ? SPECIAL_GLYPH_TREE_VERTICAL : SPECIAL_GLYPH_TREE_SPACE));
+        if (!subprefix)
+                return log_oom();
+
+        subsubprefix = strjoin(subprefix, special_glyph(SPECIAL_GLYPH_VERTICAL_DOTTED), " ");
+        if (!subsubprefix)
+                return log_oom();
+
+        (void) print_record(device, subsubprefix);
+
+        return draw_tree(device, array, n, subprefix, level + 1);
+}
+
+static int draw_tree(
+                sd_device *parent,
+                sd_device *const array[], size_t n,
+                const char *prefix,
+                unsigned level) {
+
+        const char *parent_path;
+        size_t i = 0;
+        int r;
+
+        if (n == 0)
+                return 0;
+
+        assert(array);
+
+        if (parent) {
+                r = sd_device_get_devpath(parent, &parent_path);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to get sysfs path of parent device: %m");
+        } else
+                parent_path = NULL;
+
+        if (level > TREE_DEPTH_MAX) {
+                log_warning("Eliding tree below '%s', too deep.", strna(parent_path));
+                return 0;
+        }
+
+        while (i < n) {
+                sd_device *device = array[i];
+                const char *device_path, *str;
+                bool more = false;
+                size_t j;
+
+                r = sd_device_get_devpath(device, &device_path);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to get sysfs path of enumerated device: %m");
+
+                /* Scan through the subsequent devices looking children of the device we are looking at. */
+                for (j = i + 1; j < n; j++) {
+                        sd_device *next = array[j];
+                        const char *next_path;
+
+                        r = sd_device_get_devpath(next, &next_path);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to get sysfs of child device: %m");
+
+                        if (!path_startswith(next_path, device_path)) {
+                                more = !parent_path || path_startswith(next_path, parent_path);
+                                break;
+                        }
+                }
+
+                /* Determine the string to display for this node. If we are at the top of the tree, the full
+                 * device path so far, otherwise just the part suffixing the parent's device path. */
+                str = parent ? ASSERT_PTR(path_startswith(device_path, parent_path)) : device_path;
+
+                r = output_tree_device(device, str, prefix, more, array + i + 1, j - i - 1, level);
+                if (r < 0)
+                        return r;
+
+                i = j;
+        }
+
+        return 0;
+}
+
+static int print_tree(sd_device* below) {
+        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+        const char *below_path;
+        sd_device **array;
+        size_t n = 0;
+        int r;
+
+        if (below) {
+                r = sd_device_get_devpath(below, &below_path);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to get sysfs path of device: %m");
+
+        } else
+                below_path = NULL;
+
+        r = sd_device_enumerator_new(&e);
+        if (r < 0)
+                return log_error_errno(r, "Failed to allocate device enumerator: %m");
+
+        if (below) {
+                r = sd_device_enumerator_add_match_parent(e, below);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to install parent enumerator match: %m");
+        }
+
+        r = sd_device_enumerator_allow_uninitialized(e);
+        if (r < 0)
+                return log_error_errno(r, "Failed to enable enumeration of uninitialized devices: %m");
+
+        r = device_enumerator_scan_devices_and_subsystems(e);
+        if (r < 0)
+                return log_error_errno(r, "Failed to scan for devices and subsystems: %m");
+
+        assert_se(array = device_enumerator_get_devices(e, &n));
+
+        if (n == 0) {
+                log_info("No items.");
+                return 0;
+        }
+
+        r = draw_tree(NULL, array, n, NULL, 0);
+        if (r < 0)
+                return r;
+
+        printf("\n%zu items shown.\n", n);
+        return 0;
+}
+
 int info_main(int argc, char *argv[], void *userdata) {
         _cleanup_strv_free_ char **devices = NULL;
         _cleanup_free_ char *name = NULL;
@@ -498,6 +664,7 @@ int info_main(int argc, char *argv[], void *userdata) {
 
         static const struct option options[] = {
                 { "attribute-walk",          no_argument,       NULL, 'a'          },
+                { "tree",                    no_argument,       NULL, 't'          },
                 { "cleanup-db",              no_argument,       NULL, 'c'          },
                 { "device-id-of-file",       required_argument, NULL, 'd'          },
                 { "export",                  no_argument,       NULL, 'x'          },
@@ -518,7 +685,7 @@ int info_main(int argc, char *argv[], void *userdata) {
         ActionType action = ACTION_QUERY;
         QueryType query = QUERY_ALL;
 
-        while ((c = getopt_long(argc, argv, "aced:n:p:q:rxP:w::Vh", options, NULL)) >= 0)
+        while ((c = getopt_long(argc, argv, "atced:n:p:q:rxP:w::Vh", options, NULL)) >= 0)
                 switch (c) {
                 case ARG_PROPERTY:
                         /* Make sure that if the empty property list was specified, we won't show any
@@ -578,6 +745,9 @@ int info_main(int argc, char *argv[], void *userdata) {
                 case 'a':
                         action = ACTION_ATTRIBUTE_WALK;
                         break;
+                case 't':
+                        action = ACTION_TREE;
+                        break;
                 case 'e':
                         return export_devices();
                 case 'c':
@@ -620,17 +790,23 @@ int info_main(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return log_error_errno(r, "Failed to build argument list: %m");
 
-        if (strv_isempty(devices))
+        if (action != ACTION_TREE && strv_isempty(devices))
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                        "A device name or path is required");
-        if (action == ACTION_ATTRIBUTE_WALK && strv_length(devices) > 1)
+        if (IN_SET(action, ACTION_ATTRIBUTE_WALK, ACTION_TREE) && strv_length(devices) > 1)
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "Only one device may be specified with -a/--attribute-walk");
+                                       "Only one device may be specified with -a/--attribute-walk and -t/--tree");
 
         if (arg_export && arg_value)
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                        "-x/--export or -P/--export-prefix cannot be used with --value");
 
+        if (strv_isempty(devices)) {
+                assert(action == ACTION_TREE);
+                pager_open(0);
+                return print_tree(NULL);
+        }
+
         ret = 0;
         STRV_FOREACH(p, devices) {
                 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
@@ -666,6 +842,8 @@ int info_main(int argc, char *argv[], void *userdata) {
                         r = query_device(query, device);
                 else if (action == ACTION_ATTRIBUTE_WALK)
                         r = print_device_chain(device);
+                else if (action == ACTION_TREE)
+                        r = print_tree(device);
                 else
                         assert_not_reached();
                 if (r < 0)
index 951711f1203d0bcee4a2a368ae0667bfcd38759b..32935e8aa41ab250d4064ce4c5f4578e80c1a13b 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "blockdev-util.h"
 #include "btrfs-util.h"
+#include "devnum-util.h"
 #include "fd-util.h"
 #include "fdset.h"
 #include "main-func.h"
@@ -16,7 +17,6 @@
 #include "process-util.h"
 #include "signal-util.h"
 #include "sort-util.h"
-#include "stat-util.h"
 #include "strv.h"
 #include "time-util.h"
 #include "udevadm.h"
index 078cd960b429f17e4a1fa163460934be37e4366b..d140dcf6f648137b40d89956b35ff91975adb48f 100644 (file)
@@ -151,6 +151,7 @@ typedef enum WorkerState {
 typedef struct Worker {
         Manager *manager;
         pid_t pid;
+        sd_event_source *child_event_source;
         sd_device_monitor *monitor;
         WorkerState state;
         Event *event;
@@ -160,6 +161,7 @@ typedef struct Worker {
 typedef enum EventResult {
         EVENT_RESULT_NERRNO_MIN       = -ERRNO_MAX,
         EVENT_RESULT_NERRNO_MAX       = -1,
+        EVENT_RESULT_SUCCESS          = 0,
         EVENT_RESULT_EXIT_STATUS_BASE = 0,
         EVENT_RESULT_EXIT_STATUS_MAX  = 255,
         EVENT_RESULT_TRY_AGAIN        = 256, /* when the block device is locked by another process. */
@@ -202,9 +204,10 @@ static Worker *worker_free(Worker *worker) {
         if (!worker)
                 return NULL;
 
-        assert(worker->manager);
+        if (worker->manager)
+                hashmap_remove(worker->manager->workers, PID_TO_PTR(worker->pid));
 
-        hashmap_remove(worker->manager->workers, PID_TO_PTR(worker->pid));
+        sd_event_source_unref(worker->child_event_source);
         sd_device_monitor_unref(worker->monitor);
         event_free(worker->event);
 
@@ -255,6 +258,8 @@ static Manager* manager_free(Manager *manager) {
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
 
+static int on_sigchld(sd_event_source *s, const siginfo_t *si, void *userdata);
+
 static int worker_new(Worker **ret, Manager *manager, sd_device_monitor *worker_monitor, pid_t pid) {
         _cleanup_(worker_freep) Worker *worker = NULL;
         int r;
@@ -272,17 +277,21 @@ static int worker_new(Worker **ret, Manager *manager, sd_device_monitor *worker_
                 return -ENOMEM;
 
         *worker = (Worker) {
-                .manager = manager,
                 .monitor = sd_device_monitor_ref(worker_monitor),
                 .pid = pid,
         };
 
+        r = sd_event_add_child(manager->event, &worker->child_event_source, pid, WEXITED, on_sigchld, worker);
+        if (r < 0)
+                return r;
+
         r = hashmap_ensure_put(&manager->workers, &worker_hash_op, PID_TO_PTR(pid), worker);
         if (r < 0)
                 return r;
 
-        *ret = TAKE_PTR(worker);
+        worker->manager = manager;
 
+        *ret = TAKE_PTR(worker);
         return 0;
 }
 
@@ -363,7 +372,7 @@ static int on_kill_workers_event(sd_event_source *s, uint64_t usec, void *userda
         return 1;
 }
 
-static void device_broadcast(sd_device_monitor *monitor, sd_device *dev, int result) {
+static void device_broadcast(sd_device_monitor *monitor, sd_device *dev, EventResult result) {
         int r;
 
         assert(dev);
@@ -372,7 +381,7 @@ static void device_broadcast(sd_device_monitor *monitor, sd_device *dev, int res
         if (!monitor)
                 return;
 
-        if (result != 0) {
+        if (result != EVENT_RESULT_SUCCESS) {
                 (void) device_add_property(dev, "UDEV_WORKER_FAILED", "1");
 
                 switch (result) {
@@ -415,7 +424,7 @@ static void device_broadcast(sd_device_monitor *monitor, sd_device *dev, int res
                                          "Failed to broadcast event to libudev listeners, ignoring: %m");
 }
 
-static int worker_send_result(Manager *manager, int result) {
+static int worker_send_result(Manager *manager, EventResult result) {
         assert(manager);
         assert(manager->worker_watch[WRITE_END] >= 0);
 
@@ -1200,7 +1209,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
         assert(manager);
 
         for (;;) {
-                int result;
+                EventResult result;
                 struct iovec iovec = IOVEC_MAKE(&result, sizeof(result));
                 CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
                 struct msghdr msghdr = {
@@ -1543,59 +1552,47 @@ static int on_sighup(sd_event_source *s, const struct signalfd_siginfo *si, void
         return 1;
 }
 
-static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
-        Manager *manager = userdata;
+static int on_sigchld(sd_event_source *s, const siginfo_t *si, void *userdata) {
+        Worker *worker = ASSERT_PTR(userdata);
+        Manager *manager = ASSERT_PTR(worker->manager);
+        sd_device *dev = worker->event ? ASSERT_PTR(worker->event->dev) : NULL;
+        EventResult result;
         int r;
 
-        assert(manager);
-
-        for (;;) {
-                pid_t pid;
-                int status;
-                Worker *worker;
-
-                pid = waitpid(-1, &status, WNOHANG);
-                if (pid <= 0)
-                        break;
-
-                worker = hashmap_get(manager->workers, PID_TO_PTR(pid));
-                if (!worker) {
-                        log_warning("Worker ["PID_FMT"] is unknown, ignoring", pid);
-                        continue;
-                }
+        assert(si);
 
-                if (WIFEXITED(status)) {
-                        if (WEXITSTATUS(status) == 0)
-                                log_debug("Worker ["PID_FMT"] exited", pid);
-                        else
-                                log_warning("Worker ["PID_FMT"] exited with return code %i", pid, WEXITSTATUS(status));
-                } else if (WIFSIGNALED(status))
-                        log_warning("Worker ["PID_FMT"] terminated by signal %i (%s)", pid, WTERMSIG(status), signal_to_string(WTERMSIG(status)));
-                else if (WIFSTOPPED(status)) {
-                        log_info("Worker ["PID_FMT"] stopped", pid);
-                        continue;
-                } else if (WIFCONTINUED(status)) {
-                        log_info("Worker ["PID_FMT"] continued", pid);
-                        continue;
-                } else
-                        log_warning("Worker ["PID_FMT"] exit with status 0x%04x", pid, status);
+        switch (si->si_code) {
+        case CLD_EXITED:
+                if (si->si_status == 0)
+                        log_device_debug(dev, "Worker ["PID_FMT"] exited.", si->si_pid);
+                else
+                        log_device_warning(dev, "Worker ["PID_FMT"] exited with return code %i.",
+                                           si->si_pid, si->si_status);
+                result = EVENT_RESULT_EXIT_STATUS_BASE + si->si_status;
+                break;
 
-                if ((!WIFEXITED(status) || WEXITSTATUS(status) != 0) && worker->event) {
-                        log_device_error(worker->event->dev, "Worker ["PID_FMT"] failed", pid);
+        case CLD_KILLED:
+        case CLD_DUMPED:
+                log_device_warning(dev, "Worker ["PID_FMT"] terminated by signal %i (%s).",
+                                   si->si_pid, si->si_status, signal_to_string(si->si_status));
+                result = EVENT_RESULT_SIGNAL_BASE + si->si_status;
+                break;
 
-                        /* delete state from disk */
-                        device_delete_db(worker->event->dev);
-                        device_tag_index(worker->event->dev, NULL, false);
+        default:
+                assert_not_reached();
+        }
 
-                        /* Forward kernel event to libudev listeners */
-                        device_broadcast(manager->monitor, worker->event->dev,
-                                         WIFEXITED(status) ? EVENT_RESULT_EXIT_STATUS_BASE + WEXITSTATUS(status):
-                                         WIFSIGNALED(status) ? EVENT_RESULT_SIGNAL_BASE + WTERMSIG(status) : 0);
-                }
+        if (result != EVENT_RESULT_SUCCESS && dev) {
+                /* delete state from disk */
+                device_delete_db(dev);
+                device_tag_index(dev, NULL, false);
 
-                worker_free(worker);
+                /* Forward kernel event to libudev listeners */
+                device_broadcast(manager->monitor, dev, result);
         }
 
+        worker_free(worker);
+
         /* we can start new workers, try to schedule events */
         event_queue_start(manager);
 
@@ -2017,10 +2014,6 @@ static int main_loop(Manager *manager) {
         if (r < 0)
                 return log_error_errno(r, "Failed to create SIGHUP event source: %m");
 
-        r = sd_event_add_signal(manager->event, NULL, SIGCHLD, on_sigchld, manager);
-        if (r < 0)
-                return log_error_errno(r, "Failed to create SIGCHLD event source: %m");
-
         r = sd_event_set_watchdog(manager->event, true);
         if (r < 0)
                 return log_error_errno(r, "Failed to create watchdog event source: %m");
index 90065b410b075ae403247f7e6aed7a44948eeff9..aa16582d9e4f3d0cf239b30410c257e9bdacb0af 100644 (file)
@@ -5,13 +5,13 @@
 #include "alloc-util.h"
 #include "blockdev-util.h"
 #include "chase-symlinks.h"
+#include "devnum-util.h"
 #include "escape.h"
 #include "main-func.h"
 #include "mkdir.h"
 #include "mount-util.h"
 #include "mountpoint-util.h"
 #include "path-util.h"
-#include "stat-util.h"
 #include "string-util.h"
 #include "volatile-util.h"
 
index 7faa12ef793f803d54bed2206fcd19a5e5c1b2bf..1001cd7cc8eb8a0be0bb7e55859a4dd15013f502 100755 (executable)
@@ -91,7 +91,7 @@ def setUpModule():
 def tearDownModule():
     global tmpmounts
     for d in tmpmounts:
-        subprocess.check_call(["umount", d])
+        subprocess.check_call(["umount", "--lazy", d])
     for u in stopped_units:
         subprocess.call(["systemctl", "stop", u])
     for u in running_units:
index 3aeac655780f5b6810252941a3c71bf848f9adfa..802bc1f3de886b96566e01866ea65989ef2a4aee 100755 (executable)
@@ -33,6 +33,10 @@ BEGIN {
     }
 }
 
+# Relax sd-device's sysfs verification, since we want to provide a fake sysfs
+# here that actually is a tmpfs.
+$ENV{"SYSTEMD_DEVICE_VERIFY_SYSFS"}="0";
+
 my $udev_bin            = "./test-udev";
 my $valgrind            = 0;
 my $gdb                 = 0;