]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #18701 from bugaevc/mdns-unicast
authorLennart Poettering <lennart@poettering.net>
Mon, 12 Apr 2021 15:53:38 +0000 (17:53 +0200)
committerGitHub <noreply@github.com>
Mon, 12 Apr 2021 15:53:38 +0000 (17:53 +0200)
resolved: reply using unicast mDNS when appropriate

255 files changed:
.mkosi/mkosi.arch
TODO
docs/BOOT_LOADER_INTERFACE.md
docs/BOOT_LOADER_SPECIFICATION.md
docs/COREDUMP_PACKAGE_METADATA.md [new file with mode: 0644]
docs/JOURNAL_NATIVE_PROTOCOL.md [new file with mode: 0644]
hwdb.d/60-keyboard.hwdb
man/homectl.xml
man/oomd.conf.xml
man/org.freedesktop.systemd1.xml
man/sd_bus_error.xml
man/sd_bus_is_open.xml
man/sd_journal_print.xml
man/systemd-boot.xml
man/systemd-coredump.xml
man/systemd-cryptenroll.xml
man/systemd-cryptsetup@.service.xml
man/systemd-journald.service.xml
man/systemd-tmpfiles.xml
man/systemd-udevd.service.xml
man/systemd.net-naming-scheme.xml
man/systemd.resource-control.xml
man/tmpfiles.d.xml
man/udev.conf.xml
meson.build
mkosi.build
po/ko.po
shell-completion/bash/machinectl
shell-completion/bash/networkctl
shell-completion/bash/systemd-analyze
shell-completion/bash/systemd-cat
shell-completion/bash/systemd-cgls
shell-completion/bash/systemd-cgtop
shell-completion/bash/systemd-delta
shell-completion/bash/systemd-detect-virt
shell-completion/bash/systemd-id128
shell-completion/bash/systemd-nspawn
shell-completion/bash/systemd-path
src/backlight/backlight.c
src/basic/cgroup-util.c
src/basic/cgroup-util.h
src/basic/copy.c
src/basic/efivars.c
src/basic/env-util.c
src/basic/errno-util.h
src/basic/fileio.c
src/basic/in-addr-util.c
src/basic/locale-util.c
src/basic/locale-util.h
src/basic/login-util.h
src/basic/path-util.c
src/basic/path-util.h
src/basic/proc-cmdline.c
src/basic/recovery-key.c
src/basic/socket-util.h
src/basic/strbuf.c
src/basic/unit-def.c
src/core/bpf-firewall.c
src/core/bpf-foreign.c [new file with mode: 0644]
src/core/bpf-foreign.h [new file with mode: 0644]
src/core/cgroup.c
src/core/cgroup.h
src/core/dbus-cgroup.c
src/core/dbus-execute.c
src/core/dbus-manager.c
src/core/dbus-scope.c
src/core/dbus-service.c
src/core/dbus-timer.c
src/core/dbus-unit.c
src/core/dbus.c
src/core/execute.c
src/core/load-fragment-gperf.gperf.m4
src/core/load-fragment.c
src/core/load-fragment.h
src/core/main.c
src/core/manager.c
src/core/meson.build
src/core/selinux-access.c
src/core/unit.c
src/core/unit.h
src/coredump/coredump.c
src/coredump/coredumpctl.c
src/coredump/stacktrace.c
src/coredump/stacktrace.h
src/cryptsetup/cryptsetup.c
src/gpt-auto-generator/gpt-auto-generator.c
src/home/homectl.c
src/home/homed-bus.c
src/home/homed-home.c
src/home/homed-manager.c
src/home/homework-luks.c
src/home/user-record-util.c
src/import/importd.c
src/libsystemd-network/dhcp6-option.c
src/libsystemd-network/network-internal.h
src/libsystemd-network/sd-dhcp-lease.c
src/libsystemd-network/sd-dhcp6-client.c
src/libsystemd/libsystemd.sym
src/libsystemd/meson.build
src/libsystemd/sd-bus/bus-error.c
src/libsystemd/sd-bus/sd-bus.c
src/libsystemd/sd-device/device-enumerator.c
src/libsystemd/sd-device/device-monitor.c
src/libsystemd/sd-device/device-util.c [new file with mode: 0644]
src/libsystemd/sd-device/device-util.h
src/libsystemd/sd-device/sd-device.c
src/libsystemd/sd-device/test-device-util.c [new file with mode: 0644]
src/libsystemd/sd-device/test-sd-device-monitor.c
src/libsystemd/sd-event/sd-event.c
src/libsystemd/sd-netlink/generic-netlink.c
src/libudev/libudev-monitor.c
src/locale/localed.c
src/login/logind-dbus.c
src/login/logind-seat-dbus.c
src/login/logind-session-dbus.c
src/machine/image-dbus.c
src/machine/machine-dbus.c
src/machine/machined-dbus.c
src/machine/operation.c
src/network/networkctl.c
src/network/networkd-dhcp-common.c
src/network/networkd-dhcp6.c
src/network/networkd-dhcp6.h
src/network/networkd-link-bus.c
src/network/networkd-link.c
src/network/networkd-manager-bus.c
src/network/networkd-manager.c
src/network/networkd-manager.h
src/network/networkd-ndisc.c
src/notify/notify.c
src/nss-resolve/nss-resolve.c
src/oom/oomd-manager.c
src/oom/oomd-manager.h
src/oom/oomd-util.c
src/oom/oomd-util.h
src/oom/oomd.c
src/oom/test-oomd-util.c
src/partition/test-repart.sh
src/portable/portabled-bus.c
src/portable/portabled-image-bus.c
src/portable/portabled-operation.c
src/resolve/resolved-bus.c
src/resolve/resolved-dns-cache.c
src/resolve/resolved-dns-dnssec.c
src/resolve/resolved-dns-query.c
src/resolve/resolved-dns-stub.c
src/resolve/resolved-dns-trust-anchor.c
src/resolve/resolved-link-bus.c
src/shared/base-filesystem.c
src/shared/bpf-program.c
src/shared/bpf-program.h
src/shared/bus-message-util.c
src/shared/bus-unit-util.c
src/shared/conf-parser.c
src/shared/dissect-image.c
src/shared/firewall-util-iptables.c
src/shared/firewall-util-private.h
src/shared/format-table.c
src/shared/netif-naming-scheme.c
src/shared/netif-naming-scheme.h
src/shared/openssl-util.c
src/shared/pkcs11-util.c
src/shared/pretty-print.c
src/shared/qrcode-util.c
src/shared/sleep-config.c
src/shared/tpm2-util.c
src/shared/varlink.c
src/systemctl/systemctl-logind.c
src/systemctl/systemctl-show.c
src/systemctl/systemctl-start-unit.c
src/systemd/sd-device.h
src/systemd/sd-dhcp-lease.h
src/test/meson.build
src/test/test-bpf-foreign-programs.c [new file with mode: 0644]
src/test/test-capability.c
src/test/test-cgroup-mask.c
src/test/test-extract-word.c
src/test/test-firewall-util.c
src/test/test-path-util.c
src/timedate/timedatectl.c
src/timedate/timedated.c
src/tmpfiles/tmpfiles.c
src/udev/scsi_id/scsi_id.c
src/udev/udev-builtin-net_id.c
test/TEST-52-HONORFIRSTSHUTDOWN/test.sh
test/fuzz/fuzz-unit-file/directives-all.service [new file with mode: 0644]
test/fuzz/fuzz-unit-file/directives.automount [new file with mode: 0644]
test/fuzz/fuzz-unit-file/directives.mount [new file with mode: 0644]
test/fuzz/fuzz-unit-file/directives.path [new file with mode: 0644]
test/fuzz/fuzz-unit-file/directives.scope
test/fuzz/fuzz-unit-file/directives.service
test/fuzz/fuzz-unit-file/directives.slice [new file with mode: 0644]
test/fuzz/fuzz-unit-file/directives.socket [new file with mode: 0644]
test/fuzz/fuzz-unit-file/directives.swap [new file with mode: 0644]
test/fuzz/fuzz-unit-file/directives.timer [new file with mode: 0644]
test/fuzz/fuzz-unit-file/github-19178 [new file with mode: 0644]
test/fuzz/fuzz-unit-file/oss-fuzz-32991 [new file with mode: 0644]
test/test-execute/exec-standardoutput-append.service
test/test-execute/exec-standardoutput-file.service
test/test-execute/exec-standardoutput-truncate.service
test/test-functions
test/testsuite-28.units/specifier-j-wants.service
test/testsuite-52.units/testsuite-52.sh
test/units/testsuite-03.sh
test/units/testsuite-04.sh
test/units/testsuite-12.sh
test/units/testsuite-13.sh
test/units/testsuite-15.sh
test/units/testsuite-17.01.sh
test/units/testsuite-17.02.sh
test/units/testsuite-17.03.sh
test/units/testsuite-17.04.sh
test/units/testsuite-17.05.sh
test/units/testsuite-18.sh
test/units/testsuite-19.sh
test/units/testsuite-20.sh
test/units/testsuite-22.01.sh
test/units/testsuite-22.02.sh
test/units/testsuite-22.03.sh
test/units/testsuite-22.04.sh
test/units/testsuite-22.06.sh
test/units/testsuite-22.07.sh
test/units/testsuite-22.08.sh
test/units/testsuite-22.11.sh [new file with mode: 0755]
test/units/testsuite-23.sh
test/units/testsuite-25.sh
test/units/testsuite-26.sh
test/units/testsuite-29.sh
test/units/testsuite-30.sh
test/units/testsuite-31.sh
test/units/testsuite-33.sh
test/units/testsuite-34.sh
test/units/testsuite-36.sh
test/units/testsuite-37.sh
test/units/testsuite-38.sh
test/units/testsuite-39.sh
test/units/testsuite-40.sh
test/units/testsuite-41.sh
test/units/testsuite-42.sh
test/units/testsuite-43.sh
test/units/testsuite-44.sh
test/units/testsuite-46.sh
test/units/testsuite-47-repro.sh
test/units/testsuite-47.sh
test/units/testsuite-48.sh
test/units/testsuite-49.sh
test/units/testsuite-50.sh
test/units/testsuite-54.sh
test/units/testsuite-55.sh
test/units/testsuite-56.sh
tools/check-directives.sh
units/meson.build
units/system-systemd\x2dcryptsetup.slice
units/systemd-firstboot.service
units/systemd-sysusers.service

index 6192c191045fad737ed5b297eecd0d85233c110b..867a869e1afc015abcb0fd682ee1387c8209dedf 100644 (file)
@@ -42,6 +42,7 @@ BuildPackages=
         python
         python-lxml
         qrencode
+        rsync
         xz
         zstd
 
diff --git a/TODO b/TODO
index f3e0ddaac01d207df7448e5755a5faffd9569178..0df3aefc393d230b59a4ba04b0843b4274f1ffd8 100644 (file)
--- a/TODO
+++ b/TODO
@@ -22,6 +22,36 @@ Janitorial Clean-ups:
 
 Features:
 
+* nspawn: support uid mapping bind mounts, as defined available in kernel 5.12,
+  for all our disk image needs
+
+* homed: if kernel 5.12 uid mapping mounts exist, use that instead of recursive
+  chowns.
+
+* cryptsetup: tweak tpm2-device=auto logic, abort quickly if firmware tells us
+  there isn't any TPM2 device anyway. that way, we'll wait for the TPM2 device
+  to show up only if registered in LUKS header + the firmware suggests there is
+  a device worth waiting for.
+
+* systemd-sysext: optionally, run it in initrd already, before transitioning
+  into host, to open up possibility for services shipped like that.
+
+* add a flag to the GPT spec that says "grow my fs to partition size", and make
+  it settable via systemd-repart. Add in growfs jobs in
+  systemd-gpt-auto-generator when it is set, and issue the ioctls while
+  mounting in systemd-npsawn --image=. That way systemd-repart suffices to
+  enlarge an image.
+
+* add a new switch --auto-definitions=yes/no or so to systemd-repart. If
+  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.
+
+* add a switch to homectl (maybe called --first-boot) where it will check if
+  any non-system users exist, and if not prompts interactively for basic user
+  info, mimicing systemd-firstboot. Then, place this in a service that runs
+  after systemd-homed, but before gdm and friends, as a simple, barebones
+  fallback logic to get a regular user created on uninitialized systems.
+
 * maybe add a tool that displays most recent journal logs as QR code to scan
   off screen and run it automatically on boot failures, emergency logs and
   such. Use DRM APIs directly, see
@@ -36,7 +66,9 @@ Features:
 * systemd-repart: read LUKS encryption key from $CREDENTIALS_PATH
 
 * introduce /dev/disk/root/* symlinks that allow referencing partitions on the
-  disk the rootfs is on in a reasonably secure way.
+  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
+  already have it.
 
 * systemd-repart: add a switch to factory reset the partition table without
   immediately applying the new configuration again. i.e. --factory-reset=leave
@@ -179,16 +211,12 @@ Features:
 * Add service setting to run a service within the specified VRF. i.e. do the
   equivalent of "ip vrf exec".
 
-* export action of device object on sd-device, so that monitor becomes useful
-
-* add root=tmpfs that mounts a tmpfs to /sysroot (to be used in combination
-  with usr=…, for a similar effect as systemd.volatile=yes but without the
-  "hide-out" effect). Also, add root=gpt-auto-late support or so, that is like
-  root=gpt-auto but initially mounts a tmpfs to /sysroot, and then revisits
-  later after systemd-repart ran. Usecase: let's ship images with only /usr
-  partition, then on first boot create the root partition. In this case we want
-  to read the repart data from /usr before the root partition exists. Add
-  usr=gpt-auto that automatically finds a /usr partition.
+* Add root=gpt-auto-late support or so, that is like root=gpt-auto but
+  initially mounts a tmpfs to /sysroot, and then revisits later after
+  systemd-repart ran. Usecase: let's ship images with only /usr partition, then
+  on first boot create the root partition. In this case we want to read the
+  repart data from /usr before the root partition exists. Add usr=gpt-auto that
+  automatically finds a /usr partition.
 
 * change SwitchRoot() implementation in PID 1 to use pivot_root(".", "."), as
   documented in the pivot_root(2) man page, so that we can drop the /oldroot
index 15a575da53131e0ba23d9ffff30fdabee49eb1d4..be3b6e401de7bdc36c9afdb67c768db4746390af 100644 (file)
@@ -130,7 +130,7 @@ names for them in UIs.
    discovered Windows installation might have the identifier `auto-windows` or
    `auto-windows-10` or so.).
 
-4. Similar, boot menu entries referring to Apple MacOS X installations should
+4. Similar, boot menu entries referring to Apple macOS installations should
    use the identifier `osx` or one that is prefixed with `osx-`. If such an
    entry is automatically discovered by the boot loader use `auto-osx` as
    identifier, or `auto-osx-` as prefix for the identifier, see above.
index 290977142cc6055acb47a0e83f577e926bf7c362..e0ac90bb9f96ae8211a154cef2b845e9ebc7dcc8 100644 (file)
@@ -208,7 +208,7 @@ On EFI, any such images shall be added to the list of valid boot entries.
 
 Note that these configurations snippets do not need to be the only configuration source for a boot loader. It may extend this list of entries with additional items from other configuration files (for example its own native configuration files) or automatically detected other entries without explicit configuration.
 
-To make this explicitly clear: this specification is designed with "free" operating systems in mind, starting Windows or MacOS is out of focus with these configuration snippets, use boot-loader specific solutions for that. In the text above, if we say "OS" we hence imply "free", i.e. primarily Linux (though this could be easily be extended to the BSDs and whatnot).
+To make this explicitly clear: this specification is designed with "free" operating systems in mind, starting Windows or macOS is out of focus with these configuration snippets, use boot-loader specific solutions for that. In the text above, if we say "OS" we hence imply "free", i.e. primarily Linux (though this could be easily be extended to the BSDs and whatnot).
 
 Note that all paths used in the configuration snippets use a Unix-style "/" as path separator. This needs to be converted to an EFI-style "\" separator in EFI boot loaders.
 
diff --git a/docs/COREDUMP_PACKAGE_METADATA.md b/docs/COREDUMP_PACKAGE_METADATA.md
new file mode 100644 (file)
index 0000000..ab7c459
--- /dev/null
@@ -0,0 +1,106 @@
+---
+title: Package Metadata for Core Files
+category: Interfaces
+layout: default
+---
+
+# Package Metadata for Core Files
+
+*Intended audience: hackers working on userspace subsystems that create ELF binaries
+or parse ELF core files.*
+
+## Motivation
+
+ELF binaries get stamped with a unique, build-time generated hex string identifier called
+`build-id`, [which gets embedded as an ELF note called `.note.gnu.build-id`](https://fedoraproject.org/wiki/Releases/FeatureBuildId).
+In most cases, this allows to associate a stripped binary with its debugging information.
+It is used, for example, to dynamically fetch DWARF symbols from a debuginfo server, or
+to query the local package manager and find out the package metadata or, again, the DWARF
+symbols or program sources.
+
+However, this usage of the `build-id` requires either local metadata, usually set up by
+the package manager, or access to a remote server over the network. Both of those might
+be unavailable or forbidden.
+
+Thus it becomes desirable to add additional metadata to a binary at build time, so that
+`systemd-coredump` and other services analyzing core files are able to extract said
+metadata simply from the core file itself, without external dependencies.
+
+## Implementation
+
+This document will attempt to define a common metadata format specification, so that
+multiple implementers might use it when building packages, or core file analyzers, and
+so on.
+
+The metadata will be embedded in a single, new ELF header section, in a key-value JSON
+format. Implementers working on parsing core files should not assume a specific list of
+keys, but parse anything that is included in the section.
+Implementers working on build tools should strive to use the same key names, for
+consistency. The most common will be listed here. When corresponding to the content of
+os-release, the values should match, again for consistency.
+
+* Section header
+
+```
+SECTION: `.note.package`
+node-id: `0xcafe1a7e`
+Owner: `FDO` (FreeDesktop.org)
+Value: a JSON string with the structure described below
+```
+
+* JSON payload
+
+```json
+{
+     "type":"rpm",          # this provides a namespace for the package+package-version fields
+     "os":"fedora",
+     "osVersion":"33",
+     "name":"coreutils",
+     "version": "4711.0815.fc13.arm32",
+     "osCpe":               # A CPE name for the operating system, `CPE_NAME` from os-release is a good default
+}
+```
+
+A reference implementations of a [build-time tool is provided](https://github.com/systemd/package-notes)
+and can be used to generate a linker script, which can then be used at build time via
+```LDFLAGS="-Wl,-T,/path/to/generated/script"``` to include the note in the binary.
+
+Generator:
+```console
+$ ./generate-package-notes.py --rpm systemd-248~rc2-1.fc34
+SECTIONS
+{
+    .note.package : ALIGN(4) {
+        BYTE(0x04) BYTE(0x00) BYTE(0x00) BYTE(0x00) /* Length of Owner including NUL */
+        BYTE(0x64) BYTE(0x00) BYTE(0x00) BYTE(0x00) /* Length of Value including NUL */
+        BYTE(0x7e) BYTE(0x1a) BYTE(0xfe) BYTE(0xca) /* Note ID */
+        BYTE(0x46) BYTE(0x44) BYTE(0x4f) BYTE(0x00) /* Owner: 'FDO\x00' */
+        BYTE(0x7b) BYTE(0x22) BYTE(0x74) BYTE(0x79) /* Value: '{"type":"rpm","name":"systemd","version":"248~rc2-1.fc34","osCpe":"cpe:/o:fedoraproject:fedora:33"}\x00' */
+        BYTE(0x70) BYTE(0x65) BYTE(0x22) BYTE(0x3a)
+        BYTE(0x22) BYTE(0x72) BYTE(0x70) BYTE(0x6d)
+        BYTE(0x22) BYTE(0x2c) BYTE(0x22) BYTE(0x6e)
+        BYTE(0x61) BYTE(0x6d) BYTE(0x65) BYTE(0x22)
+        BYTE(0x3a) BYTE(0x22) BYTE(0x73) BYTE(0x79)
+        BYTE(0x73) BYTE(0x74) BYTE(0x65) BYTE(0x6d)
+        BYTE(0x64) BYTE(0x22) BYTE(0x2c) BYTE(0x22)
+        BYTE(0x76) BYTE(0x65) BYTE(0x72) BYTE(0x73)
+        BYTE(0x69) BYTE(0x6f) BYTE(0x6e) BYTE(0x22)
+        BYTE(0x3a) BYTE(0x22) BYTE(0x32) BYTE(0x34)
+        BYTE(0x38) BYTE(0x7e) BYTE(0x72) BYTE(0x63)
+        BYTE(0x32) BYTE(0x2d) BYTE(0x31) BYTE(0x2e)
+        BYTE(0x66) BYTE(0x63) BYTE(0x33) BYTE(0x34)
+        BYTE(0x22) BYTE(0x2c) BYTE(0x22) BYTE(0x6f)
+        BYTE(0x73) BYTE(0x43) BYTE(0x70) BYTE(0x65)
+        BYTE(0x22) BYTE(0x3a) BYTE(0x22) BYTE(0x63)
+        BYTE(0x70) BYTE(0x65) BYTE(0x3a) BYTE(0x2f)
+        BYTE(0x6f) BYTE(0x3a) BYTE(0x66) BYTE(0x65)
+        BYTE(0x64) BYTE(0x6f) BYTE(0x72) BYTE(0x61)
+        BYTE(0x70) BYTE(0x72) BYTE(0x6f) BYTE(0x6a)
+        BYTE(0x65) BYTE(0x63) BYTE(0x74) BYTE(0x3a)
+        BYTE(0x66) BYTE(0x65) BYTE(0x64) BYTE(0x6f)
+        BYTE(0x72) BYTE(0x61) BYTE(0x3a) BYTE(0x33)
+        BYTE(0x33) BYTE(0x22) BYTE(0x7d) BYTE(0x00)
+    }
+}
+INSERT AFTER .note.gnu.build-id;
+```
diff --git a/docs/JOURNAL_NATIVE_PROTOCOL.md b/docs/JOURNAL_NATIVE_PROTOCOL.md
new file mode 100644 (file)
index 0000000..fced459
--- /dev/null
@@ -0,0 +1,190 @@
+---
+title: Native Journal Protocol
+category: Interfaces
+layout: default
+---
+
+# Native Journal Protocol
+
+`systemd-journald.service` accepts log data via various protocols:
+
+* Classic RFC3164 BSD syslog via the `/dev/log` socket
+* STDOUT/STDERR of programs via `StandardOutput=journal` + `StandardError=journal` in service files (both of which are default settings)
+* Kernel log messages via the `/dev/kmsg` device node
+* Audit records via the kernel's audit subsystem
+* Structured log messages via `journald`'s native protocol
+
+The latter is what this document is about: if you are developing a program and
+want to pass structured log data to `journald`, it's the Journal's native
+protocol what you want to use. The systemd project provides the
+[`sd_journal_print(3)`](https://www.freedesktop.org/software/systemd/man/sd_journal_print.html)
+API that implements the client side of this protocol. This document explains
+what this interface does behind the scenes, in case you'd like to implement a
+client for it yourself, without linking to `libsystemd` — for example because
+you work in a programming language other than C or otherwise want to avoid the
+dependency.
+
+## Basics
+
+The native protocol of `journald` is spoken on the
+`/run/systemd/journal/socket` `AF_UNIX`/`SOCK_DGRAM` socket on which
+`systemd-journald.service` listens. Each datagram sent to this socket
+encapsulates one journal entry that shall be written. Since datagrams are
+subject to a size limit and we want to allow large journal entries, datagrams
+sent over this socket may come in one of two formats:
+
+* A datagram with the literal journal entry data as payload, without
+  any file descriptors attached.
+
+* A datagram with an empty payload, but with a single
+  [`memfd`](https://man7.org/linux/man-pages/man2/memfd_create.2.html)
+  file descriptor that contains the literal journal entry data.
+
+Other combinations are not permitted, i.e. datagrams with both payload and file
+descriptors, or datagrams with neither, or more than one file descriptor. Such
+datagrams are ignored. The `memfd` file descriptor should be fully sealed. The
+binary format in the datagram payload and in the `memfd` memory is
+identical. Typically a client would attempt to first send the data as datagram
+payload, but if this fails with an `EMSGSIZE` error it would immediately retry
+via the `memfd` logic.
+
+A client probably should bump up the `SO_SNDBUF` socket option of its `AF_UNIX`
+socket towards `journald` in order to delay blocking I/O as much as possible.
+
+## Data Format
+
+Each datagram should consist of a number of environment-like key/value
+assignments. Unlike environment variable assignments the value may contain NUL
+bytes however, as well as any other binary data. Keys may not include the `=`
+or newline characters (or any other control characters or non-ASCII characters)
+and may not be empty.
+
+Serialization into the datagram payload or `memfd` is straight-forward: each
+key/value pair is serialized via one of two methods:
+
+* The first method inserts a `=` character between key and value, and suffixes
+the result with `\n` (i.e. the newline character, ASCII code 10). Example: a
+key `FOO` with a value `BAR` is serialized `F`, `O`, `O`, `=`, `B`, `A`, `R`,
+`\n`.
+
+* The second method should be used if the value of a field contains a `\n`
+byte. In this case, the key name is serialized as is, followed by a `\n`
+character, followed by a (non-aligned) little-endian unsigned 64bit integer
+encoding the size of the value, followed by the literal value data, followed by
+`\n`. Example: a key `FOO` with a value `BAR` may be serialized using this
+second method as: `F`, `O`, `O`, `\n`, `\003`, `\000`, `\000`, `\000`, `\000`,
+`\000`, `\000`, `\000`, `B`, `A`, `R`, `\n`.
+
+If the value of a key/value pair contains a newline character (`\n`), it *must*
+be serialized using the second method. If it does not, either method is
+permitted. However, it is generally recommended to use the first method if
+possible for all key/value pairs where applicable since the generated datagrams
+are easily recognized and understood by the human eye this way, without any
+manual binary decoding — which improves the debugging experience a lot, in
+particular with tools such as `strace` that can show datagram content as text
+dump. After all, log messages are highly relevant for debugging programs, hence
+optimizing log traffic for readability without special tools is generally
+desirable.
+
+Note that keys that begin with `_` have special semantics in `journald`: they
+are *trusted* and implicitly appended by `journald` on the receiving
+side. Clients should not send them — if they do anyway, they will be ignored.
+
+The most important key/value pair to send is `MESSAGE=`, as that contains the
+actual log message text. Other relevant keys a client should send in most cases
+are `PRIORITY=`, `CODE_FILE=`, `CODE_LINE=`, `CODE_FUNC=`, `ERRNO=`. It's
+recommended to generate these fields implicitly on the client side. For further
+information see the [relevant documentation of these
+fields](https://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html).
+
+The order in which the fields are serialized within one datagram is undefined
+and may be freely chosen by the client. The server side might or might not
+retain or reorder it when writing it to the Journal.
+
+Some programs might generate multi-line log messages (e.g. a stack unwinder
+generating log output about a stack trace, with one line for each stack
+frame). It's highly recommended to send these as a single datagram, using a
+single `MESSAGE=` field with embedded newline characters between the lines (the
+second serialization method described above must hence be used for this
+field). If possible do not split up individual events into multiple Journal
+events that might then be processed and written into the Journal as separate
+entries. The Journal toolchain is capable of handling multi-line log entries
+just fine, and it's generally preferred to have a single set of metadata fields
+associated with each multi-line message.
+
+Note that the same keys may be used multiple times within the same datagram,
+with different values. The Journal supports this and will write such entries to
+disk without complaining. This is useful for associating a single log entry
+with multiple suitable objects of the same type at once. This should only be
+used for specific Journal fields however, where this is expected. Do not use
+this for Journal fields where this is not expected and where code reasonably
+assumes per-event uniqueness of the keys. In most cases code that consumes and
+displays log entries is likely to ignore such non-unique fields or only
+consider the first of the specified values. Specifically, if a Journal entry
+contains multiple `MESSAGE=` fields, likely only the first one is
+displayed. Note that a well-written logging client library thus will not use a
+plain dictionary for accepting structured log metadata, but rather a data
+structure that allows non-unique keys, for example an array, or a dictionary
+that optionally maps to a set of values instead of a single value.
+
+## Example Datagram
+
+Here's an encoded message, with various common fields, all encoded according to
+the first serialization method, with the exception of one, where the value
+contains a newline character, and thus the second method is needed to be used.
+
+```
+PRIORITY=3\n
+SYSLOG_FACILITY=3\n
+CODE_FILE=src/foobar.c\n
+CODE_LINE=77\n
+BINARY_BLOB\n
+\004\000\000\000\000\000\000\000xx\nx\n
+CODE_FUNC=some_func\n
+SYSLOG_IDENTIFIER=footool\n
+MESSAGE=Something happened.\n
+```
+
+(Lines are broken here after each `\n` to make things more readable. C-style
+backslash escaping is used.)
+
+## Automatic Protocol Upgrading
+
+It might be wise to automatically upgrade to logging via the Journal's native
+protocol in clients that previously used the BSD syslog protocol. Behaviour in
+this case should be pretty obvious: try connecting a socket to
+`/run/systemd/journal/socket` first (on success use the native Journal
+protocol), and if that fails fall back to `/dev/log` (and use the BSD syslog
+protocol).
+
+Programs normally logging to STDERR might also choose to upgrade to native
+Journal logging in case they are invoked via systemd's service logic, where
+STDOUT and STDERR are going to the Journal anyway. By preferring the native
+protocol over STDERR-based logging, structured metadata can be passed along,
+including priority information and more — which is not available on STDERR
+based logging. If a program wants to detect automatically whether its STDERR is
+connected to the Journal's stream transport, look for the `$JOURNAL_STREAM`
+environment variable. The systemd service logic sets this variable to a
+colon-separated pair of device and inode number (formatted in decimal ASCII) of
+the STDERR file descriptor. If the `.st_dev` and `.st_ino` fields of the
+`struct stat` data returned by `fstat(STDERR_FILENO, …)` match these values a
+program can be sure its STDERR is connected to the Journal, and may then opt to
+upgrade to the native Journal protocol via an `AF_UNIX` socket of its own, and
+cease to use STDERR.
+
+Why bother with this environment variable check? A service program invoked by
+systemd might employ shell-style I/O redirection on invoked subprograms, and
+those should likely not upgrade to the native Journal protocol, but instead
+continue to use the redirected file descriptors passed to them. Thus, by
+comparing the device and inode number of the actual STDERR file descriptor with
+the one the service manager passed, one can make sure that no I/O redirection
+took place for the current program.
+
+## Alternative Implementations
+
+If you are looking for alternative implementations of this protocol (besides
+systemd's own in `sd_journal_print()`), consider
+[GLib's](https://gitlab.gnome.org/GNOME/glib/-/blob/master/glib/gmessages.c) or
+[`dbus-broker`'s](https://github.com/bus1/dbus-broker/blob/main/src/util/log.c).
+
+And that's already all there is to it.
index 5485f892bb56cb4504b1e5213f7a0bbb4b014bd5..323d9b0de7ba882562a18648c35d310af304c8bc 100644 (file)
@@ -684,6 +684,21 @@ evdev:atkbd:dmi:bvn*:bvr*:svnHP*:pnHP*ProBook*645*G4*:*
  KEYBOARD_KEY_73=slash                                  # Slash key
  KEYBOARD_KEY_f8=wlan                                   # Wireless HW switch button
 
+# HP ProBook 455 G5
+evdev:atkbd:dmi:bvn*:bvr*:svnHP*:pnHP*ProBook*455*G5*:*
+ KEYBOARD_KEY_85=unknown                                # lid close; also reported via special evdev
+ KEYBOARD_KEY_f8=wlan                                   # Wireless HW switch button
+
+# HP mt44 Mobile Thin Client
+evdev:atkbd:dmi:bvn*:bvr*:svnHP*:pnHP*mt44*Mobile*Thin*Client*:*
+ KEYBOARD_KEY_64=calendar                               # Calendar icon (Fn + F12)
+ KEYBOARD_KEY_6d=displaytoggle                          # Display icon
+ KEYBOARD_KEY_66=connect                                # Pickup phone button → connect → XF86Go
+ KEYBOARD_KEY_65=cancel                                 # Hangup phone button → cancel → Cancel
+ KEYBOARD_KEY_81=f20                                    # Fn+F8; Microphone mute button, should be micmute
+ KEYBOARD_KEY_85=unknown                                # lid close; also reported via special evdev
+ KEYBOARD_KEY_f8=wlan                                   # Wireless HW switch button
+
 # HP Stream 7
 # The ACPI tables contains a gpio-keys entry for a non connected GPIO
 # causing spurious events, map this to unknown to disable it
@@ -1282,13 +1297,18 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*A10SC*:*
 
 # MSI Modern series
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-StarInternational*:pnModern*:*
+ KEYBOARD_KEY_56=backslash                              # secondary backslash key
  KEYBOARD_KEY_f1=f20                                    # Fn+F5 micmute
  KEYBOARD_KEY_76=f21                                    # Fn+F4 touchpad, becomes meta+ctrl+toggle
  KEYBOARD_KEY_91=prog1                                  # Fn+F7 Creation Center, sometime F7
  KEYBOARD_KEY_f2=prog2                                  # Fn+F12 screen rotation
+ KEYBOARD_KEY_8d=prog3                                  # Fn+a
+ KEYBOARD_KEY_8c=prog4                                  # Fn+z
+ KEYBOARD_KEY_f5=fn_esc                                 # Fn+esc toggle the behaviour of Fn keys
  KEYBOARD_KEY_97=unknown                                # lid close
  KEYBOARD_KEY_98=unknown                                # lid open
-                                                        #Fn+PrntScr sends meta+shif+s
+                                                        # Fn+PrntScr sends meta+shift+s
+
 
 ###########################################################
 # MSI
index 184bdcf6fd0305271faf9e0e6d6127192bbb3923..f2858166f7babdde64d67265d4bb9ed83ab532fc 100644 (file)
     <title>Exit status</title>
 
     <para>On success, 0 is returned, a non-zero failure code otherwise.</para>
+
+    <para>When a command is invoked with <command>with</command>, the exit status of the child is
+    propagated. Effectively, <command>homectl</command> will exit without error if the command is
+    successfully invoked <emphasis>and</emphasis> finishes successfully.</para>
   </refsect1>
 
   <xi:include href="common-variables.xml" />
index 6156c98fbd90dc04976a888deef5bf1fbc68d6c9..27914e06999137a04cd1bd0ece21b70e878be42b 100644 (file)
@@ -52,9 +52,9 @@
 
         <listitem><para>Sets the limit for swap usage on the system before <command>systemd-oomd</command>
         will take action. If the fraction of swap used on the system is more than what is defined here,
-        <command>systemd-oomd</command> will act on eligible descendant control groups, starting from the
-        ones with the highest swap usage to the lowest swap usage. Which control groups are monitored and
-        what action gets taken depends on what the unit has configured for
+        <command>systemd-oomd</command> will act on eligible descendant control groups with swap usage greater
+        than 5% of total swap, starting from the ones with the highest swap usage. Which
+        control groups are monitored and what action gets taken depends on what the unit has configured for
         <varname>ManagedOOMSwap=</varname>.  Takes a value specified in percent (when suffixed with "%"),
         permille ("‰") or permyriad ("‱"), between 0% and 100%, inclusive. Defaults to 90%.</para></listitem>
       </varlistentry>
@@ -81,7 +81,7 @@
         <listitem><para>Sets the amount of time a unit's control group needs to have exceeded memory pressure
         limits before <command>systemd-oomd</command> will take action. Memory pressure limits are defined by
         <varname>DefaultMemoryPressureLimit=</varname> and <varname>ManagedOOMMemoryPressureLimit=</varname>.
-        Defaults to 30 seconds when this property is unset or set to 0.</para></listitem>
+        Must be set to 0, or at least 1 second. Defaults to 30 seconds when unset or 0.</para></listitem>
       </varlistentry>
 
     </variablelist>
index 614871bce206ec72004e6973fa8e3e3fb57fca66..e1b9a5e490e81c57f526a1918f98325ae98fbd08 100644 (file)
@@ -2474,6 +2474,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
       readonly u ManagedOOMMemoryPressureLimit = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly s ManagedOOMPreference = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly a(ss) BPFProgram = [...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly as Environment = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
@@ -3008,6 +3010,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <!--property ManagedOOMPreference is not documented!-->
 
+    <!--property BPFProgram is not documented!-->
+
     <!--property EnvironmentFiles is not documented!-->
 
     <!--property PassEnvironment is not documented!-->
@@ -3566,6 +3570,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMPreference"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="BPFProgram"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="Environment"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="EnvironmentFiles"/>
@@ -4251,6 +4257,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
       readonly u ManagedOOMMemoryPressureLimit = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly s ManagedOOMPreference = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly a(ss) BPFProgram = [...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly as Environment = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
@@ -4811,6 +4819,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
 
     <!--property ManagedOOMPreference is not documented!-->
 
+    <!--property BPFProgram is not documented!-->
+
     <!--property EnvironmentFiles is not documented!-->
 
     <!--property PassEnvironment is not documented!-->
@@ -5365,6 +5375,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
 
     <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMPreference"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="BPFProgram"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="Environment"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="EnvironmentFiles"/>
@@ -5952,6 +5964,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
       readonly u ManagedOOMMemoryPressureLimit = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly s ManagedOOMPreference = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly a(ss) BPFProgram = [...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly as Environment = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
@@ -6440,6 +6454,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
 
     <!--property ManagedOOMPreference is not documented!-->
 
+    <!--property BPFProgram is not documented!-->
+
     <!--property EnvironmentFiles is not documented!-->
 
     <!--property PassEnvironment is not documented!-->
@@ -6912,6 +6928,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
 
     <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMPreference"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="BPFProgram"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="Environment"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="EnvironmentFiles"/>
@@ -7620,6 +7638,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
       readonly u ManagedOOMMemoryPressureLimit = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly s ManagedOOMPreference = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly a(ss) BPFProgram = [...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly as Environment = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
@@ -8094,6 +8114,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
 
     <!--property ManagedOOMPreference is not documented!-->
 
+    <!--property BPFProgram is not documented!-->
+
     <!--property EnvironmentFiles is not documented!-->
 
     <!--property PassEnvironment is not documented!-->
@@ -8552,6 +8574,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
 
     <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMPreference"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="BPFProgram"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="Environment"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="EnvironmentFiles"/>
@@ -9113,6 +9137,8 @@ node /org/freedesktop/systemd1/unit/system_2eslice {
       readonly u ManagedOOMMemoryPressureLimit = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly s ManagedOOMPreference = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly a(ss) BPFProgram = [...];
   };
   interface org.freedesktop.DBus.Peer { ... };
   interface org.freedesktop.DBus.Introspectable { ... };
@@ -9251,6 +9277,8 @@ node /org/freedesktop/systemd1/unit/system_2eslice {
 
     <!--property ManagedOOMPreference is not documented!-->
 
+    <!--property BPFProgram is not documented!-->
+
     <!--Autogenerated cross-references for systemd.directives, do not edit-->
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
@@ -9393,6 +9421,8 @@ node /org/freedesktop/systemd1/unit/system_2eslice {
 
     <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMPreference"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="BPFProgram"/>
+
     <!--End of Autogenerated section-->
 
     <refsect2>
@@ -9554,6 +9584,8 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
       readonly u ManagedOOMMemoryPressureLimit = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly s ManagedOOMPreference = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+      readonly a(ss) BPFProgram = [...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s KillMode = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
@@ -9708,6 +9740,8 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
 
     <!--property ManagedOOMPreference is not documented!-->
 
+    <!--property BPFProgram is not documented!-->
+
     <!--property KillMode is not documented!-->
 
     <!--property KillSignal is not documented!-->
@@ -9876,6 +9910,8 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
 
     <variablelist class="dbus-property" generated="True" extra-ref="ManagedOOMPreference"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="BPFProgram"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="KillMode"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="KillSignal"/>
index bfc5caf4e24b43d2f87c613c4d1a6dc7b87f49ad..bb8015de5ee7fd94067ac0a5c94b0062b2f73c74 100644 (file)
   <refsect1>
     <title>Description</title>
 
-    <para>The <structname>sd_bus_error</structname> structure carries
-    information about a D-Bus error condition. The functions described
-    below may be used to set and query fields in this structure. The
-    <structfield>name</structfield> field contains a short identifier
-    of an error. It should follow the rules for error names described
-    in the D-Bus specification, subsection <ulink
-    url="http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names">Valid
-    Names</ulink>. A number of common, standardized error names are
-    described in
-    <citerefentry><refentrytitle>sd-bus-errors</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
-    but additional domain-specific errors may be defined by
-    applications. The <structfield>message</structfield> field usually
-    contains a human-readable string describing the details, but might
-    be <constant>NULL</constant>. An unset <structname>sd_bus_error</structname> structure
-    should have both fields initialized to <constant>NULL</constant>. Set an error
-    structure to <constant>SD_BUS_ERROR_NULL</constant> in order to
-    reset both fields to <constant>NULL</constant>. When no longer necessary, resources
-    held by the <structname>sd_bus_error</structname> structure should
-    be destroyed with <function>sd_bus_error_free()</function>.</para>
-
-    <para><function>sd_bus_error_set()</function> sets an error
-    structure to the specified name and message strings. The strings
-    will be copied into internal, newly allocated memory. It is
-    essential to free the error structure again when it is not
-    required anymore (see above). The function will return an
-    <varname>errno</varname>-like negative value (see <citerefentry
+    <para>The <structname>sd_bus_error</structname> structure carries information about a D-Bus error
+    condition, or lack thereof. The functions described below may be used to set and query fields in this
+    structure.
+    <itemizedlist>
+      <listitem><para>The <structfield>name</structfield> field contains a short identifier of an error. It
+      should follow the rules for error names described in the D-Bus specification, subsection <ulink
+      url="http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names">Valid
+      Names</ulink>. A number of common, standardized error names are described in
+      <citerefentry><refentrytitle>sd-bus-errors</refentrytitle><manvolnum>3</manvolnum></citerefentry>, but
+      additional domain-specific errors may be defined by applications.</para></listitem>
+
+      <listitem><para>The <structfield>message</structfield> field usually contains a human-readable string
+      describing the details, but might be <constant>NULL</constant>.</para></listitem>
+    </itemizedlist>
+    An unset <structname>sd_bus_error</structname> structure should have both fields initialized to
+    <constant>NULL</constant>, and signifies lack of an error, i.e. success. Assign
+    <constant>SD_BUS_ERROR_NULL</constant> to the structure in order to initialize both fields to
+    <constant>NULL</constant>. When no longer necessary, resources held by the
+    <structname>sd_bus_error</structname> structure should be destroyed with
+    <function>sd_bus_error_free()</function>.</para>
+
+    <para><function>sd_bus_error_set()</function> sets an error structure to the specified name and message
+    strings. The strings will be copied into internal, newly allocated memory. It is essential to free the
+    contents again when they are not required anymore (see above). Do not use this call on error structures
+    that have already been set. If you intend to reuse an error structure, free the old data stored in it
+    with <function>sd_bus_error_free()</function> first.</para>
+
+    <para><function>sd_bus_error_set()</function> will return an <varname>errno</varname>-like value (see
+    <citerefentry
     project='man-pages'><refentrytitle>errno</refentrytitle><manvolnum>3</manvolnum></citerefentry>)
-    determined from the specified error name.  Various well-known
-    D-Bus errors are converted to well-known <varname>errno</varname>
-    counterparts, and the other ones to <constant>-EIO</constant>. See
-    <citerefentry><refentrytitle>sd-bus-errors</refentrytitle><manvolnum>3</manvolnum></citerefentry>
-    for a list of well-known error names. Additional error mappings
-    may be defined with
-    <citerefentry><refentrytitle>sd_bus_error_add_map</refentrytitle><manvolnum>3</manvolnum></citerefentry>. If
-    <parameter>e</parameter> is <constant>NULL</constant>, no error structure is initialized,
-    but the error is still converted into an
-    <varname>errno</varname>-style error. If
-    <parameter>name</parameter> is <constant>NULL</constant>, it is
-    assumed that no error occurred, and 0 is returned. This means that
-    this function may be conveniently used in a
-    <function>return</function> statement. If
-    <parameter>message</parameter> is <constant>NULL</constant>, no message is set. This
-    call can fail if no memory may be allocated for the name and
-    message strings, in which case an
-    <constant>SD_BUS_ERROR_NO_MEMORY</constant> error might be set
-    instead and -ENOMEM be returned. Do not use this call on error
-    structures that are already initialized. If you intend to reuse an
-    error structure, free the old data stored in it with
-    <function>sd_bus_error_free()</function> first.</para>
+    determined from the specified error name <parameter>name</parameter>. If <parameter>name</parameter> is
+    <constant>NULL</constant>, it is assumed that no error occurred, and <constant>0</constant> is returned.
+    If <parameter>name</parameter> is nonnull, a negative value is always returned. If
+    <parameter>e</parameter> is <constant>NULL</constant>, no error structure is initialized, but
+    <parameter>name</parameter> is still converted into an <varname>errno</varname>-style value.</para>
+
+    <para>Various well-known D-Bus errors are converted to well-known <varname>errno</varname> counterparts,
+    and the other ones to <constant>-EIO</constant>. See
+    <citerefentry><refentrytitle>sd-bus-errors</refentrytitle><manvolnum>3</manvolnum></citerefentry> for a
+    list of well-known error names. Additional error mappings may be defined with
+    <citerefentry><refentrytitle>sd_bus_error_add_map</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+    </para>
+
+    <para><function>sd_bus_error_set()</function> is designed to be conveniently used in a
+    <function>return</function> statement. If <parameter>message</parameter> is <constant>NULL</constant>, no
+    message is set. This call can fail if no memory may be allocated for the name and message strings, in
+    which case an <constant>SD_BUS_ERROR_NO_MEMORY</constant> error will be set instead and
+    <constant>-ENOMEM</constant> returned. </para>
 
     <para><function>sd_bus_error_setf()</function> is similar to
     <function>sd_bus_error_set()</function>, but takes a <citerefentry
     <structfield>message</structfield> field.</para>
 
     <para><function>sd_bus_error_set_const()</function> is similar to
-    <function>sd_bus_error_set()</function>, but the string parameters
-    are not copied internally, and must hence remain constant and
-    valid for the lifetime of <parameter>e</parameter>. Use this call
-    to avoid memory allocations when setting error structures. Since
-    this call does not allocate memory, it will not fail with an
-    out-of-memory condition as
-    <function>sd_bus_error_set()</function> can, as described
-    above. Alternatively, the
-    <constant>SD_BUS_ERROR_MAKE_CONST()</constant> macro may be used
-    to generate a literal, constant bus error structure
-    on-the-fly.</para>
-
-    <para><function>sd_bus_error_set_errno()</function> will set
-    <structfield>name</structfield> from an
-    <varname>errno</varname>-like value that is converted to a D-Bus
+    <function>sd_bus_error_set()</function>, but the string parameters are not copied internally, and must
+    hence remain constant and valid for the lifetime of <parameter>e</parameter>. Use this call to avoid
+    memory allocations when setting error structures. Since this call does not allocate memory, it will not
+    fail with an out-of-memory condition as <function>sd_bus_error_set()</function> may, as described
+    above. Alternatively, the <constant>SD_BUS_ERROR_MAKE_CONST()</constant> macro may be used to generate a
+    literal, constant bus error structure on-the-fly.</para>
+
+    <para><function>sd_bus_error_set_errno()</function> will immediately return <constant>0</constant> if the
+    specified error parameter <parameter>error</parameter> is <constant>0</constant>. Otherwise, it will set
+    <structfield>name</structfield> from an <varname>errno</varname>-like value that is converted to a D-Bus
     error. <citerefentry
-    project='die-net'><refentrytitle>strerror_r</refentrytitle><manvolnum>3</manvolnum></citerefentry>
-    will be used to set <structfield>message</structfield>. Well-known
-    D-Bus error names will be used for <structfield>name</structfield>
-    if applicable, otherwise a name in the
-    <literal>System.Error.</literal> namespace will be generated. The
-    sign of the specified error number is ignored. The absolute value
-    is used implicitly. The call always returns a negative value, for
-    convenient usage in <function>return</function> statements. This
-    call might fail due to lack of memory, in which case an
-    <constant>SD_BUS_ERROR_NO_MEMORY</constant> error is set instead,
-    and -ENOMEM is returned.</para>
+    project='die-net'><refentrytitle>strerror_r</refentrytitle><manvolnum>3</manvolnum></citerefentry> will
+    be used to set <structfield>message</structfield>. Well-known D-Bus error names will be used for
+    <structfield>name</structfield> if applicable, otherwise a name in the <literal>System.Error.</literal>
+    namespace will be generated. The sign of the specified error number is ignored and the absolute value is
+    used implicitly. If the specified error <parameter>error</parameter> is non-zero, the call always returns
+    a negative value, for convenient usage in <function>return</function> statements. This call might fail
+    due to lack of memory, in which case an <constant>SD_BUS_ERROR_NO_MEMORY</constant> error is set instead,
+    and <constant>-ENOMEM</constant> is returned.</para>
 
     <para><function>sd_bus_error_set_errnof()</function> is similar to
     <function>sd_bus_error_set_errno()</function>, but in addition to
     project='man-pages'><refentrytitle>va_arg</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     parameter list.</para>
 
-    <para><function>sd_bus_error_get_errno()</function> converts the
-    <structfield>name</structfield> field of an error structure to an
-    <varname>errno</varname>-like (positive) value using the same
-    rules as <function>sd_bus_error_set()</function>.  If
-    <parameter>e</parameter> is <constant>NULL</constant>, 0 will be
-    returned.</para>
-
-    <para><function>sd_bus_error_copy()</function> will initialize
-    <parameter>dst</parameter> using the values in
-    <parameter>e</parameter>. If the strings in
-    <parameter>e</parameter> were set using
-    <function>sd_bus_error_set_const()</function>, they will be shared.
-    Otherwise, they will be copied. Returns a converted
-    <varname>errno</varname>-like, negative error code.</para>
-
-    <para><function>sd_bus_error_move()</function> is similar to <function>sd_bus_error_copy()</function>, but will
-    move any error information from <parameter>e</parameter> into <parameter>dst</parameter>, resetting the
-    former. This function cannot fail, as no new memory is allocated. Note that if <parameter>e</parameter> is not set
-    (or <constant>NULL</constant>) <parameter>dst</parameter> is initializated to
-    <constant>SD_BUS_ERROR_NULL</constant>. Moreover, if <parameter>dst</parameter> is <constant>NULL</constant> no
-    operation is executed on it and resources held by <parameter>e</parameter> are freed and reset. Returns a
-    converted <varname>errno</varname>-like, negative error code.</para>
+    <para><function>sd_bus_error_get_errno()</function> converts the <structfield>name</structfield> field of
+    an error structure to an <varname>errno</varname>-like (positive) value using the same rules as
+    <function>sd_bus_error_set()</function>.  If <parameter>e</parameter> is <constant>NULL</constant>,
+    <constant>0</constant> will be returned.</para>
+
+    <para><function>sd_bus_error_copy()</function> will initialize <parameter>dst</parameter> using the
+    values in <parameter>e</parameter>, if <parameter>e</parameter> has been set with an error value before.
+    Otherwise, it will return immediately. If the strings in <parameter>e</parameter> were set using
+    <function>sd_bus_error_set_const()</function>, they will be shared. Otherwise, they will be
+    copied. Returns a converted <varname>errno</varname>-like, negative error code or <constant>0</constant>.
+    Before this call, <parameter>dst</parameter> must be unset, i.e. either freshly initialized with
+    <constant>NULL</constant> or reset using <function>sd_bus_error_free()</function>.</para>
+
+    <para><function>sd_bus_error_move()</function> is similar to <function>sd_bus_error_copy()</function>,
+    but will move any error information from <parameter>e</parameter> into <parameter>dst</parameter>,
+    resetting the former. This function cannot fail, as no new memory is allocated. Note that if
+    <parameter>e</parameter> is not set, <parameter>dst</parameter> is initializated to
+    <constant>SD_BUS_ERROR_NULL</constant>. Moreover, if <parameter>dst</parameter> is
+    <constant>NULL</constant> no operation is executed on it and resources held by <parameter>e</parameter>
+    are freed and reset. Returns a converted <varname>errno</varname>-like, non-positive error value.</para>
 
     <para><function>sd_bus_error_is_set()</function> will return a
     non-zero value if <parameter>e</parameter> is
   <refsect1>
     <title>Return Value</title>
 
-    <para>The functions <function>sd_bus_error_set()</function>,
-    <function>sd_bus_error_setf()</function>, and
-    <function>sd_bus_error_set_const()</function>, when successful,
-    return the negative errno value corresponding to the
-    <parameter>name</parameter> parameter. The functions
-    <function>sd_bus_error_set_errno()</function>,
-    <function>sd_bus_error_set_errnof()</function> and
-    <function>sd_bus_error_set_errnofv()</function>, when successful,
-    return the negative value of the <parameter>error</parameter>
-    parameter. If an error occurs, one of the negative error values
-    listed below will be returned.</para>
+    <para>The functions <function>sd_bus_error_set()</function>, <function>sd_bus_error_setf()</function>,
+    and <function>sd_bus_error_set_const()</function> always return <constant>0</constant> when the specified
+    error value is <constant>NULL</constant>, and a negative errno-like value corresponding to the
+    <parameter>name</parameter> parameter otherwise. The functions
+    <function>sd_bus_error_set_errno()</function>, <function>sd_bus_error_set_errnof()</function> and
+    <function>sd_bus_error_set_errnofv()</function>, return <constant>0</constant> when the specified error
+    value is <constant>0</constant>, and a a negative errno-like value corresponding to the
+    <parameter>error</parameter> parameter otherwise. If an error occurs internally, one of the negative
+    error values listed below will be returned.</para>
 
     <para><function>sd_bus_error_get_errno()</function> returns
     <constant>false</constant> when <parameter>e</parameter> is
     <constant>NULL</constant>, and a positive errno value mapped from
     <parameter>e-&gt;name</parameter> otherwise.</para>
 
-    <para><function>sd_bus_error_copy()</function> and <function>sd_bus_error_move()</function> return 0 or a positive
-    integer on success, and a negative error value converted from the error name otherwise.</para>
+    <para><function>sd_bus_error_copy()</function> and <function>sd_bus_error_move()</function> return a
+    negative error value converted from the source error, and zero if the error has not been set.</para>
 
     <para><function>sd_bus_error_is_set()</function> returns a
     non-zero value when <parameter>e</parameter> and the
index 8e0aed29b3319c6768a1d99f703507215cb6eecd..621ed272bb8eba1b990f4f28551c58b90d4d29f1 100644 (file)
@@ -57,6 +57,9 @@
     zero outside of this state, and positive otherwise. Effectively, this function returns positive while regular
     messages can be sent or received on the connection.</para>
 
+    <para>The <parameter>bus</parameter> argument may be <constant>NULL</constant>, zero is also returned in
+    that case.</para>
+
     <para>To be notified when the connection is fully established, use
     <citerefentry><refentrytitle>sd_bus_set_connected_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry> and
     install a match for the <function>Connected()</function> signal on the
@@ -68,8 +71,8 @@
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success, these functions return 0 or a positive integer. On failure, they return a negative errno-style
-    error code.</para>
+    <para>Those functions return 0 if the bus is <emphasis>not</emphasis> in the given state, and a positive
+    integer when it is. On failure, a negative errno-style error code is returned.</para>
 
     <refsect2>
       <title>Errors</title>
index 68a4a0a5c0e4b6afa9ad7523daba8d1b7dc22bc4..f7a70e9b0f836dc91b474d6b0626578abeaf1cc5 100644 (file)
@@ -218,6 +218,9 @@ sd_journal_send("MESSAGE=Hello World, this is PID %lu!", (unsigned long) getpid(
     <function>sd_journal_send()</function>. Using
     <function>syslog()</function> has the benefit of being
     more portable.</para>
+
+    <para>These functions implement a client to the <ulink
+    url="https://systemd.io/JOURNAL_NATIVE_PROTOCOL">Native Journal Protocol</ulink>.</para>
   </refsect1>
 
   <refsect1>
index 09f2854d83a2a7d3931d92a2e46ab18e440aa7d7..139f79fa6b7d56ef9450315b48053ea09397812c 100644 (file)
@@ -51,7 +51,7 @@
 
       <listitem><para>The Microsoft Windows EFI boot manager, if installed</para></listitem>
 
-      <listitem><para>The Apple MacOS X boot manager, if installed</para></listitem>
+      <listitem><para>The Apple macOS boot manager, if installed</para></listitem>
 
       <listitem><para>The EFI Shell binary, if installed</para></listitem>
 
 
       <varlistentry>
         <term><keycap>a</keycap></term>
-        <listitem><para>OS X</para></listitem>
+        <listitem><para>macOS</para></listitem>
       </varlistentry>
 
       <varlistentry>
index 117b9eb6d08711e8d437d40094ea273d07749ab0..707905f1ba922952823936ef4d2b7aa50453dd74 100644 (file)
@@ -352,6 +352,20 @@ flags:   ...
         </para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>COREDUMP_PACKAGE_NAME=</varname></term>
+        <term><varname>COREDUMP_PACKAGE_VERSION=</varname></term>
+        <term><varname>COREDUMP_PACKAGE_JSON=</varname></term>
+
+        <listitem><para>If the executable contained .package metadata ELF notes, they will be
+        parsed and attached. The <varname>package</varname> and <varname>packageVersion</varname>
+        of the 'main' ELF module (ie: the excutable) will be appended individually. The
+        JSON-formatted content of all modules will be appended as a single JSON object, each with
+        the module name as the key. For more information about this metadata format and content, see
+        <ulink url="https://systemd.io/COREDUMP_PACKAGE_METADATA/">the coredump metadata spec</ulink>.</para>
+        </listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><varname>MESSAGE=</varname></term>
 
index 93acdd02a5bfbc35b19a9d21e629614466d52c15..9751444e50860353c0307ff612da81f0abff9afb 100644 (file)
 
               <row>
                 <entry>8</entry>
-                <entry><citerefentry><refentrytitle>sd-boot</refentrytitle><manvolnum>8</manvolnum></citerefentry> measures the kernel command line in this PCR.</entry>
+                <entry><citerefentry><refentrytitle>sd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry> measures the kernel command line in this PCR.</entry>
               </row>
             </tbody>
           </tgroup>
index c70d6a9d3ed3b0f6dc15c8879f901ee2fcf4f3b2..668208a01d35a8828ee1e3b3fccbedf6317226f8 100644 (file)
 
   <refnamediv>
     <refname>systemd-cryptsetup@.service</refname>
+    <!-- <refname>system-systemd\x2dcryptsetup.slice</refname> — this causes meson to go haywire because it
+         thinks this is a (windows) path. Let's just not create the alias for this name, and only include it
+         in the synopsis. -->
     <refname>systemd-cryptsetup</refname>
     <refpurpose>Full disk decryption logic</refpurpose>
   </refnamediv>
 
   <refsynopsisdiv>
     <para><filename>systemd-cryptsetup@.service</filename></para>
+    <para><filename>system-systemd\x2dcryptsetup.slice</filename></para>
     <para><filename>/usr/lib/systemd/systemd-cryptsetup</filename></para>
   </refsynopsisdiv>
 
   <refsect1>
     <title>Description</title>
 
-    <para><filename>systemd-cryptsetup@.service</filename> is a
-    service responsible for setting up encrypted block devices. It is
-    instantiated for each device that requires decryption for
-    access.</para>
+    <para><filename>systemd-cryptsetup@.service</filename> is a service responsible for setting up encrypted
+    block devices. It is instantiated for each device that requires decryption for access.</para>
+
+    <para><filename>systemd-cryptsetup@.service</filename> instances are part of the
+    <filename>system-systemd\x2dcryptsetup.slice</filename> slice, which is destroyed only very late in the
+    shutdown procedure. This allows the encrypted devices to remain up until filesystems have been unmounted.
+    </para>
 
     <para><filename>systemd-cryptsetup@.service</filename> will ask
     for hard disk passwords via the <ulink
index 35cfbde86c8b94e728657ad7f8aa3f64c6e5b5cc..875393b4081cf6c68783a1246e27cc00a9e7bfac 100644 (file)
       project='man-pages'><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>
       call</para></listitem>
 
-      <listitem><para>Structured system log messages via the native
-      Journal API, see
-      <citerefentry><refentrytitle>sd_journal_print</refentrytitle><manvolnum>3</manvolnum></citerefentry></para></listitem>
+      <listitem><para>Structured system log messages via the native Journal API, see
+      <citerefentry><refentrytitle>sd_journal_print</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+      and <ulink url="https://systemd.io/JOURNAL_NATIVE_PROTOCOL">Native Journal
+      Protocol</ulink></para></listitem>
 
       <listitem><para>Standard output and standard error of service units. For further details see
       below.</para></listitem>
index 5f97e37025f3b530de4c56efd7d3e91a96c5dcbb..15bc1ea889b830d5c029513611e82dd79899f5fa 100644 (file)
   <refsect1>
     <title>Exit status</title>
 
-    <para>On success, 0 is returned. If the configuration was syntactically invalid (syntax errors,
-    missing arguments, …), so some lines had to be ignored, but no other errors occurred,
-    <constant>65</constant> is returned (<constant>EX_DATAERR</constant> from
-    <filename>/usr/include/sysexits.h</filename>). If the configuration was syntactically valid, but
-    could not be executed (lack of permissions, creation of files in missing directories, invalid
-    contents when writing to <filename>/sys/</filename> values, …), <constant>73</constant> is
-    returned (<constant>EX_CANTCREAT</constant> from <filename>/usr/include/sysexits.h</filename>).
-    Otherwise, <constant>1</constant> is returned (<constant>EXIT_FAILURE</constant> from
-    <filename>/usr/include/stdlib.h</filename>).
-    </para>
+    <para>On success, 0 is returned. If the configuration was syntactically invalid (syntax errors, missing
+    arguments, …), so some lines had to be ignored, but no other errors occurred, <constant>65</constant> is
+    returned (<constant>EX_DATAERR</constant> from <filename>/usr/include/sysexits.h</filename>). If the
+    configuration was syntactically valid, but could not be executed (lack of permissions, creation of files
+    in missing directories, invalid contents when writing to <filename>/sys/</filename> values, …),
+    <constant>73</constant> is returned (<constant>EX_CANTCREAT</constant> from
+    <filename>/usr/include/sysexits.h</filename>). Otherwise, <constant>1</constant> is returned
+    (<constant>EXIT_FAILURE</constant> from <filename>/usr/include/stdlib.h</filename>).</para>
+
+    <para>Note: when creating items, if the target already exists, but is of the wrong type or otherwise does
+    not match the requested state, and forced operation has not been requested with <literal>+</literal>,
+    a message is emitted, but the failure is otherwise ignored.</para>
   </refsect1>
 
   <refsect1>
index 5df4cd6a223ef98018c6883cc7ef82335c4f1ee5..32cb82bac304d1a5b04f824cd4e8b31dffa29ac4 100644 (file)
@@ -88,8 +88,8 @@
         <term><option>-e</option></term>
         <term><option>--exec-delay=</option></term>
         <listitem>
-          <para>Delay the execution of <varname>RUN</varname>
-          instructions by the given number of seconds. This option
+          <para>Delay the execution of each <varname>RUN{<replaceable>program</replaceable>}</varname>
+          parameter by the given number of seconds. This option
           might be useful when debugging system crashes during
           coldplug caused by loading non-working kernel
           modules.</para>
         <term><varname>udev.exec_delay=</varname></term>
         <term><varname>rd.udev.exec_delay=</varname></term>
         <listitem>
-          <para>Delay the execution of <varname>RUN</varname> instructions by the given
+          <para>Delay the execution of each <varname>RUN{<replaceable>program</replaceable>}</varname> parameter by the given
           number of seconds. This option might be useful when
           debugging system crashes during coldplug caused by loading
           non-working kernel modules.</para>
index 646dd3e561108b1a9f32cb32dd763ed3920e08f7..fe044d236aba564c517fcb4afb191c393f148f56 100644 (file)
           property.</para></listitem>
         </varlistentry>
 
+        <varlistentry>
+          <term><constant>v249</constant></term>
+
+          <listitem><para>PCI hotplug slot names for the s390 PCI driver are a hexadecimal representation
+          of the <filename>function_id</filename> device attribute. This attribute is now used to build the
+          <varname>ID_NET_NAME_SLOT</varname>. Before that, all slot names were parsed as decimal
+          numbers, which could either result in an incorrect value of the <varname>ID_NET_NAME_SLOT</varname>
+          property or none at all.</para></listitem>
+        </varlistentry>
+
       </variablelist>
 
     <para>Note that <constant>latest</constant> may be used to denote the latest scheme known (to this
index 1bc45a9f007acb0c5bda6670246c2ff5ce2f9c3d..a2d01f7afbf10ad4e51ff6b55a0831e719fd0030 100644 (file)
           <para>If these settings are used multiple times in the same unit all the specified programs are attached. If an
           empty string is assigned to these settings the program list is reset and all previous specified programs ignored.</para>
 
+          <para>If the path <replaceable>BPF_FS_PROGRAM_PATH</replaceable> in <varname>IPIngressFilterPath=</varname> assignment
+          is already being handled by <varname>BPFProgram=</varname> ingress hook, e.g.
+          <varname>BPFProgram=</varname><constant>ingress</constant>:<replaceable>BPF_FS_PROGRAM_PATH</replaceable>,
+          the assignment will be still considered valid and the program will be attached to a cgroup. Same for
+          <varname>IPEgressFilterPath=</varname> path and <constant>egress</constant> hook.</para>
+
           <para>Note that for socket-activated services, the IP filter programs configured on the socket unit apply to
           all sockets associated with it directly, but not to any sockets created by the ultimately activated services
           for it. Conversely, the IP filter programs configured for the service are not applied to any sockets passed into
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>BPFProgram=<replaceable>type</replaceable><constant>:</constant><replaceable>program-path</replaceable></varname></term>
+        <listitem>
+          <para>Add a custom cgroup BPF program.</para>
+
+          <para><varname>BPFProgram=</varname> allows attaching BPF hooks to the cgroup of a systemd unit.
+          (This generalizes the functionality exposed via <varname>IPEgressFilterPath=</varname> for egress and
+          <varname>IPIngressFilterPath=</varname> for ingress.)
+          Cgroup-bpf hooks in the form of BPF programs loaded to the BPF filesystem are attached with cgroup-bpf attach
+          flags determined by the unit. For details about attachment types and flags see <ulink
+          url="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/bpf.h"/>.
+          For general BPF documentation please refer to <ulink url="https://www.kernel.org/doc/html/latest/bpf/index.html"/>.</para>
+
+          <para>The specification of BPF program consists of a <replaceable>type</replaceable> followed by a
+          <replaceable>program-path</replaceable> with <literal>:</literal> as the separator:
+          <replaceable>type</replaceable><constant>:</constant><replaceable>program-path</replaceable>.</para>
+
+          <para><replaceable>type</replaceable> is the string name of BPF attach type also used in
+          <command>bpftool</command>. <replaceable>type</replaceable> can be one of <constant>egress</constant>,
+          <constant>ingress</constant>, <constant>sock_create</constant>, <constant>sock_ops</constant>,
+          <constant>device</constant>, <constant>bind4</constant>, <constant>bind6</constant>,
+          <constant>connect4</constant>, <constant>connect6</constant>, <constant>post_bind4</constant>,
+          <constant>post_bind6</constant>, <constant>sendmsg4</constant>, <constant>sendmsg6</constant>,
+          <constant>sysctl</constant>, <constant>recvmsg4</constant>, <constant>recvmsg6</constant>,
+          <constant>getsockopt</constant>, <constant>setsockopt</constant>.</para>
+
+          <para>Setting <varname>BPFProgram=</varname> to an empty value makes previous assignments ineffective.</para>
+          <para>Multiple assignments of the same <replaceable>type</replaceable>:<replaceable>program-path</replaceable>
+          value have the same effect as a single assignment: the program with the path <replaceable>program-path</replaceable>
+          will be attached to cgroup hook <replaceable>type</replaceable> just once.</para>
+          <para>If BPF <constant>egress</constant> pinned to <replaceable>program-path</replaceable> path is already being
+          handled by <varname>IPEgressFilterPath=</varname>, <varname>BPFProgram=</varname>
+          assignment will be considered valid and <varname>BPFProgram=</varname> will be attached to a cgroup.
+          Similarly for <constant>ingress</constant> hook and <varname>IPIngressFilterPath=</varname> assignment.</para>
+
+          <para>BPF programs passed with <varname>BPFProgram=</varname> are attached to the cgroup of a unit with BPF
+          attach flag <constant>multi</constant>, that allows further attachments of the same
+          <replaceable>type</replaceable> within cgroup hierarchy topped by the unit cgroup.</para>
+
+          <para>Examples:<programlisting>
+BPFProgram=egress:/sys/fs/bpf/egress-hook
+BPFProgram=bind6:/sys/fs/bpf/sock-addr-hook
+</programlisting></para>
+        </listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><varname>DeviceAllow=</varname></term>
 
index 55b763e26d587f504f5047ac38592b7e94def5c6..35b762ca3f7c7d3b6d2d79cc844f64e4275e9d41 100644 (file)
@@ -58,8 +58,8 @@ c+    /dev/char-device-to-[re]create           mode user group -           major
 b     /dev/block-device-to-create              mode user group -           major:minor
 b+    /dev/block-device-to-[re]create          mode user group -           major:minor
 C     /target/to/create                        -    -    -     -           /source/to/copy
-x     /path-or-glob/to/ignore                  -    -    -     -           -
-X     /path-or-glob/to/ignore/recursively      -    -    -     -           -
+x     /path-or-glob/to/ignore/recursively      -    -    -     -           -
+X     /path-or-glob/to/ignore                  -    -    -     -           -
 r     /empty/dir/to/remove                     -    -    -     -           -
 R     /dir/to/remove/recursively               -    -    -     -           -
 z     /path-or-glob/to/adjust/mode             mode user group -           -
index df0a70c9fb0d6c1c529b63bcacbc8088981089e5..0f51a1aaefe98b123a93f5a7712d4c5fba97a8b1 100644 (file)
@@ -63,8 +63,8 @@
         <term><varname>exec_delay=</varname></term>
 
         <listitem>
-          <para>An integer. Delay the execution of <varname>RUN</varname>
-          instructions by the given number of seconds. This option
+          <para>An integer. Delay the execution of each <varname>RUN{<replaceable>program</replaceable>}</varname>
+          parameter by the given number of seconds. This option
           might be useful when debugging system crashes during
           coldplug caused by loading non-working kernel
           modules.</para>
index 6a474afdac33a284350f96f48bb7526e4bb49d9b..a8976c203745206e94989443371eeb6d837797df 100644 (file)
@@ -395,10 +395,6 @@ possible_cc_flags = [
         '-Wno-error=#warnings',  # clang
         '-Wno-string-plus-int',  # clang
 
-        # Disable -Wmaybe-uninitialized, since it's noisy on gcc 8 with
-        # optimizations enabled, producing essentially false positives.
-        '-Wno-maybe-uninitialized',
-
         '-ffast-math',
         '-fno-common',
         '-fdiagnostics-show-option',
@@ -409,6 +405,15 @@ possible_cc_flags = [
         '--param=ssp-buffer-size=4',
 ]
 
+# Disable -Wmaybe-unitialized when compiling with -Os/-O1/-O3/etc. There are
+# too many false positives with gcc >= 8. Effectively, we only test with -O0
+# and -O2; this should be enough to catch most important cases without too much
+# busywork. See https://github.com/systemd/systemd/pull/19226.
+if cc.get_id() == 'gcc' and (not '02'.contains(get_option('optimization')) or
+                             cc.version().version_compare('<10'))
+        possible_cc_flags += '-Wno-maybe-uninitialized'
+endif
+
 # --as-needed and --no-undefined are provided by meson by default,
 # run mesonconf to see what is enabled
 possible_link_flags = [
@@ -3515,7 +3520,7 @@ check_directives_sh = find_program('tools/check-directives.sh')
 if want_tests != 'false'
         test('check-directives',
              check_directives_sh,
-             args : project_source_root)
+             args : [project_source_root, project_build_root])
 endif
 
 ############################################################
index a74fc196be5b3630536b8cf7b01f38c087ac5c95..ff339b440c29f1950878dd02dcbd3fc146241f36 100755 (executable)
@@ -14,6 +14,18 @@ if ! mountpoint -q "$SRCDIR"; then
         umask 022
 fi
 
+# On Fedora "ld" is (unfortunately — if you ask me) managed via
+# "alternatives". Since we'd like to support building images in environments
+# with only /usr/ around (e.g. mkosi's UsrOnly=1 option), we have the problem
+# that /usr/bin/ld is a symlink that points to a non-existing file in
+# /etc/alternative/ in this mode. Let's work around this for now by manually
+# redirect "ld" to "ld.bfd", i.e. circumventing the /usr/bin/ld symlink.
+if [ ! -x /usr/bin/ld -a -x /usr/bin/ld.bfd ] ; then
+        mkdir -p "$HOME"/bin
+        ln -s /usr/bin/ld.bfd "$HOME"/bin/ld
+        PATH="$HOME/bin:$PATH"
+fi
+
 # If mkosi.builddir/ exists mkosi will set $BUILDDIR to it, let's then use it
 # as out-of-tree build dir. Otherwise, let's make up our own builddir.
 [ -z "$BUILDDIR" ] && BUILDDIR=build
index 3713b161ecfe9865ca03528279969ce1ff0bde84..3a6811c00fcd3d1f99b2c49e260388b64a588f87 100644 (file)
--- a/po/ko.po
+++ b/po/ko.po
@@ -9,7 +9,7 @@ msgstr ""
 "Project-Id-Version: systemd\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2021-01-08 17:48+0100\n"
-"PO-Revision-Date: 2021-03-25 03:01+0000\n"
+"PO-Revision-Date: 2021-04-09 07:01+0000\n"
 "Last-Translator: simmon <simmon@nplob.com>\n"
 "Language-Team: Korean <https://translate.fedoraproject.org/projects/systemd/"
 "master/ko/>\n"
@@ -18,7 +18,7 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.5.1\n"
+"X-Generator: Weblate 4.5.3\n"
 "X-Poedit-SourceCharset: UTF-8\n"
 
 #: src/core/org.freedesktop.systemd1.policy.in:22
@@ -132,7 +132,7 @@ msgstr "정적 호스트 이름 설정"
 msgid ""
 "Authentication is required to set the statically configured local hostname, "
 "as well as the pretty hostname."
-msgstr "로컬호스트 이름을 모양새를 갖춘 호스트이름 처럼 정적으로 설정하려면 인증이 필요합니다."
+msgstr "로컬호스트 이름을 지정 호스트이름 처럼 정적으로 설정하려면 인증이 필요합니다."
 
 #: src/hostname/org.freedesktop.hostname1.policy:41
 msgid "Set machine information"
index cd16e47721350060ac4a21617d6c5cd520c0e5d8..bc3a7889b3882e1b0fb880ae1721c49b286a40d9 100644 (file)
@@ -30,7 +30,7 @@ __get_machines() {
 }
 
 _machinectl() {
-    local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
+    local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} words cword
     local i verb comps
 
     local -A OPTS=(
index 9282ee873773cabcf429d031529b8408087d0a86..ab2a5f7015ef6f1786f94e565e7a851e0f585992 100644 (file)
@@ -30,7 +30,7 @@ __get_links() {
 
 _networkctl() {
     local i verb comps
-    local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
+    local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} words cword
     local -A OPTS=(
         [STANDALONE]='-a --all -h --help --version --no-pager --no-legend -s --stats -l --full'
         [ARG]='-n --lines'
index 92f81a60fc718261a1489546bf9381c9c7980ea2..eded49b50e7d769029c7c1e1eca62e3ab7c7c2d9 100644 (file)
@@ -46,7 +46,7 @@ __get_syscall_sets() {
 
 _systemd_analyze() {
     local i verb comps mode
-    local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
+    local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} words cword
 
     local -A OPTS=(
         [STANDALONE]='-h --help --version --system --user --global --order --require --no-pager
index 9413b6fa70ab00ca72a687eef46b214b13c93e82..737f33981bb5a30ff255be6c73c2caa39c473206 100644 (file)
@@ -25,7 +25,7 @@ __contains_word() {
 }
 
 _systemd_cat() {
-    local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
+    local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} words cword
     local i verb comps
 
     local -A OPTS=(
index 7caaf89ddb903a34f32f2a6b2dddfc990283767d..0b6a8fda0d28319715f1d9c2c06a9270e80b67f8 100644 (file)
@@ -37,7 +37,7 @@ __get_units_have_cgroup() {
 }
 
 _systemd_cgls() {
-    local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
+    local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} words cword
     local i verb comps
 
     local -A OPTS=(
index b186f1bd537ca37018ac113a5789309a98c3c2f7..2c59b6c9f69d36bce9a0d9554193338b18be1e05 100644 (file)
@@ -29,7 +29,7 @@ __get_machines() {
 }
 
 _systemd_cgtop() {
-    local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
+    local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} words cword
     local comps
 
     local -A OPTS=(
index baf86b081343d64822ce70dcbada1dc1863f0071..f97b6dd5b2eabbc0d22769c76c4faed5d288f34d 100644 (file)
@@ -24,7 +24,7 @@ __contains_word() {
 }
 
 _systemd-delta() {
-    local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
+    local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} words cword
     local comps
 
     local -A OPTS=(
index fb35efaadb9648faff181d340649cbbc00c66214..0c9da3a22e1ad0adfd4f8e3dc7ab35498373511b 100644 (file)
@@ -24,7 +24,7 @@ __contains_word() {
 }
 
 _systemd_detect_virt() {
-    local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
+    local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} words cword
     local i verb comps
 
     local -A OPTS=(
index 937556154a8593e42f815adacb05528aca861653..25110d13091948c1d92e50a6bbf22c515f8e3aad 100644 (file)
@@ -26,7 +26,7 @@ __contains_word () {
 
 _systemd_id128() {
     local i verb comps
-    local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
+    local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} words cword
     local -A OPTS=(
         [STANDALONE]='-h --help --version -p --pretty'
         [ARG]='-a --app-specific'
index ebd97a9de1b683205050814a8e54c53453ad2276..ed1296a87883cba8e3c47a0cf4c4415372011a45 100644 (file)
@@ -58,7 +58,7 @@ __get_rlimit() {
 }
 
 _systemd_nspawn() {
-    local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
+    local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} words cword
     local i verb comps
 
     local -A OPTS=(
index cae4ac1b3093f4e04c667f7705e296feb5bcf619..4330c3e05b32d81fc555019fb846abe7ff1a57f2 100644 (file)
@@ -30,7 +30,7 @@ __get_names() {
 
 _systemd_path() {
     local comps
-    local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
+    local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} words cword
     local -A OPTS=(
         [STANDALONE]='-h --help --version'
         [ARG]='--suffix'
index 86927be62e98cd61eb541446f86f8e5a435863cb..7c0970a60c24502a587784fd52ce05ce609934b7 100644 (file)
@@ -226,26 +226,20 @@ static int validate_device(sd_device *device) {
 }
 
 static int get_max_brightness(sd_device *device, unsigned *ret) {
-        const char *max_brightness_str;
-        unsigned max_brightness;
+        const char *s;
         int r;
 
         assert(device);
         assert(ret);
 
-        r = sd_device_get_sysattr_value(device, "max_brightness", &max_brightness_str);
+        r = sd_device_get_sysattr_value(device, "max_brightness", &s);
         if (r < 0)
                 return log_device_warning_errno(device, r, "Failed to read 'max_brightness' attribute: %m");
 
-        r = safe_atou(max_brightness_str, &max_brightness);
+        r = safe_atou(s, ret);
         if (r < 0)
-                return log_device_warning_errno(device, r, "Failed to parse 'max_brightness' \"%s\": %m", max_brightness_str);
-
-        if (max_brightness <= 0)
-                return log_device_warning_errno(device, SYNTHETIC_ERRNO(EINVAL), "Maximum brightness is 0, ignoring device.");
+                return log_device_warning_errno(device, r, "Failed to parse 'max_brightness' \"%s\": %m", s);
 
-        log_device_debug(device, "Maximum brightness is %u", max_brightness);
-        *ret = max_brightness;
         return 0;
 }
 
@@ -409,6 +403,13 @@ static int run(int argc, char *argv[]) {
         if (get_max_brightness(device, &max_brightness) < 0)
                 return 0;
 
+        if (max_brightness == 0) {
+                log_device_warning(device, "Maximum brightness is 0, ignoring device.");
+                return 0;
+        }
+
+        log_device_debug(device, "Maximum brightness is %u", max_brightness);
+
         escaped_ss = cescape(ss);
         if (!escaped_ss)
                 return log_oom();
index 8dd3f8cd95018b46a9cef8800e3835e665b908da..1ac1f6dff0b05c26ea96f8aedcc7e765cd74c1b4 100644 (file)
@@ -660,7 +660,7 @@ int cg_remove_xattr(const char *controller, const char *path, const char *name)
 
 int cg_pid_get_path(const char *controller, pid_t pid, char **ret_path) {
         _cleanup_fclose_ FILE *f = NULL;
-        const char *fs, *controller_str;
+        const char *fs, *controller_str = NULL;  /* avoid false maybe-uninitialized warning */
         int unified, r;
 
         assert(pid >= 0);
@@ -720,6 +720,7 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **ret_path) {
                                 continue;
                         *e = 0;
 
+                        assert(controller_str);
                         r = string_contains_word(l, ",", controller_str);
                         if (r < 0)
                                 return r;
@@ -2162,6 +2163,7 @@ static const char *const cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = {
         [CGROUP_CONTROLLER_PIDS] = "pids",
         [CGROUP_CONTROLLER_BPF_FIREWALL] = "bpf-firewall",
         [CGROUP_CONTROLLER_BPF_DEVICES] = "bpf-devices",
+        [CGROUP_CONTROLLER_BPF_FOREIGN] = "bpf-foreign",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(cgroup_controller, CGroupController);
index f79e384147d11712e229d0c6c0fd56e123b04865..8894fd9b0afbb07025396122f81c98d65672ed5f 100644 (file)
@@ -30,6 +30,7 @@ typedef enum CGroupController {
         /* BPF-based pseudo-controllers, v2 only */
         CGROUP_CONTROLLER_BPF_FIREWALL,
         CGROUP_CONTROLLER_BPF_DEVICES,
+        CGROUP_CONTROLLER_BPF_FOREIGN,
 
         _CGROUP_CONTROLLER_MAX,
         _CGROUP_CONTROLLER_INVALID = -EINVAL,
@@ -49,6 +50,7 @@ typedef enum CGroupMask {
         CGROUP_MASK_PIDS = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_PIDS),
         CGROUP_MASK_BPF_FIREWALL = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_FIREWALL),
         CGROUP_MASK_BPF_DEVICES = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_DEVICES),
+        CGROUP_MASK_BPF_FOREIGN = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_FOREIGN),
 
         /* All real cgroup v1 controllers */
         CGROUP_MASK_V1 = CGROUP_MASK_CPU|CGROUP_MASK_CPUACCT|CGROUP_MASK_BLKIO|CGROUP_MASK_MEMORY|CGROUP_MASK_DEVICES|CGROUP_MASK_PIDS,
@@ -57,7 +59,7 @@ typedef enum CGroupMask {
         CGROUP_MASK_V2 = CGROUP_MASK_CPU|CGROUP_MASK_CPUSET|CGROUP_MASK_IO|CGROUP_MASK_MEMORY|CGROUP_MASK_PIDS,
 
         /* All cgroup v2 BPF pseudo-controllers */
-        CGROUP_MASK_BPF = CGROUP_MASK_BPF_FIREWALL|CGROUP_MASK_BPF_DEVICES,
+        CGROUP_MASK_BPF = CGROUP_MASK_BPF_FIREWALL|CGROUP_MASK_BPF_DEVICES|CGROUP_MASK_BPF_FOREIGN,
 
         _CGROUP_MASK_ALL = CGROUP_CONTROLLER_TO_MASK(_CGROUP_CONTROLLER_MAX) - 1
 } CGroupMask;
index d25777cc4b47a030b03014ab1b55aea20d323a43..af9ac842a1150250f4f046b1e2d28e3043cbdb48 100644 (file)
@@ -1072,7 +1072,7 @@ int copy_file_full(
 
         _cleanup_close_ int fdf = -1;
         struct stat st;
-        int fdt = -1, r;
+        int r, fdt = -1;  /* avoid false maybe-uninitialized warning */
 
         assert(from);
         assert(to);
index 26d34bb94f8ab46a8a326f818c325aebaebaa316..2139cf3a693ddeb7da217c5144bf978287f4bbe2 100644 (file)
@@ -63,7 +63,7 @@ int efi_get_variable(
         _cleanup_free_ char *p = NULL;
         _cleanup_free_ void *buf = NULL;
         struct stat st;
-        usec_t begin;
+        usec_t begin = 0; /* Unnecessary initialization to appease gcc */
         uint32_t a;
         ssize_t n;
 
index c110a750a55dd49bd70b1f66c9968b4502a4a032..0e8c2878d61a17574142c0c9c3ee18fa98c47388 100644 (file)
@@ -515,10 +515,10 @@ char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) {
                 ALTERNATE_VALUE,
         } state = WORD;
 
-        const char *e, *word = format, *test_value;
+        const char *e, *word = format, *test_value = NULL; /* test_value is initialized to appease gcc */
         char *k;
         _cleanup_free_ char *r = NULL;
-        size_t i, len;
+        size_t i, len = 0; /* len is initialized to appease gcc */
         int nest = 0;
 
         assert(format);
@@ -581,13 +581,12 @@ char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) {
                                 word = e+1;
                                 state = WORD;
                         } else if (*e == ':') {
-                                if (!(flags & REPLACE_ENV_ALLOW_EXTENDED))
+                                if (flags & REPLACE_ENV_ALLOW_EXTENDED) {
+                                        len = e - word - 2;
+                                        state = TEST;
+                                } else
                                         /* Treat this as unsupported syntax, i.e. do no replacement */
                                         state = WORD;
-                                else {
-                                        len = e-word-2;
-                                        state = TEST;
-                                }
                         }
                         break;
 
index 5609820b882f528a0ab756f1e15a4756391e3ab2..3f2d0af56d9524bcda780741a034044f09d57931 100644 (file)
@@ -33,7 +33,7 @@ static inline int negative_errno(void) {
 
 static inline const char *strerror_safe(int error) {
         /* 'safe' here does NOT mean thread safety. */
-        return strerror(abs(error));
+        return strerror(abs(error)); /* lgtm [cpp/potentially-dangerous-function] */
 }
 
 static inline int errno_or_else(int fallback) {
index df30870a1a25f90c76fb2d9d251891958349bc55..abd822796e7f02df814a404c2cda58181d31f36a 100644 (file)
@@ -121,7 +121,7 @@ int write_string_stream_ts(
                 const struct timespec *ts) {
 
         bool needs_nl;
-        int r, fd;
+        int r, fd = -1;
 
         assert(f);
         assert(line);
@@ -140,8 +140,8 @@ int write_string_stream_ts(
         needs_nl = !(flags & WRITE_STRING_FILE_AVOID_NEWLINE) && !endswith(line, "\n");
 
         if (needs_nl && (flags & WRITE_STRING_FILE_DISABLE_BUFFER)) {
-                /* If STDIO buffering was disabled, then let's append the newline character to the string itself, so
-                 * that the write goes out in one go, instead of two */
+                /* If STDIO buffering was disabled, then let's append the newline character to the string
+                 * itself, so that the write goes out in one go, instead of two */
 
                 line = strjoina(line, "\n");
                 needs_nl = false;
@@ -164,6 +164,7 @@ int write_string_stream_ts(
         if (ts) {
                 const struct timespec twice[2] = {*ts, *ts};
 
+                assert(fd >= 0);
                 if (futimens(fd, twice) < 0)
                         return -errno;
         }
index f7a7252f1af4d5f9e0722b0c424d6299b8279e8f..c11e6ceb9065c2c79fb2dae6d1162d6ae7274c0f 100644 (file)
@@ -51,7 +51,7 @@ bool in4_addr_is_link_local(const struct in_addr *a) {
 bool in6_addr_is_link_local(const struct in6_addr *a) {
         assert(a);
 
-        return IN6_IS_ADDR_LINKLOCAL(a);
+        return IN6_IS_ADDR_LINKLOCAL(a); /* lgtm [cpp/potentially-dangerous-function] */
 }
 
 int in_addr_is_link_local(int family, const union in_addr_union *u) {
@@ -116,7 +116,7 @@ int in_addr_is_localhost(int family, const union in_addr_union *u) {
                 return in4_addr_is_localhost(&u->in);
 
         if (family == AF_INET6)
-                return IN6_IS_ADDR_LOOPBACK(&u->in6);
+                return IN6_IS_ADDR_LOOPBACK(&u->in6); /* lgtm [cpp/potentially-dangerous-function] */
 
         return -EAFNOSUPPORT;
 }
index 93261e675e2ff4009c3569af30027db001341f7d..b818078158bd2af87b4883f3a1c88989d8046121 100644 (file)
@@ -427,8 +427,10 @@ const char *special_glyph(SpecialGlyph code) {
                 },
         };
 
-        assert(code < _SPECIAL_GLYPH_MAX);
+        if (code < 0)
+                return NULL;
 
+        assert(code < _SPECIAL_GLYPH_MAX);
         return draw_table[code >= _SPECIAL_GLYPH_FIRST_EMOJI ? emoji_enabled() : is_locale_utf8()][code];
 }
 
index 558c5a898bb5c9f7ae659f9d9993639c8d53c5f9..df259d1bbd9f169907e45382d0800dca67a3d6eb 100644 (file)
@@ -39,7 +39,7 @@ void init_gettext(void);
 
 bool is_locale_utf8(void);
 
-typedef enum {
+typedef enum SpecialGlyph {
         SPECIAL_GLYPH_TREE_VERTICAL,
         SPECIAL_GLYPH_TREE_BRANCH,
         SPECIAL_GLYPH_TREE_RIGHT,
@@ -70,6 +70,7 @@ typedef enum {
         SPECIAL_GLYPH_LOCK_AND_KEY,
         SPECIAL_GLYPH_TOUCH,
         _SPECIAL_GLYPH_MAX,
+        _SPECIAL_GLYPH_INVALID = -EINVAL,
 } SpecialGlyph;
 
 const char *special_glyph(SpecialGlyph code) _const_;
index dc63fffdea37583db72daaeccdc08f4e9ec46d8b..841fd324f1606cd541738c15e33cc1ab72f70918 100644 (file)
@@ -5,12 +5,12 @@
 #include <unistd.h>
 
 #define SD_LOGIND_ROOT_CHECK_INHIBITORS           (UINT64_C(1) << 0)
-#define SD_LOGIND_KEXEC_REBOOT                    (UINT64_C(1) << 1)
+#define SD_LOGIND_REBOOT_VIA_KEXEC                (UINT64_C(1) << 1)
 
 /* For internal use only */
 #define SD_LOGIND_INTERACTIVE                     (UINT64_C(1) << 63)
 
-#define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC (SD_LOGIND_ROOT_CHECK_INHIBITORS|SD_LOGIND_KEXEC_REBOOT)
+#define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC (SD_LOGIND_ROOT_CHECK_INHIBITORS|SD_LOGIND_REBOOT_VIA_KEXEC)
 #define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_ALL    (SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC|SD_LOGIND_INTERACTIVE)
 
 bool session_id_valid(const char *id);
index f40f3f27e96c862c64bdf1dfd0736404c39f553c..f98859939cddad1994d4a73504bbfcb8dcf9edb2 100644 (file)
@@ -527,6 +527,27 @@ bool path_equal_or_files_same(const char *a, const char *b, int flags) {
         return path_equal(a, b) || files_same(a, b, flags) > 0;
 }
 
+bool path_equal_filename(const char *a, const char *b) {
+        _cleanup_free_ char *a_basename = NULL, *b_basename = NULL;
+        int r;
+
+        assert(a);
+        assert(b);
+
+        r = path_extract_filename(a, &a_basename);
+        if (r < 0) {
+                log_debug_errno(r, "Failed to parse basename of %s: %m", a);
+                return false;
+        }
+        r = path_extract_filename(b, &b_basename);
+        if (r < 0) {
+                log_debug_errno(r, "Failed to parse basename of %s: %m", b);
+                return false;
+        }
+
+        return path_equal(a_basename, b_basename);
+}
+
 char* path_join_internal(const char *first, ...) {
         char *joined, *q;
         const char *p;
index c0746f68d7aea12331861700c5c5109751c7d906..f82d935dc5c739d8d76afae6cbcaf6fee61ba568 100644 (file)
@@ -61,6 +61,8 @@ char* path_startswith(const char *path, const char *prefix) _pure_;
 int path_compare(const char *a, const char *b) _pure_;
 bool path_equal(const char *a, const char *b) _pure_;
 bool path_equal_or_files_same(const char *a, const char *b, int flags);
+/* Compares only the last portion of the input paths, ie: the filenames */
+bool path_equal_filename(const char *a, const char *b);
 char* path_join_internal(const char *first, ...);
 #define path_join(x, ...) path_join_internal(x, __VA_ARGS__, POINTER_MAX)
 
index 0b6fb137bdc304e3921aed759b56a4871d6e92f6..410b8a3eb5de67e7d1defd0a5377bf8441520102 100644 (file)
@@ -47,7 +47,7 @@ static int proc_cmdline_extract_first(const char **p, char **ret_word, ProcCmdli
                 _cleanup_free_ char *word = NULL;
                 const char *c;
 
-                r = extract_first_word(&q, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RELAX);
+                r = extract_first_word(&q, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RELAX|EXTRACT_RETAIN_ESCAPE);
                 if (r < 0)
                         return r;
                 if (r == 0)
index a3c4500dff4537fb6c4ccc27446035c62fd49aed..cad639a023b97fe5098b5968114d7c909a647c98 100644 (file)
@@ -74,6 +74,7 @@ int normalize_recovery_key(const char *password, char **ret) {
 int make_recovery_key(char **ret) {
         _cleanup_(erase_and_freep) char *formatted = NULL;
         _cleanup_(erase_and_freep) uint8_t *key = NULL;
+        size_t j = 0;
         int r;
 
         assert(ret);
@@ -91,7 +92,7 @@ int make_recovery_key(char **ret) {
         if (!formatted)
                 return -ENOMEM;
 
-        for (size_t i = 0, j = 0; i < RECOVERY_KEY_MODHEX_RAW_LENGTH; i++) {
+        for (size_t i = 0; i < RECOVERY_KEY_MODHEX_RAW_LENGTH; i++) {
                 formatted[j++] = modhex_alphabet[key[i] >> 4];
                 formatted[j++] = modhex_alphabet[key[i] & 0xF];
 
@@ -99,7 +100,9 @@ int make_recovery_key(char **ret) {
                         formatted[j++] = '-';
         }
 
-        formatted[RECOVERY_KEY_MODHEX_FORMATTED_LENGTH-1] = 0;
+        assert(j == RECOVERY_KEY_MODHEX_FORMATTED_LENGTH);
+        assert(formatted[RECOVERY_KEY_MODHEX_FORMATTED_LENGTH-1] == '-');
+        formatted[RECOVERY_KEY_MODHEX_FORMATTED_LENGTH-1] = 0; /* replace final dash with a NUL */
 
         *ret = TAKE_PTR(formatted);
         return 0;
index 507a599d7cfa072833b1364d2e55f4ff45ca5abf..e0b959f5da550cc1bd60c430bc64bee179fe5561 100644 (file)
@@ -14,6 +14,7 @@
 #include <sys/types.h>
 #include <sys/un.h>
 
+#include "errno-util.h"
 #include "macro.h"
 #include "missing_network.h"
 #include "missing_socket.h"
@@ -264,7 +265,7 @@ static inline int getsockopt_int(int fd, int level, int optname, int *ret) {
         socklen_t sl = sizeof(v);
 
         if (getsockopt(fd, level, optname, &v, &sl) < 0)
-                return -errno;
+                return negative_errno();
         if (sl != sizeof(v))
                 return -EIO;
 
index 212b561fa645bb2fbcca76271d1f04402feb6576..0617acc8d215308b58af4cab8101cc6d3e76c2cf 100644 (file)
@@ -107,11 +107,9 @@ static void bubbleinsert(struct strbuf_node *node,
 /* add string, return the index/offset into the buffer */
 ssize_t strbuf_add_string(struct strbuf *str, const char *s, size_t len) {
         uint8_t c;
-        struct strbuf_node *node;
-        size_t depth;
         char *buf_new;
         struct strbuf_child_entry *child;
-        struct strbuf_node *node_child;
+        struct strbuf_node *node;
         ssize_t off;
 
         if (!str->root)
@@ -127,7 +125,7 @@ ssize_t strbuf_add_string(struct strbuf *str, const char *s, size_t len) {
         str->in_len += len;
 
         node = str->root;
-        for (depth = 0; depth <= len; depth++) {
+        for (size_t depth = 0; depth <= len; depth++) {
                 struct strbuf_child_entry search;
 
                 /* match against current node */
@@ -159,6 +157,8 @@ ssize_t strbuf_add_string(struct strbuf *str, const char *s, size_t len) {
         str->buf[str->len++] = '\0';
 
         /* new node */
+        _cleanup_free_ struct strbuf_node *node_child = NULL;
+
         node_child = new(struct strbuf_node, 1);
         if (!node_child)
                 return -ENOMEM;
@@ -169,15 +169,13 @@ ssize_t strbuf_add_string(struct strbuf *str, const char *s, size_t len) {
 
         /* extend array, add new entry, sort for bisection */
         child = reallocarray(node->children, node->children_count + 1, sizeof(struct strbuf_child_entry));
-        if (!child) {
-                free(node_child);
+        if (!child)
                 return -ENOMEM;
-        }
 
         str->nodes_count++;
 
         node->children = child;
-        bubbleinsert(node, c, node_child);
+        bubbleinsert(node, c, TAKE_PTR(node_child));
 
         return off;
 }
index 6fbb947f096dab7146b7517cd2cb9f43c0f8529b..5cfabca83fb08fcae548ce83943483c1b564ef66 100644 (file)
@@ -296,22 +296,19 @@ static const char* const notify_access_table[_NOTIFY_ACCESS_MAX] = {
 DEFINE_STRING_TABLE_LOOKUP(notify_access, NotifyAccess);
 
 SpecialGlyph unit_active_state_to_glyph(UnitActiveState state) {
-        switch (state) {
-                case UNIT_ACTIVE:
-                    return SPECIAL_GLYPH_BLACK_CIRCLE;
-                case UNIT_RELOADING:
-                    return SPECIAL_GLYPH_CIRCLE_ARROW;
-                case UNIT_INACTIVE:
-                    return SPECIAL_GLYPH_WHITE_CIRCLE;
-                case UNIT_FAILED:
-                    return SPECIAL_GLYPH_MULTIPLICATION_SIGN;
-                case UNIT_ACTIVATING:
-                case UNIT_DEACTIVATING:
-                    return SPECIAL_GLYPH_BLACK_CIRCLE;
-                case UNIT_MAINTENANCE:
-                    return SPECIAL_GLYPH_WHITE_CIRCLE;
-
-                default:
-                    return SPECIAL_GLYPH_BLACK_CIRCLE;
-            }
+        static const SpecialGlyph map[_UNIT_ACTIVE_STATE_MAX] = {
+                [UNIT_ACTIVE]       = SPECIAL_GLYPH_BLACK_CIRCLE,
+                [UNIT_RELOADING]    = SPECIAL_GLYPH_CIRCLE_ARROW,
+                [UNIT_INACTIVE]     = SPECIAL_GLYPH_WHITE_CIRCLE,
+                [UNIT_FAILED]       = SPECIAL_GLYPH_MULTIPLICATION_SIGN,
+                [UNIT_ACTIVATING]   = SPECIAL_GLYPH_BLACK_CIRCLE,
+                [UNIT_DEACTIVATING] = SPECIAL_GLYPH_BLACK_CIRCLE,
+                [UNIT_MAINTENANCE]  = SPECIAL_GLYPH_WHITE_CIRCLE,
+        };
+
+        if (state < 0)
+                return _SPECIAL_GLYPH_INVALID;
+
+        assert(state < _UNIT_ACTIVE_STATE_MAX);
+        return map[state];
 }
index 0f588b6ca5fce2e64aa23f04ff6bdacc2068b376..02e33399c3e36615f9b0932bfbdd0e7363608221 100644 (file)
@@ -698,8 +698,7 @@ int bpf_firewall_install(Unit *u) {
         if (r < 0)
                 return log_unit_error_errno(u, r, "Failed to determine cgroup path: %m");
 
-        flags = (supported == BPF_FIREWALL_SUPPORTED_WITH_MULTI &&
-                 (u->type == UNIT_SLICE || unit_cgroup_delegate(u))) ? BPF_F_ALLOW_MULTI : 0;
+        flags = supported == BPF_FIREWALL_SUPPORTED_WITH_MULTI ? BPF_F_ALLOW_MULTI : 0;
 
         /* Unref the old BPF program (which will implicitly detach it) right before attaching the new program, to
          * minimize the time window when we don't account for IP traffic. */
@@ -707,8 +706,7 @@ int bpf_firewall_install(Unit *u) {
         u->ip_bpf_ingress_installed = bpf_program_unref(u->ip_bpf_ingress_installed);
 
         if (u->ip_bpf_egress) {
-                r = bpf_program_cgroup_attach(u->ip_bpf_egress, BPF_CGROUP_INET_EGRESS, path,
-                                              flags | (set_isempty(u->ip_bpf_custom_egress) ? 0 : BPF_F_ALLOW_MULTI));
+                r = bpf_program_cgroup_attach(u->ip_bpf_egress, BPF_CGROUP_INET_EGRESS, path, flags);
                 if (r < 0)
                         return log_unit_error_errno(u, r, "Attaching egress BPF program to cgroup %s failed: %m", path);
 
@@ -717,8 +715,7 @@ int bpf_firewall_install(Unit *u) {
         }
 
         if (u->ip_bpf_ingress) {
-                r = bpf_program_cgroup_attach(u->ip_bpf_ingress, BPF_CGROUP_INET_INGRESS, path,
-                                              flags | (set_isempty(u->ip_bpf_custom_ingress) ? 0 : BPF_F_ALLOW_MULTI));
+                r = bpf_program_cgroup_attach(u->ip_bpf_ingress, BPF_CGROUP_INET_INGRESS, path, flags);
                 if (r < 0)
                         return log_unit_error_errno(u, r, "Attaching ingress BPF program to cgroup %s failed: %m", path);
 
diff --git a/src/core/bpf-foreign.c b/src/core/bpf-foreign.c
new file mode 100644 (file)
index 0000000..98655bd
--- /dev/null
@@ -0,0 +1,151 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bpf-foreign.h"
+#include "bpf-program.h"
+#include "cgroup.h"
+#include "memory-util.h"
+#include "mountpoint-util.h"
+#include "set.h"
+
+typedef struct BPFForeignKey BPFForeignKey;
+struct BPFForeignKey {
+        uint32_t prog_id;
+        uint32_t attach_type;
+};
+
+static int bpf_foreign_key_new(uint32_t prog_id,
+                enum bpf_attach_type attach_type,
+                BPFForeignKey **ret) {
+        _cleanup_free_ BPFForeignKey *p = NULL;
+
+        assert(ret);
+
+        p = new(BPFForeignKey, 1);
+        if (!p)
+                return log_oom();
+
+        *p = (BPFForeignKey) {
+                .prog_id = prog_id,
+                .attach_type = attach_type,
+        };
+
+        *ret = TAKE_PTR(p);
+
+        return 0;
+}
+
+static int bpf_foreign_key_compare_func(const BPFForeignKey *a, const BPFForeignKey *b) {
+        int r = CMP(a->prog_id, b->prog_id);
+        if (r != 0)
+                return r;
+
+        return CMP(a->attach_type, b->attach_type);
+}
+
+static void bpf_foreign_key_hash_func(const BPFForeignKey *p, struct siphash *h) {
+        siphash24_compress(&p->prog_id, sizeof(p->prog_id), h);
+        siphash24_compress(&p->attach_type, sizeof(p->attach_type), h);
+}
+
+DEFINE_PRIVATE_HASH_OPS_FULL(bpf_foreign_by_key_hash_ops,
+                BPFForeignKey, bpf_foreign_key_hash_func, bpf_foreign_key_compare_func, free,
+                BPFProgram, bpf_program_unref);
+
+static int attach_programs(Unit *u, const char *path, Hashmap* foreign_by_key, uint32_t attach_flags) {
+        const BPFForeignKey *key;
+        BPFProgram *prog;
+        int r;
+
+        assert(u);
+
+        HASHMAP_FOREACH_KEY(prog, key, foreign_by_key) {
+                r = bpf_program_cgroup_attach(prog, key->attach_type, path, attach_flags);
+                if (r < 0)
+                        return log_unit_error_errno(u, r, "Attaching foreign BPF program to cgroup %s failed: %m", path);
+        }
+
+        return 0;
+}
+
+/*
+ * Prepare foreign BPF program for installation:
+ * - Load the program from BPF filesystem to the kernel;
+ * - Store program FD identified by program ID and attach type in the unit.
+ */
+static int bpf_foreign_prepare(
+                Unit *u,
+                enum bpf_attach_type attach_type,
+                const char *bpffs_path) {
+        _cleanup_(bpf_program_unrefp) BPFProgram *prog = NULL;
+        _cleanup_free_ BPFForeignKey *key = NULL;
+        uint32_t prog_id;
+        int r;
+
+        assert(u);
+        assert(bpffs_path);
+
+        r = bpf_program_new_from_bpffs_path(bpffs_path, &prog);
+        if (r < 0)
+                return log_unit_error_errno(u, r, "Failed to create foreign BPFProgram: %m");
+
+        r = bpf_program_get_id_by_fd(prog->kernel_fd, &prog_id);
+        if (r < 0)
+                return log_unit_error_errno(u, r, "Failed to get BPF program id by fd: %m");
+
+        r = bpf_foreign_key_new(prog_id, attach_type, &key);
+        if (r < 0)
+                return log_unit_error_errno(u, r,
+                                "Failed to create foreign BPF program key from path '%s': %m", bpffs_path);
+
+        r = hashmap_ensure_put(&u->bpf_foreign_by_key, &bpf_foreign_by_key_hash_ops, key, prog);
+        if (r == -EEXIST) {
+                log_unit_warning_errno(u, r, "Foreign BPF program already exists, ignoring: %m");
+                return 0;
+        }
+        if (r < 0)
+                return log_unit_error_errno(u, r, "Failed to put foreign BPFProgram into map: %m");
+
+        TAKE_PTR(key);
+        TAKE_PTR(prog);
+
+        return 0;
+}
+
+int bpf_foreign_supported(void) {
+        int r;
+
+        r = cg_all_unified();
+        if (r <= 0)
+                return r;
+
+        return path_is_mount_point("/sys/fs/bpf", NULL, 0);
+}
+
+int bpf_foreign_install(Unit *u) {
+        _cleanup_free_ char *cgroup_path = NULL;
+        CGroupBPFForeignProgram *p;
+        CGroupContext *cc;
+        int r;
+
+        assert(u);
+
+        cc = unit_get_cgroup_context(u);
+        if (!cc)
+                return 0;
+
+        r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, NULL, &cgroup_path);
+        if (r < 0)
+                return log_unit_error_errno(u, r, "Failed to get cgroup path: %m");
+
+        LIST_FOREACH(programs, p, cc->bpf_foreign_programs) {
+                r = bpf_foreign_prepare(u, p->attach_type, p->bpffs_path);
+                if (r < 0)
+                        return log_unit_error_errno(u, r, "Failed to prepare foreign BPF hashmap: %m");
+        }
+
+        r = attach_programs(u, cgroup_path, u->bpf_foreign_by_key, BPF_F_ALLOW_MULTI);
+        if (r < 0)
+                  return log_unit_error_errno(u, r, "Failed to install foreign BPF programs: %m");
+
+        return 0;
+}
diff --git a/src/core/bpf-foreign.h b/src/core/bpf-foreign.h
new file mode 100644 (file)
index 0000000..7704986
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#pragma once
+
+#include "unit.h"
+
+int bpf_foreign_supported(void);
+/*
+ * Attach cgroup-bpf programs foreign to systemd, i.e. loaded to the kernel by an entity
+ * external to systemd.
+ */
+int bpf_foreign_install(Unit *u);
index 96073b108b2e7674e88bd4b4936cf64bb0967a3a..8b5df7610c80c4ed982ffa9332c18601d96bc175 100644 (file)
@@ -8,6 +8,7 @@
 #include "blockdev-util.h"
 #include "bpf-devices.h"
 #include "bpf-firewall.h"
+#include "bpf-foreign.h"
 #include "btrfs-util.h"
 #include "bus-error.h"
 #include "cgroup-setup.h"
@@ -190,6 +191,15 @@ void cgroup_context_free_blockio_device_bandwidth(CGroupContext *c, CGroupBlockI
         free(b);
 }
 
+void cgroup_context_remove_bpf_foreign_program(CGroupContext *c, CGroupBPFForeignProgram *p) {
+        assert(c);
+        assert(p);
+
+        LIST_REMOVE(programs, c->bpf_foreign_programs, p);
+        free(p->bpffs_path);
+        free(p);
+}
+
 void cgroup_context_done(CGroupContext *c) {
         assert(c);
 
@@ -217,6 +227,9 @@ void cgroup_context_done(CGroupContext *c) {
         c->ip_filters_ingress = strv_free(c->ip_filters_ingress);
         c->ip_filters_egress = strv_free(c->ip_filters_egress);
 
+        while (c->bpf_foreign_programs)
+                cgroup_context_remove_bpf_foreign_program(c, c->bpf_foreign_programs);
+
         cpu_set_reset(&c->cpuset_cpus);
         cpu_set_reset(&c->cpuset_mems);
 }
@@ -360,6 +373,7 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
         CGroupIODeviceLatency *l;
         CGroupBlockIODeviceBandwidth *b;
         CGroupBlockIODeviceWeight *w;
+        CGroupBPFForeignProgram *p;
         CGroupDeviceAllow *a;
         CGroupContext *c;
         IPAddressAccessItem *iaai;
@@ -544,6 +558,10 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
 
         STRV_FOREACH(path, c->ip_filters_egress)
                 fprintf(f, "%sIPEgressFilterPath: %s\n", prefix, *path);
+
+        LIST_FOREACH(programs, p, c->bpf_foreign_programs)
+                fprintf(f, "%sBPFProgram: %s:%s",
+                        prefix, bpf_cgroup_attach_type_to_string(p->attach_type), p->bpffs_path);
 }
 
 int cgroup_add_device_allow(CGroupContext *c, const char *dev, const char *mode) {
@@ -575,6 +593,34 @@ int cgroup_add_device_allow(CGroupContext *c, const char *dev, const char *mode)
         return 0;
 }
 
+int cgroup_add_bpf_foreign_program(CGroupContext *c, uint32_t attach_type, const char *bpffs_path) {
+        CGroupBPFForeignProgram *p;
+        _cleanup_free_ char *d = NULL;
+
+        assert(c);
+        assert(bpffs_path);
+
+        if (!path_is_normalized(bpffs_path) || !path_is_absolute(bpffs_path))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Path is not normalized: %m");
+
+        d = strdup(bpffs_path);
+        if (!d)
+                return log_oom();
+
+        p = new(CGroupBPFForeignProgram, 1);
+        if (!p)
+                return log_oom();
+
+        *p = (CGroupBPFForeignProgram) {
+                .attach_type = attach_type,
+                .bpffs_path = TAKE_PTR(d),
+        };
+
+        LIST_PREPEND(programs, c->bpf_foreign_programs, TAKE_PTR(p));
+
+        return 0;
+}
+
 #define UNIT_DEFINE_ANCESTOR_MEMORY_LOOKUP(entry)                       \
         uint64_t unit_get_ancestor_##entry(Unit *u) {                   \
                 CGroupContext *c;                                       \
@@ -1115,6 +1161,12 @@ static void set_io_weight(Unit *u, const char *controller, uint64_t weight) {
         (void) set_attribute_and_warn(u, controller, p, buf);
 }
 
+static void cgroup_apply_bpf_foreign_program(Unit *u) {
+        assert(u);
+
+        (void) bpf_foreign_install(u);
+}
+
 static void cgroup_context_apply(
                 Unit *u,
                 CGroupMask apply_mask,
@@ -1428,6 +1480,9 @@ static void cgroup_context_apply(
 
         if (apply_mask & CGROUP_MASK_BPF_FIREWALL)
                 cgroup_apply_firewall(u);
+
+        if (apply_mask & CGROUP_MASK_BPF_FOREIGN)
+                cgroup_apply_bpf_foreign_program(u);
 }
 
 static bool unit_get_needs_bpf_firewall(Unit *u) {
@@ -1460,6 +1515,17 @@ static bool unit_get_needs_bpf_firewall(Unit *u) {
         return false;
 }
 
+static bool unit_get_needs_bpf_foreign_program(Unit *u) {
+        CGroupContext *c;
+        assert(u);
+
+        c = unit_get_cgroup_context(u);
+        if (!c)
+                return false;
+
+        return !LIST_IS_EMPTY(c->bpf_foreign_programs);
+}
+
 static CGroupMask unit_get_cgroup_mask(Unit *u) {
         CGroupMask mask = 0;
         CGroupContext *c;
@@ -1511,6 +1577,9 @@ static CGroupMask unit_get_bpf_mask(Unit *u) {
         if (unit_get_needs_bpf_firewall(u))
                 mask |= CGROUP_MASK_BPF_FIREWALL;
 
+        if (unit_get_needs_bpf_foreign_program(u))
+                mask |= CGROUP_MASK_BPF_FOREIGN;
+
         return mask;
 }
 
@@ -2989,6 +3058,11 @@ static int cg_bpf_mask_supported(CGroupMask *ret) {
         if (r > 0)
                 mask |= CGROUP_MASK_BPF_DEVICES;
 
+        /* BPF pinned prog */
+        r = bpf_foreign_supported();
+        if (r > 0)
+                mask |= CGROUP_MASK_BPF_FOREIGN;
+
         *ret = mask;
         return 0;
 }
index fa79ba15239e80407e3158343ce112f0c2bd039e..be3060eba7c06bf52949634bde21c1930ceebbd3 100644 (file)
@@ -31,6 +31,7 @@ typedef struct CGroupIODeviceLimit CGroupIODeviceLimit;
 typedef struct CGroupIODeviceLatency CGroupIODeviceLatency;
 typedef struct CGroupBlockIODeviceWeight CGroupBlockIODeviceWeight;
 typedef struct CGroupBlockIODeviceBandwidth CGroupBlockIODeviceBandwidth;
+typedef struct CGroupBPFForeignProgram CGroupBPFForeignProgram;
 
 typedef enum CGroupDevicePolicy {
         /* When devices listed, will allow those, plus built-in ones, if none are listed will allow
@@ -94,6 +95,12 @@ struct CGroupBlockIODeviceBandwidth {
         uint64_t wbps;
 };
 
+struct CGroupBPFForeignProgram {
+        LIST_FIELDS(CGroupBPFForeignProgram, programs);
+        uint32_t attach_type;
+        char *bpffs_path;
+};
+
 struct CGroupContext {
         bool cpu_accounting;
         bool io_accounting;
@@ -142,6 +149,7 @@ struct CGroupContext {
 
         char **ip_filters_ingress;
         char **ip_filters_egress;
+        LIST_HEAD(CGroupBPFForeignProgram, bpf_foreign_programs);
 
         /* For legacy hierarchies */
         uint64_t cpu_shares;
@@ -202,8 +210,10 @@ void cgroup_context_free_io_device_limit(CGroupContext *c, CGroupIODeviceLimit *
 void cgroup_context_free_io_device_latency(CGroupContext *c, CGroupIODeviceLatency *l);
 void cgroup_context_free_blockio_device_weight(CGroupContext *c, CGroupBlockIODeviceWeight *w);
 void cgroup_context_free_blockio_device_bandwidth(CGroupContext *c, CGroupBlockIODeviceBandwidth *b);
+void cgroup_context_remove_bpf_foreign_program(CGroupContext *c, CGroupBPFForeignProgram *p);
 
 int cgroup_add_device_allow(CGroupContext *c, const char *dev, const char *mode);
+int cgroup_add_bpf_foreign_program(CGroupContext *c, uint32_t attach_type, const char *path);
 
 void cgroup_oomd_xattr_apply(Unit *u, const char *cgroup_path);
 
index 04d2ba34f30f6e9a1fbf7db93ad4bf3d7d7eb41c..60a2ad781626dc7f02cecd23a6f0e8b15da2a501 100644 (file)
@@ -5,6 +5,7 @@
 #include "af-list.h"
 #include "alloc-util.h"
 #include "bpf-firewall.h"
+#include "bpf-foreign.h"
 #include "bus-get-properties.h"
 #include "cgroup-util.h"
 #include "cgroup.h"
@@ -347,6 +348,33 @@ static int property_get_ip_address_access(
         return sd_bus_message_close_container(reply);
 }
 
+static int property_get_bpf_foreign_program(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+        CGroupContext *c = userdata;
+        CGroupBPFForeignProgram *p;
+        int r;
+
+        r = sd_bus_message_open_container(reply, 'a', "(ss)");
+        if (r < 0)
+                return r;
+
+        LIST_FOREACH(programs, p, c->bpf_foreign_programs) {
+                const char *attach_type = bpf_cgroup_attach_type_to_string(p->attach_type);
+
+                r = sd_bus_message_append(reply, "(ss)", attach_type, p->bpffs_path);
+                if (r < 0)
+                        return r;
+        }
+
+        return sd_bus_message_close_container(reply);
+}
+
 const sd_bus_vtable bus_cgroup_vtable[] = {
         SD_BUS_VTABLE_START(0),
         SD_BUS_PROPERTY("Delegate", "b", bus_property_get_bool, offsetof(CGroupContext, delegate), 0),
@@ -398,6 +426,7 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
         SD_BUS_PROPERTY("ManagedOOMMemoryPressure", "s", property_get_managed_oom_mode, offsetof(CGroupContext, moom_mem_pressure), 0),
         SD_BUS_PROPERTY("ManagedOOMMemoryPressureLimit", "u", NULL, offsetof(CGroupContext, moom_mem_pressure_limit), 0),
         SD_BUS_PROPERTY("ManagedOOMPreference", "s", property_get_managed_oom_preference, offsetof(CGroupContext, moom_preference), 0),
+        SD_BUS_PROPERTY("BPFProgram", "a(ss)", property_get_bpf_foreign_program, 0, 0),
         SD_BUS_VTABLE_END
 };
 
@@ -422,7 +451,7 @@ static int bus_cgroup_set_transient_property(
                 int b;
 
                 if (!UNIT_VTABLE(u)->can_delegate)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Delegation not available for unit type");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Delegation not available for unit type");
 
                 r = sd_bus_message_read(message, "b", &b);
                 if (r < 0)
@@ -441,7 +470,7 @@ static int bus_cgroup_set_transient_property(
                 CGroupMask mask = 0;
 
                 if (streq(name, "DelegateControllers") && !UNIT_VTABLE(u)->can_delegate)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Delegation not available for unit type");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Delegation not available for unit type");
 
                 r = sd_bus_message_enter_container(message, 'a', "s");
                 if (r < 0)
@@ -570,6 +599,85 @@ static int bus_cgroup_set_transient_property(
                         }
                 }
 
+                return 1;
+        } else if (streq(name, "BPFProgram")) {
+                const char *a, *p;
+                size_t n = 0;
+
+                r = sd_bus_message_enter_container(message, 'a', "(ss)");
+                if (r < 0)
+                        return r;
+
+                while ((r = sd_bus_message_read(message, "(ss)", &a, &p)) > 0) {
+                        int attach_type = bpf_cgroup_attach_type_from_string(a);
+                        if (attach_type < 0)
+                                return sd_bus_error_setf(
+                                                error,
+                                                SD_BUS_ERROR_INVALID_ARGS,
+                                                "%s expects a valid BPF attach type, got '%s'.",
+                                                name, a);
+
+                        if (!path_is_normalized(p) || !path_is_absolute(p))
+                                return sd_bus_error_setf(
+                                                error,
+                                                SD_BUS_ERROR_INVALID_ARGS,
+                                                "%s= expects a normalized absolute path.",
+                                                name);
+
+                        if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+                                r = cgroup_add_bpf_foreign_program(c, attach_type, p);
+                                if (r < 0)
+                                        return r;
+                        }
+                        n++;
+                }
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_exit_container(message);
+                if (r < 0)
+                        return r;
+
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+                        _cleanup_free_ char *buf = NULL;
+                        _cleanup_fclose_ FILE *f = NULL;
+                        CGroupBPFForeignProgram *fp;
+                        size_t size = 0;
+
+                        if (n == 0)
+                                while (c->bpf_foreign_programs)
+                                        cgroup_context_remove_bpf_foreign_program(c, c->bpf_foreign_programs);
+
+                        f = open_memstream_unlocked(&buf, &size);
+                        if (!f)
+                                return -ENOMEM;
+
+                        fputs(name, f);
+                        fputs("=\n", f);
+
+                        LIST_FOREACH(programs, fp, c->bpf_foreign_programs)
+                                fprintf(f, "%s=%s:%s\n", name,
+                                                bpf_cgroup_attach_type_to_string(fp->attach_type),
+                                                fp->bpffs_path);
+
+                        r = fflush_and_check(f);
+                        if (r < 0)
+                                return r;
+
+                        unit_write_setting(u, flags, name, buf);
+
+                        if (!LIST_IS_EMPTY(c->bpf_foreign_programs)) {
+                                r = bpf_foreign_supported();
+                                if (r < 0)
+                                        return r;
+                                if (r == 0)
+                                        log_full(LOG_DEBUG,
+                                                 "Transient unit %s configures a BPF program pinned to BPF "
+                                                 "filesystem, but the local system does not support that.\n"
+                                                 "Starting this unit will fail!", u->id);
+                        }
+                }
+
                 return 1;
         }
 
@@ -944,7 +1052,7 @@ int bus_cgroup_set_property(
                         return r;
 
                 if (u64 <= 0)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "CPUQuotaPerSecUSec= value out of range");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "CPUQuotaPerSecUSec= value out of range");
 
                 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->cpu_quota_per_sec_usec = u64;
@@ -1122,7 +1230,7 @@ int bus_cgroup_set_property(
                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path '%s' specified in %s= is not normalized.", name, path);
 
                         if (!CGROUP_WEIGHT_IS_OK(weight) || weight == CGROUP_WEIGHT_INVALID)
-                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "IODeviceWeight= value out of range");
+                                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "IODeviceWeight= value out of range");
 
                         if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                                 CGroupIODeviceWeight *a = NULL, *b;
@@ -1380,7 +1488,7 @@ int bus_cgroup_set_property(
                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path '%s' specified in %s= is not normalized.", name, path);
 
                         if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight) || weight == CGROUP_BLKIO_WEIGHT_INVALID)
-                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "BlockIODeviceWeight= out of range");
+                                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "BlockIODeviceWeight= out of range");
 
                         if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                                 CGroupBlockIODeviceWeight *a = NULL, *b;
@@ -1476,12 +1584,12 @@ int bus_cgroup_set_property(
                 while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
 
                         if (!valid_device_allow_pattern(path) || strpbrk(path, WHITESPACE))
-                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires device node or pattern");
+                                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires device node or pattern");
 
                         if (isempty(rwm))
                                 rwm = "rwm";
                         else if (!in_charset(rwm, "rwm"))
-                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires combination of rwm flags");
+                                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires combination of rwm flags");
 
                         if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                                 CGroupDeviceAllow *a = NULL, *b;
index eda21f4734ec71b9a90aafcd20c7caccf346178b..3d4a06c0ff5acc116259ef56507dea49528d933f 100644 (file)
@@ -2060,7 +2060,7 @@ int bus_exec_context_set_transient_property(
                         return r;
 
                 if (!log_level_is_valid(level))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log level value out of range");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Log level value out of range");
 
                 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->syslog_priority = (c->syslog_priority & LOG_FACMASK) | level;
@@ -2077,7 +2077,7 @@ int bus_exec_context_set_transient_property(
                         return r;
 
                 if (!log_facility_unshifted_is_valid(facility))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log facility value out of range");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Log facility value out of range");
 
                 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->syslog_priority = (facility << 3) | LOG_PRI(c->syslog_priority);
@@ -2094,7 +2094,7 @@ int bus_exec_context_set_transient_property(
                         return r;
 
                 if (!isempty(n) && !log_namespace_name_valid(n))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log namespace name not valid");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Log namespace name not valid");
 
                 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
 
@@ -2140,13 +2140,13 @@ int bus_exec_context_set_transient_property(
                                 break;
 
                         if (memchr(p, 0, sz))
-                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Journal field contains zero byte");
+                                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Journal field contains zero byte");
 
                         eq = memchr(p, '=', sz);
                         if (!eq)
-                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Journal field contains no '=' character");
+                                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Journal field contains no '=' character");
                         if (!journal_field_valid(p, eq - (const char*) p, false))
-                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Journal field invalid");
+                                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Journal field invalid");
 
                         if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                                 t = reallocarray(c->log_extra_fields, c->n_log_extra_fields+1, sizeof(struct iovec));
@@ -2163,7 +2163,7 @@ int bus_exec_context_set_transient_property(
                         ((uint8_t*) copy)[sz] = 0;
 
                         if (!utf8_is_valid(copy))
-                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Journal field is not valid UTF-8");
+                                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Journal field is not valid UTF-8");
 
                         if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                                 c->log_extra_fields[c->n_log_extra_fields++] = IOVEC_MAKE(copy, sz);
@@ -2649,7 +2649,7 @@ int bus_exec_context_set_transient_property(
                         missing_ok = false;
 
                 if (!isempty(s) && !streq(s, "~") && !path_is_absolute(s))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "WorkingDirectory= expects an absolute path or '~'");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "WorkingDirectory= expects an absolute path or '~'");
 
                 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         if (streq(s, "~")) {
@@ -2678,7 +2678,7 @@ int bus_exec_context_set_transient_property(
                         return r;
 
                 if (!isempty(s) && !fdname_is_valid(s))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid file descriptor name");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid file descriptor name");
 
                 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
 
@@ -2830,7 +2830,7 @@ int bus_exec_context_set_transient_property(
                         return r;
 
                 if (!strv_env_is_valid(l))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment block.");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment block.");
 
                 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         if (strv_isempty(l)) {
@@ -2864,7 +2864,7 @@ int bus_exec_context_set_transient_property(
                         return r;
 
                 if (!strv_env_name_or_assignment_is_valid(l))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid UnsetEnvironment= list.");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid UnsetEnvironment= list.");
 
                 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         if (strv_isempty(l)) {
@@ -2897,7 +2897,7 @@ int bus_exec_context_set_transient_property(
                         return r;
 
                 if (!oom_score_adjust_is_valid(oa))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "OOM score adjust value out of range");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "OOM score adjust value out of range");
 
                 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->oom_score_adjust = oa;
@@ -3018,7 +3018,7 @@ int bus_exec_context_set_transient_property(
                         return r;
 
                 if (!strv_env_name_is_valid(l))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid PassEnvironment= block.");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid PassEnvironment= block.");
 
                 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         if (strv_isempty(l)) {
@@ -3193,7 +3193,7 @@ int bus_exec_context_set_transient_property(
                         if (!path_is_absolute(destination))
                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path %s is not absolute.", destination);
                         if (!IN_SET(mount_flags, 0, MS_REC))
-                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown mount flags.");
+                                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown mount flags.");
 
                         if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                                 r = bind_mount_add(&c->bind_mounts, &c->n_bind_mounts,
index e33896f9763f49a3f1293a0f67b460c6a0d24b19..974221199cbdb96e02de7d27720e9d533af030b9 100644 (file)
@@ -380,7 +380,7 @@ static int bus_get_unit_by_name(Manager *m, sd_bus_message *message, const char
 
                 u = manager_get_unit_by_pid(m, pid);
                 if (!u)
-                        return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Client not member of any unit.");
+                        return sd_bus_error_set(error, BUS_ERROR_NO_SUCH_UNIT, "Client not member of any unit.");
         } else {
                 u = manager_get_unit(m, name);
                 if (!u)
@@ -504,7 +504,7 @@ static int method_get_unit_by_invocation_id(sd_bus_message *message, void *userd
         else if (sz == 16)
                 memcpy(&id, a, sz);
         else
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid invocation ID");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid invocation ID");
 
         if (sd_id128_is_null(id)) {
                 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
@@ -1235,7 +1235,7 @@ static int method_subscribe(sd_bus_message *message, void *userdata, sd_bus_erro
                 if (r < 0)
                         return r;
                 if (r == 0)
-                        return sd_bus_error_setf(error, BUS_ERROR_ALREADY_SUBSCRIBED, "Client is already subscribed.");
+                        return sd_bus_error_set(error, BUS_ERROR_ALREADY_SUBSCRIBED, "Client is already subscribed.");
         }
 
         return sd_bus_reply_method_return(message, NULL);
@@ -1259,7 +1259,7 @@ static int method_unsubscribe(sd_bus_message *message, void *userdata, sd_bus_er
                 if (r < 0)
                         return r;
                 if (r == 0)
-                        return sd_bus_error_setf(error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
+                        return sd_bus_error_set(error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
         }
 
         return sd_bus_reply_method_return(message, NULL);
@@ -1309,7 +1309,7 @@ static int method_dump_by_fd(sd_bus_message *message, void *userdata, sd_bus_err
 }
 
 static int method_refuse_snapshot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Support for snapshots has been removed.");
+        return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Support for snapshots has been removed.");
 }
 
 static int verify_run_space(const char *message, sd_bus_error *error) {
@@ -1624,7 +1624,7 @@ static int method_set_environment(sd_bus_message *message, void *userdata, sd_bu
         if (r < 0)
                 return r;
         if (!strv_env_is_valid(plus))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments");
 
         r = bus_verify_set_environment_async(m, message, error);
         if (r < 0)
@@ -1729,7 +1729,7 @@ static int method_set_exit_code(sd_bus_message *message, void *userdata, sd_bus_
                 return r;
 
         if (MANAGER_IS_SYSTEM(m) && detect_container() <= 0)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "ExitCode can only be set for user service managers or in containers.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "ExitCode can only be set for user service managers or in containers.");
 
         m->return_value = code;
 
index 1bcb4836f63e9790a59c92a8dea5f4c8b33edf97..90ec6a686cdf46c3ff5095cc6c8fad453970c40b 100644 (file)
@@ -133,7 +133,7 @@ static int bus_scope_set_transient_property(
                 /* We can't support direct connections with this, as direct connections know no service or unique name
                  * concept, but the Controller field stores exactly that. */
                 if (sd_bus_message_get_bus(message) != u->manager->api_bus)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Sorry, Controller= logic only supported via the bus.");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Sorry, Controller= logic only supported via the bus.");
 
                 r = sd_bus_message_read(message, "s", &controller);
                 if (r < 0)
index 73906ebab73d23862b6ae4e71e1f752cb20fe479..4dea8d5aec1f333e0d214f18a4b16b658e797543 100644 (file)
@@ -109,7 +109,7 @@ static int bus_service_method_mount(sd_bus_message *message, void *userdata, sd_
         assert(u);
 
         if (!MANAGER_IS_SYSTEM(u->manager))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Adding bind mounts at runtime is only supported for system managers.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Adding bind mounts at runtime is only supported for system managers.");
 
         r = mac_selinux_unit_access_check(u, message, "start", error);
         if (r < 0)
@@ -120,12 +120,12 @@ static int bus_service_method_mount(sd_bus_message *message, void *userdata, sd_
                 return r;
 
         if (!path_is_absolute(src) || !path_is_normalized(src))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and normalized.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and normalized.");
 
         if (!is_image && isempty(dest))
                 dest = src;
         else if (!path_is_absolute(dest) || !path_is_normalized(dest))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and normalized.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and normalized.");
 
         if (is_image) {
                 r = bus_read_mount_options(message, error, &options, NULL, "");
@@ -147,23 +147,23 @@ static int bus_service_method_mount(sd_bus_message *message, void *userdata, sd_
                 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
 
         if (u->type != UNIT_SERVICE)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit is not of type .service");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Unit is not of type .service");
 
         /* If it would be dropped at startup time, return an error. The context should always be available, but
          * there's an assert in exec_needs_mount_namespace, so double-check just in case. */
         c = unit_get_exec_context(u);
         if (!c)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot access unit execution context");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot access unit execution context");
         if (path_startswith_strv(dest, c->inaccessible_paths))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s is not accessible to this unit", dest);
 
         /* Ensure that the unit was started in a private mount namespace */
         if (!exec_needs_mount_namespace(c, NULL, unit_get_exec_runtime(u)))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit not running in private mount namespace, cannot activate bind mount");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Unit not running in private mount namespace, cannot activate bind mount");
 
         unit_pid = unit_main_pid(u);
         if (unit_pid == 0 || !UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u)))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit is not running");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Unit is not running");
 
         propagate_directory = strjoina("/run/systemd/propagate/", u->id);
         if (is_image)
index 88b2f2cacf58647482d199875c8121a64fb772f9..e54c473d1101c2a16f572dd3596534b8266fa273 100644 (file)
@@ -183,7 +183,7 @@ static int timer_add_one_calendar_spec(
 
         r = calendar_spec_from_string(str, &c);
         if (r == -EINVAL)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid calendar spec");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid calendar spec");
         if (r < 0)
                 return r;
 
index 39d6799b59a7f91818bbb19b226c4543ce1ace02..d73161c76c07917b2be28e302a1f3e93bafe8319 100644 (file)
@@ -527,7 +527,7 @@ int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *
         }
 
         if (!SIGNAL_VALID(signo))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
 
         r = bus_verify_manage_units_async_full(
                         u,
@@ -653,7 +653,7 @@ int bus_unit_method_unref(sd_bus_message *message, void *userdata, sd_bus_error
 
         r = bus_unit_track_remove_sender(u, message);
         if (r == -EUNATCH)
-                return sd_bus_error_setf(error, BUS_ERROR_NOT_REFERENCED, "Unit has not been referenced yet.");
+                return sd_bus_error_set(error, BUS_ERROR_NOT_REFERENCED, "Unit has not been referenced yet.");
         if (r < 0)
                 return r;
 
@@ -719,9 +719,9 @@ int bus_unit_method_clean(sd_bus_message *message, void *userdata, sd_bus_error
         if (r == -EOPNOTSUPP)
                 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Unit '%s' does not supporting cleaning.", u->id);
         if (r == -EUNATCH)
-                return sd_bus_error_setf(error, BUS_ERROR_NOTHING_TO_CLEAN, "No matching resources found.");
+                return sd_bus_error_set(error, BUS_ERROR_NOTHING_TO_CLEAN, "No matching resources found.");
         if (r == -EBUSY)
-                return sd_bus_error_setf(error, BUS_ERROR_UNIT_BUSY, "Unit is not inactive or has pending job.");
+                return sd_bus_error_set(error, BUS_ERROR_UNIT_BUSY, "Unit is not inactive or has pending job.");
         if (r < 0)
                 return r;
 
@@ -768,9 +768,9 @@ static int bus_unit_method_freezer_generic(sd_bus_message *message, void *userda
         if (r == -EOPNOTSUPP)
                 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Unit '%s' does not support freezing.", u->id);
         if (r == -EBUSY)
-                return sd_bus_error_setf(error, BUS_ERROR_UNIT_BUSY, "Unit has a pending job.");
+                return sd_bus_error_set(error, BUS_ERROR_UNIT_BUSY, "Unit has a pending job.");
         if (r == -EHOSTDOWN)
-                return sd_bus_error_setf(error, BUS_ERROR_UNIT_INACTIVE, "Unit is inactive.");
+                return sd_bus_error_set(error, BUS_ERROR_UNIT_INACTIVE, "Unit is inactive.");
         if (r == -EALREADY)
                 return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Previously requested freezer operation for unit '%s' is still in progress.", u->id);
         if (r < 0)
@@ -1442,10 +1442,10 @@ int bus_unit_method_attach_processes(sd_bus_message *message, void *userdata, sd
         }
 
         if (!unit_cgroup_delegate(u))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Process migration not available on non-delegated units.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Process migration not available on non-delegated units.");
 
         if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u)))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit is not active, refusing.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Unit is not active, refusing.");
 
         r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID, &creds);
         if (r < 0)
@@ -1930,7 +1930,7 @@ static int bus_unit_set_live_property(
                         return r;
 
                 if (some_plus_minus && some_absolute)
-                        return sd_bus_error_setf(error, BUS_ERROR_BAD_UNIT_SETTING, "Bad marker syntax.");
+                        return sd_bus_error_set(error, BUS_ERROR_BAD_UNIT_SETTING, "Bad marker syntax.");
 
                 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         if (some_absolute)
@@ -1999,7 +1999,7 @@ static int bus_set_transient_exit_status(
                 return r;
 
         if (k > 255)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Exit status must be in range 0…255 or negative.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Exit status must be in range 0…255 or negative.");
 
         if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                 *p = k < 0 ? -1 : k;
@@ -2205,11 +2205,11 @@ static int bus_unit_set_transient_property(
                 const char *s;
 
                 if (!UNIT_HAS_CGROUP_CONTEXT(u))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "The slice property is only available for units with control groups.");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "The slice property is only available for units with control groups.");
                 if (u->type == UNIT_SLICE)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Slice may not be set for slice units.");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Slice may not be set for slice units.");
                 if (unit_has_name(u, SPECIAL_INIT_SCOPE))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot set slice for init.scope");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot set slice for init.scope");
 
                 r = sd_bus_message_read(message, "s", &s);
                 if (r < 0)
index 5db484b8de64531da0a9c5a0dc126d0d813b6dd7..26e34ac4d0f93be186c2b02f2de73676478de5c2 100644 (file)
@@ -164,7 +164,7 @@ static int signal_activation_request(sd_bus_message *message, void *userdata, sd
 
         if (manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SERVICE) ||
             manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SOCKET)) {
-                r = sd_bus_error_setf(&error, BUS_ERROR_SHUTTING_DOWN, "Refusing activation, D-Bus is shutting down.");
+                r = sd_bus_error_set(&error, BUS_ERROR_SHUTTING_DOWN, "Refusing activation, D-Bus is shutting down.");
                 goto failed;
         }
 
index 2152fa8500077021eb7fe879a826fc6390eb0268..4d6b75e8458b8d95fafdd6f7064c61f3b621ab22 100644 (file)
@@ -4916,6 +4916,7 @@ void exec_context_done(ExecContext *c) {
         c->stdin_data_size = 0;
 
         c->network_namespace_path = mfree(c->network_namespace_path);
+        c->ipc_namespace_path = mfree(c->ipc_namespace_path);
 
         c->log_namespace = mfree(c->log_namespace);
 
index 5ef785c0deea156e4606834653ab5282c47faeb1..4bd1207e2c55ba5d7039e0cf2b4f7fcddec05f97 100644 (file)
@@ -234,7 +234,8 @@ $1.ManagedOOMSwap,                       config_parse_managed_oom_mode,
 $1.ManagedOOMMemoryPressure,             config_parse_managed_oom_mode,               0,                                  offsetof($1, cgroup_context.moom_mem_pressure)
 $1.ManagedOOMMemoryPressureLimit,        config_parse_managed_oom_mem_pressure_limit, 0,                                  offsetof($1, cgroup_context.moom_mem_pressure_limit)
 $1.ManagedOOMPreference,                 config_parse_managed_oom_preference,         0,                                  offsetof($1, cgroup_context.moom_preference)
-$1.NetClass,                             config_parse_warn_compat,                    DISABLED_LEGACY,                    0'
+$1.NetClass,                             config_parse_warn_compat,                    DISABLED_LEGACY,                    0
+$1.BPFProgram,                           config_parse_bpf_foreign_program,            0,                                  offsetof($1, cgroup_context)'
 )m4_dnl
 Unit.Description,                        config_parse_unit_string_printf,             0,                                  offsetof(Unit, description)
 Unit.Documentation,                      config_parse_documentation,                  0,                                  offsetof(Unit, documentation)
index 1a1e58976ae3310d2302b142b9fa8dd6156ff052..a0c403a60c93d78529b98dfd446cc681d084eb53 100644 (file)
@@ -19,6 +19,7 @@
 #include "all-units.h"
 #include "alloc-util.h"
 #include "bpf-firewall.h"
+#include "bpf-program.h"
 #include "bus-error.h"
 #include "bus-internal.h"
 #include "bus-util.h"
@@ -5581,6 +5582,64 @@ int config_parse_ip_filter_bpf_progs(
         return 0;
 }
 
+int config_parse_bpf_foreign_program(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+        _cleanup_free_ char *resolved = NULL, *word = NULL;
+        CGroupContext *c = data;
+        Unit *u = userdata;
+        int attach_type, r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+
+        if (isempty(rvalue)) {
+                while (c->bpf_foreign_programs)
+                        cgroup_context_remove_bpf_foreign_program(c, c->bpf_foreign_programs);
+
+                return 0;
+        }
+
+        r = extract_first_word(&rvalue, &word, ":", 0);
+        if (r == -ENOMEM)
+                return log_oom();
+        if (r < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse foreign BPF program, ignoring: %s", rvalue);
+                return 0;
+        }
+
+        attach_type = bpf_cgroup_attach_type_from_string(word);
+        if (attach_type < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown BPF attach type=%s, ignoring: %s", word, rvalue);
+                return 0;
+        }
+
+        r = unit_full_printf(u, rvalue, &resolved);
+        if (r < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
+                return 0;
+        }
+
+        r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
+        if (r < 0)
+                return 0;
+
+        r = cgroup_add_bpf_foreign_program(c, attach_type, resolved);
+        if (r < 0)
+                return log_error_errno(r, "Failed to add foreign BPF program to cgroup context: %m");
+
+        return 0;
+}
+
 static int merge_by_names(Unit **u, Set *names, const char *id) {
         char *k;
         int r;
index 4746a8a792b2674f841bb3c9673be6b359d099bc..e99c9a405598859a930877c7da8fded95f78c5ba 100644 (file)
@@ -140,6 +140,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_swap_priority);
 CONFIG_PARSER_PROTOTYPE(config_parse_mount_images);
 CONFIG_PARSER_PROTOTYPE(config_parse_socket_timestamping);
 CONFIG_PARSER_PROTOTYPE(config_parse_extension_images);
+CONFIG_PARSER_PROTOTYPE(config_parse_bpf_foreign_program);
 
 /* gperf prototypes */
 const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
index 0ddd6298513cba22f08be59d99ed3c85b5e9a550..63254b4a9c83e7213932bd50b856338a6bbb4ec1 100644 (file)
@@ -1367,7 +1367,7 @@ static int status_welcome(void) {
 
 static int write_container_id(void) {
         const char *c;
-        int r;
+        int r = 0;  /* avoid false maybe-uninitialized warning */
 
         c = getenv("container");
         if (isempty(c))
index 57bb25ca2543507ff5a82dc989af453a81435abe..f7f67065c6722ea79d3848c3ce1d57f5cda3010c 100644 (file)
@@ -1732,13 +1732,13 @@ int manager_add_job(
         assert(mode < _JOB_MODE_MAX);
 
         if (mode == JOB_ISOLATE && type != JOB_START)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Isolate is only valid for start.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Isolate is only valid for start.");
 
         if (mode == JOB_ISOLATE && !unit->allow_isolate)
-                return sd_bus_error_setf(error, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
+                return sd_bus_error_set(error, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
 
         if (mode == JOB_TRIGGERING && type != JOB_STOP)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "--job-mode=triggering is only valid for stop.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "--job-mode=triggering is only valid for stop.");
 
         log_unit_debug(unit, "Trying to enqueue job %s/%s/%s", unit->id, job_type_to_string(type), job_mode_to_string(mode));
 
index a389c906b368609084a171fd8cd9235a56ef8110..a1294f3a7251cc3ebc80cc34ee81b6d7bffad4f0 100644 (file)
@@ -11,6 +11,8 @@ libcore_sources = '''
         bpf-devices.h
         bpf-firewall.c
         bpf-firewall.h
+        bpf-foreign.c
+        bpf-foreign.h
         cgroup.c
         cgroup.h
         core-varlink.c
index 18f6fb59bc0a0a75b17799032dcc887940937c99..5605c710536796abe170e91a753740406a91f8b9 100644 (file)
@@ -250,7 +250,7 @@ int mac_selinux_generic_access_check(
                         if (!enforce)
                                 return 0;
 
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get current context.");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get current context.");
                 }
 
                 tclass = "system";
@@ -270,7 +270,7 @@ int mac_selinux_generic_access_check(
                 r = errno_or_else(EPERM);
 
                 if (enforce)
-                        sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "SELinux policy denies access.");
+                        sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "SELinux policy denies access.");
         }
 
         log_debug_errno(r, "SELinux access check scon=%s tcon=%s tclass=%s perm=%s state=%s path=%s cmdline=%s: %m",
index 2c5dc54379a77e0e86f2816ba79c58a91ee6e6d3..cf83272dcbed6b01abfe3034206c9fa0ff377413 100644 (file)
@@ -11,6 +11,7 @@
 #include "all-units.h"
 #include "alloc-util.h"
 #include "bpf-firewall.h"
+#include "bpf-foreign.h"
 #include "bus-common-errors.h"
 #include "bus-util.h"
 #include "cgroup-setup.h"
@@ -723,6 +724,8 @@ Unit* unit_free(Unit *u) {
         set_free(u->ip_bpf_custom_ingress_installed);
         set_free(u->ip_bpf_custom_egress_installed);
 
+        hashmap_free(u->bpf_foreign_by_key);
+
         bpf_program_unref(u->bpf_device_control_installed);
 
         condition_free_list(u->conditions);
index 6d38e6668031112855e81e66f88d18549f982758..128122b8df7bc82081d553824e05d8166675747c 100644 (file)
@@ -305,6 +305,10 @@ typedef struct Unit {
         Set *ip_bpf_custom_egress;
         Set *ip_bpf_custom_egress_installed;
 
+        /* BPF programs managed (e.g. loaded to kernel) by an entity external to systemd,
+         * attached to unit cgroup by provided program fd and attach type. */
+        Hashmap *bpf_foreign_by_key;
+
         uint64_t ip_accounting_extra[_CGROUP_IP_ACCOUNTING_METRIC_MAX];
 
         /* Low-priority event source which is used to remove watched PIDs that have gone away, and subscribe to any new
index 2fb2404500e88c026241b69ad03c71178ac831e8..b6cc7e3887f97497911a176ba1ab9790caf84748 100644 (file)
@@ -703,14 +703,16 @@ static int submit_coredump(
                 struct iovec_wrapper *iovw,
                 int input_fd) {
 
+        _cleanup_(json_variant_unrefp) JsonVariant *json_metadata = NULL;
         _cleanup_close_ int coredump_fd = -1, coredump_node_fd = -1;
         _cleanup_free_ char *filename = NULL, *coredump_data = NULL;
         _cleanup_free_ char *stacktrace = NULL;
         char *core_message;
+        const char *module_name;
         uint64_t coredump_size = UINT64_MAX;
         bool truncated = false;
+        JsonVariant *module_json;
         int r;
-
         assert(context);
         assert(iovw);
         assert(input_fd >= 0);
@@ -757,7 +759,7 @@ static int submit_coredump(
                           "than %"PRIu64" (the configured maximum)",
                           coredump_size, arg_process_size_max);
         } else
-                coredump_make_stack_trace(coredump_fd, context->meta[META_EXE], &stacktrace);
+                coredump_parse_core(coredump_fd, context->meta[META_EXE], &stacktrace, &json_metadata);
 #endif
 
 log:
@@ -781,6 +783,34 @@ log:
         if (truncated)
                 (void) iovw_put_string_field(iovw, "COREDUMP_TRUNCATED=", "1");
 
+        /* If we managed to parse any ELF metadata (build-id, ELF package meta),
+         * attach it as journal metadata. */
+        if (json_metadata) {
+                _cleanup_free_ char *formatted_json = NULL;
+
+                r = json_variant_format(json_metadata, 0, &formatted_json);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to format JSON package metadata: %m");
+
+                (void) iovw_put_string_field(iovw, "COREDUMP_PACKAGE_JSON=", formatted_json);
+        }
+
+        JSON_VARIANT_OBJECT_FOREACH(module_name, module_json, json_metadata) {
+                JsonVariant *package_name, *package_version;
+
+                /* We only add structured fields for the 'main' ELF module */
+                if (!path_equal_filename(module_name, context->meta[META_EXE]))
+                        continue;
+
+                package_name = json_variant_by_key(module_json, "name");
+                if (package_name)
+                        (void) iovw_put_string_field(iovw, "COREDUMP_PACKAGE_NAME=", json_variant_string(package_name));
+
+                package_version = json_variant_by_key(module_json, "version");
+                if (package_version)
+                        (void) iovw_put_string_field(iovw, "COREDUMP_PACKAGE_VERSION=", json_variant_string(package_version));
+        }
+
         /* Optionally store the entire coredump in the journal */
         if (arg_storage == COREDUMP_STORAGE_JOURNAL) {
                 if (coredump_size <= arg_journal_size_max) {
index 0c4ef2e123486216213435956539b90482b4454c..02bad966c1cc7dd96bffc231889cd6f9d89c4003 100644 (file)
@@ -545,7 +545,8 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) {
                 *boot_id = NULL, *machine_id = NULL, *hostname = NULL,
                 *slice = NULL, *cgroup = NULL, *owner_uid = NULL,
                 *message = NULL, *timestamp = NULL, *filename = NULL,
-                *truncated = NULL, *coredump = NULL;
+                *truncated = NULL, *coredump = NULL,
+                *pkgmeta_name = NULL, *pkgmeta_version = NULL, *pkgmeta_json = NULL;
         const void *d;
         size_t l;
         bool normal_coredump;
@@ -574,6 +575,9 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) {
                 RETRIEVE(d, l, "COREDUMP_FILENAME", filename);
                 RETRIEVE(d, l, "COREDUMP_TRUNCATED", truncated);
                 RETRIEVE(d, l, "COREDUMP", coredump);
+                RETRIEVE(d, l, "COREDUMP_PACKAGE_NAME", pkgmeta_name);
+                RETRIEVE(d, l, "COREDUMP_PACKAGE_VERSION", pkgmeta_version);
+                RETRIEVE(d, l, "COREDUMP_PACKAGE_JSON", pkgmeta_json);
                 RETRIEVE(d, l, "_BOOT_ID", boot_id);
                 RETRIEVE(d, l, "_MACHINE_ID", machine_id);
                 RETRIEVE(d, l, "MESSAGE", message);
@@ -716,6 +720,37 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) {
         else
                 fprintf(file, "       Storage: none\n");
 
+        if (pkgmeta_name && pkgmeta_version)
+                fprintf(file, "       Package: %s/%s\n", pkgmeta_name, pkgmeta_version);
+
+        /* Print out the build-id of the 'main' ELF module, by matching the JSON key
+         * with the 'exe' field. */
+        if (exe && pkgmeta_json) {
+                _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
+
+                r = json_parse(pkgmeta_json, 0, &v, NULL, NULL);
+                if (r < 0)
+                        log_warning_errno(r, "json_parse on %s failed, ignoring: %m", pkgmeta_json);
+                else {
+                        const char *module_name;
+                        JsonVariant *module_json;
+
+                        JSON_VARIANT_OBJECT_FOREACH(module_name, module_json, v) {
+                                JsonVariant *build_id;
+
+                                /* We only print the build-id for the 'main' ELF module */
+                                if (!path_equal_filename(module_name, exe))
+                                        continue;
+
+                                build_id = json_variant_by_key(module_json, "buildId");
+                                if (build_id)
+                                        fprintf(file, "      build-id: %s\n", json_variant_string(build_id));
+
+                                break;
+                        }
+                }
+        }
+
         if (message) {
                 _cleanup_free_ char *m = NULL;
 
index a29ab1211c2feae5a5f4e6f59301639a0abf8df6..102ad2e65beb51ec0f8ff402b49ecc1590fa4621 100644 (file)
@@ -1,7 +1,9 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <dwarf.h>
+#include <elfutils/libdwelf.h>
 #include <elfutils/libdwfl.h>
+#include <libelf.h>
 #include <sys/types.h>
 #include <unistd.h>
 
@@ -9,6 +11,7 @@
 #include "fileio.h"
 #include "fd-util.h"
 #include "format-util.h"
+#include "hexdecoct.h"
 #include "macro.h"
 #include "stacktrace.h"
 #include "string-util.h"
@@ -16,6 +19,7 @@
 
 #define FRAMES_MAX 64
 #define THREADS_MAX 64
+#define ELF_PACKAGE_METADATA_ID 0xcafe1a7e
 
 struct stack_context {
         FILE *f;
@@ -23,6 +27,8 @@ struct stack_context {
         Elf *elf;
         unsigned n_thread;
         unsigned n_frame;
+        JsonVariant **package_metadata;
+        Set **modules;
 };
 
 static int frame_callback(Dwfl_Frame *frame, void *userdata) {
@@ -111,14 +117,212 @@ static int thread_callback(Dwfl_Thread *thread, void *userdata) {
         return DWARF_CB_OK;
 }
 
-static int make_stack_trace(int fd, const char *executable, char **ret) {
+static int parse_package_metadata(const char *name, JsonVariant *id_json, Elf *elf, struct stack_context *c) {
+        size_t n_program_headers;
+        int r;
+
+        assert(name);
+        assert(elf);
+        assert(c);
+
+        /* When iterating over PT_LOAD we will visit modules more than once */
+        if (set_contains(*c->modules, name))
+                return DWARF_CB_OK;
+
+        r = elf_getphdrnum(elf, &n_program_headers);
+        if (r < 0) /* Not the handle we are looking for - that's ok, skip it */
+                return DWARF_CB_OK;
+
+        /* Iterate over all program headers in that ELF object. These will have been copied by
+         * the kernel verbatim when the core file is generated. */
+        for (size_t i = 0; i < n_program_headers; ++i) {
+                size_t note_offset = 0, name_offset, desc_offset;
+                GElf_Phdr mem, *program_header;
+                GElf_Nhdr note_header;
+                Elf_Data *data;
+
+                /* Package metadata is in PT_NOTE headers. */
+                program_header = gelf_getphdr(elf, i, &mem);
+                if (!program_header || program_header->p_type != PT_NOTE)
+                        continue;
+
+                /* Fortunately there is an iterator we can use to walk over the
+                 * elements of a PT_NOTE program header. We are interested in the
+                 * note with type. */
+                data = elf_getdata_rawchunk(elf,
+                                            program_header->p_offset,
+                                            program_header->p_filesz,
+                                            ELF_T_NHDR);
+
+                while (note_offset < data->d_size &&
+                       (note_offset = gelf_getnote(data, note_offset, &note_header, &name_offset, &desc_offset)) > 0) {
+                        const char *note_name = (const char *)data->d_buf + name_offset;
+                        const char *payload = (const char *)data->d_buf + desc_offset;
+
+                        if (note_header.n_namesz == 0 || note_header.n_descsz == 0)
+                                continue;
+
+                        /* Package metadata might have different owners, but the
+                         * magic ID is always the same. */
+                        if (note_header.n_type == ELF_PACKAGE_METADATA_ID) {
+                                _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL;
+
+                                r = json_parse(payload, 0, &v, NULL, NULL);
+                                if (r < 0) {
+                                        log_error_errno(r, "json_parse on %s failed: %m", payload);
+                                        return DWARF_CB_ABORT;
+                                }
+
+                                /* First pretty-print to the buffer, so that the metadata goes as
+                                 * plaintext in the journal. */
+                                fprintf(c->f, "Metadata for module %s owned by %s found: ",
+                                        name, note_name);
+                                json_variant_dump(v, JSON_FORMAT_NEWLINE|JSON_FORMAT_PRETTY, c->f, NULL);
+                                fputc('\n', c->f);
+
+                                /* Secondly, if we have a build-id, merge it in the same JSON object
+                                 * so that it appears all nicely together in the logs/metadata. */
+                                if (id_json) {
+                                        r = json_variant_merge(&v, id_json);
+                                        if (r < 0) {
+                                                log_error_errno(r, "json_variant_merge of package meta with buildid failed: %m");
+                                                return DWARF_CB_ABORT;
+                                        }
+                                }
+
+                                /* Then we build a new object using the module name as the key, and merge it
+                                 * with the previous parses, so that in the end it all fits together in a single
+                                 * JSON blob. */
+                                r = json_build(&w, JSON_BUILD_OBJECT(JSON_BUILD_PAIR(name, JSON_BUILD_VARIANT(v))));
+                                if (r < 0) {
+                                        log_error_errno(r, "Failed to build JSON object: %m");
+                                        return DWARF_CB_ABORT;
+                                }
+                                r = json_variant_merge(c->package_metadata, w);
+                                if (r < 0) {
+                                        log_error_errno(r, "json_variant_merge of package meta with buildid failed: %m");
+                                        return DWARF_CB_ABORT;
+                                }
+
+                                /* Finally stash the name, so we avoid double visits. */
+                                r = set_put_strdup(c->modules, name);
+                                if (r < 0) {
+                                        log_error_errno(r, "set_put_strdup failed: %m");
+                                        return DWARF_CB_ABORT;
+                                }
+
+                                return DWARF_CB_OK;
+                        }
+                }
+        }
+
+        /* Didn't find package metadata for this module - that's ok, just go to the next. */
+        return DWARF_CB_OK;
+}
+
+static int module_callback(Dwfl_Module *mod, void **userdata, const char *name, Dwarf_Addr start, void *arg) {
+        _cleanup_(json_variant_unrefp) JsonVariant *id_json = NULL;
+        struct stack_context *c = arg;
+        size_t n_program_headers;
+        GElf_Addr id_vaddr, bias;
+        const unsigned char *id;
+        int id_len, r;
+        Elf *elf;
+
+        assert(mod);
+        assert(c);
+
+        if (!name)
+                name = "(unnamed)"; /* For logging purposes */
+
+        /* We are iterating on each "module", which is what dwfl calls ELF objects contained in the
+         * core file, and extracting the build-id first and then the package metadata.
+         * We proceed in a best-effort fashion - not all ELF objects might contain both or either.
+         * The build-id is easy, as libdwfl parses it during the dwfl_core_file_report() call and
+         * stores it separately in an internal library struct. */
+        id_len = dwfl_module_build_id(mod, &id, &id_vaddr);
+        if (id_len <= 0)
+                /* If we don't find a build-id, note it in the journal message, and try
+                 * anyway to find the package metadata. It's unlikely to have the latter
+                 * without the former, but there's no hard rule. */
+                fprintf(c->f, "Found module %s without build-id.\n", name);
+        else {
+                JsonVariant *build_id;
+
+                /* We will later parse package metadata json and pass it to our caller. Prepare the
+                * build-id in json format too, so that it can be appended and parsed cleanly. It
+                * will then be added as metadata to the journal message with the stack trace. */
+                r = json_build(&id_json, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("buildId", JSON_BUILD_HEX(id, id_len))));
+                if (r < 0) {
+                        log_error_errno(r, "json_build on build-id failed: %m");
+                        return DWARF_CB_ABORT;
+                }
+
+                build_id = json_variant_by_key(id_json, "buildId");
+                assert_se(build_id);
+                fprintf(c->f, "Found module %s with build-id: %s\n", name, json_variant_string(build_id));
+        }
+
+        /* The .note.package metadata is more difficult. From the module, we need to get a reference
+         * to the ELF object first. We might be lucky and just get it from elfutils. */
+        elf = dwfl_module_getelf(mod, &bias);
+        if (elf)
+                return parse_package_metadata(name, id_json, elf, c);
+
+        /* We did not get the ELF object. That is likely because we didn't get direct
+         * access to the executable, and the version of elfutils does not yet support
+         * parsing it out of the core file directly.
+         * So fallback to manual extraction - get the PT_LOAD section from the core,
+         * and if it's the right one we can interpret it as an Elf object, and parse
+         * its notes manually. */
+
+        r = elf_getphdrnum(c->elf, &n_program_headers);
+        if (r < 0) {
+                log_warning("Could not parse number of program headers from core file: %s",
+                            elf_errmsg(-1)); /* -1 retrieves the most recent error */
+                return DWARF_CB_OK;
+        }
+
+        for (size_t i = 0; i < n_program_headers; ++i) {
+                GElf_Phdr mem, *program_header;
+                Elf_Data *data;
+
+                /* The core file stores the ELF files in the PT_LOAD segment .*/
+                program_header = gelf_getphdr(c->elf, i, &mem);
+                if (!program_header || program_header->p_type != PT_LOAD)
+                        continue;
+
+                /* Now get a usable Elf reference, and parse the notes from it. */
+                data = elf_getdata_rawchunk(c->elf,
+                                            program_header->p_offset,
+                                            program_header->p_filesz,
+                                            ELF_T_NHDR);
+
+                Elf *memelf = elf_memory(data->d_buf, data->d_size);
+                if (!memelf)
+                        continue;
+                r = parse_package_metadata(name, id_json, memelf, c);
+                if (r != DWARF_CB_OK)
+                        return r;
+        }
+
+        return DWARF_CB_OK;
+}
+
+static int parse_core(int fd, const char *executable, char **ret, JsonVariant **ret_package_metadata) {
 
         static const Dwfl_Callbacks callbacks = {
                 .find_elf = dwfl_build_id_find_elf,
+                .section_address = dwfl_offline_section_address,
                 .find_debuginfo = dwfl_standard_find_debuginfo,
         };
 
-        struct stack_context c = {};
+        _cleanup_(json_variant_unrefp) JsonVariant *package_metadata = NULL;
+        _cleanup_(set_freep) Set *modules = NULL;
+        struct stack_context c = {
+                .package_metadata = &package_metadata,
+                .modules = &modules,
+        };
         char *buf = NULL;
         size_t sz = 0;
         int r;
@@ -157,6 +361,11 @@ static int make_stack_trace(int fd, const char *executable, char **ret) {
                 goto finish;
         }
 
+        if (dwfl_getmodules(c.dwfl, &module_callback, &c, 0) < 0) {
+                r = -EINVAL;
+                goto finish;
+        }
+
         if (dwfl_core_file_attach(c.dwfl, c.elf) < 0) {
                 r = -EINVAL;
                 goto finish;
@@ -170,6 +379,8 @@ static int make_stack_trace(int fd, const char *executable, char **ret) {
         c.f = safe_fclose(c.f);
 
         *ret = TAKE_PTR(buf);
+        if (ret_package_metadata)
+                *ret_package_metadata = TAKE_PTR(package_metadata);
 
         r = 0;
 
@@ -187,10 +398,10 @@ finish:
         return r;
 }
 
-void coredump_make_stack_trace(int fd, const char *executable, char **ret) {
+void coredump_parse_core(int fd, const char *executable, char **ret, JsonVariant **ret_package_metadata) {
         int r;
 
-        r = make_stack_trace(fd, executable, ret);
+        r = parse_core(fd, executable, ret, ret_package_metadata);
         if (r == -EINVAL)
                 log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno()));
         else if (r < 0)
index b93574840424e5161366382d4da2a6a90c6f64ad..5039b934dda4ca30a51515f8bcb067b1b4f503fe 100644 (file)
@@ -1,4 +1,6 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
-void coredump_make_stack_trace(int fd, const char *executable, char **ret);
+#include "json.h"
+
+void coredump_parse_core(int fd, const char *executable, char **ret, JsonVariant **ret_package_metadata);
index 5c55dcd19757e559334f1a89c67e622733410c8d..ee31400e3f76c59a10fa6f5288d49be75bb93435 100644 (file)
@@ -1008,7 +1008,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
         _cleanup_(sd_event_unrefp) sd_event *event = NULL;
         _cleanup_free_ char *friendly = NULL;
         int keyslot = arg_key_slot, r;
-        size_t decrypted_key_size;
+        size_t decrypted_key_size = 0; /* Silence gcc warning about unitialized variable */
 
         assert(cd);
         assert(name);
@@ -1058,15 +1058,12 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
                                                 &policy_hash, &policy_hash_size,
                                                 &keyslot,
                                                 &token);
-                                if (r == -ENXIO) {
+                                if (r == -ENXIO)
                                         /* No further TPM2 tokens found in the LUKS2 header.*/
-                                        if (found_some)
-                                                return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
-                                                                       "No TPM2 metadata matching the current system state found in LUKS2 header, falling back to traditional unlocking.");
-                                        else
-                                                return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
-                                                                       "No TPM2 metadata enrolled in LUKS2 header, falling back to traditional unlocking.");
-                                }
+                                        return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
+                                                               found_some
+                                                               ? "No TPM2 metadata matching the current system state found in LUKS2 header, falling back to traditional unlocking."
+                                                               : "No TPM2 metadata enrolled in LUKS2 header, falling back to traditional unlocking.");
                                 if (r < 0)
                                         return r;
 
@@ -1091,6 +1088,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
                         if (r != -EAGAIN) /* EAGAIN means: no tpm2 chip found */
                                 return r;
                 }
+                assert(decrypted_key);
 
                 if (!monitor) {
                         /* We didn't find the TPM2 device. In this case, watch for it via udev. Let's create
index dda9b1881581b058b07907e8c05bca0159908877..42549a2cd8c6785c864767433fc30376b175b2ff 100644 (file)
@@ -105,6 +105,7 @@ static int open_parent_block_device(dev_t devnum, int *ret_fd) {
 }
 
 static int add_cryptsetup(const char *id, const char *what, bool rw, bool require, char **device) {
+#if HAVE_LIBCRYPTSETUP
         _cleanup_free_ char *e = NULL, *n = NULL, *d = NULL;
         _cleanup_fclose_ FILE *f = NULL;
         int r;
@@ -182,6 +183,9 @@ static int add_cryptsetup(const char *id, const char *what, bool rw, bool requir
         }
 
         return 0;
+#else
+        return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Partition is encrypted, but the project was compiled without libcryptsetup support");
+#endif
 }
 
 static int add_mount(
index cf1a2d9f9bb4e2a3477dc89d240b2e654d2f3f31..a187a75d863c9dc1c0492e09d84a9a133a05944b 100644 (file)
@@ -3362,4 +3362,4 @@ static int run(int argc, char *argv[]) {
         return dispatch_verb(argc, argv, verbs, NULL);
 }
 
-DEFINE_MAIN_FUNCTION(run);
+DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);
index d70fda5f4403e5d13b99db230cb8217b9ac811fb..8f7a646d4a7efdaa548d175103280dffd3af2052 100644 (file)
@@ -59,7 +59,7 @@ int bus_message_read_home_record(sd_bus_message *m, UserRecordLoadFlags flags, U
 
         r = user_record_load(hr, v, flags);
         if (r < 0)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "JSON data is not a valid identity record");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "JSON data is not a valid identity record");
 
         *ret = TAKE_PTR(hr);
         return 0;
index b0c5ce4232a6b6429f443b7910a707d773316c70..dc9a446c71474ffed9751607cb11e6daaa807fe1 100644 (file)
@@ -437,19 +437,19 @@ static int convert_worker_errno(Home *h, int e, sd_bus_error *error) {
         switch (e) {
 
         case -EMSGSIZE:
-                return sd_bus_error_setf(error, BUS_ERROR_BAD_HOME_SIZE, "File systems of this type cannot be shrunk");
+                return sd_bus_error_set(error, BUS_ERROR_BAD_HOME_SIZE, "File systems of this type cannot be shrunk");
         case -ETXTBSY:
-                return sd_bus_error_setf(error, BUS_ERROR_BAD_HOME_SIZE, "File systems of this type can only be shrunk offline");
+                return sd_bus_error_set(error, BUS_ERROR_BAD_HOME_SIZE, "File systems of this type can only be shrunk offline");
         case -ERANGE:
-                return sd_bus_error_setf(error, BUS_ERROR_BAD_HOME_SIZE, "File system size too small");
+                return sd_bus_error_set(error, BUS_ERROR_BAD_HOME_SIZE, "File system size too small");
         case -ENOLINK:
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "System does not support selected storage backend");
+                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "System does not support selected storage backend");
         case -EPROTONOSUPPORT:
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "System does not support selected file system");
+                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "System does not support selected file system");
         case -ENOTTY:
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Operation not supported on storage backend");
+                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Operation not supported on storage backend");
         case -ESOCKTNOSUPPORT:
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Operation not supported on file system");
+                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Operation not supported on file system");
         case -ENOKEY:
                 return sd_bus_error_setf(error, BUS_ERROR_BAD_PASSWORD, "Password for home %s is incorrect or not sufficient for authentication.", h->user_name);
         case -EBADSLT:
@@ -457,21 +457,21 @@ static int convert_worker_errno(Home *h, int e, sd_bus_error *error) {
         case -EREMOTEIO:
                 return sd_bus_error_setf(error, BUS_ERROR_BAD_RECOVERY_KEY, "Recovery key for home %s is incorrect or not sufficient for authentication.", h->user_name);
         case -ENOANO:
-                return sd_bus_error_setf(error, BUS_ERROR_TOKEN_PIN_NEEDED, "PIN for security token required.");
+                return sd_bus_error_set(error, BUS_ERROR_TOKEN_PIN_NEEDED, "PIN for security token required.");
         case -ERFKILL:
-                return sd_bus_error_setf(error, BUS_ERROR_TOKEN_PROTECTED_AUTHENTICATION_PATH_NEEDED, "Security token requires protected authentication path.");
+                return sd_bus_error_set(error, BUS_ERROR_TOKEN_PROTECTED_AUTHENTICATION_PATH_NEEDED, "Security token requires protected authentication path.");
         case -EMEDIUMTYPE:
-                return sd_bus_error_setf(error, BUS_ERROR_TOKEN_USER_PRESENCE_NEEDED, "Security token requires user presence.");
+                return sd_bus_error_set(error, BUS_ERROR_TOKEN_USER_PRESENCE_NEEDED, "Security token requires user presence.");
         case -ENOSTR:
-                return sd_bus_error_setf(error, BUS_ERROR_TOKEN_ACTION_TIMEOUT, "Token action timeout. (User was supposed to verify presence or similar, by interacting with the token, and didn't do that in time.)");
+                return sd_bus_error_set(error, BUS_ERROR_TOKEN_ACTION_TIMEOUT, "Token action timeout. (User was supposed to verify presence or similar, by interacting with the token, and didn't do that in time.)");
         case -EOWNERDEAD:
-                return sd_bus_error_setf(error, BUS_ERROR_TOKEN_PIN_LOCKED, "PIN of security token locked.");
+                return sd_bus_error_set(error, BUS_ERROR_TOKEN_PIN_LOCKED, "PIN of security token locked.");
         case -ENOLCK:
-                return sd_bus_error_setf(error, BUS_ERROR_TOKEN_BAD_PIN, "Bad PIN of security token.");
+                return sd_bus_error_set(error, BUS_ERROR_TOKEN_BAD_PIN, "Bad PIN of security token.");
         case -ETOOMANYREFS:
-                return sd_bus_error_setf(error, BUS_ERROR_TOKEN_BAD_PIN_FEW_TRIES_LEFT, "Bad PIN of security token, and only a few tries left.");
+                return sd_bus_error_set(error, BUS_ERROR_TOKEN_BAD_PIN_FEW_TRIES_LEFT, "Bad PIN of security token, and only a few tries left.");
         case -EUCLEAN:
-                return sd_bus_error_setf(error, BUS_ERROR_TOKEN_BAD_PIN_ONE_TRY_LEFT, "Bad PIN of security token, and only one try left.");
+                return sd_bus_error_set(error, BUS_ERROR_TOKEN_BAD_PIN_ONE_TRY_LEFT, "Bad PIN of security token, and only one try left.");
         case -EBUSY:
                 return sd_bus_error_setf(error, BUS_ERROR_HOME_BUSY, "Home %s is currently being used, or an operation on home %s is currently being executed.", h->user_name, h->user_name);
         case -ENOEXEC:
@@ -1104,7 +1104,7 @@ static int home_ratelimit(Home *h, sd_bus_error *error) {
                         return sd_bus_error_setf(error, BUS_ERROR_AUTHENTICATION_LIMIT_HIT, "Too many login attempts, please try again in %s!",
                                                  format_timespan(buf, sizeof(buf), t - n, USEC_PER_SEC));
 
-                return sd_bus_error_setf(error, BUS_ERROR_AUTHENTICATION_LIMIT_HIT, "Too many login attempts, please try again later.");
+                return sd_bus_error_set(error, BUS_ERROR_AUTHENTICATION_LIMIT_HIT, "Too many login attempts, please try again later.");
         }
 
         return 0;
@@ -1402,10 +1402,10 @@ static int home_update_internal(
         assert(hr);
 
         if (!user_record_compatible(hr, h->record))
-                return sd_bus_error_setf(error, BUS_ERROR_HOME_RECORD_MISMATCH, "Updated user record is not compatible with existing one.");
+                return sd_bus_error_set(error, BUS_ERROR_HOME_RECORD_MISMATCH, "Updated user record is not compatible with existing one.");
         c = user_record_compare_last_change(hr, h->record); /* refuse downgrades */
         if (c < 0)
-                return sd_bus_error_setf(error, BUS_ERROR_HOME_RECORD_DOWNGRADE, "Refusing to update to older home record.");
+                return sd_bus_error_set(error, BUS_ERROR_HOME_RECORD_DOWNGRADE, "Refusing to update to older home record.");
 
         if (!secret && FLAGS_SET(hr->mask, USER_RECORD_SECRET)) {
                 r = user_record_clone(hr, USER_RECORD_EXTRACT_SECRET, &saved_secret);
@@ -1454,7 +1454,7 @@ static int home_update_internal(
                 if (r < 0)
                         return r;
                 if (r == 0)
-                        return sd_bus_error_setf(error, BUS_ERROR_HOME_RECORD_MISMATCH, "Home record different but timestamp remained the same, refusing.");
+                        return sd_bus_error_set(error, BUS_ERROR_HOME_RECORD_MISMATCH, "Home record different but timestamp remained the same, refusing.");
         }
 
         r = home_start_work(h, verb, new_hr, secret);
@@ -1528,7 +1528,7 @@ int home_resize(Home *h, uint64_t disk_size, UserRecord *secret, sd_bus_error *e
 
         if (disk_size == UINT64_MAX || disk_size == h->record->disk_size) {
                 if (h->record->disk_size == UINT64_MAX)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "No disk size to resize to specified.");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "No disk size to resize to specified.");
 
                 c = user_record_ref(h->record); /* Shortcut if size is unspecified or matches the record */
         } else {
@@ -2349,6 +2349,8 @@ static int home_dispatch_acquire(Home *h, Operation *o) {
         assert(o);
         assert(o->type == OPERATION_ACQUIRE);
 
+        assert(!h->current_operation);
+
         switch (home_get_state(h)) {
 
         case HOME_UNFIXATED:
@@ -2357,8 +2359,9 @@ static int home_dispatch_acquire(Home *h, Operation *o) {
                 break;
 
         case HOME_ABSENT:
-                r = sd_bus_error_setf(&error, BUS_ERROR_HOME_ABSENT, "Home %s is currently missing or not plugged in.", h->user_name);
-                break;
+                r = sd_bus_error_setf(&error, BUS_ERROR_HOME_ABSENT,
+                                      "Home %s is currently missing or not plugged in.", h->user_name);
+                goto check;
 
         case HOME_INACTIVE:
         case HOME_DIRTY:
@@ -2382,14 +2385,11 @@ static int home_dispatch_acquire(Home *h, Operation *o) {
                 return 0;
         }
 
-        assert(!h->current_operation);
-
-        if (call) {
-                r = home_ratelimit(h, &error);
-                if (r >= 0)
-                        r = call(h, o->secret, for_state, &error);
-        }
+        r = home_ratelimit(h, &error);
+        if (r >= 0)
+                r = call(h, o->secret, for_state, &error);
 
+ check:
         if (r != 0) /* failure or completed */
                 operation_result(o, r, &error);
         else /* ongoing */
@@ -2660,7 +2660,7 @@ int home_schedule_operation(Home *h, Operation *o, sd_bus_error *error) {
 
         if (o) {
                 if (ordered_set_size(h->pending_operations) >= PENDING_OPERATIONS_MAX)
-                        return sd_bus_error_setf(error, BUS_ERROR_TOO_MANY_OPERATIONS, "Too many client operations requested");
+                        return sd_bus_error_set(error, BUS_ERROR_TOO_MANY_OPERATIONS, "Too many client operations requested");
 
                 r = ordered_set_ensure_put(&h->pending_operations, &operation_hash_ops, o);
                 if (r < 0)
index 85fdc88962c6c8a0772044fe176e6d9b189a1085..bd104f68112b127cd3bcb605e0ca6c1d58917c33 100644 (file)
@@ -1457,7 +1457,7 @@ int manager_sign_user_record(Manager *m, UserRecord *u, UserRecord **ret, sd_bus
         if (r < 0)
                 return r;
         if (r == 0)
-                return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_KEY, "Can't sign without local key.");
+                return sd_bus_error_set(error, BUS_ERROR_NO_PRIVATE_KEY, "Can't sign without local key.");
 
         return user_record_sign(u, m->private_key, ret);
 }
index 07d5bcfdb6136eb79fd9f6f4708f6f4bdadb74ac..543195914fb3632c7ddb603a6eeebf054cd9d58c 100644 (file)
@@ -1870,7 +1870,8 @@ int home_create_luks(
                 UserRecord **ret_home) {
 
         _cleanup_free_ char *dm_name = NULL, *dm_node = NULL, *subdir = NULL, *disk_uuid_path = NULL, *temporary_image_path = NULL;
-        uint64_t host_size, encrypted_size, partition_offset, partition_size;
+        uint64_t encrypted_size,
+                host_size = 0, partition_offset = 0, partition_size = 0; /* Unnecessary initialization to appease gcc */
         bool image_created = false, dm_activated = false, mounted = false;
         _cleanup_(user_record_unrefp) UserRecord *new_home = NULL;
         sd_id128_t partition_uuid, fs_uuid, luks_uuid, disk_uuid;
index b8f59c55ecbd7795825ceab206001e510733ffa2..e244ba5772a106baf574d6c853ab8d6d6b4c644b 100644 (file)
@@ -1351,16 +1351,16 @@ int user_record_is_supported(UserRecord *hr, sd_bus_error *error) {
         assert(hr);
 
         if (hr->disposition >= 0 && hr->disposition != USER_REGULAR)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot manage anything but regular users.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot manage anything but regular users.");
 
         if (hr->storage >= 0 && !IN_SET(hr->storage, USER_LUKS, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT, USER_CIFS))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User record has storage type this service cannot manage.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "User record has storage type this service cannot manage.");
 
         if (gid_is_valid(hr->gid) && hr->uid != (uid_t) hr->gid)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User record has to have matching UID/GID fields.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "User record has to have matching UID/GID fields.");
 
         if (hr->service && !streq(hr->service, "io.systemd.Home"))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Not accepted with service not matching io.systemd.Home.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Not accepted with service not matching io.systemd.Home.");
 
         return 0;
 }
index fa8ff68a461bd2c8994d4dbc23dfdf18f873df8e..f0f61ca7848e62153b5dad7f5bcb450615147c6e 100644 (file)
@@ -1080,7 +1080,7 @@ static int method_cancel_transfer(sd_bus_message *msg, void *userdata, sd_bus_er
         if (r < 0)
                 return r;
         if (id <= 0)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid transfer id");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid transfer id");
 
         t = hashmap_get(m->transfers, UINT32_TO_PTR(id));
         if (!t)
index ff51758e0bc05f51bbfdbf0b38044d97dd1a0ce4..6aca898d336756fc69784830bd499c719be7e802 100644 (file)
@@ -602,7 +602,7 @@ int dhcp6_option_parse_ia(sd_dhcp6_client *client, DHCP6Option *iaoption, DHCP6I
 
                 case SD_DHCP6_OPTION_IA_PD_PREFIX:
 
-                        if (!IN_SET(ia->type, SD_DHCP6_OPTION_IA_PD))
+                        if (ia->type != SD_DHCP6_OPTION_IA_PD)
                                 return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
                                                               "IA PD Prefix option not in IA PD option");
 
index e5b853c0cd7acec6a8924e79dedc9353b75ed34b..9e7a67cbe360ed6a03291f73e1e419bb967b62bf 100644 (file)
@@ -27,5 +27,5 @@ int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t
 /* It is not necessary to add deserialize_dhcp_option(). Use unhexmem() instead. */
 int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size);
 
-int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file);
+int dhcp_lease_save(const sd_dhcp_lease *lease, const char *lease_file);
 int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file);
index 6d88c88e6bb794c6ac3e9360c80f4b0bdec65653..37e37ef780931cd46c939e126c3b8d0970410c9d 100644 (file)
@@ -31,7 +31,7 @@
 #include "tmpfile-util.h"
 #include "unaligned.h"
 
-int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
+int sd_dhcp_lease_get_address(const sd_dhcp_lease *lease, struct in_addr *addr) {
         assert_return(lease, -EINVAL);
         assert_return(addr, -EINVAL);
 
@@ -42,7 +42,7 @@ int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
         return 0;
 }
 
-int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr) {
+int sd_dhcp_lease_get_broadcast(const sd_dhcp_lease *lease, struct in_addr *addr) {
         assert_return(lease, -EINVAL);
         assert_return(addr, -EINVAL);
 
@@ -53,7 +53,7 @@ int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr) {
         return 0;
 }
 
-int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) {
+int sd_dhcp_lease_get_lifetime(const sd_dhcp_lease *lease, uint32_t *lifetime) {
         assert_return(lease, -EINVAL);
         assert_return(lifetime, -EINVAL);
 
@@ -64,7 +64,7 @@ int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) {
         return 0;
 }
 
-int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1) {
+int sd_dhcp_lease_get_t1(const sd_dhcp_lease *lease, uint32_t *t1) {
         assert_return(lease, -EINVAL);
         assert_return(t1, -EINVAL);
 
@@ -75,7 +75,7 @@ int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1) {
         return 0;
 }
 
-int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2) {
+int sd_dhcp_lease_get_t2(const sd_dhcp_lease *lease, uint32_t *t2) {
         assert_return(lease, -EINVAL);
         assert_return(t2, -EINVAL);
 
@@ -86,7 +86,7 @@ int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2) {
         return 0;
 }
 
-int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) {
+int sd_dhcp_lease_get_mtu(const sd_dhcp_lease *lease, uint16_t *mtu) {
         assert_return(lease, -EINVAL);
         assert_return(mtu, -EINVAL);
 
@@ -98,7 +98,7 @@ int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) {
 }
 
 int sd_dhcp_lease_get_servers(
-                sd_dhcp_lease *lease,
+                const sd_dhcp_lease *lease,
                 sd_dhcp_lease_server_type_t what,
                 const struct in_addr **addr) {
 
@@ -114,26 +114,26 @@ int sd_dhcp_lease_get_servers(
         return (int) lease->servers[what].size;
 }
 
-int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr) {
+int sd_dhcp_lease_get_dns(const sd_dhcp_lease *lease, const struct in_addr **addr) {
         return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_DNS, addr);
 }
-int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr) {
+int sd_dhcp_lease_get_ntp(const sd_dhcp_lease *lease, const struct in_addr **addr) {
         return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_NTP, addr);
 }
-int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **addr) {
+int sd_dhcp_lease_get_sip(const sd_dhcp_lease *lease, const struct in_addr **addr) {
         return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_SIP, addr);
 }
-int sd_dhcp_lease_get_pop3(sd_dhcp_lease *lease, const struct in_addr **addr) {
+int sd_dhcp_lease_get_pop3(const sd_dhcp_lease *lease, const struct in_addr **addr) {
         return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_POP3, addr);
 }
-int sd_dhcp_lease_get_smtp(sd_dhcp_lease *lease, const struct in_addr **addr) {
+int sd_dhcp_lease_get_smtp(const sd_dhcp_lease *lease, const struct in_addr **addr) {
         return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_SMTP, addr);
 }
-int sd_dhcp_lease_get_lpr(sd_dhcp_lease *lease, const struct in_addr **addr) {
+int sd_dhcp_lease_get_lpr(const sd_dhcp_lease *lease, const struct in_addr **addr) {
         return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_LPR, addr);
 }
 
-int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) {
+int sd_dhcp_lease_get_domainname(const sd_dhcp_lease *lease, const char **domainname) {
         assert_return(lease, -EINVAL);
         assert_return(domainname, -EINVAL);
 
@@ -144,7 +144,7 @@ int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname)
         return 0;
 }
 
-int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) {
+int sd_dhcp_lease_get_hostname(const sd_dhcp_lease *lease, const char **hostname) {
         assert_return(lease, -EINVAL);
         assert_return(hostname, -EINVAL);
 
@@ -155,7 +155,7 @@ int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) {
         return 0;
 }
 
-int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) {
+int sd_dhcp_lease_get_root_path(const sd_dhcp_lease *lease, const char **root_path) {
         assert_return(lease, -EINVAL);
         assert_return(root_path, -EINVAL);
 
@@ -166,7 +166,7 @@ int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) {
         return 0;
 }
 
-int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr) {
+int sd_dhcp_lease_get_router(const sd_dhcp_lease *lease, const struct in_addr **addr) {
         assert_return(lease, -EINVAL);
         assert_return(addr, -EINVAL);
 
@@ -177,7 +177,7 @@ int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr)
         return (int) lease->router_size;
 }
 
-int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
+int sd_dhcp_lease_get_netmask(const sd_dhcp_lease *lease, struct in_addr *addr) {
         assert_return(lease, -EINVAL);
         assert_return(addr, -EINVAL);
 
@@ -188,7 +188,7 @@ int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
         return 0;
 }
 
-int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr) {
+int sd_dhcp_lease_get_server_identifier(const sd_dhcp_lease *lease, struct in_addr *addr) {
         assert_return(lease, -EINVAL);
         assert_return(addr, -EINVAL);
 
@@ -199,7 +199,7 @@ int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *ad
         return 0;
 }
 
-int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) {
+int sd_dhcp_lease_get_next_server(const sd_dhcp_lease *lease, struct in_addr *addr) {
         assert_return(lease, -EINVAL);
         assert_return(addr, -EINVAL);
 
@@ -214,7 +214,7 @@ int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) {
  * The returned routes array must be freed by the caller.
  * Route objects have the same lifetime of the lease and must not be freed.
  */
-int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, sd_dhcp_route ***routes) {
+int sd_dhcp_lease_get_routes(const sd_dhcp_lease *lease, sd_dhcp_route ***routes) {
         sd_dhcp_route **ret;
         unsigned i;
 
@@ -235,7 +235,7 @@ int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, sd_dhcp_route ***routes) {
         return (int) lease->static_route_size;
 }
 
-int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains) {
+int sd_dhcp_lease_get_search_domains(const sd_dhcp_lease *lease, char ***domains) {
         size_t r;
 
         assert_return(lease, -EINVAL);
@@ -250,7 +250,7 @@ int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains) {
         return -ENODATA;
 }
 
-int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len) {
+int sd_dhcp_lease_get_vendor_specific(const sd_dhcp_lease *lease, const void **data, size_t *data_len) {
         assert_return(lease, -EINVAL);
         assert_return(data, -EINVAL);
         assert_return(data_len, -EINVAL);
@@ -868,7 +868,7 @@ int dhcp_lease_new(sd_dhcp_lease **ret) {
         return 0;
 }
 
-int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
+int dhcp_lease_save(const sd_dhcp_lease *lease, const char *lease_file) {
         _cleanup_(unlink_and_freep) char *temp_path = NULL;
         _cleanup_fclose_ FILE *f = NULL;
         struct sd_dhcp_raw_option *option;
@@ -1313,7 +1313,7 @@ int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
         return 0;
 }
 
-int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len) {
+int sd_dhcp_lease_get_client_id(const sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len) {
         assert_return(lease, -EINVAL);
         assert_return(client_id, -EINVAL);
         assert_return(client_id_len, -EINVAL);
@@ -1348,7 +1348,7 @@ int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t
         return 0;
 }
 
-int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **tz) {
+int sd_dhcp_lease_get_timezone(const sd_dhcp_lease *lease, const char **tz) {
         assert_return(lease, -EINVAL);
         assert_return(tz, -EINVAL);
 
@@ -1359,7 +1359,7 @@ int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **tz) {
         return 0;
 }
 
-int sd_dhcp_route_get_destination(sd_dhcp_route *route, struct in_addr *destination) {
+int sd_dhcp_route_get_destination(const sd_dhcp_route *route, struct in_addr *destination) {
         assert_return(route, -EINVAL);
         assert_return(destination, -EINVAL);
 
@@ -1367,7 +1367,7 @@ int sd_dhcp_route_get_destination(sd_dhcp_route *route, struct in_addr *destinat
         return 0;
 }
 
-int sd_dhcp_route_get_destination_prefix_length(sd_dhcp_route *route, uint8_t *length) {
+int sd_dhcp_route_get_destination_prefix_length(const sd_dhcp_route *route, uint8_t *length) {
         assert_return(route, -EINVAL);
         assert_return(length, -EINVAL);
 
@@ -1375,7 +1375,7 @@ int sd_dhcp_route_get_destination_prefix_length(sd_dhcp_route *route, uint8_t *l
         return 0;
 }
 
-int sd_dhcp_route_get_gateway(sd_dhcp_route *route, struct in_addr *gateway) {
+int sd_dhcp_route_get_gateway(const sd_dhcp_route *route, struct in_addr *gateway) {
         assert_return(route, -EINVAL);
         assert_return(gateway, -EINVAL);
 
@@ -1383,7 +1383,7 @@ int sd_dhcp_route_get_gateway(sd_dhcp_route *route, struct in_addr *gateway) {
         return 0;
 }
 
-int sd_dhcp_route_get_option(sd_dhcp_route *route) {
+int sd_dhcp_route_get_option(const sd_dhcp_route *route) {
         assert_return(route, -EINVAL);
 
         return route->option;
index c8a4c79ffe6e52f21c4cc2d34b387ee7b60ba347..10f82996c8c260f3633113a1158b86f1b34e9c0c 100644 (file)
@@ -161,7 +161,7 @@ int sd_dhcp6_client_set_callback(
 int sd_dhcp6_client_set_ifindex(sd_dhcp6_client *client, int ifindex) {
         assert_return(client, -EINVAL);
         assert_return(ifindex > 0, -EINVAL);
-        assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
+        assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
 
         client->ifindex = ifindex;
         return 0;
@@ -191,8 +191,7 @@ int sd_dhcp6_client_set_local_address(
         assert_return(client, -EINVAL);
         assert_return(local_address, -EINVAL);
         assert_return(in6_addr_is_link_local(local_address) > 0, -EINVAL);
-
-        assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
+        assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
 
         client->local_address = *local_address;
 
@@ -207,8 +206,7 @@ int sd_dhcp6_client_set_mac(
         assert_return(client, -EINVAL);
         assert_return(addr, -EINVAL);
         assert_return(addr_len <= MAX_MAC_ADDR_LEN, -EINVAL);
-
-        assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
+        assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
 
         if (arp_type == ARPHRD_ETHER)
                 assert_return(addr_len == ETH_ALEN, -EINVAL);
@@ -238,8 +236,7 @@ int sd_dhcp6_client_set_prefix_delegation_hint(
 
         assert_return(client, -EINVAL);
         assert_return(pd_address, -EINVAL);
-
-        assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
+        assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
 
         client->hint_pd_prefix.iapdprefix.address = *pd_address;
         client->hint_pd_prefix.iapdprefix.prefixlen = prefixlen;
@@ -284,7 +281,7 @@ static int dhcp6_client_set_duid_internal(
 
         assert_return(client, -EINVAL);
         assert_return(duid_len == 0 || duid != NULL, -EINVAL);
-        assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
+        assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
 
         if (duid) {
                 r = dhcp_validate_duid_len(duid_type, duid_len, true);
@@ -393,7 +390,7 @@ int sd_dhcp6_client_duid_as_string(
 
 int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid) {
         assert_return(client, -EINVAL);
-        assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
+        assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
 
         client->ia_na.ia_na.id = htobe32(iaid);
         client->ia_pd.ia_pd.id = htobe32(iaid);
@@ -430,7 +427,7 @@ int sd_dhcp6_client_set_fqdn(
 
 int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled) {
         assert_return(client, -EINVAL);
-        assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
+        assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
 
         client->information_request = enabled;
 
@@ -1705,7 +1702,7 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
         assert_return(client->ifindex > 0, -EINVAL);
         assert_return(in6_addr_is_link_local(&client->local_address) > 0, -EINVAL);
 
-        if (!IN_SET(client->state, DHCP6_STATE_STOPPED))
+        if (client->state != DHCP6_STATE_STOPPED)
                 return -EBUSY;
 
         if (!client->information_request && !client->request)
index 74eff7fcf0822ab998ede1b69d975f793f9125a7..b025b550267426f787cef377679d54695d873882 100644 (file)
@@ -751,3 +751,9 @@ global:
         sd_device_new_from_stat_rdev;
         sd_device_trigger;
 } LIBSYSTEMD_247;
+
+LIBSYSTEMD_249 {
+global:
+        sd_device_monitor_filter_add_match_sysattr;
+        sd_device_monitor_filter_add_match_parent;
+} LIBSYSTEMD_248;
index ad50815a7b6ddd289207c9f872d9799458618477..f55bdcd1a5c0da725d90d57e3d7e9f30c7636e4d 100644 (file)
@@ -127,6 +127,7 @@ libsystemd_sources = files('''
         sd-device/device-monitor.c
         sd-device/device-private.c
         sd-device/device-private.h
+        sd-device/device-util.c
         sd-device/device-util.h
         sd-device/sd-device.c
         sd-hwdb/hwdb-internal.h
@@ -307,6 +308,8 @@ tests += [
 
         [['src/libsystemd/sd-device/test-sd-device.c']],
 
+        [['src/libsystemd/sd-device/test-device-util.c']],
+
         [['src/libsystemd/sd-device/test-sd-device-monitor.c']],
 ]
 
index 8da2024a5028ffcfa8776cfb5f66799ad545c1fa..7483b46a11d7dc79367c0351573c3ed577e0ef10 100644 (file)
@@ -86,8 +86,10 @@ static int bus_error_name_to_errno(const char *name) {
                                 if (m->code == BUS_ERROR_MAP_END_MARKER)
                                         break;
 
-                                if (streq(m->name, name))
+                                if (streq(m->name, name)) {
+                                        assert(m->code > 0);
                                         return m->code;
+                                }
                         }
 
         m = ALIGN_TO_PTR(__start_SYSTEMD_BUS_ERROR_MAP, sizeof(void*));
@@ -103,8 +105,10 @@ static int bus_error_name_to_errno(const char *name) {
                         continue;
                 }
 
-                if (streq(m->name, name))
+                if (streq(m->name, name)) {
+                        assert(m->code > 0);
                         return m->code;
+                }
 
                 m++;
         }
@@ -208,30 +212,33 @@ _public_ void sd_bus_error_free(sd_bus_error *e) {
 }
 
 _public_ int sd_bus_error_set(sd_bus_error *e, const char *name, const char *message) {
+        int r;
 
         if (!name)
                 return 0;
-        if (!e)
-                goto finish;
 
-        assert_return(!bus_error_is_dirty(e), -EINVAL);
+        if (e) {
+                assert_return(!bus_error_is_dirty(e), -EINVAL);
 
-        e->name = strdup(name);
-        if (!e->name) {
-                *e = BUS_ERROR_OOM;
-                return -ENOMEM;
-        }
+                e->name = strdup(name);
+                if (!e->name) {
+                        *e = BUS_ERROR_OOM;
+                        return -ENOMEM;
+                }
 
-        if (message)
-                e->message = strdup(message);
+                if (message)
+                        e->message = strdup(message);
 
-        e->_need_free = 1;
+                e->_need_free = 1;
+        }
 
-finish:
-        return -bus_error_name_to_errno(name);
+        r = bus_error_name_to_errno(name);
+        assert(r > 0);
+        return -r;
 }
 
 int bus_error_setfv(sd_bus_error *e, const char *name, const char *format, va_list ap) {
+        int r;
 
         if (!name)
                 return 0;
@@ -253,23 +260,28 @@ int bus_error_setfv(sd_bus_error *e, const char *name, const char *format, va_li
                 e->_need_free = 1;
         }
 
-        return -bus_error_name_to_errno(name);
+        r = bus_error_name_to_errno(name);
+        assert(r > 0);
+        return -r;
 }
 
 _public_ int sd_bus_error_setf(sd_bus_error *e, const char *name, const char *format, ...) {
+        int r;
 
         if (format) {
-                int r;
                 va_list ap;
 
                 va_start(ap, format);
                 r = bus_error_setfv(e, name, format, ap);
+                assert(!name || r < 0);
                 va_end(ap);
 
                 return r;
         }
 
-        return sd_bus_error_set(e, name, NULL);
+        r = sd_bus_error_set(e, name, NULL);
+        assert(!name || r < 0);
+        return r;
 }
 
 _public_ int sd_bus_error_copy(sd_bus_error *dest, const sd_bus_error *e) {
@@ -455,7 +467,7 @@ _public_ int sd_bus_error_set_errno(sd_bus_error *e, int error) {
         if (!e)
                 return -error;
         if (error == 0)
-                return -error;
+                return 0;
 
         assert_return(!bus_error_is_dirty(e), -EINVAL);
 
index e719c74370f3f081e54f9acb9eca48c6a43b5f06..8bcf4f6c50630401d6b07a8bf2e3241575d9f5c6 100644 (file)
@@ -1800,7 +1800,9 @@ void bus_enter_closing(sd_bus *bus) {
 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_bus, sd_bus, bus_free);
 
 _public_ int sd_bus_is_open(sd_bus *bus) {
-        assert_return(bus, -EINVAL);
+        if (!bus)
+                return 0;
+
         assert_return(bus = bus_resolve(bus), -ENOPKG);
         assert_return(!bus_pid_changed(bus), -ECHILD);
 
@@ -1808,7 +1810,9 @@ _public_ int sd_bus_is_open(sd_bus *bus) {
 }
 
 _public_ int sd_bus_is_ready(sd_bus *bus) {
-        assert_return(bus, -EINVAL);
+        if (!bus)
+                return 0;
+
         assert_return(bus = bus_resolve(bus), -ENOPKG);
         assert_return(!bus_pid_changed(bus), -ECHILD);
 
@@ -2410,7 +2414,7 @@ _public_ int sd_bus_call(
                                                 return 1;
                                         }
 
-                                        return sd_bus_error_setf(error, SD_BUS_ERROR_INCONSISTENT_MESSAGE, "Reply message contained file descriptors which I couldn't accept. Sorry.");
+                                        return sd_bus_error_set(error, SD_BUS_ERROR_INCONSISTENT_MESSAGE, "Reply message contained file descriptors which I couldn't accept. Sorry.");
 
                                 } else if (incoming->header->type == SD_BUS_MESSAGE_METHOD_ERROR)
                                         return sd_bus_error_copy(error, &incoming->error);
index 2434fb625e58dbccdedc909097eb88e01a8124ca..a290dbcc9ce5b17ced396878ad95360cc36a69ce 100644 (file)
@@ -287,42 +287,6 @@ int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *de
         return 0;
 }
 
-static bool match_sysattr_value(sd_device *device, const char *sysattr, const char *match_value) {
-        const char *value;
-
-        assert(device);
-        assert(sysattr);
-
-        if (sd_device_get_sysattr_value(device, sysattr, &value) < 0)
-                return false;
-
-        if (!match_value)
-                return true;
-
-        if (fnmatch(match_value, value, 0) == 0)
-                return true;
-
-        return false;
-}
-
-static bool match_sysattr(sd_device_enumerator *enumerator, sd_device *device) {
-        const char *sysattr;
-        const char *value;
-
-        assert(enumerator);
-        assert(device);
-
-        HASHMAP_FOREACH_KEY(value, sysattr, enumerator->nomatch_sysattr)
-                if (match_sysattr_value(device, sysattr, value))
-                        return false;
-
-        HASHMAP_FOREACH_KEY(value, sysattr, enumerator->match_sysattr)
-                if (!match_sysattr_value(device, sysattr, value))
-                        return false;
-
-        return true;
-}
-
 static bool match_property(sd_device_enumerator *enumerator, sd_device *device) {
         const char *property;
         const char *value;
@@ -367,24 +331,6 @@ static bool match_tag(sd_device_enumerator *enumerator, sd_device *device) {
         return true;
 }
 
-static bool match_parent(sd_device_enumerator *enumerator, sd_device *device) {
-        const char *syspath_parent, *syspath;
-
-        assert(enumerator);
-        assert(device);
-
-        if (set_isempty(enumerator->match_parent))
-                return true;
-
-        assert_se(sd_device_get_syspath(device, &syspath) >= 0);
-
-        SET_FOREACH(syspath_parent, enumerator->match_parent)
-                if (path_startswith(syspath, syspath_parent))
-                        return true;
-
-        return false;
-}
-
 static bool match_sysname(sd_device_enumerator *enumerator, const char *sysname) {
         const char *sysname_match;
 
@@ -470,7 +416,7 @@ static int enumerator_scan_dir_and_add_devices(sd_device_enumerator *enumerator,
                      sd_device_get_ifindex(device, NULL) >= 0))
                         continue;
 
-                if (!match_parent(enumerator, device))
+                if (!device_match_parent(device, enumerator->match_parent, NULL))
                         continue;
 
                 if (!match_tag(enumerator, device))
@@ -479,7 +425,7 @@ static int enumerator_scan_dir_and_add_devices(sd_device_enumerator *enumerator,
                 if (!match_property(enumerator, device))
                         continue;
 
-                if (!match_sysattr(enumerator, device))
+                if (!device_match_sysattr(device, enumerator->match_sysattr, enumerator->nomatch_sysattr))
                         continue;
 
                 k = device_enumerator_add_device(enumerator, device);
@@ -600,13 +546,13 @@ static int enumerator_scan_devices_tag(sd_device_enumerator *enumerator, const c
                 if (!match_sysname(enumerator, sysname))
                         continue;
 
-                if (!match_parent(enumerator, device))
+                if (!device_match_parent(device, enumerator->match_parent, NULL))
                         continue;
 
                 if (!match_property(enumerator, device))
                         continue;
 
-                if (!match_sysattr(enumerator, device))
+                if (!device_match_sysattr(device, enumerator->match_sysattr, enumerator->nomatch_sysattr))
                         continue;
 
                 k = device_enumerator_add_device(enumerator, device);
@@ -667,7 +613,7 @@ static int parent_add_child(sd_device_enumerator *enumerator, const char *path)
         if (!match_property(enumerator, device))
                 return 0;
 
-        if (!match_sysattr(enumerator, device))
+        if (!device_match_sysattr(device, enumerator->match_sysattr, enumerator->nomatch_sysattr))
                 return 0;
 
         r = device_enumerator_add_device(enumerator, device);
index 3948e862a9f81be01cda8e70e90f4c07b09b78c8..b485e3e2b632aba145bd654b28b0316bcabaa307 100644 (file)
@@ -37,6 +37,10 @@ struct sd_device_monitor {
 
         Hashmap *subsystem_filter;
         Set *tag_filter;
+        Hashmap *match_sysattr_filter;
+        Hashmap *nomatch_sysattr_filter;
+        Set *match_parent_filter;
+        Set *nomatch_parent_filter;
         bool filter_uptodate;
 
         sd_event *event;
@@ -336,55 +340,78 @@ static sd_device_monitor *device_monitor_free(sd_device_monitor *m) {
 
         hashmap_free(m->subsystem_filter);
         set_free(m->tag_filter);
+        hashmap_free(m->match_sysattr_filter);
+        hashmap_free(m->nomatch_sysattr_filter);
+        set_free(m->match_parent_filter);
+        set_free(m->nomatch_parent_filter);
 
         return mfree(m);
 }
 
 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_device_monitor, sd_device_monitor, device_monitor_free);
 
-static int passes_filter(sd_device_monitor *m, sd_device *device) {
-        const char *tag, *subsystem, *devtype, *s, *d = NULL;
+static int check_subsystem_filter(sd_device_monitor *m, sd_device *device) {
+        const char *s, *subsystem, *d, *devtype = NULL;
         int r;
 
         assert(m);
         assert(device);
 
         if (hashmap_isempty(m->subsystem_filter))
-                goto tag;
+                return true;
 
-        r = sd_device_get_subsystem(device, &s);
+        r = sd_device_get_subsystem(device, &subsystem);
         if (r < 0)
                 return r;
 
-        r = sd_device_get_devtype(device, &d);
+        r = sd_device_get_devtype(device, &devtype);
         if (r < 0 && r != -ENOENT)
                 return r;
 
-        HASHMAP_FOREACH_KEY(devtype, subsystem, m->subsystem_filter) {
+        HASHMAP_FOREACH_KEY(d, s, m->subsystem_filter) {
                 if (!streq(s, subsystem))
                         continue;
 
-                if (!devtype)
-                        goto tag;
+                if (!d || streq_ptr(d, devtype))
+                        return true;
+        }
 
-                if (!d)
-                        continue;
+        return false;
+}
 
-                if (streq(d, devtype))
-                        goto tag;
-        }
+static bool check_tag_filter(sd_device_monitor *m, sd_device *device) {
+        const char *tag;
 
-        return 0;
+        assert(m);
+        assert(device);
 
-tag:
         if (set_isempty(m->tag_filter))
-                return 1;
+                return true;
 
         SET_FOREACH(tag, m->tag_filter)
                 if (sd_device_has_tag(device, tag) > 0)
-                        return 1;
+                        return true;
 
-        return 0;
+        return false;
+}
+
+static int passes_filter(sd_device_monitor *m, sd_device *device) {
+        int r;
+
+        assert(m);
+        assert(device);
+
+        r = check_subsystem_filter(m, device);
+        if (r <= 0)
+                return r;
+
+        if (!check_tag_filter(m, device))
+                return false;
+
+        if (!device_match_sysattr(device, m->match_sysattr_filter, m->nomatch_sysattr_filter))
+                return false;
+
+        return device_match_parent(device, m->match_parent_filter, m->nomatch_parent_filter);
 }
 
 int device_monitor_receive_device(sd_device_monitor *m, sd_device **ret) {
@@ -747,6 +774,42 @@ _public_ int sd_device_monitor_filter_add_match_tag(sd_device_monitor *m, const
         return r;
 }
 
+_public_ int sd_device_monitor_filter_add_match_sysattr(sd_device_monitor *m, const char *sysattr, const char *value, int match) {
+        Hashmap **hashmap;
+
+        assert_return(m, -EINVAL);
+        assert_return(sysattr, -EINVAL);
+
+        if (match)
+                hashmap = &m->match_sysattr_filter;
+        else
+                hashmap = &m->nomatch_sysattr_filter;
+
+        /* TODO: unset m->filter_uptodate on success when we support this filter on BPF. */
+        return hashmap_put_strdup_full(hashmap, &trivial_hash_ops_free_free, sysattr, value);
+}
+
+_public_ int sd_device_monitor_filter_add_match_parent(sd_device_monitor *m, sd_device *device, int match) {
+        const char *syspath;
+        Set **set;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(device, -EINVAL);
+
+        r = sd_device_get_syspath(device, &syspath);
+        if (r < 0)
+                return r;
+
+        if (match)
+                set = &m->match_parent_filter;
+        else
+                set = &m->nomatch_parent_filter;
+
+        /* TODO: unset m->filter_uptodate on success when we support this filter on BPF. */
+        return set_put_strdup(set, syspath);
+}
+
 _public_ int sd_device_monitor_filter_remove(sd_device_monitor *m) {
         static const struct sock_fprog filter = { 0, NULL };
 
@@ -754,6 +817,10 @@ _public_ int sd_device_monitor_filter_remove(sd_device_monitor *m) {
 
         m->subsystem_filter = hashmap_free(m->subsystem_filter);
         m->tag_filter = set_free(m->tag_filter);
+        m->match_sysattr_filter = hashmap_free(m->match_sysattr_filter);
+        m->nomatch_sysattr_filter = hashmap_free(m->nomatch_sysattr_filter);
+        m->match_parent_filter = set_free(m->match_parent_filter);
+        m->nomatch_parent_filter = set_free(m->nomatch_parent_filter);
 
         if (setsockopt(m->sock, SOL_SOCKET, SO_DETACH_FILTER, &filter, sizeof(filter)) < 0)
                 return -errno;
diff --git a/src/libsystemd/sd-device/device-util.c b/src/libsystemd/sd-device/device-util.c
new file mode 100644 (file)
index 0000000..616c16c
--- /dev/null
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <fnmatch.h>
+
+#include "device-util.h"
+#include "path-util.h"
+
+static bool device_match_sysattr_value(sd_device *device, const char *sysattr, const char *match_value) {
+        const char *value;
+
+        assert(device);
+        assert(sysattr);
+
+        if (sd_device_get_sysattr_value(device, sysattr, &value) < 0)
+                return false;
+
+        if (!match_value)
+                return true;
+
+        if (fnmatch(match_value, value, 0) == 0)
+                return true;
+
+        return false;
+}
+
+bool device_match_sysattr(sd_device *device, Hashmap *match_sysattr, Hashmap *nomatch_sysattr) {
+        const char *sysattr;
+        const char *value;
+
+        assert(device);
+
+        HASHMAP_FOREACH_KEY(value, sysattr, match_sysattr)
+                if (!device_match_sysattr_value(device, sysattr, value))
+                        return false;
+
+        HASHMAP_FOREACH_KEY(value, sysattr, nomatch_sysattr)
+                if (device_match_sysattr_value(device, sysattr, value))
+                        return false;
+
+        return true;
+}
+
+bool device_match_parent(sd_device *device, Set *match_parent, Set *nomatch_parent) {
+        const char *syspath_parent, *syspath;
+
+        assert(device);
+
+        if (sd_device_get_syspath(device, &syspath) < 0)
+                return false;
+
+        SET_FOREACH(syspath_parent, nomatch_parent)
+                if (path_startswith(syspath, syspath_parent))
+                        return false;
+
+        if (set_isempty(match_parent))
+                return true;
+
+        SET_FOREACH(syspath_parent, match_parent)
+                if (path_startswith(syspath, syspath_parent))
+                        return true;
+
+        return false;
+}
index 122620953a3aee9ddeb4fbb081807989ba902d36..026bdcd644caad600c29e5ac9f65642de6699b21 100644 (file)
@@ -1,6 +1,15 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
+#include <stdbool.h>
+
+#include "sd-device.h"
+
+#include "hashmap.h"
+#include "log.h"
+#include "macro.h"
+#include "set.h"
+
 #define FOREACH_DEVICE_PROPERTY(device, key, value)                \
         for (key = sd_device_get_property_first(device, &(value)); \
              key;                                                  \
@@ -62,3 +71,6 @@
 #define log_device_notice_errno(device, error, ...)  log_device_full_errno(device, LOG_NOTICE, error, __VA_ARGS__)
 #define log_device_warning_errno(device, error, ...) log_device_full_errno(device, LOG_WARNING, error, __VA_ARGS__)
 #define log_device_error_errno(device, error, ...)   log_device_full_errno(device, LOG_ERR, error, __VA_ARGS__)
+
+bool device_match_sysattr(sd_device *device, Hashmap *match_sysattr, Hashmap *nomatch_sysattr);
+bool device_match_parent(sd_device *device, Set *match_parent, Set *nomatch_parent);
index e556a6f838ca9237913c5b747296c8b8d0ae40d7..d9ea9852e364eb19b91d53de950016ca1f6052d2 100644 (file)
@@ -491,7 +491,6 @@ int device_read_uevent_file(sd_device *device) {
         const char *syspath, *key = NULL, *value = NULL, *major = NULL, *minor = NULL;
         char *path;
         size_t uevent_len;
-        unsigned i;
         int r;
 
         enum {
@@ -527,7 +526,7 @@ int device_read_uevent_file(sd_device *device) {
 
         device->uevent_loaded = true;
 
-        for (i = 0; i < uevent_len; i++)
+        for (size_t i = 0; i < uevent_len; i++)
                 switch (state) {
                 case PRE_KEY:
                         if (!strchr(NEWLINE, uevent[i])) {
@@ -706,7 +705,7 @@ static int device_new_from_child(sd_device **ret, sd_device *child) {
 
                 pos = strrchr(subdir, '/');
                 if (!pos || pos < subdir + 2)
-                        break;
+                        return -ENODEV;
 
                 *pos = '\0';
 
@@ -716,8 +715,6 @@ static int device_new_from_child(sd_device **ret, sd_device *child) {
 
                 return 0;
         }
-
-        return -ENODEV;
 }
 
 _public_ int sd_device_get_parent(sd_device *child, sd_device **ret) {
@@ -1321,7 +1318,7 @@ int device_get_id_filename(sd_device *device, const char **ret) {
 int device_read_db_internal_filename(sd_device *device, const char *filename) {
         _cleanup_free_ char *db = NULL;
         const char *value;
-        size_t db_len, i;
+        size_t db_len;
         char key;
         int r;
 
@@ -1349,7 +1346,7 @@ int device_read_db_internal_filename(sd_device *device, const char *filename) {
 
         device->db_loaded = true;
 
-        for (i = 0; i < db_len; i++) {
+        for (size_t i = 0; i < db_len; i++) {
                 switch (state) {
                 case PRE_KEY:
                         if (!strchr(NEWLINE, db[i])) {
@@ -1387,7 +1384,8 @@ int device_read_db_internal_filename(sd_device *device, const char *filename) {
                                 db[i] = '\0';
                                 r = handle_db_line(device, key, value);
                                 if (r < 0)
-                                        log_device_debug_errno(device, r, "sd-device: Failed to handle db entry '%c:%s', ignoring: %m", key, value);
+                                        log_device_debug_errno(device, r, "sd-device: Failed to handle db entry '%c:%s', ignoring: %m",
+                                                               key, value);
 
                                 state = PRE_KEY;
                         }
@@ -1895,10 +1893,11 @@ _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr,
                 return r;
 
         path = prefix_roota(syspath, sysattr);
-        r = lstat(path, &statbuf);
-        if (r < 0) {
+        if (lstat(path, &statbuf) < 0) {
                 int k;
 
+                r = -errno;
+
                 /* remember that we could not access the sysattr */
                 k = device_cache_sysattr_value(device, sysattr, NULL);
                 if (k < 0)
diff --git a/src/libsystemd/sd-device/test-device-util.c b/src/libsystemd/sd-device/test-device-util.c
new file mode 100644 (file)
index 0000000..93fc105
--- /dev/null
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "device-util.h"
+#include "tests.h"
+
+static void test_log_device_full(void) {
+        int r;
+
+        log_info("/* %s */", __func__);
+
+        for (int level = LOG_ERR; level <= LOG_DEBUG; level++) {
+                log_device_full(NULL, level, "test level=%d: %m", level);
+
+                r = log_device_full_errno(NULL, level, EUCLEAN, "test level=%d errno=EUCLEAN: %m", level);
+                assert_se(r == -EUCLEAN);
+
+                r = log_device_full_errno(NULL, level, 0, "test level=%d errno=0: %m", level);
+                assert_se(r == 0);
+
+                r = log_device_full_errno(NULL, level, SYNTHETIC_ERRNO(ENODATA), "test level=%d errno=S(ENODATA): %m", level);
+                assert_se(r == -ENODATA);
+        }
+}
+
+int main(int argc, char **argv) {
+        test_setup_logging(LOG_INFO);
+
+        test_log_device_full();
+        return 0;
+}
index fddd1c152c91b2229f578340d95fefa8ffcee8d3..ae973cdba395aa03e91caac9688868c64d628ad6 100644 (file)
@@ -95,10 +95,10 @@ static void test_send_receive_one(sd_device *device, bool subsystem_filter, bool
 static void test_subsystem_filter(sd_device *device) {
         _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
         _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
-        const char *syspath, *subsystem, *p, *s;
+        const char *syspath, *subsystem;
         sd_device *d;
 
-        log_info("/* %s */", __func__);
+        log_device_info(device, "/* %s */", __func__);
 
         assert_se(sd_device_get_syspath(device, &syspath) >= 0);
         assert_se(sd_device_get_subsystem(device, &subsystem) >= 0);
@@ -116,16 +116,140 @@ static void test_subsystem_filter(sd_device *device) {
         assert_se(sd_device_enumerator_new(&e) >= 0);
         assert_se(sd_device_enumerator_add_match_subsystem(e, subsystem, false) >= 0);
         FOREACH_DEVICE(e, d) {
+                const char *p, *s;
+
                 assert_se(sd_device_get_syspath(d, &p) >= 0);
                 assert_se(sd_device_get_subsystem(d, &s) >= 0);
 
-                log_info("Sending device subsystem:%s syspath:%s", s, p);
+                log_device_debug(d, "Sending device subsystem:%s syspath:%s", s, p);
+                assert_se(device_monitor_send_device(monitor_server, monitor_client, d) >= 0);
+        }
+
+        log_device_info(device, "Sending device subsystem:%s syspath:%s", subsystem, syspath);
+        assert_se(device_monitor_send_device(monitor_server, monitor_client, device) >= 0);
+        assert_se(sd_event_loop(sd_device_monitor_get_event(monitor_client)) == 100);
+}
+
+static void test_tag_filter(sd_device *device) {
+        _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
+        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+        const char *syspath;
+        sd_device *d;
+
+        log_device_info(device, "/* %s */", __func__);
+
+        assert_se(sd_device_get_syspath(device, &syspath) >= 0);
+
+        assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
+        assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
+        assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_server), "sender") >= 0);
+
+        assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
+        assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
+        assert_se(sd_device_monitor_filter_add_match_tag(monitor_client, "TEST_SD_DEVICE_MONITOR") >= 0);
+        assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
+        assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0);
+
+        assert_se(sd_device_enumerator_new(&e) >= 0);
+        FOREACH_DEVICE(e, d) {
+                const char *p;
+
+                assert_se(sd_device_get_syspath(d, &p) >= 0);
+
+                log_device_debug(d, "Sending device syspath:%s", p);
                 assert_se(device_monitor_send_device(monitor_server, monitor_client, d) >= 0);
         }
 
-        log_info("Sending device subsystem:%s syspath:%s", subsystem, syspath);
+        log_device_info(device, "Sending device syspath:%s", syspath);
         assert_se(device_monitor_send_device(monitor_server, monitor_client, device) >= 0);
         assert_se(sd_event_loop(sd_device_monitor_get_event(monitor_client)) == 100);
+
+}
+
+static void test_sysattr_filter(sd_device *device, const char *sysattr) {
+        _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
+        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+        const char *syspath, *subsystem, *sysattr_value;
+        sd_device *d;
+
+        log_device_info(device, "/* %s(%s) */", __func__, sysattr);
+
+        assert_se(sd_device_get_syspath(device, &syspath) >= 0);
+        assert_se(sd_device_get_subsystem(device, &subsystem) >= 0);
+        assert_se(sd_device_get_sysattr_value(device, sysattr, &sysattr_value) >= 0);
+
+        assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
+        assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
+        assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_server), "sender") >= 0);
+
+        assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
+        assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
+        /* The sysattr filter is not implemented in BPF yet, so the below device_monito_send_device()
+         * may cause EAGAIN. So, let's also filter devices with subsystem. */
+        assert_se(sd_device_monitor_filter_add_match_subsystem_devtype(monitor_client, subsystem, NULL) >= 0);
+        assert_se(sd_device_monitor_filter_add_match_sysattr(monitor_client, sysattr, sysattr_value, true) >= 0);
+        assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
+        assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0);
+
+        assert_se(sd_device_enumerator_new(&e) >= 0);
+        assert_se(sd_device_enumerator_add_match_sysattr(e, sysattr, sysattr_value, false) >= 0);
+        FOREACH_DEVICE(e, d) {
+                const char *p;
+
+                assert_se(sd_device_get_syspath(d, &p) >= 0);
+
+                log_device_debug(d, "Sending device syspath:%s", p);
+                assert_se(device_monitor_send_device(monitor_server, monitor_client, d) >= 0);
+        }
+
+        log_device_info(device, "Sending device syspath:%s", syspath);
+        assert_se(device_monitor_send_device(monitor_server, monitor_client, device) >= 0);
+        assert_se(sd_event_loop(sd_device_monitor_get_event(monitor_client)) == 100);
+
+}
+
+static void test_parent_filter(sd_device *device) {
+        _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
+        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+        const char *syspath, *subsystem;
+        sd_device *parent, *d;
+        int r;
+
+        log_device_info(device, "/* %s */", __func__);
+
+        assert_se(sd_device_get_syspath(device, &syspath) >= 0);
+        assert_se(sd_device_get_subsystem(device, &subsystem) >= 0);
+        r = sd_device_get_parent(device, &parent);
+        if (r < 0)
+                return (void) log_device_info(device, "Device does not have parent, skipping.");
+
+        assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
+        assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
+        assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_server), "sender") >= 0);
+
+        assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
+        assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
+        /* The parent filter is not implemented in BPF yet, so the below device_monito_send_device()
+         * may cause EAGAIN. So, let's also filter devices with subsystem. */
+        assert_se(sd_device_monitor_filter_add_match_subsystem_devtype(monitor_client, subsystem, NULL) >= 0);
+        assert_se(sd_device_monitor_filter_add_match_parent(monitor_client, parent, true) >= 0);
+        assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
+        assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0);
+
+        assert_se(sd_device_enumerator_new(&e) >= 0);
+        FOREACH_DEVICE(e, d) {
+                const char *p;
+
+                assert_se(sd_device_get_syspath(d, &p) >= 0);
+
+                log_device_debug(d, "Sending device syspath:%s", p);
+                assert_se(device_monitor_send_device(monitor_server, monitor_client, d) >= 0);
+        }
+
+        log_device_info(device, "Sending device syspath:%s", syspath);
+        assert_se(device_monitor_send_device(monitor_server, monitor_client, device) >= 0);
+        assert_se(sd_event_loop(sd_device_monitor_get_event(monitor_client)) == 100);
+
 }
 
 static void test_sd_device_monitor_filter_remove(sd_device *device) {
@@ -184,6 +308,7 @@ int main(int argc, char *argv[]) {
         assert_se(sd_device_new_from_syspath(&loopback, "/sys/class/net/lo") >= 0);
         assert_se(device_add_property(loopback, "ACTION", "add") >= 0);
         assert_se(device_add_property(loopback, "SEQNUM", "10") >= 0);
+        assert_se(device_add_tag(loopback, "TEST_SD_DEVICE_MONITOR", true) >= 0);
 
         test_send_receive_one(loopback, false, false, false);
         test_send_receive_one(loopback,  true, false, false);
@@ -194,6 +319,8 @@ int main(int argc, char *argv[]) {
         test_send_receive_one(loopback,  true,  true,  true);
 
         test_subsystem_filter(loopback);
+        test_tag_filter(loopback);
+        test_sysattr_filter(loopback, "ifindex");
         test_sd_device_monitor_filter_remove(loopback);
         test_device_copy_properties(loopback);
 
@@ -214,5 +341,7 @@ int main(int argc, char *argv[]) {
         test_send_receive_one(sda, false,  true,  true);
         test_send_receive_one(sda,  true,  true,  true);
 
+        test_parent_filter(sda);
+
         return 0;
 }
index b76b0623fe3562f80f8751ac3a0ec177931dbc3b..172be4e07e855c6f4b8b258ea599b020ed172852 100644 (file)
@@ -3171,7 +3171,7 @@ static int process_child(sd_event *e, int64_t threshold, int64_t *ret_min_priori
                 zero(s->child.siginfo);
                 if (waitid(P_PID, s->child.pid, &s->child.siginfo,
                            WNOHANG | (s->child.options & WEXITED ? WNOWAIT : 0) | s->child.options) < 0)
-                        return -errno;
+                        return negative_errno();
 
                 if (s->child.siginfo.si_pid != 0) {
                         bool zombie = IN_SET(s->child.siginfo.si_code, CLD_EXITED, CLD_KILLED, CLD_DUMPED);
index cd5a0104a6c90e26a4186a271d5c7c68b68a473d..a939d655698aa9b3ec93cc22cf39563ec8fd32ea 100644 (file)
@@ -26,7 +26,6 @@ static const genl_family genl_families[] = {
 int sd_genl_socket_open(sd_netlink **ret) {
         return netlink_open_family(ret, NETLINK_GENERIC);
 }
-static int lookup_id(sd_netlink *nl, sd_genl_family_t family, uint16_t *id);
 
 static int genl_message_new(sd_netlink *nl, sd_genl_family_t family, uint16_t nlmsg_type, uint8_t cmd, sd_netlink_message **ret) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
@@ -73,17 +72,6 @@ static int genl_message_new(sd_netlink *nl, sd_genl_family_t family, uint16_t nl
         return 0;
 }
 
-int sd_genl_message_new(sd_netlink *nl, sd_genl_family_t family, uint8_t cmd, sd_netlink_message **ret) {
-        uint16_t id;
-        int r;
-
-        r = lookup_id(nl, family, &id);
-        if (r < 0)
-                return r;
-
-        return genl_message_new(nl, family, id, cmd, ret);
-}
-
 static int lookup_id(sd_netlink *nl, sd_genl_family_t family, uint16_t *id) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
         uint16_t u;
@@ -129,6 +117,17 @@ static int lookup_id(sd_netlink *nl, sd_genl_family_t family, uint16_t *id) {
         return 0;
 }
 
+int sd_genl_message_new(sd_netlink *nl, sd_genl_family_t family, uint8_t cmd, sd_netlink_message **ret) {
+        uint16_t id = 0; /* Unnecessary initialization to appease gcc */
+        int r;
+
+        r = lookup_id(nl, family, &id);
+        if (r < 0)
+                return r;
+
+        return genl_message_new(nl, family, id, cmd, ret);
+}
+
 int nlmsg_type_to_genl_family(const sd_netlink *nl, uint16_t type, sd_genl_family_t *ret) {
         void *p;
 
index 4ddcf95d05f57300c7b62b75e2c245a304de3515..d7c931d9f929d42d47a86b744781fa869d48683c 100644 (file)
@@ -265,9 +265,12 @@ _public_ struct udev_device *udev_monitor_receive_device(struct udev_monitor *ud
  * Returns: 0 on success, otherwise a negative error value.
  */
 _public_ int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype) {
+        int r;
+
         assert_return(udev_monitor, -EINVAL);
 
-        return sd_device_monitor_filter_add_match_subsystem_devtype(udev_monitor->monitor, subsystem, devtype);
+        r = sd_device_monitor_filter_add_match_subsystem_devtype(udev_monitor->monitor, subsystem, devtype);
+        return r < 0 ? r : 0;
 }
 
 /**
@@ -283,9 +286,12 @@ _public_ int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor
  * Returns: 0 on success, otherwise a negative error value.
  */
 _public_ int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag) {
+        int r;
+
         assert_return(udev_monitor, -EINVAL);
 
-        return sd_device_monitor_filter_add_match_tag(udev_monitor->monitor, tag);
+        r = sd_device_monitor_filter_add_match_tag(udev_monitor->monitor, tag);
+        return r < 0 ? r : 0;
 }
 
 /**
index f44c0bab2a9e46e016ad1efc3fed1a8a963ae038..953cf6a0d7b4128b4b1c85cd026867c62a16e0a1 100644 (file)
@@ -399,7 +399,7 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er
         r = locale_read_data(c, m);
         if (r < 0) {
                 log_error_errno(r, "Failed to read locale data: %m");
-                return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Failed to read locale data");
+                return sd_bus_error_set(error, SD_BUS_ERROR_FAILED, "Failed to read locale data");
         }
 
         /* Merge with the current settings */
@@ -673,7 +673,7 @@ static int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_err
         r = x11_read_data(c, m);
         if (r < 0) {
                 log_error_errno(r, "Failed to read x11 keyboard layout data: %m");
-                return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Failed to read x11 keyboard layout data");
+                return sd_bus_error_set(error, SD_BUS_ERROR_FAILED, "Failed to read x11 keyboard layout data");
         }
 
         if (streq_ptr(layout, c->x11_layout) &&
@@ -686,7 +686,7 @@ static int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_err
             (model && !string_is_safe(model)) ||
             (variant && !string_is_safe(variant)) ||
             (options && !string_is_safe(options)))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Received invalid keyboard data");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Received invalid keyboard data");
 
         r = verify_xkb_rmlvo(model, layout, variant, options);
         if (r < 0) {
@@ -694,7 +694,7 @@ static int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_err
                                 strempty(model), strempty(layout), strempty(variant), strempty(options));
 
                 if (r == -EOPNOTSUPP)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Local keyboard configuration not supported on this system.");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Local keyboard configuration not supported on this system.");
 
                 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Specified keymap cannot be compiled, refusing as invalid.");
         }
index 532be12e7a3cf2dbd83c7e3bd45e5cdc1c00df8e..694a99fba14c76f721ddc3a080ab3252abecb139 100644 (file)
@@ -695,9 +695,9 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
                 return r;
 
         if (!uid_is_valid(uid))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid UID");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid UID");
         if (leader < 0 || leader == 1 || leader == getpid_cached())
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
 
         if (isempty(type))
                 t = _SESSION_TYPE_INVALID;
@@ -831,7 +831,7 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
             vtnr < m->seat0->position_count &&
             m->seat0->positions[vtnr] &&
             m->seat0->positions[vtnr]->class != SESSION_GREETER)
-                return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY, "Already occupied by a session");
+                return sd_bus_error_set(error, BUS_ERROR_SESSION_BUSY, "Already occupied by a session");
 
         if (hashmap_size(m->sessions) >= m->sessions_max)
                 return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED,
@@ -1879,9 +1879,9 @@ static int method_do_shutdown_or_sleep(
                 if (r < 0)
                         return r;
                 if ((flags & ~SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC) != 0)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter");
-                if (!streq(unit_name, SPECIAL_REBOOT_TARGET) && (flags & SD_LOGIND_KEXEC_REBOOT))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter");
+                if (!streq(unit_name, SPECIAL_REBOOT_TARGET) && (flags & SD_LOGIND_REBOOT_VIA_KEXEC))
+                        return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Reboot via kexec is only applicable with reboot operations");
         } else {
                 /* Old style method: no flags parameter, but interactive bool passed as boolean in
                  * payload. Let's convert this argument to the new-style flags parameter for our internal
@@ -1895,7 +1895,7 @@ static int method_do_shutdown_or_sleep(
                 flags = interactive ? SD_LOGIND_INTERACTIVE : 0;
         }
 
-        if ((flags & SD_LOGIND_KEXEC_REBOOT) && kexec_loaded())
+        if ((flags & SD_LOGIND_REBOOT_VIA_KEXEC) && kexec_loaded())
                 unit_name = SPECIAL_KEXEC_TARGET;
 
         /* Don't allow multiple jobs being executed at the same time */
@@ -2140,6 +2140,8 @@ static int manager_scheduled_shutdown_handler(
                 target = SPECIAL_POWEROFF_TARGET;
         else if (streq(m->scheduled_shutdown_type, "reboot"))
                 target = SPECIAL_REBOOT_TARGET;
+        else if (streq(m->scheduled_shutdown_type, "kexec"))
+                target = SPECIAL_KEXEC_TARGET;
         else if (streq(m->scheduled_shutdown_type, "halt"))
                 target = SPECIAL_HALT_TARGET;
         else
@@ -2205,7 +2207,7 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_
                 action = "org.freedesktop.login1.power-off";
                 action_multiple_sessions = "org.freedesktop.login1.power-off-multiple-sessions";
                 action_ignore_inhibit = "org.freedesktop.login1.power-off-ignore-inhibit";
-        } else if (streq(type, "reboot")) {
+        } else if (STR_IN_SET(type, "reboot", "kexec")) {
                 action = "org.freedesktop.login1.reboot";
                 action_multiple_sessions = "org.freedesktop.login1.reboot-multiple-sessions";
                 action_ignore_inhibit = "org.freedesktop.login1.reboot-ignore-inhibit";
@@ -2214,7 +2216,7 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_
                 action_multiple_sessions = "org.freedesktop.login1.halt-multiple-sessions";
                 action_ignore_inhibit = "org.freedesktop.login1.halt-ignore-inhibit";
         } else
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unsupported shutdown type");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Unsupported shutdown type");
 
         r = verify_shutdown_creds(m, message, INHIBIT_SHUTDOWN, action, action_multiple_sessions,
                                   action_ignore_inhibit, 0, error);
@@ -2672,7 +2674,7 @@ static int method_set_reboot_to_firmware_setup(
 
                 r = efi_reboot_to_firmware_supported();
                 if (r == -EOPNOTSUPP)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Firmware does not support boot into firmware.");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Firmware does not support boot into firmware.");
                 if (r < 0)
                         return r;
 
@@ -2684,7 +2686,7 @@ static int method_set_reboot_to_firmware_setup(
                 if (r < 0)
                         log_warning_errno(r, "Failed to parse $SYSTEMD_REBOOT_TO_FIRMWARE_SETUP: %m");
 
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Firmware does not support boot into firmware.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Firmware does not support boot into firmware.");
         } else
                 /* non-EFI case: $SYSTEMD_REBOOT_TO_FIRMWARE_SETUP is set to on */
                 use_efi = false;
@@ -2840,7 +2842,7 @@ static int method_set_reboot_to_boot_loader_menu(
                 if (r < 0)
                         log_warning_errno(r, "Failed to determine whether reboot to boot loader menu is supported: %m");
                 if (r < 0 || !FLAGS_SET(features, EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Boot loader does not support boot into boot loader menu.");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Boot loader does not support boot into boot loader menu.");
 
                 use_efi = true;
 
@@ -2850,7 +2852,7 @@ static int method_set_reboot_to_boot_loader_menu(
                 if (r < 0)
                         log_warning_errno(r, "Failed to parse $SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU: %m");
 
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Boot loader does not support boot into boot loader menu.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Boot loader does not support boot into boot loader menu.");
         } else
                 /* non-EFI case: $SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU is set to on */
                 use_efi = false;
@@ -3042,7 +3044,7 @@ static int method_set_reboot_to_boot_loader_entry(
                 if (r < 0)
                         log_warning_errno(r, "Failed to determine whether reboot into boot loader entry is supported: %m");
                 if (r < 0 || !FLAGS_SET(features, EFI_LOADER_FEATURE_ENTRY_ONESHOT))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Loader does not support boot into boot loader entry.");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Loader does not support boot into boot loader entry.");
 
                 use_efi = true;
 
@@ -3052,7 +3054,7 @@ static int method_set_reboot_to_boot_loader_entry(
                 if (r < 0)
                         log_warning_errno(r, "Failed to parse $SYSTEMD_REBOOT_TO_BOOT_LOADER_ENTRY: %m");
 
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Loader does not support boot into boot loader entry.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Loader does not support boot into boot loader entry.");
         } else
                 /* non-EFI case: $SYSTEMD_REBOOT_TO_BOOT_LOADER_ENTRY is set to on */
                 use_efi = false;
index 9c2625cdcc3245cbddcec808fc63c14c846d98af..cceb3b1d2d309fc22eb03ea9076ad7976c32af0d 100644 (file)
@@ -206,7 +206,7 @@ static int method_switch_to(sd_bus_message *message, void *userdata, sd_bus_erro
                 return r;
 
         if (to <= 0)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid virtual terminal");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid virtual terminal");
 
         r = check_polkit_chvt(message, s->manager, error);
         if (r < 0)
index d342dc4193aa42d53a969568d519ed640ac919b4..afaef1123d98e2bc156d484902f48e1defbbdfc7 100644 (file)
@@ -256,11 +256,11 @@ static int method_set_idle_hint(sd_bus_message *message, void *userdata, sd_bus_
                 return r;
 
         if (uid != 0 && uid != s->user->user_record->uid)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may set idle hint");
+                return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may set idle hint");
 
         r = session_set_idle_hint(s, b);
         if (r == -ENOTTY)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Idle hint control is not supported on non-graphical sessions.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Idle hint control is not supported on non-graphical sessions.");
         if (r < 0)
                 return r;
 
@@ -289,7 +289,7 @@ static int method_set_locked_hint(sd_bus_message *message, void *userdata, sd_bu
                 return r;
 
         if (uid != 0 && uid != s->user->user_record->uid)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may set locked hint");
+                return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may set locked hint");
 
         session_set_locked_hint(s, b);
 
@@ -364,7 +364,7 @@ static int method_take_control(sd_bus_message *message, void *userdata, sd_bus_e
                 return r;
 
         if (uid != 0 && (force || uid != s->user->user_record->uid))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may take control");
+                return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may take control");
 
         r = session_set_controller(s, sd_bus_message_get_sender(message), force, true);
         if (r < 0)
@@ -380,7 +380,7 @@ static int method_release_control(sd_bus_message *message, void *userdata, sd_bu
         assert(s);
 
         if (!session_is_controller(s, sd_bus_message_get_sender(message)))
-                return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
+                return sd_bus_error_set(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
 
         session_drop_controller(s);
 
@@ -406,7 +406,7 @@ static int method_set_type(sd_bus_message *message, void *userdata, sd_bus_error
                                          "Invalid session type '%s'", t);
 
         if (!session_is_controller(s, sd_bus_message_get_sender(message)))
-                return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You must be in control of this session to set type");
+                return sd_bus_error_set(error, BUS_ERROR_NOT_IN_CONTROL, "You must be in control of this session to set type");
 
         session_set_type(s, type);
 
@@ -428,10 +428,10 @@ static int method_take_device(sd_bus_message *message, void *userdata, sd_bus_er
                 return r;
 
         if (!DEVICE_MAJOR_VALID(major) || !DEVICE_MINOR_VALID(minor))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Device major/minor is not valid.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Device major/minor is not valid.");
 
         if (!session_is_controller(s, sd_bus_message_get_sender(message)))
-                return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
+                return sd_bus_error_set(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
 
         dev = makedev(major, minor);
         sd = hashmap_get(s->devices, &dev);
@@ -441,7 +441,7 @@ static int method_take_device(sd_bus_message *message, void *userdata, sd_bus_er
                  * The caller should use dup() if it requires more
                  * than one fd (it would be functionally
                  * equivalent). */
-                return sd_bus_error_setf(error, BUS_ERROR_DEVICE_IS_TAKEN, "Device already taken");
+                return sd_bus_error_set(error, BUS_ERROR_DEVICE_IS_TAKEN, "Device already taken");
 
         r = session_device_new(s, dev, true, &sd);
         if (r < 0)
@@ -478,15 +478,15 @@ static int method_release_device(sd_bus_message *message, void *userdata, sd_bus
                 return r;
 
         if (!DEVICE_MAJOR_VALID(major) || !DEVICE_MINOR_VALID(minor))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Device major/minor is not valid.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Device major/minor is not valid.");
 
         if (!session_is_controller(s, sd_bus_message_get_sender(message)))
-                return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
+                return sd_bus_error_set(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
 
         dev = makedev(major, minor);
         sd = hashmap_get(s->devices, &dev);
         if (!sd)
-                return sd_bus_error_setf(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
+                return sd_bus_error_set(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
 
         session_device_free(sd);
         session_save(s);
@@ -509,15 +509,15 @@ static int method_pause_device_complete(sd_bus_message *message, void *userdata,
                 return r;
 
         if (!DEVICE_MAJOR_VALID(major) || !DEVICE_MINOR_VALID(minor))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Device major/minor is not valid.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Device major/minor is not valid.");
 
         if (!session_is_controller(s, sd_bus_message_get_sender(message)))
-                return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
+                return sd_bus_error_set(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
 
         dev = makedev(major, minor);
         sd = hashmap_get(s->devices, &dev);
         if (!sd)
-                return sd_bus_error_setf(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
+                return sd_bus_error_set(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
 
         session_device_complete_pause(sd);
 
@@ -546,9 +546,9 @@ static int method_set_brightness(sd_bus_message *message, void *userdata, sd_bus
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Not a valid device name %s, refusing.", name);
 
         if (!s->seat)
-                return sd_bus_error_setf(error, BUS_ERROR_NOT_YOUR_DEVICE, "Your session has no seat, refusing.");
+                return sd_bus_error_set(error, BUS_ERROR_NOT_YOUR_DEVICE, "Your session has no seat, refusing.");
         if (s->seat->active != s)
-                return sd_bus_error_setf(error, BUS_ERROR_NOT_YOUR_DEVICE, "Session is not in foreground, refusing.");
+                return sd_bus_error_set(error, BUS_ERROR_NOT_YOUR_DEVICE, "Session is not in foreground, refusing.");
 
         r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
         if (r < 0)
@@ -559,7 +559,7 @@ static int method_set_brightness(sd_bus_message *message, void *userdata, sd_bus
                 return r;
 
         if (uid != 0 && uid != s->user->user_record->uid)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may change brightness.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may change brightness.");
 
         r = sd_device_new_from_subsystem_sysname(&d, subsystem, name);
         if (r < 0)
index 309de0b116c80bc2e6d754987c159cd2b2fc9923..e6ffb52924c0f845f641e5f68ee3419e06400b1b 100644 (file)
@@ -41,7 +41,7 @@ int bus_image_method_remove(
         assert(image);
 
         if (m->n_operations >= OPERATIONS_MAX)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
 
         r = bus_verify_polkit_async(
                         message,
@@ -146,7 +146,7 @@ int bus_image_method_clone(
         assert(m);
 
         if (m->n_operations >= OPERATIONS_MAX)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
 
         r = sd_bus_message_read(message, "sb", &new_name, &read_only);
         if (r < 0)
@@ -252,7 +252,7 @@ int bus_image_method_set_limit(
         if (r < 0)
                 return r;
         if (!FILE_SIZE_VALID_OR_INFINITY(limit))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New limit out of range");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "New limit out of range");
 
         r = bus_verify_polkit_async(
                         message,
index e7c4ed3c7c17cdfef73b28e4edf482bd4ac1fd76..0022a980c52655d8c562911a1e66e59df374a203 100644 (file)
@@ -331,12 +331,12 @@ int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd
                 if (r < 0)
                         return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
                 if (r != EXIT_SUCCESS)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
                 break;
         }
 
         default:
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting IP address data is only supported on container machines.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting IP address data is only supported on container machines.");
         }
 
         r = sd_bus_message_close_container(reply);
@@ -415,15 +415,15 @@ int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, s
                 if (r < 0)
                         return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
                 if (r == EXIT_NOT_FOUND)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Machine does not contain OS release information");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_FAILED, "Machine does not contain OS release information");
                 if (r != EXIT_SUCCESS)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
 
                 break;
         }
 
         default:
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting OS release data is only supported on container machines.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting OS release data is only supported on container machines.");
         }
 
         return bus_reply_pair_array(message, l);
@@ -628,7 +628,7 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
         if (r < 0)
                 return r;
         if (!strv_env_is_valid(env))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments");
 
         const char *details[] = {
                 "machine", m->name,
@@ -820,19 +820,19 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
         assert(m);
 
         if (m->class != MACHINE_CONTAINER)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Bind mounting is only supported on container machines.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Bind mounting is only supported on container machines.");
 
         r = sd_bus_message_read(message, "ssbb", &src, &dest, &read_only, &make_file_or_directory);
         if (r < 0)
                 return r;
 
         if (!path_is_absolute(src) || !path_is_normalized(src))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and normalized.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and normalized.");
 
         if (isempty(dest))
                 dest = src;
         else if (!path_is_absolute(dest) || !path_is_normalized(dest))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and normalized.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and normalized.");
 
         r = bus_verify_polkit_async(
                         message,
@@ -852,7 +852,7 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
         if (r < 0)
                 return r;
         if (uid != 0)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Can't bind mount on container with user namespacing applied.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Can't bind mount on container with user namespacing applied.");
 
         propagate_directory = strjoina("/run/systemd/nspawn/propagate/", m->name);
         r = bind_mount_in_namespace(m->leader,
@@ -881,22 +881,22 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
         assert(m);
 
         if (m->manager->n_operations >= OPERATIONS_MAX)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing copies.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing copies.");
 
         if (m->class != MACHINE_CONTAINER)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Copying files is only supported on container machines.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Copying files is only supported on container machines.");
 
         r = sd_bus_message_read(message, "ss", &src, &dest);
         if (r < 0)
                 return r;
 
         if (!path_is_absolute(src))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute.");
 
         if (isempty(dest))
                 dest = src;
         else if (!path_is_absolute(dest))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute.");
 
         r = bus_verify_polkit_async(
                         message,
@@ -1074,7 +1074,7 @@ int bus_machine_method_open_root_directory(sd_bus_message *message, void *userda
                 if (r < 0)
                         return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
                 if (r != EXIT_SUCCESS)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
 
                 fd = receive_one_fd(pair[0], MSG_DONTWAIT);
                 if (fd < 0)
@@ -1084,7 +1084,7 @@ int bus_machine_method_open_root_directory(sd_bus_message *message, void *userda
         }
 
         default:
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening the root directory is only supported on container machines.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening the root directory is only supported on container machines.");
         }
 
         return sd_bus_reply_method_return(message, "h", fd);
@@ -1105,7 +1105,7 @@ int bus_machine_method_get_uid_shift(sd_bus_message *message, void *userdata, sd
                 return sd_bus_reply_method_return(message, "u", UINT32_C(0));
 
         if (m->class != MACHINE_CONTAINER)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "UID/GID shift may only be determined for container machines.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "UID/GID shift may only be determined for container machines.");
 
         r = machine_get_uid_shift(m, &shift);
         if (r == -ENXIO)
index 0a6ae96bc6eeee50176195476b755808d558761a..342b18a8df925622e8f3a15f6507f4d12e8791af 100644 (file)
@@ -241,7 +241,7 @@ static int method_create_or_register_machine(Manager *manager, sd_bus_message *m
         if (r < 0)
                 return r;
         if (!hostname_is_valid(name, 0))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
 
         r = sd_bus_message_read_array(message, 'y', &v, &n);
         if (r < 0)
@@ -251,7 +251,7 @@ static int method_create_or_register_machine(Manager *manager, sd_bus_message *m
         else if (n == 16)
                 memcpy(&id, v, n);
         else
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
 
         r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
         if (r < 0)
@@ -275,14 +275,14 @@ static int method_create_or_register_machine(Manager *manager, sd_bus_message *m
         else {
                 c = machine_class_from_string(class);
                 if (c < 0)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
         }
 
         if (leader == 1)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
 
         if (!isempty(root_directory) && !path_is_absolute(root_directory))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
 
         if (leader == 0) {
                 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
@@ -701,7 +701,7 @@ static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_err
         assert(message);
 
         if (m->n_operations >= OPERATIONS_MAX)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
 
         r = sd_bus_message_read(message, "s", &mm);
         if (r < 0)
@@ -842,7 +842,7 @@ static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus
         if (r < 0)
                 return r;
         if (!FILE_SIZE_VALID_OR_INFINITY(limit))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New limit out of range");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "New limit out of range");
 
         r = bus_verify_polkit_async(
                         message,
@@ -867,7 +867,7 @@ static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus
 
         r = btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, limit);
         if (r == -ENOTTY)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
         if (r < 0)
                 return sd_bus_error_set_errnof(error, r, "Failed to adjust quota limit: %m");
 
@@ -898,7 +898,7 @@ static int method_map_from_machine_user(sd_bus_message *message, void *userdata,
                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
 
         if (machine->class != MACHINE_CONTAINER)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Not supported for non-container machines.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Not supported for non-container machines.");
 
         r = machine_translate_uid(machine, uid, &converted);
         if (r == -ESRCH)
@@ -957,7 +957,7 @@ static int method_map_from_machine_group(sd_bus_message *message, void *userdata
                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
 
         if (machine->class != MACHINE_CONTAINER)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Not supported for non-container machines.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Not supported for non-container machines.");
 
         r = machine_translate_gid(machine, gid, &converted);
         if (r == -ESRCH)
index 34565e3e69532f93be43a89a9e9d5bb9641b2ffb..42432f1f7fdd89ee69a03b208689827084df6655 100644 (file)
@@ -22,14 +22,14 @@ static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdat
         o->pid = 0;
 
         if (si->si_code != CLD_EXITED) {
-                r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
+                r = sd_bus_error_set(&error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
                 goto fail;
         }
 
         if (si->si_status == EXIT_SUCCESS)
                 r = 0;
         else if (read(o->errno_fd, &r, sizeof(r)) != sizeof(r)) { /* Try to acquire error code for failed operation */
-                r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child failed.");
+                r = sd_bus_error_set(&error, SD_BUS_ERROR_FAILED, "Child failed.");
                 goto fail;
         }
 
index faaa6a7b6caefec839dfe4e094a2c8fee963c959..52abcddd641a0da872d2019ed48e7bb3fa270f3c 100644 (file)
@@ -77,35 +77,47 @@ static bool arg_full = false;
 static unsigned arg_lines = 10;
 
 static void operational_state_to_color(const char *name, const char *state, const char **on, const char **off) {
-        assert(on);
-        assert(off);
-
         if (STRPTR_IN_SET(state, "routable", "enslaved") ||
             (streq_ptr(name, "lo") && streq_ptr(state, "carrier"))) {
-                *on = ansi_highlight_green();
-                *off = ansi_normal();
+                if (on)
+                        *on = ansi_highlight_green();
+                if (off)
+                        *off = ansi_normal();
         } else if (streq_ptr(state, "degraded")) {
-                *on = ansi_highlight_yellow();
-                *off = ansi_normal();
-        } else
-                *on = *off = "";
+                if (on)
+                        *on = ansi_highlight_yellow();
+                if (off)
+                        *off = ansi_normal();
+        } else {
+                if (on)
+                        *on = "";
+                if (off)
+                        *off = "";
+        }
 }
 
 static void setup_state_to_color(const char *state, const char **on, const char **off) {
-        assert(on);
-        assert(off);
-
         if (streq_ptr(state, "configured")) {
-                *on = ansi_highlight_green();
-                *off = ansi_normal();
+                if (on)
+                        *on = ansi_highlight_green();
+                if (off)
+                        *off = ansi_normal();
         } else if (streq_ptr(state, "configuring")) {
-                *on = ansi_highlight_yellow();
-                *off = ansi_normal();
+                if (on)
+                        *on = ansi_highlight_yellow();
+                if (off)
+                        *off = ansi_normal();
         } else if (STRPTR_IN_SET(state, "failed", "linger")) {
-                *on = ansi_highlight_red();
-                *off = ansi_normal();
-        } else
-                *on = *off = "";
+                if (on)
+                        *on = ansi_highlight_red();
+                if (off)
+                        *off = ansi_normal();
+        } else {
+                if (on)
+                        *on = "";
+                if (off)
+                        *off = "";
+        }
 }
 
 typedef struct VxLanInfo {
@@ -692,17 +704,16 @@ static int list_links(int argc, char *argv[], void *userdata) {
 
         for (int i = 0; i < c; i++) {
                 _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
-                const char *on_color_operational, *off_color_operational,
-                           *on_color_setup, *off_color_setup;
+                const char *on_color_operational, *on_color_setup;
                 _cleanup_free_ char *t = NULL;
 
                 (void) sd_network_link_get_operational_state(links[i].ifindex, &operational_state);
-                operational_state_to_color(links[i].name, operational_state, &on_color_operational, &off_color_operational);
+                operational_state_to_color(links[i].name, operational_state, &on_color_operational, NULL);
 
                 r = sd_network_link_get_setup_state(links[i].ifindex, &setup_state);
                 if (r == -ENODATA) /* If there's no info available about this iface, it's unmanaged by networkd */
                         setup_state = strdup("unmanaged");
-                setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
+                setup_state_to_color(setup_state, &on_color_setup, NULL);
 
                 t = link_get_type_string(links[i].sd_device, links[i].iftype);
 
@@ -2145,7 +2156,7 @@ static int link_status_one(
 static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) {
         _cleanup_free_ char *operational_state = NULL;
         _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains = NULL;
-        const char *on_color_operational, *off_color_operational;
+        const char *on_color_operational;
         _cleanup_(table_unrefp) Table *table = NULL;
         TableCell *cell;
         int r;
@@ -2153,7 +2164,7 @@ static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) {
         assert(rtnl);
 
         (void) sd_network_get_operational_state(&operational_state);
-        operational_state_to_color(NULL, operational_state, &on_color_operational, &off_color_operational);
+        operational_state_to_color(NULL, operational_state, &on_color_operational, NULL);
 
         table = table_new("dot", "key", "value");
         if (!table)
index 0de1892fc955bbdc97d662c3f4d99b3c2dc50469..9677dfb0c36b39e4998613f8b1153ea1c2453302 100644 (file)
@@ -167,7 +167,7 @@ int manager_request_product_uuid(Manager *m, Link *link) {
                         return log_oom();
         }
 
-        if (!m->bus || sd_bus_is_ready(m->bus) <= 0) {
+        if (sd_bus_is_ready(m->bus) <= 0) {
                 log_debug("Not connected to system bus, requesting product UUID later.");
                 return 0;
         }
index 72bb46b18650a87549814cf8557769dfdbad60be..aa077d6219ffc7848ab97608b512dabe5d548686 100644 (file)
 #include "radv-internal.h"
 #include "web-util.h"
 
+bool link_dhcp6_with_address_enabled(Link *link) {
+        if (!link_dhcp6_enabled(link))
+                return false;
+
+        return link->network->dhcp6_use_address;
+}
+
 bool link_dhcp6_pd_is_enabled(Link *link) {
         assert(link);
 
index f74476d575ec1e67226f57d5413b72dfaadc5832..a8028a95abd8838dbbebf042fe251bbf60526719 100644 (file)
@@ -26,6 +26,7 @@ typedef struct DHCP6DelegatedPrefix {
 DHCP6DelegatedPrefix *dhcp6_pd_free(DHCP6DelegatedPrefix *p);
 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCP6DelegatedPrefix*, dhcp6_pd_free);
 
+bool link_dhcp6_with_address_enabled(Link *link);
 bool link_dhcp6_pd_is_enabled(Link *link);
 int dhcp6_pd_remove(Link *link);
 int dhcp6_configure(Link *link);
index 4d0e4815db2ce7abf400821800cde6d0286bcb52..16058c6fcf2649ccc2d5cfd13d489bcfcf6c01b1 100644 (file)
@@ -211,7 +211,7 @@ int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_
                 if (r == 0)
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search domain %s", name);
                 if (!route_only && dns_name_is_root(name))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root domain is not suitable as search domain");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Root domain is not suitable as search domain");
 
                 r = dns_name_normalize(name, 0, &str);
                 if (r < 0)
@@ -854,7 +854,7 @@ int link_send_changed_strv(Link *link, char **properties) {
         assert(link->manager);
         assert(properties);
 
-        if (!link->manager->bus)
+        if (sd_bus_is_ready(link->manager->bus) <= 0)
                 return 0;
 
         p = link_bus_path(link);
index de453fa72e0a7d979d4a58a98d7cb99ff98ca74d..6c08203c54ade0395d1eb74822e31c65704b7e35 100644 (file)
@@ -779,7 +779,7 @@ void link_check_ready(Link *link) {
                                 break;
                         }
 
-                if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || link_ipv4ll_enabled(link)) &&
+                if ((link_dhcp4_enabled(link) || link_dhcp6_with_address_enabled(link) || link_ipv4ll_enabled(link)) &&
                     !link->dhcp_address && set_isempty(link->dhcp6_addresses) && !has_ndisc_address &&
                     !link->ipv4ll_address_configured)
                         /* When DHCP[46] or IPv4LL is enabled, at least one address is acquired by them. */
@@ -2202,7 +2202,7 @@ static int link_reconfigure_internal(Link *link, sd_netlink_message *m, bool for
                 return r;
 
         if (!IN_SET(link->state, LINK_STATE_UNMANAGED, LINK_STATE_PENDING, LINK_STATE_INITIALIZED)) {
-                log_link_debug(link, "State is %s, dropping config", link_state_to_string(link->state));
+                log_link_debug(link, "State is %s, dropping foreign config", link_state_to_string(link->state));
                 r = link_drop_foreign_config(link);
                 if (r < 0)
                         return r;
@@ -2638,7 +2638,7 @@ static int link_carrier_lost(Link *link) {
                 return r;
 
         if (!IN_SET(link->state, LINK_STATE_UNMANAGED, LINK_STATE_PENDING, LINK_STATE_INITIALIZED)) {
-                log_link_debug(link, "State is %s, dropping config", link_state_to_string(link->state));
+                log_link_debug(link, "State is %s, dropping foreign config", link_state_to_string(link->state));
                 r = link_drop_foreign_config(link);
                 if (r < 0)
                         return r;
index fce10a7e7dcfaeb20f80713b093fec735c35fcf7..138d76541415a2d0fa8b73df34d455342421eb83 100644 (file)
@@ -339,7 +339,7 @@ int manager_send_changed_strv(Manager *manager, char **properties) {
         assert(manager);
         assert(properties);
 
-        if (!manager->bus)
+        if (sd_bus_is_ready(manager->bus) <= 0)
                 return 0;
 
         return sd_bus_emit_properties_changed_strv(
index bfdb1f8c96643574015257448cbcbb1ea7a453dd..a8db2cc44bb437458cab93c52670b39d1891c6ac 100644 (file)
@@ -767,8 +767,8 @@ int manager_set_hostname(Manager *m, const char *hostname) {
         if (r < 0)
                 return r;
 
-        if (!m->bus || sd_bus_is_ready(m->bus) <= 0) {
-                log_debug("Not connected to system bus, setting hostname later.");
+        if (sd_bus_is_ready(m->bus) <= 0) {
+                log_debug("Not connected to system bus, setting system hostname later.");
                 return 0;
         }
 
@@ -784,7 +784,6 @@ int manager_set_hostname(Manager *m, const char *hostname) {
                         "sb",
                         hostname,
                         false);
-
         if (r < 0)
                 return log_error_errno(r, "Could not set transient hostname: %m");
 
@@ -817,8 +816,8 @@ int manager_set_timezone(Manager *m, const char *tz) {
         if (r < 0)
                 return r;
 
-        if (!m->bus || sd_bus_is_ready(m->bus) <= 0) {
-                log_debug("Not connected to system bus, setting timezone later.");
+        if (sd_bus_is_ready(m->bus) <= 0) {
+                log_debug("Not connected to system bus, setting system timezone later.");
                 return 0;
         }
 
index 929855daaf1bd2b1300fd0a9e6944d10981ae58a..7f630fccc7fbdad51544dd1d248f099dd345234f 100644 (file)
@@ -28,9 +28,9 @@ struct Manager {
         Hashmap *polkit_registry;
         int ethtool_fd;
 
-        bool enumerating:1;
-        bool dirty:1;
-        bool restarting:1;
+        bool enumerating;
+        bool dirty;
+        bool restarting;
         bool manage_foreign_routes;
 
         Set *dirty_links;
index ba7c184b662d115f51c87c6111c3fa43b0415e7b..6830cf592e231be985d8884c4386e03b46f42bfb 100644 (file)
@@ -1315,15 +1315,16 @@ int ndisc_configure(Link *link) {
         if (!link_ipv6_accept_ra_enabled(link))
                 return 0;
 
-        if (!link->ndisc) {
-                r = sd_ndisc_new(&link->ndisc);
-                if (r < 0)
-                        return r;
+        if (link->ndisc)
+                return 0; /* Already configured. */
 
-                r = sd_ndisc_attach_event(link->ndisc, link->manager->event, 0);
-                if (r < 0)
-                        return r;
-        }
+        r = sd_ndisc_new(&link->ndisc);
+        if (r < 0)
+                return r;
+
+        r = sd_ndisc_attach_event(link->ndisc, link->manager->event, 0);
+        if (r < 0)
+                return r;
 
         r = sd_ndisc_set_mac(link->ndisc, &link->hw_addr.addr.ether);
         if (r < 0)
index 40cbc296bd516d05f47743d9eb261eabced4da2d..99f54ceaaab609d8c3b1bd0f24c88c4d91af2e96 100644 (file)
@@ -202,8 +202,15 @@ static int run(int argc, char* argv[]) {
         if (r <= 0)
                 return r;
 
-        if (arg_booted)
-                return sd_booted() <= 0;
+        if (arg_booted) {
+                r = sd_booted();
+                if (r < 0)
+                        log_debug_errno(r, "Failed to determine whether we are booted with systemd, assuming we aren't: %m");
+                else
+                        log_debug("The system %s booted with systemd.", r ? "was" : "was not");
+
+                return r <= 0;
+        }
 
         if (arg_ready)
                 our_env[i++] = (char*) "READY=1";
@@ -278,4 +285,4 @@ static int run(int argc, char* argv[]) {
         return 0;
 }
 
-DEFINE_MAIN_FUNCTION(run);
+DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE (run);
index dfc0977c849c3692479bdc1428fa0bd20da716dd..e2a29475a225536ffb0c49ce71269393de1dbe29 100644 (file)
@@ -207,14 +207,10 @@ enum nss_status _nss_resolve_gethostbyname4_r(
                 int *errnop, int *h_errnop,
                 int32_t *ttlp) {
 
-        _cleanup_(resolve_hostname_reply_destroy) ResolveHostnameReply p = {};
-        _cleanup_(json_variant_unrefp) JsonVariant *cparams = NULL;
-        struct gaih_addrtuple *r_tuple = NULL, *r_tuple_first = NULL;
         _cleanup_(varlink_unrefp) Varlink *link = NULL;
-        const char *canonical = NULL, *error_id = NULL;
-        JsonVariant *entry, *rparams;
-        size_t l, ms, idx, c = 0;
-        char *r_name;
+        _cleanup_(json_variant_unrefp) JsonVariant *cparams = NULL;
+        _cleanup_(resolve_hostname_reply_destroy) ResolveHostnameReply p = {};
+        JsonVariant *rparams, *entry;
         int r;
 
         PROTECT_ERRNO;
@@ -241,6 +237,7 @@ enum nss_status _nss_resolve_gethostbyname4_r(
          * DNSSEC errors and suchlike. (We don't use UNAVAIL in this case so that the nsswitch.conf
          * configuration can distinguish such executed but negative replies from complete failure to
          * talk to resolved). */
+        const char *error_id;
         r = varlink_call(link, "io.systemd.Resolve.ResolveHostname", cparams, &rparams, &error_id, NULL);
         if (r < 0)
                 goto fail;
@@ -256,6 +253,7 @@ enum nss_status _nss_resolve_gethostbyname4_r(
         if (json_variant_is_blank_object(p.addresses))
                 goto not_found;
 
+        size_t n_addresses = 0;
         JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) {
                 AddressParameters q = {};
 
@@ -271,13 +269,13 @@ enum nss_status _nss_resolve_gethostbyname4_r(
                         goto fail;
                 }
 
-                c++;
+                n_addresses++;
         }
 
-        canonical = p.name ?: name;
+        const char *canonical = p.name ?: name;
+        size_t l = strlen(canonical);
+        size_t idx, ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * n_addresses;
 
-        l = strlen(canonical);
-        ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * c;
         if (buflen < ms) {
                 UNPROTECT_ERRNO;
                 *errnop = ERANGE;
@@ -286,12 +284,13 @@ enum nss_status _nss_resolve_gethostbyname4_r(
         }
 
         /* First, append name */
-        r_name = buffer;
-        memcpy(r_name, canonical, l+1);
-        idx = ALIGN(l+1);
+        char *r_name = buffer;
+        memcpy(r_name, canonical, l + 1);
+        idx = ALIGN(l + 1);
 
         /* Second, append addresses */
-        r_tuple_first = (struct gaih_addrtuple*) (buffer + idx);
+        struct gaih_addrtuple *r_tuple = NULL,
+                *r_tuple_first = (struct gaih_addrtuple*) (buffer + idx);
 
         JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) {
                 AddressParameters q = {};
@@ -313,7 +312,7 @@ enum nss_status _nss_resolve_gethostbyname4_r(
                 idx += ALIGN(sizeof(struct gaih_addrtuple));
         }
 
-        assert(r_tuple);
+        assert(r_tuple);  /* We had at least one address, so r_tuple must be set */
         r_tuple->next = NULL;  /* Override last next pointer */
 
         assert(idx == ms);
@@ -353,13 +352,10 @@ enum nss_status _nss_resolve_gethostbyname3_r(
                 int32_t *ttlp,
                 char **canonp) {
 
-        _cleanup_(resolve_hostname_reply_destroy) ResolveHostnameReply p = {};
-        _cleanup_(json_variant_unrefp) JsonVariant *cparams = NULL;
-        char *r_name, *r_aliases, *r_addr, *r_addr_list;
         _cleanup_(varlink_unrefp) Varlink *link = NULL;
-        const char *canonical, *error_id = NULL;
-        size_t l, idx, ms, alen, i = 0, c = 0;
-        JsonVariant *entry, *rparams;
+        _cleanup_(json_variant_unrefp) JsonVariant *cparams = NULL;
+        _cleanup_(resolve_hostname_reply_destroy) ResolveHostnameReply p = {};
+        JsonVariant *rparams, *entry;
         int r;
 
         PROTECT_ERRNO;
@@ -389,6 +385,7 @@ enum nss_status _nss_resolve_gethostbyname3_r(
         if (r < 0)
                 goto fail;
 
+        const char *error_id;
         r = varlink_call(link, "io.systemd.Resolve.ResolveHostname", cparams, &rparams, &error_id, NULL);
         if (r < 0)
                 goto fail;
@@ -404,6 +401,7 @@ enum nss_status _nss_resolve_gethostbyname3_r(
         if (json_variant_is_blank_object(p.addresses))
                 goto not_found;
 
+        size_t n_addresses = 0;
         JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) {
                 AddressParameters q = {};
 
@@ -419,15 +417,15 @@ enum nss_status _nss_resolve_gethostbyname3_r(
                         goto fail;
                 }
 
-                c++;
+                n_addresses++;
         }
 
-        canonical = p.name ?: name;
+        const char *canonical = p.name ?: name;
 
-        alen = FAMILY_ADDRESS_SIZE(af);
-        l = strlen(canonical);
+        size_t alen = FAMILY_ADDRESS_SIZE(af);
+        size_t l = strlen(canonical);
 
-        ms = ALIGN(l+1) + c*ALIGN(alen) + (c+2) * sizeof(char*);
+        size_t idx, ms = ALIGN(l + 1) + n_addresses * ALIGN(alen) + (n_addresses + 2) * sizeof(char*);
 
         if (buflen < ms) {
                 UNPROTECT_ERRNO;
@@ -437,18 +435,19 @@ enum nss_status _nss_resolve_gethostbyname3_r(
         }
 
         /* First, append name */
-        r_name = buffer;
+        char *r_name = buffer;
         memcpy(r_name, canonical, l+1);
         idx = ALIGN(l+1);
 
         /* Second, create empty aliases array */
-        r_aliases = buffer + idx;
+        char *r_aliases = buffer + idx;
         ((char**) r_aliases)[0] = NULL;
         idx += sizeof(char*);
 
         /* Third, append addresses */
-        r_addr = buffer + idx;
+        char *r_addr = buffer + idx;
 
+        size_t i = 0;
         JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) {
                 AddressParameters q = {};
 
@@ -468,16 +467,16 @@ enum nss_status _nss_resolve_gethostbyname3_r(
                 i++;
         }
 
-        assert(i == c);
-        idx += c * ALIGN(alen);
+        assert(i == n_addresses);
+        idx += n_addresses * ALIGN(alen);
 
         /* Fourth, append address pointer array */
-        r_addr_list = buffer + idx;
-        for (i = 0; i < c; i++)
+        char *r_addr_list = buffer + idx;
+        for (i = 0; i < n_addresses; i++)
                 ((char**) r_addr_list)[i] = r_addr + i*ALIGN(alen);
 
         ((char**) r_addr_list)[i] = NULL;
-        idx += (c+1) * sizeof(char*);
+        idx += (n_addresses + 1) * sizeof(char*);
 
         assert(idx == ms);
 
@@ -540,8 +539,8 @@ static void name_parameters_destroy(NameParameters *p) {
 }
 
 static const JsonDispatch name_parameters_dispatch_table[] = {
-        { "ifindex", JSON_VARIANT_INTEGER,  json_dispatch_ifindex, offsetof(NameParameters, ifindex), 0              },
-        { "name",    JSON_VARIANT_UNSIGNED, json_dispatch_string,  offsetof(NameParameters, name),    JSON_MANDATORY },
+        { "ifindex", JSON_VARIANT_INTEGER, json_dispatch_ifindex, offsetof(NameParameters, ifindex), 0              },
+        { "name",    JSON_VARIANT_STRING,  json_dispatch_string,  offsetof(NameParameters, name),    JSON_MANDATORY },
         {}
 };
 
@@ -553,14 +552,10 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
                 int *errnop, int *h_errnop,
                 int32_t *ttlp) {
 
-        _cleanup_(resolve_address_reply_destroy) ResolveAddressReply p = {};
-        _cleanup_(json_variant_unrefp) JsonVariant *cparams = NULL;
-        char *r_name, *r_aliases, *r_addr, *r_addr_list;
         _cleanup_(varlink_unrefp) Varlink *link = NULL;
-        JsonVariant *entry, *rparams;
-        const char *n, *error_id;
-        unsigned c = 0, i = 0;
-        size_t ms = 0, idx;
+        _cleanup_(json_variant_unrefp) JsonVariant *cparams = NULL;
+        _cleanup_(resolve_address_reply_destroy) ResolveAddressReply p = {};
+        JsonVariant *rparams, *entry;
         int r;
 
         PROTECT_ERRNO;
@@ -594,6 +589,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
         if (r < 0)
                 goto fail;
 
+        const char* error_id;
         r = varlink_call(link, "io.systemd.Resolve.ResolveAddress", cparams, &rparams, &error_id, NULL);
         if (r < 0)
                 goto fail;
@@ -609,6 +605,8 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
         if (json_variant_is_blank_object(p.names))
                 goto not_found;
 
+        size_t ms = 0, idx;
+
         JSON_VARIANT_ARRAY_FOREACH(entry, p.names) {
                 _cleanup_(name_parameters_destroy) NameParameters q = {};
 
@@ -619,9 +617,10 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
                 ms += ALIGN(strlen(q.name) + 1);
         }
 
-        ms += ALIGN(len) +                                           /* the address */
-              2 * sizeof(char*) +                                    /* pointers to the address, plus trailing NULL */
-              json_variant_elements(p.names) * sizeof(char*);        /* pointers to aliases, plus trailing NULL */
+        size_t n_names = json_variant_elements(p.names);
+        ms += ALIGN(len) +                    /* the address */
+              2 * sizeof(char*) +             /* pointer to the address, plus trailing NULL */
+              n_names * sizeof(char*);        /* pointers to aliases, plus trailing NULL */
 
         if (buflen < ms) {
                 UNPROTECT_ERRNO;
@@ -631,44 +630,43 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
         }
 
         /* First, place address */
-        r_addr = buffer;
+        char *r_addr = buffer;
         memcpy(r_addr, addr, len);
         idx = ALIGN(len);
 
         /* Second, place address list */
-        r_addr_list = buffer + idx;
+        char *r_addr_list = buffer + idx;
         ((char**) r_addr_list)[0] = r_addr;
         ((char**) r_addr_list)[1] = NULL;
         idx += sizeof(char*) * 2;
 
-        /* Third, reserve space for the aliases array */
-        r_aliases = buffer + idx;
-        idx += sizeof(char*) * c;
+        /* Third, reserve space for the aliases array, plus trailing NULL */
+        char *r_aliases = buffer + idx;
+        idx += sizeof(char*) * n_names;
 
         /* Fourth, place aliases */
-        i = 0;
-        r_name = buffer + idx;
+        char *r_name = buffer + idx;
+
+        size_t i = 0;
         JSON_VARIANT_ARRAY_FOREACH(entry, p.names) {
                 _cleanup_(name_parameters_destroy) NameParameters q = {};
-                size_t l;
-                char *z;
 
                 r = json_dispatch(entry, name_parameters_dispatch_table, NULL, json_dispatch_flags, &q);
                 if (r < 0)
                         goto fail;
 
-                l = strlen(q.name);
-                z = buffer + idx;
-                memcpy(z, n, l+1);
+                size_t l = strlen(q.name);
+                char *z = buffer + idx;
+                memcpy(z, q.name, l + 1);
 
                 if (i > 0)
-                        ((char**) r_aliases)[i-1] = z;
+                        ((char**) r_aliases)[i - 1] = z;
                 i++;
 
-                idx += ALIGN(l+1);
+                idx += ALIGN(l + 1);
         }
+        ((char**) r_aliases)[n_names - 1] = NULL;
 
-        ((char**) r_aliases)[c-1] = NULL;
         assert(idx == ms);
 
         result->h_name = r_name;
index c3e84aadde98183fae6c6b5a9d3658807f25be2b..49dc5eb26e84480a2ded8aff77fb8638c8d625c9 100644 (file)
@@ -299,8 +299,7 @@ static int acquire_managed_oom_connect(Manager *m) {
         return 0;
 }
 
-static int monitor_cgroup_contexts_handler(sd_event_source *s, uint64_t usec, void *userdata) {
-        _cleanup_set_free_ Set *targets = NULL;
+static int monitor_swap_contexts_handler(sd_event_source *s, uint64_t usec, void *userdata) {
         Manager *m = userdata;
         usec_t usec_now;
         int r;
@@ -313,7 +312,7 @@ static int monitor_cgroup_contexts_handler(sd_event_source *s, uint64_t usec, vo
         if (r < 0)
                 return log_error_errno(r, "Failed to reset event timer: %m");
 
-        r = sd_event_source_set_time_relative(s, INTERVAL_USEC);
+        r = sd_event_source_set_time_relative(s, SWAP_INTERVAL_USEC);
         if (r < 0)
                 return log_error_errno(r, "Failed to set relative time for timer: %m");
 
@@ -324,97 +323,29 @@ static int monitor_cgroup_contexts_handler(sd_event_source *s, uint64_t usec, vo
                         return log_error_errno(r, "Failed to acquire varlink connection: %m");
         }
 
-        /* Update the cgroups used for detection/action */
-        r = update_monitored_cgroup_contexts(&m->monitored_swap_cgroup_contexts);
-        if (r == -ENOMEM)
-                return log_oom();
-        if (r < 0)
-                log_debug_errno(r, "Failed to update monitored swap cgroup contexts, ignoring: %m");
-
-        r = update_monitored_cgroup_contexts(&m->monitored_mem_pressure_cgroup_contexts);
-        if (r == -ENOMEM)
-                return log_oom();
-        if (r < 0)
-                log_debug_errno(r, "Failed to update monitored memory pressure cgroup contexts, ignoring: %m");
-
-        r = update_monitored_cgroup_contexts_candidates(
-                        m->monitored_mem_pressure_cgroup_contexts, &m->monitored_mem_pressure_cgroup_contexts_candidates);
-        if (r == -ENOMEM)
-                return log_oom();
-        if (r < 0)
-                log_debug_errno(r, "Failed to update monitored memory pressure candidate cgroup contexts, ignoring: %m");
-
+        /* We still try to acquire swap information for oomctl even if no units want swap monitoring */
         r = oomd_system_context_acquire("/proc/swaps", &m->system_context);
-        /* If there aren't units depending on swap actions, the only error we exit on is ENOMEM.
+        /* If there are no units depending on swap actions, the only error we exit on is ENOMEM.
          * Allow ENOENT in the event that swap is disabled on the system. */
-        if (r == -ENOMEM || (r < 0 && r != -ENOENT && !hashmap_isempty(m->monitored_swap_cgroup_contexts)))
-                return log_error_errno(r, "Failed to acquire system context: %m");
-        else if (r == -ENOENT)
+        if (r == -ENOENT) {
                 zero(m->system_context);
+                return 0;
+        } else if (r == -ENOMEM || (r < 0 && !hashmap_isempty(m->monitored_swap_cgroup_contexts)))
+                return log_error_errno(r, "Failed to acquire system context: %m");
 
-        if (oomd_memory_reclaim(m->monitored_mem_pressure_cgroup_contexts))
-                m->last_reclaim_at = usec_now;
+        /* Return early if nothing is requesting swap monitoring */
+        if (hashmap_isempty(m->monitored_swap_cgroup_contexts))
+                return 0;
 
-        /* If we're still recovering from a kill, don't try to kill again yet */
-        if (m->post_action_delay_start > 0) {
-                if (m->post_action_delay_start + POST_ACTION_DELAY_USEC > usec_now)
-                        return 0;
-                else
-                        m->post_action_delay_start = 0;
-        }
-
-        r = oomd_pressure_above(m->monitored_mem_pressure_cgroup_contexts, m->default_mem_pressure_duration_usec, &targets);
-        if (r == -ENOMEM)
-                return log_oom();
-        if (r < 0)
-                log_debug_errno(r, "Failed to check if memory pressure exceeded limits, ignoring: %m");
-        else if (r == 1) {
-                /* Check if there was reclaim activity in the given interval. The concern is the following case:
-                 * Pressure climbed, a lot of high-frequency pages were reclaimed, and we killed the offending
-                 * cgroup. Even after this, well-behaved processes will fault in recently resident pages and
-                 * this will cause pressure to remain high. Thus if there isn't any reclaim pressure, no need
-                 * to kill something (it won't help anyways). */
-                if ((usec_now - m->last_reclaim_at) <= RECLAIM_DURATION_USEC) {
-                        OomdCGroupContext *t;
-
-                        SET_FOREACH(t, targets) {
-                                _cleanup_free_ char *selected = NULL;
-                                char ts[FORMAT_TIMESPAN_MAX];
-
-                                log_debug("Memory pressure for %s is %lu.%02lu%% > %lu.%02lu%% for > %s with reclaim activity",
-                                          t->path,
-                                          LOAD_INT(t->memory_pressure.avg10), LOAD_FRAC(t->memory_pressure.avg10),
-                                          LOAD_INT(t->mem_pressure_limit), LOAD_FRAC(t->mem_pressure_limit),
-                                          format_timespan(ts, sizeof ts,
-                                                          m->default_mem_pressure_duration_usec,
-                                                          USEC_PER_SEC));
-
-                                r = oomd_kill_by_pgscan_rate(m->monitored_mem_pressure_cgroup_contexts_candidates, t->path, m->dry_run, &selected);
-                                if (r == -ENOMEM)
-                                        return log_oom();
-                                if (r < 0)
-                                        log_notice_errno(r, "Failed to kill any cgroup(s) under %s based on pressure: %m", t->path);
-                                else {
-                                        /* Don't act on all the high pressure cgroups at once; return as soon as we kill one */
-                                        m->post_action_delay_start = usec_now;
-                                        if (selected)
-                                                log_notice("Killed %s due to memory pressure for %s being %lu.%02lu%% > %lu.%02lu%%"
-                                                           " for > %s with reclaim activity",
-                                                           selected, t->path,
-                                                           LOAD_INT(t->memory_pressure.avg10), LOAD_FRAC(t->memory_pressure.avg10),
-                                                           LOAD_INT(t->mem_pressure_limit), LOAD_FRAC(t->mem_pressure_limit),
-                                                           format_timespan(ts, sizeof ts,
-                                                                           m->default_mem_pressure_duration_usec,
-                                                                           USEC_PER_SEC));
-                                        return 0;
-                                }
-                        }
-                }
-        }
+        /* Note that m->monitored_swap_cgroup_contexts does not need to be updated every interval because only the
+         * system context is used for deciding whether the swap threshold is hit. m->monitored_swap_cgroup_contexts
+         * is only used to decide which cgroups to kill (and even then only the resource usages of its descendent
+         * nodes are the ones that matter). */
 
         if (oomd_swap_free_below(&m->system_context, 10000 - m->swap_used_limit_permyriad)) {
                 _cleanup_hashmap_free_ Hashmap *candidates = NULL;
                 _cleanup_free_ char *selected = NULL;
+                uint64_t threshold;
 
                 log_debug("Swap used (%"PRIu64") / total (%"PRIu64") is more than " PERMYRIAD_AS_PERCENT_FORMAT_STR,
                           m->system_context.swap_used, m->system_context.swap_total,
@@ -426,13 +357,13 @@ static int monitor_cgroup_contexts_handler(sd_event_source *s, uint64_t usec, vo
                 if (r < 0)
                         log_debug_errno(r, "Failed to get monitored swap cgroup candidates, ignoring: %m");
 
-                r = oomd_kill_by_swap_usage(candidates, m->dry_run, &selected);
+                threshold = m->system_context.swap_total * THRESHOLD_SWAP_USED_PERCENT / 100;
+                r = oomd_kill_by_swap_usage(candidates, threshold, m->dry_run, &selected);
                 if (r == -ENOMEM)
                         return log_oom();
                 if (r < 0)
                         log_notice_errno(r, "Failed to kill any cgroup(s) based on swap: %m");
                 else {
-                        m->post_action_delay_start = usec_now;
                         if (selected)
                                 log_notice("Killed %s due to swap used (%"PRIu64") / total (%"PRIu64") being more than "
                                            PERMYRIAD_AS_PERCENT_FORMAT_STR,
@@ -445,14 +376,183 @@ static int monitor_cgroup_contexts_handler(sd_event_source *s, uint64_t usec, vo
         return 0;
 }
 
-static int monitor_cgroup_contexts(Manager *m) {
+static void clear_candidate_hashmapp(Manager **m) {
+        if (*m)
+                hashmap_clear((*m)->monitored_mem_pressure_cgroup_contexts_candidates);
+}
+
+static int monitor_memory_pressure_contexts_handler(sd_event_source *s, uint64_t usec, void *userdata) {
+        /* Don't want to use stale candidate data. Setting this will clear the candidate hashmap on return unless we
+         * update the candidate data (in which case clear_candidates will be NULL). */
+        _cleanup_(clear_candidate_hashmapp) Manager *clear_candidates = userdata;
+        _cleanup_set_free_ Set *targets = NULL;
+        bool in_post_action_delay = false;
+        Manager *m = userdata;
+        usec_t usec_now;
+        int r;
+
+        assert(s);
+        assert(userdata);
+
+        /* Reset timer */
+        r = sd_event_now(sd_event_source_get_event(s), CLOCK_MONOTONIC, &usec_now);
+        if (r < 0)
+                return log_error_errno(r, "Failed to reset event timer: %m");
+
+        r = sd_event_source_set_time_relative(s, MEM_PRESSURE_INTERVAL_USEC);
+        if (r < 0)
+                return log_error_errno(r, "Failed to set relative time for timer: %m");
+
+        /* Reconnect if our connection dropped */
+        if (!m->varlink) {
+                r = acquire_managed_oom_connect(m);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to acquire varlink connection: %m");
+        }
+
+        /* Return early if nothing is requesting memory pressure monitoring */
+        if (hashmap_isempty(m->monitored_mem_pressure_cgroup_contexts))
+                return 0;
+
+        /* Update the cgroups used for detection/action */
+        r = update_monitored_cgroup_contexts(&m->monitored_mem_pressure_cgroup_contexts);
+        if (r == -ENOMEM)
+                return log_oom();
+        if (r < 0)
+                log_debug_errno(r, "Failed to update monitored memory pressure cgroup contexts, ignoring: %m");
+
+        r = update_monitored_cgroup_contexts_candidates(
+                        m->monitored_mem_pressure_cgroup_contexts, &m->monitored_mem_pressure_cgroup_contexts_candidates);
+        if (r == -ENOMEM)
+                return log_oom();
+        if (r < 0)
+                log_debug_errno(r, "Failed to update monitored memory pressure candidate cgroup contexts, ignoring: %m");
+
+        /* Since pressure counters are lagging, we need to wait a bit after a kill to ensure we don't read stale
+         * values and go on a kill storm. */
+        if (m->mem_pressure_post_action_delay_start > 0) {
+                if (m->mem_pressure_post_action_delay_start + POST_ACTION_DELAY_USEC > usec_now)
+                        in_post_action_delay = true;
+                else
+                        m->mem_pressure_post_action_delay_start = 0;
+        }
+
+        r = oomd_pressure_above(m->monitored_mem_pressure_cgroup_contexts, m->default_mem_pressure_duration_usec, &targets);
+        if (r == -ENOMEM)
+                return log_oom();
+        if (r < 0)
+                log_debug_errno(r, "Failed to check if memory pressure exceeded limits, ignoring: %m");
+        else if (r == 1 && !in_post_action_delay) {
+                OomdCGroupContext *t;
+                SET_FOREACH(t, targets) {
+                        _cleanup_free_ char *selected = NULL;
+                        char ts[FORMAT_TIMESPAN_MAX];
+
+                        /* Check if there was reclaim activity in the given interval. The concern is the following case:
+                         * Pressure climbed, a lot of high-frequency pages were reclaimed, and we killed the offending
+                         * cgroup. Even after this, well-behaved processes will fault in recently resident pages and
+                         * this will cause pressure to remain high. Thus if there isn't any reclaim pressure, no need
+                         * to kill something (it won't help anyways). */
+                        if ((now(CLOCK_MONOTONIC) - t->last_had_mem_reclaim) > RECLAIM_DURATION_USEC)
+                                continue;
+
+                        log_debug("Memory pressure for %s is %lu.%02lu%% > %lu.%02lu%% for > %s with reclaim activity",
+                                  t->path,
+                                  LOAD_INT(t->memory_pressure.avg10), LOAD_FRAC(t->memory_pressure.avg10),
+                                  LOAD_INT(t->mem_pressure_limit), LOAD_FRAC(t->mem_pressure_limit),
+                                  format_timespan(ts, sizeof ts,
+                                                  m->default_mem_pressure_duration_usec,
+                                                  USEC_PER_SEC));
+
+                        r = update_monitored_cgroup_contexts_candidates(
+                                        m->monitored_mem_pressure_cgroup_contexts, &m->monitored_mem_pressure_cgroup_contexts_candidates);
+                        if (r == -ENOMEM)
+                                return log_oom();
+                        if (r < 0)
+                                log_debug_errno(r, "Failed to update monitored memory pressure candidate cgroup contexts, ignoring: %m");
+                        else
+                                clear_candidates = NULL;
+
+                        r = oomd_kill_by_pgscan_rate(m->monitored_mem_pressure_cgroup_contexts_candidates, t->path, m->dry_run, &selected);
+                        if (r == -ENOMEM)
+                                return log_oom();
+                        if (r < 0)
+                                log_notice_errno(r, "Failed to kill any cgroup(s) under %s based on pressure: %m", t->path);
+                        else {
+                                /* Don't act on all the high pressure cgroups at once; return as soon as we kill one */
+                                m->mem_pressure_post_action_delay_start = usec_now;
+                                if (selected)
+                                        log_notice("Killed %s due to memory pressure for %s being %lu.%02lu%% > %lu.%02lu%%"
+                                                   " for > %s with reclaim activity",
+                                                   selected, t->path,
+                                                   LOAD_INT(t->memory_pressure.avg10), LOAD_FRAC(t->memory_pressure.avg10),
+                                                   LOAD_INT(t->mem_pressure_limit), LOAD_FRAC(t->mem_pressure_limit),
+                                                   format_timespan(ts, sizeof ts,
+                                                                   m->default_mem_pressure_duration_usec,
+                                                                   USEC_PER_SEC));
+                                return 0;
+                        }
+                }
+        } else {
+                /* If any monitored cgroup is over their pressure limit, get all the kill candidates for every
+                 * monitored cgroup. This saves CPU cycles from doing it every interval by only doing it when a kill
+                 * might happen.
+                 * Candidate cgroup data will continue to get updated during the post-action delay period in case
+                 * pressure continues to be high after a kill. */
+                OomdCGroupContext *c;
+                HASHMAP_FOREACH(c, m->monitored_mem_pressure_cgroup_contexts) {
+                        if (c->mem_pressure_limit_hit_start == 0)
+                                continue;
+
+                        r = update_monitored_cgroup_contexts_candidates(
+                                        m->monitored_mem_pressure_cgroup_contexts, &m->monitored_mem_pressure_cgroup_contexts_candidates);
+                        if (r == -ENOMEM)
+                                return log_oom();
+                        if (r < 0)
+                                log_debug_errno(r, "Failed to update monitored memory pressure candidate cgroup contexts, ignoring: %m");
+                        else {
+                                clear_candidates = NULL;
+                                break;
+                        }
+                }
+        }
+
+        return 0;
+}
+
+static int monitor_swap_contexts(Manager *m) {
+        _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
+        int r;
+
+        assert(m);
+        assert(m->event);
+
+        r = sd_event_add_time(m->event, &s, CLOCK_MONOTONIC, 0, 0, monitor_swap_contexts_handler, m);
+        if (r < 0)
+                return r;
+
+        r = sd_event_source_set_exit_on_failure(s, true);
+        if (r < 0)
+                return r;
+
+        r = sd_event_source_set_enabled(s, SD_EVENT_ON);
+        if (r < 0)
+                return r;
+
+        (void) sd_event_source_set_description(s, "oomd-swap-timer");
+
+        m->swap_context_event_source = TAKE_PTR(s);
+        return 0;
+}
+
+static int monitor_memory_pressure_contexts(Manager *m) {
         _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
         int r;
 
         assert(m);
         assert(m->event);
 
-        r = sd_event_add_time(m->event, &s, CLOCK_MONOTONIC, 0, 0, monitor_cgroup_contexts_handler, m);
+        r = sd_event_add_time(m->event, &s, CLOCK_MONOTONIC, 0, 0, monitor_memory_pressure_contexts_handler, m);
         if (r < 0)
                 return r;
 
@@ -464,9 +564,9 @@ static int monitor_cgroup_contexts(Manager *m) {
         if (r < 0)
                 return r;
 
-        (void) sd_event_source_set_description(s, "oomd-timer");
+        (void) sd_event_source_set_description(s, "oomd-memory-pressure-timer");
 
-        m->cgroup_context_event_source = TAKE_PTR(s);
+        m->mem_pressure_context_event_source = TAKE_PTR(s);
         return 0;
 }
 
@@ -474,7 +574,8 @@ Manager* manager_free(Manager *m) {
         assert(m);
 
         varlink_close_unref(m->varlink);
-        sd_event_source_unref(m->cgroup_context_event_source);
+        sd_event_source_unref(m->swap_context_event_source);
+        sd_event_source_unref(m->mem_pressure_context_event_source);
         sd_event_unref(m->event);
 
         bus_verify_polkit_async_registry_free(m->polkit_registry);
@@ -596,7 +697,11 @@ int manager_start(
         if (r < 0)
                 return r;
 
-        r = monitor_cgroup_contexts(m);
+        r = monitor_memory_pressure_contexts(m);
+        if (r < 0)
+                return r;
+
+        r = monitor_swap_contexts(m);
         if (r < 0)
                 return r;
 
index 9c580c8a249c5bd7f1841077ed69d9633fb58a02..dc170f2bdaac0dc4f94fbee49570c0596ce374cc 100644 (file)
@@ -7,10 +7,9 @@
 #include "varlink.h"
 
 /* Polling interval for monitoring stats */
-#define INTERVAL_USEC (1 * USEC_PER_SEC)
-
-/* Used to weight the averages */
-#define AVERAGE_SIZE_DECAY 4
+#define SWAP_INTERVAL_USEC 150000 /* 0.15 seconds */
+/* Pressure counters are lagging (~2 seconds) compared to swap so polling too frequently just wastes CPU */
+#define MEM_PRESSURE_INTERVAL_USEC (1 * USEC_PER_SEC)
 
 /* Take action if 10s of memory pressure > 60 for more than 30s. We use the "full" value from PSI so this is the
  * percentage of time all tasks were delayed (i.e. unproductive).
@@ -20,6 +19,9 @@
 #define DEFAULT_MEM_PRESSURE_LIMIT_PERCENT 60
 #define DEFAULT_SWAP_USED_LIMIT_PERCENT 90
 
+/* Only tackle candidates with large swap usage. */
+#define THRESHOLD_SWAP_USED_PERCENT 5
+
 #define RECLAIM_DURATION_USEC (30 * USEC_PER_SEC)
 #define POST_ACTION_DELAY_USEC (15 * USEC_PER_SEC)
 
@@ -44,10 +46,10 @@ struct Manager {
 
         OomdSystemContext system_context;
 
-        usec_t last_reclaim_at;
-        usec_t post_action_delay_start;
+        usec_t mem_pressure_post_action_delay_start;
 
-        sd_event_source *cgroup_context_event_source;
+        sd_event_source *swap_context_event_source;
+        sd_event_source *mem_pressure_context_event_source;
 
         Varlink *varlink;
 };
index 894d23a83a4a19746efec90d6de105fc622ed9bc..5bf81479c9f44b61acda229b2b1d279d55800151 100644 (file)
@@ -82,17 +82,17 @@ int oomd_pressure_above(Hashmap *h, usec_t duration, Set **ret) {
                 if (ctx->memory_pressure.avg10 > ctx->mem_pressure_limit) {
                         usec_t diff;
 
-                        if (ctx->last_hit_mem_pressure_limit == 0)
-                                ctx->last_hit_mem_pressure_limit = now(CLOCK_MONOTONIC);
+                        if (ctx->mem_pressure_limit_hit_start == 0)
+                                ctx->mem_pressure_limit_hit_start = now(CLOCK_MONOTONIC);
 
-                        diff = now(CLOCK_MONOTONIC) - ctx->last_hit_mem_pressure_limit;
+                        diff = now(CLOCK_MONOTONIC) - ctx->mem_pressure_limit_hit_start;
                         if (diff >= duration) {
                                 r = set_put(targets, ctx);
                                 if (r < 0)
                                         return -ENOMEM;
                         }
                 } else
-                        ctx->last_hit_mem_pressure_limit = 0;
+                        ctx->mem_pressure_limit_hit_start = 0;
         }
 
         if (!set_isempty(targets)) {
@@ -104,34 +104,21 @@ int oomd_pressure_above(Hashmap *h, usec_t duration, Set **ret) {
         return 0;
 }
 
-bool oomd_memory_reclaim(Hashmap *h) {
-        uint64_t pgscan = 0, pgscan_of = 0, last_pgscan = 0, last_pgscan_of = 0;
-        OomdCGroupContext *ctx;
-
-        assert(h);
-
-        /* If sum of all the current pgscan values are greater than the sum of all the last_pgscan values,
-         * there was reclaim activity. Used along with pressure checks to decide whether to take action. */
+uint64_t oomd_pgscan_rate(const OomdCGroupContext *c) {
+        uint64_t last_pgscan;
 
-        HASHMAP_FOREACH(ctx, h) {
-                uint64_t sum;
+        assert(c);
 
-                sum = pgscan + ctx->pgscan;
-                if (sum < pgscan || sum < ctx->pgscan)
-                        pgscan_of++; /* count overflows */
-                pgscan = sum;
-
-                sum = last_pgscan + ctx->last_pgscan;
-                if (sum < last_pgscan || sum < ctx->last_pgscan)
-                        last_pgscan_of++; /* count overflows */
-                last_pgscan = sum;
+        /* If last_pgscan > pgscan, assume the cgroup was recreated and reset last_pgscan to zero.
+         * pgscan is monotonic and in practice should not decrease (except in the recreation case). */
+        last_pgscan = c->last_pgscan;
+        if (c->last_pgscan > c->pgscan) {
+                log_debug("Last pgscan %"PRIu64" greater than current pgscan %"PRIu64" for %s. Using last pgscan of zero.",
+                                c->last_pgscan, c->pgscan, c->path);
+                last_pgscan = 0;
         }
 
-        /* overflow counts are the same, return sums comparison */
-        if (last_pgscan_of == pgscan_of)
-                return pgscan > last_pgscan;
-
-        return pgscan_of > last_pgscan_of;
+        return c->pgscan - last_pgscan;
 }
 
 bool oomd_swap_free_below(const OomdSystemContext *ctx, int threshold_permyriad) {
@@ -246,7 +233,7 @@ int oomd_kill_by_pgscan_rate(Hashmap *h, const char *prefix, bool dry_run, char
         return ret;
 }
 
-int oomd_kill_by_swap_usage(Hashmap *h, bool dry_run, char **ret_selected) {
+int oomd_kill_by_swap_usage(Hashmap *h, uint64_t threshold_usage, bool dry_run, char **ret_selected) {
         _cleanup_free_ OomdCGroupContext **sorted = NULL;
         int n, r, ret = 0;
 
@@ -257,12 +244,12 @@ int oomd_kill_by_swap_usage(Hashmap *h, bool dry_run, char **ret_selected) {
         if (n < 0)
                 return n;
 
-        /* Try to kill cgroups with non-zero swap usage until we either succeed in
-         * killing or we get to a cgroup with no swap usage. */
+        /* Try to kill cgroups with non-zero swap usage until we either succeed in killing or we get to a cgroup with
+         * no swap usage. Threshold killing only cgroups with more than threshold swap usage. */
         for (int i = 0; i < n; i++) {
-                /* Skip over cgroups with no resource usage.
-                 * Continue break since there might be "avoid" cgroups at the end. */
-                if (sorted[i]->swap_usage == 0)
+                /* Skip over cgroups with not enough swap usage. Don't break since there might be "avoid"
+                 * cgroups at the end. */
+                if (sorted[i]->swap_usage <= threshold_usage)
                         continue;
 
                 r = oomd_cgroup_kill(sorted[i]->path, true, dry_run);
@@ -430,9 +417,13 @@ int oomd_insert_cgroup_context(Hashmap *old_h, Hashmap *new_h, const char *path)
         if (old_ctx) {
                 curr_ctx->last_pgscan = old_ctx->pgscan;
                 curr_ctx->mem_pressure_limit = old_ctx->mem_pressure_limit;
-                curr_ctx->last_hit_mem_pressure_limit = old_ctx->last_hit_mem_pressure_limit;
+                curr_ctx->mem_pressure_limit_hit_start = old_ctx->mem_pressure_limit_hit_start;
+                curr_ctx->last_had_mem_reclaim = old_ctx->last_had_mem_reclaim;
         }
 
+        if (oomd_pgscan_rate(curr_ctx) > 0)
+                curr_ctx->last_had_mem_reclaim = now(CLOCK_MONOTONIC);
+
         r = hashmap_put(new_h, curr_ctx->path, curr_ctx);
         if (r < 0)
                 return r;
@@ -456,7 +447,11 @@ void oomd_update_cgroup_contexts_between_hashmaps(Hashmap *old_h, Hashmap *curr_
 
                 ctx->last_pgscan = old_ctx->pgscan;
                 ctx->mem_pressure_limit = old_ctx->mem_pressure_limit;
-                ctx->last_hit_mem_pressure_limit = old_ctx->last_hit_mem_pressure_limit;
+                ctx->mem_pressure_limit_hit_start = old_ctx->mem_pressure_limit_hit_start;
+                ctx->last_had_mem_reclaim = old_ctx->last_had_mem_reclaim;
+
+                if (oomd_pgscan_rate(ctx) > 0)
+                        ctx->last_had_mem_reclaim = now(CLOCK_MONOTONIC);
         }
 }
 
index 51423130d1b8c8c964d3b608f04fa0841e02148c..81fdc5e088c03b79a332b4ddcb15d1bf4b3a8bc5 100644 (file)
@@ -32,10 +32,10 @@ struct OomdCGroupContext {
 
         ManagedOOMPreference preference;
 
-        /* These are only used by oomd_pressure_above for acting on high memory pressure. */
+        /* These are only used for acting on high memory pressure. */
         loadavg_t mem_pressure_limit;
-        usec_t mem_pressure_duration_usec;
-        usec_t last_hit_mem_pressure_limit;
+        usec_t mem_pressure_limit_hit_start;
+        usec_t last_had_mem_reclaim;
 };
 
 struct OomdSystemContext {
@@ -51,23 +51,22 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(OomdCGroupContext*, oomd_cgroup_context_free);
 
 /* Scans all the OomdCGroupContexts in `h` and returns 1 and a set of pointers to those OomdCGroupContexts in `ret`
  * if any of them have exceeded their supplied memory pressure limits for the `duration` length of time.
- * `last_hit_mem_pressure_limit` is updated accordingly for each entry when the limit is exceeded, and when it returns
+ * `mem_pressure_limit_hit_start` is updated accordingly for the first time the limit is exceeded, and when it returns
  * below the limit.
  * Returns 0 and sets `ret` to an empty set if no entries exceeded limits for `duration`.
  * Returns -ENOMEM for allocation errors. */
 int oomd_pressure_above(Hashmap *h, usec_t duration, Set **ret);
 
-/* Sum up current OomdCGroupContexts' pgscan values and last interval's pgscan values in `h`. Returns true if the
- * current sum is higher than the last interval's sum (there was some reclaim activity). */
-bool oomd_memory_reclaim(Hashmap *h);
-
 /* Returns true if the amount of swap free is below the permyriad of swap specified by `threshold_permyriad`. */
 bool oomd_swap_free_below(const OomdSystemContext *ctx, int threshold_permyriad);
 
+/* Returns pgscan - last_pgscan, accounting for corner cases. */
+uint64_t oomd_pgscan_rate(const OomdCGroupContext *c);
+
 /* The compare functions will sort from largest to smallest, putting all the contexts with "avoid" at the end
  * (after the smallest values). */
 static inline int compare_pgscan_rate_and_memory_usage(OomdCGroupContext * const *c1, OomdCGroupContext * const *c2) {
-        uint64_t last1, last2;
+        uint64_t diff1, diff2;
         int r;
 
         assert(c1);
@@ -77,22 +76,9 @@ static inline int compare_pgscan_rate_and_memory_usage(OomdCGroupContext * const
         if (r != 0)
                 return r;
 
-        /* If last_pgscan > pgscan, assume the cgroup was recreated and reset last_pgscan to zero. */
-        last2 = (*c2)->last_pgscan;
-        if ((*c2)->last_pgscan > (*c2)->pgscan) {
-                log_info("Last pgscan %" PRIu64 "greater than current pgscan %" PRIu64 "for %s. Using last pgscan of zero.",
-                                (*c2)->last_pgscan, (*c2)->pgscan, (*c2)->path);
-                last2 = 0;
-        }
-
-        last1 = (*c1)->last_pgscan;
-        if ((*c1)->last_pgscan > (*c1)->pgscan) {
-                log_info("Last pgscan %" PRIu64 "greater than current pgscan %" PRIu64 "for %s. Using last pgscan of zero.",
-                                (*c1)->last_pgscan, (*c1)->pgscan, (*c1)->path);
-                last1 = 0;
-        }
-
-        r = CMP((*c2)->pgscan - last2, (*c1)->pgscan - last1);
+        diff1 = oomd_pgscan_rate(*c1);
+        diff2 = oomd_pgscan_rate(*c2);
+        r = CMP(diff2, diff1);
         if (r != 0)
                 return r;
 
@@ -125,7 +111,7 @@ int oomd_cgroup_kill(const char *path, bool recurse, bool dry_run);
  * everything in `h` is a candidate.
  * Returns the killed cgroup in ret_selected. */
 int oomd_kill_by_pgscan_rate(Hashmap *h, const char *prefix, bool dry_run, char **ret_selected);
-int oomd_kill_by_swap_usage(Hashmap *h, bool dry_run, char **ret_selected);
+int oomd_kill_by_swap_usage(Hashmap *h, uint64_t threshold_usage, bool dry_run, char **ret_selected);
 
 int oomd_cgroup_context_acquire(const char *path, OomdCGroupContext **ret);
 int oomd_system_context_acquire(const char *proc_swaps_path, OomdSystemContext *ret);
index 6e2a5889d1e276bd8a8be810f6b5bfd811cdc5bb..deb7b094d504b49858f78f57a1ff9bf5361ac859 100644 (file)
@@ -155,6 +155,9 @@ static int run(int argc, char *argv[]) {
 
         assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
 
+        if (arg_mem_pressure_usec > 0 && arg_mem_pressure_usec < 1 * USEC_PER_SEC)
+                log_error_errno(SYNTHETIC_ERRNO(EINVAL), "DefaultMemoryPressureDurationSec= must be 0 or at least 1s");
+
         r = manager_new(&m);
         if (r < 0)
                 return log_error_errno(r, "Failed to create manager: %m");
index bd1c574ca7fa02cabb24d155edcf9f541d190625..7ebea29c1a6b3e3b2e044b27d9321b3ab354b080 100644 (file)
@@ -88,9 +88,10 @@ static void test_oomd_cgroup_context_acquire_and_insert(void) {
         _cleanup_hashmap_free_ Hashmap *h1 = NULL, *h2 = NULL;
         _cleanup_(oomd_cgroup_context_freep) OomdCGroupContext *ctx = NULL;
         _cleanup_free_ char *cgroup = NULL;
+        ManagedOOMPreference root_pref;
         OomdCGroupContext *c1, *c2;
         bool test_xattrs;
-        int r;
+        int root_xattrs, r;
 
         if (geteuid() != 0)
                 return (void) log_tests_skipped("not root");
@@ -140,10 +141,16 @@ static void test_oomd_cgroup_context_acquire_and_insert(void) {
         ctx = oomd_cgroup_context_free(ctx);
 
         /* Test the root cgroup */
+        /* Root cgroup is live and not made on demand like the cgroup the test runs in. It can have varying
+         * xattrs set already so let's read in the booleans first to get the final preference value. */
+        root_xattrs = cg_get_xattr_bool(SYSTEMD_CGROUP_CONTROLLER, "", "user.oomd_omit");
+        root_pref = root_xattrs > 0 ? MANAGED_OOM_PREFERENCE_OMIT : MANAGED_OOM_PREFERENCE_NONE;
+        root_xattrs = cg_get_xattr_bool(SYSTEMD_CGROUP_CONTROLLER, "", "user.oomd_avoid");
+        root_pref = root_xattrs > 0 ? MANAGED_OOM_PREFERENCE_AVOID : MANAGED_OOM_PREFERENCE_NONE;
         assert_se(oomd_cgroup_context_acquire("", &ctx) == 0);
         assert_se(streq(ctx->path, "/"));
         assert_se(ctx->current_memory_usage > 0);
-        assert_se(ctx->preference == MANAGED_OOM_PREFERENCE_NONE);
+        assert_se(ctx->preference == root_pref);
 
         /* Test hashmap inserts */
         assert_se(h1 = hashmap_new(&oomd_cgroup_ctx_hash_ops));
@@ -153,9 +160,10 @@ static void test_oomd_cgroup_context_acquire_and_insert(void) {
         assert_se(oomd_insert_cgroup_context(NULL, h1, cgroup) == -EEXIST);
 
          /* make sure certain values from h1 get updated in h2 */
-        c1->pgscan = 5555;
+        c1->pgscan = UINT64_MAX;
         c1->mem_pressure_limit = 6789;
-        c1->last_hit_mem_pressure_limit = 42;
+        c1->mem_pressure_limit_hit_start = 42;
+        c1->last_had_mem_reclaim = 888;
         assert_se(h2 = hashmap_new(&oomd_cgroup_ctx_hash_ops));
         assert_se(oomd_insert_cgroup_context(h1, h2, cgroup) == 0);
         c1 = hashmap_get(h1, cgroup);
@@ -163,9 +171,10 @@ static void test_oomd_cgroup_context_acquire_and_insert(void) {
         assert_se(c1);
         assert_se(c2);
         assert_se(c1 != c2);
-        assert_se(c2->last_pgscan == 5555);
+        assert_se(c2->last_pgscan == UINT64_MAX);
         assert_se(c2->mem_pressure_limit == 6789);
-        assert_se(c2->last_hit_mem_pressure_limit == 42);
+        assert_se(c2->mem_pressure_limit_hit_start == 42);
+        assert_se(c2->last_had_mem_reclaim == 888); /* assumes the live pgscan is less than UINT64_MAX */
 
         /* Assert that avoid/omit are not set if the cgroup is not owned by root */
         if (test_xattrs) {
@@ -182,20 +191,22 @@ static void test_oomd_update_cgroup_contexts_between_hashmaps(void) {
         char **paths = STRV_MAKE("/0.slice",
                                  "/1.slice");
 
-        OomdCGroupContext ctx_old[3] = {
+        OomdCGroupContext ctx_old[2] = {
                 { .path = paths[0],
                   .mem_pressure_limit = 5,
-                  .last_hit_mem_pressure_limit = 777,
+                  .mem_pressure_limit_hit_start = 777,
+                  .last_had_mem_reclaim = 888,
                   .pgscan = 57 },
                 { .path = paths[1],
                   .mem_pressure_limit = 6,
-                  .last_hit_mem_pressure_limit = 888,
+                  .mem_pressure_limit_hit_start = 888,
+                  .last_had_mem_reclaim = 888,
                   .pgscan = 42 },
         };
 
-        OomdCGroupContext ctx_new[3] = {
+        OomdCGroupContext ctx_new[2] = {
                 { .path = paths[0],
-                  .pgscan = 100 },
+                  .pgscan = 57 },
                 { .path = paths[1],
                   .pgscan = 101 },
         };
@@ -214,13 +225,15 @@ static void test_oomd_update_cgroup_contexts_between_hashmaps(void) {
         assert_se(c_new = hashmap_get(h_new, "/0.slice"));
         assert_se(c_old->pgscan == c_new->last_pgscan);
         assert_se(c_old->mem_pressure_limit == c_new->mem_pressure_limit);
-        assert_se(c_old->last_hit_mem_pressure_limit == c_new->last_hit_mem_pressure_limit);
+        assert_se(c_old->mem_pressure_limit_hit_start == c_new->mem_pressure_limit_hit_start);
+        assert_se(c_old->last_had_mem_reclaim == c_new->last_had_mem_reclaim);
 
         assert_se(c_old = hashmap_get(h_old, "/1.slice"));
         assert_se(c_new = hashmap_get(h_new, "/1.slice"));
         assert_se(c_old->pgscan == c_new->last_pgscan);
         assert_se(c_old->mem_pressure_limit == c_new->mem_pressure_limit);
-        assert_se(c_old->last_hit_mem_pressure_limit == c_new->last_hit_mem_pressure_limit);
+        assert_se(c_old->mem_pressure_limit_hit_start == c_new->mem_pressure_limit_hit_start);
+        assert_se(c_new->last_had_mem_reclaim > c_old->last_had_mem_reclaim);
 }
 
 static void test_oomd_system_context_acquire(void) {
@@ -283,7 +296,7 @@ static void test_oomd_pressure_above(void) {
         assert_se(oomd_pressure_above(h1, 0 /* duration */, &t1) == 1);
         assert_se(set_contains(t1, &ctx[0]) == true);
         assert_se(c = hashmap_get(h1, "/herp.slice"));
-        assert_se(c->last_hit_mem_pressure_limit > 0);
+        assert_se(c->mem_pressure_limit_hit_start > 0);
 
         /* Low memory pressure */
         assert_se(h2 = hashmap_new(&string_hash_ops));
@@ -291,7 +304,7 @@ static void test_oomd_pressure_above(void) {
         assert_se(oomd_pressure_above(h2, 0 /* duration */, &t2) == 0);
         assert_se(t2 == NULL);
         assert_se(c = hashmap_get(h2, "/derp.slice"));
-        assert_se(c->last_hit_mem_pressure_limit == 0);
+        assert_se(c->mem_pressure_limit_hit_start == 0);
 
         /* High memory pressure w/ multiple cgroups */
         assert_se(hashmap_put(h1, "/derp.slice", &ctx[1]) >= 0);
@@ -299,50 +312,9 @@ static void test_oomd_pressure_above(void) {
         assert_se(set_contains(t3, &ctx[0]) == true);
         assert_se(set_size(t3) == 1);
         assert_se(c = hashmap_get(h1, "/herp.slice"));
-        assert_se(c->last_hit_mem_pressure_limit > 0);
+        assert_se(c->mem_pressure_limit_hit_start > 0);
         assert_se(c = hashmap_get(h1, "/derp.slice"));
-        assert_se(c->last_hit_mem_pressure_limit == 0);
-}
-
-static void test_oomd_memory_reclaim(void) {
-        _cleanup_hashmap_free_ Hashmap *h1 = NULL;
-        char **paths = STRV_MAKE("/0.slice",
-                                 "/1.slice",
-                                 "/2.slice",
-                                 "/3.slice",
-                                 "/4.slice");
-
-        OomdCGroupContext ctx[5] = {
-                { .path = paths[0],
-                  .last_pgscan = 100,
-                  .pgscan = 100 },
-                { .path = paths[1],
-                  .last_pgscan = 100,
-                  .pgscan = 100 },
-                { .path = paths[2],
-                  .last_pgscan = 77,
-                  .pgscan = 33 },
-                { .path = paths[3],
-                  .last_pgscan = UINT64_MAX,
-                  .pgscan = 100 },
-                { .path = paths[4],
-                  .last_pgscan = 100,
-                  .pgscan = UINT64_MAX },
-        };
-
-        assert_se(h1 = hashmap_new(&string_hash_ops));
-        assert_se(hashmap_put(h1, paths[0], &ctx[0]) >= 0);
-        assert_se(hashmap_put(h1, paths[1], &ctx[1]) >= 0);
-        assert_se(oomd_memory_reclaim(h1) == false);
-
-        assert_se(hashmap_put(h1, paths[2], &ctx[2]) >= 0);
-        assert_se(oomd_memory_reclaim(h1) == false);
-
-        assert_se(hashmap_put(h1, paths[4], &ctx[4]) >= 0);
-        assert_se(oomd_memory_reclaim(h1) == true);
-
-        assert_se(hashmap_put(h1, paths[3], &ctx[3]) >= 0);
-        assert_se(oomd_memory_reclaim(h1) == false);
+        assert_se(c->mem_pressure_limit_hit_start == 0);
 }
 
 static void test_oomd_swap_free_below(void) {
@@ -461,7 +433,6 @@ int main(void) {
         test_oomd_update_cgroup_contexts_between_hashmaps();
         test_oomd_system_context_acquire();
         test_oomd_pressure_above();
-        test_oomd_memory_reclaim();
         test_oomd_swap_free_below();
         test_oomd_sort_cgroups();
 
index d21865dd6470d4b8b7418e0b1e968fb29732e5ef..3696c3cbd6fbbac34efbb9a16de513625aed49f2 100755 (executable)
@@ -200,10 +200,11 @@ EOF
     cryptsetup open --type=luks2 --key-file=$D/empty-password ${LOOP}p7 $VOLUME
     mkdir $D/mount
     mount -t ext4 /dev/mapper/$VOLUME $D/mount
+    # Use deferred closing on the mapper and autoclear on the loop, so they are cleaned up on umount
+    cryptsetup close --deferred $VOLUME
+    losetup -d $LOOP
     diff -r $D/mount/def $D/definitions > /dev/null
     umount $D/mount
-    cryptsetup close $VOLUME
-    losetup -d $LOOP
 else
     echo "### Skipping Format=/Encrypt=/CopyFiles= test, lacking privileges or missing cryptsetup/diff/losetup"
 fi
index 72f685f76db10f57de784705d75c336d00bc82da..5b992d9df83937b0777076700be2f8cedfbbeb6a 100644 (file)
@@ -357,7 +357,7 @@ static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus
         if (r < 0)
                 return r;
         if (!FILE_SIZE_VALID_OR_INFINITY(limit))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New limit out of range");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "New limit out of range");
 
         r = bus_verify_polkit_async(
                         message,
@@ -377,7 +377,7 @@ static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus
 
         r = btrfs_subvol_set_subtree_quota_limit("/var/lib/portables", 0, limit);
         if (r == -ENOTTY)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
         if (r < 0)
                 return sd_bus_error_set_errnof(error, r, "Failed to adjust quota limit: %m");
 
index 88d8f914e031d7d25bde6e8f0457a3f41ca0605f..595fe8a60a4fd7a9fec381d972ce3f6a85194295 100644 (file)
@@ -443,7 +443,7 @@ int bus_image_common_remove(
         }
 
         if (m->n_operations >= OPERATIONS_MAX)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
 
         r = bus_image_acquire(m,
                               message,
@@ -781,7 +781,7 @@ int bus_image_common_set_limit(
         if (r < 0)
                 return r;
         if (!FILE_SIZE_VALID_OR_INFINITY(limit))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New limit out of range");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "New limit out of range");
 
         r = bus_image_acquire(m,
                               message,
index 848b784908f0693680d57607e6d2bfdfdaeab1d3..6f06367d2067199ffd53697f0a096e82c87d7a80 100644 (file)
@@ -20,14 +20,14 @@ static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdat
         o->pid = 0;
 
         if (si->si_code != CLD_EXITED) {
-                r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
+                r = sd_bus_error_set(&error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
                 goto fail;
         }
 
         if (si->si_status == EXIT_SUCCESS)
                 r = 0;
         else if (read(o->errno_fd, &r, sizeof(r)) != sizeof(r)) { /* Try to acquire error code for failed operation */
-                r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child failed.");
+                r = sd_bus_error_set(&error, SD_BUS_ERROR_FAILED, "Child failed.");
                 goto fail;
         }
 
index 4c9c9a47e606797fa4547415be354108473371c6..31c96706a21bd9cd8a25006ec942f0e5ffde2809 100644 (file)
@@ -299,7 +299,7 @@ static int validate_and_mangle_flags(
                        SD_RESOLVED_NO_TRUST_ANCHOR|
                        SD_RESOLVED_NO_NETWORK|
                        ok))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter");
 
         if ((*flags & SD_RESOLVED_PROTOCOLS_ALL) == 0) /* If no protocol is enabled, enable all */
                 *flags |= SD_RESOLVED_PROTOCOLS_ALL;
@@ -420,7 +420,7 @@ static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata,
                 return r;
 
         if (ifindex < 0)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
 
         if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
@@ -581,7 +581,7 @@ static int bus_method_resolve_address(sd_bus_message *message, void *userdata, s
                 return r;
 
         if (ifindex < 0)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
 
         r = validate_and_mangle_flags(NULL, &flags, 0, error);
         if (r < 0)
@@ -738,7 +738,7 @@ static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd
                 return r;
 
         if (ifindex < 0)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
 
         r = dns_name_is_valid(name);
         if (r < 0)
@@ -749,7 +749,7 @@ static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd
         if (!dns_type_is_valid_query(type))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified resource record type %" PRIu16 " may not be used in a query.", type);
         if (dns_type_is_zone_transer(type))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Zone transfers not permitted via this programming interface.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Zone transfers not permitted via this programming interface.");
         if (dns_type_is_obsolete(type))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Specified DNS resource record type %" PRIu16 " is obsolete.", type);
 
@@ -1267,7 +1267,7 @@ static int bus_method_resolve_service(sd_bus_message *message, void *userdata, s
                 return r;
 
         if (ifindex < 0)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
 
         if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
@@ -1289,7 +1289,7 @@ static int bus_method_resolve_service(sd_bus_message *message, void *userdata, s
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid domain '%s'", domain);
 
         if (name && !type)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Service name cannot be specified without service type.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Service name cannot be specified without service type.");
 
         r = validate_and_mangle_flags(name, &flags, SD_RESOLVED_NO_TXT|SD_RESOLVED_NO_ADDRESS, error);
         if (r < 0)
@@ -1861,7 +1861,7 @@ static int bus_method_register_service(sd_bus_message *message, void *userdata,
         assert(m);
 
         if (m->mdns_support != RESOLVE_SUPPORT_YES)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Support for MulticastDNS is disabled");
+                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Support for MulticastDNS is disabled");
 
         service = new0(DnssdService, 1);
         if (!service)
@@ -1928,7 +1928,7 @@ static int bus_method_register_service(sd_bus_message *message, void *userdata,
                                 return r;
 
                         if (isempty(key))
-                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Keys in DNS-SD TXT RRs can't be empty");
+                                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Keys in DNS-SD TXT RRs can't be empty");
 
                         if (!ascii_is_valid(key))
                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "TXT key '%s' contains non-ASCII symbols", key);
index b74141e641558263711bc1e644b720455ad8378e..f73ead872dd616efe7c3b799d1118da7dd2bd5e4 100644 (file)
@@ -938,6 +938,8 @@ static int answer_add_clamp_ttl(
         if (FLAGS_SET(query_flags, SD_RESOLVED_CLAMP_TTL)) {
                 uint32_t left_ttl;
 
+                assert(current > 0);
+
                 /* Let's determine how much time is left for this cache entry. Note that we round down, but
                  * clamp this to be 1s at minimum, since we usually want records to remain cached better too
                  * short a time than too long a time, but otoh don't want to return 0 ever, since that has
@@ -988,7 +990,7 @@ int dns_cache_lookup(
         bool nxdomain = false;
         DnsCacheItem *j, *first, *nsec = NULL;
         bool have_authenticated = false, have_non_authenticated = false, have_confidential = false, have_non_confidential = false;
-        usec_t current;
+        usec_t current = 0;
         int found_rcode = -1;
         DnssecResult dnssec_result = -1;
         int have_dnssec_result = -1;
@@ -1014,8 +1016,12 @@ int dns_cache_lookup(
                 goto miss;
         }
 
-        if (FLAGS_SET(query_flags, SD_RESOLVED_CLAMP_TTL))
+        if (FLAGS_SET(query_flags, SD_RESOLVED_CLAMP_TTL)) {
+                /* 'current' is always passed to answer_add_clamp_ttl(), but is only used conditionally.
+                 * We'll do the same assert there to make sure that it was initialized properly. */
                 current = now(clock_boottime_or_monotonic());
+                assert(current > 0);
+        }
 
         LIST_FOREACH(by_key, j, first) {
                 /* If the caller doesn't allow us to answer questions from cache data learned from
index d14e5a90af09aac8aee3b49d34f45ef6876596d2..a107769130b0f042d33a364ce5594f24ecafdd45 100644 (file)
@@ -1205,7 +1205,7 @@ static int nsec3_hash_to_gcrypt_md(uint8_t algorithm) {
 
 int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) {
         uint8_t wire_format[DNS_WIRE_FORMAT_HOSTNAME_MAX];
-        gcry_md_hd_t md = NULL;
+        _cleanup_(gcry_md_closep) gcry_md_hd_t md = NULL;
         gcry_error_t err;
         size_t hash_size;
         int algorithm;
@@ -1249,10 +1249,8 @@ int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) {
         gcry_md_write(md, nsec3->nsec3.salt, nsec3->nsec3.salt_size);
 
         result = gcry_md_read(md, 0);
-        if (!result) {
-                r = -EIO;
-                goto finish;
-        }
+        if (!result)
+                return -EIO;
 
         for (k = 0; k < nsec3->nsec3.iterations; k++) {
                 uint8_t tmp[hash_size];
@@ -1263,18 +1261,12 @@ int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) {
                 gcry_md_write(md, nsec3->nsec3.salt, nsec3->nsec3.salt_size);
 
                 result = gcry_md_read(md, 0);
-                if (!result) {
-                        r = -EIO;
-                        goto finish;
-                }
+                if (!result)
+                        return -EIO;
         }
 
         memcpy(ret, result, hash_size);
-        r = (int) hash_size;
-
-finish:
-        gcry_md_close(md);
-        return r;
+        return (int) hash_size;
 }
 
 static int nsec3_is_good(DnsResourceRecord *rr, DnsResourceRecord *nsec3) {
index b429c452740a7f7c41d336b090eb5f3d9983a14a..5517db149d0827465686c1f8d09b5b4e596df751 100644 (file)
@@ -183,7 +183,7 @@ static DnsTransactionState dns_query_candidate_state(DnsQueryCandidate *c) {
         if (c->error_code != 0)
                 return DNS_TRANSACTION_ERRNO;
 
-        SET_FOREACH(t, c->transactions) {
+        SET_FOREACH(t, c->transactions)
 
                 switch (t->state) {
 
@@ -213,7 +213,6 @@ static DnsTransactionState dns_query_candidate_state(DnsQueryCandidate *c) {
 
                         break;
                 }
-        }
 
         return state;
 }
index 6846eb2dbd21659f85f13773765a71c260123cbb..5b9d32f0013085758eb228541f089c8bc7232e85 100644 (file)
@@ -433,6 +433,7 @@ static int dns_stub_finish_reply_packet(
                 int rcode,
                 bool tc,        /* set the Truncated bit? */
                 bool aa,        /* set the Authoritative Answer bit? */
+                bool rd,        /* set the Recursion Desired bit? */
                 bool add_opt,   /* add an OPT RR to this packet? */
                 bool edns0_do,  /* set the EDNS0 DNSSEC OK bit? */
                 bool ad,        /* set the DNSSEC authenticated data bit? */
@@ -473,7 +474,7 @@ static int dns_stub_finish_reply_packet(
                                                               0  /* opcode */,
                                                               aa /* aa */,
                                                               tc /* tc */,
-                                                               /* rd */,
+                                                              rd /* rd */,
                                                               1  /* ra */,
                                                               ad /* ad */,
                                                               cd /* cd */,
@@ -581,6 +582,7 @@ static int dns_stub_send_reply(
                         rcode,
                         truncated,
                         dns_query_fully_authoritative(q),
+                        DNS_PACKET_RD(q->request_packet),
                         !!q->request_packet->opt,
                         edns0_do,
                         DNS_PACKET_AD(q->request_packet) && dns_query_fully_authenticated(q),
@@ -622,6 +624,7 @@ static int dns_stub_send_failure(
                         rcode,
                         truncated,
                         false,
+                        DNS_PACKET_RD(p),
                         !!p->opt,
                         DNS_PACKET_DO(p),
                         DNS_PACKET_AD(p) && authenticated,
index 8ba459b3e53bfa19e90d34e6dd2a9f57aeb62ed3..b036aa402c4411fce7b9cb4b7814949bbddeee38 100644 (file)
@@ -160,7 +160,10 @@ static int dns_trust_anchor_add_builtin_negative(DnsTrustAnchor *d) {
                 "lan\0"
                 "intranet\0"
                 "internal\0"
-                "private\0";
+                "private\0"
+
+                /* Defined by RFC 8375. The most official choice. */
+                "home.arpa\0";
 
         const char *name;
         int r;
index d56d5de4df7cafe1f710596ff3255d998d7b3119..8d533d7ecf9ad1dc2f63f862a8872a402e94efcb 100644 (file)
@@ -386,7 +386,7 @@ int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_
                 if (r == 0)
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search domain %s", name);
                 if (!route_only && dns_name_is_root(name))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root domain is not suitable as search domain");
+                        return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Root domain is not suitable as search domain");
 
                 if (route_only) {
                         prefixed = strjoin("~", name);
index 1d054090863e68ed4fee2fd2b9c86ec417e270f1..016eb7b82a733590e7626a22a96a35f7b04d6abb 100644 (file)
@@ -46,14 +46,13 @@ static const BaseFilesystem table[] = {
 
 int base_filesystem_create(const char *root, uid_t uid, gid_t gid) {
         _cleanup_close_ int fd = -1;
-        size_t i;
         int r;
 
         fd = open(root, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
         if (fd < 0)
                 return log_error_errno(errno, "Failed to open root file system: %m");
 
-        for (i = 0; i < ELEMENTSOF(table); i ++) {
+        for (size_t i = 0; i < ELEMENTSOF(table); i++) {
                 if (faccessat(fd, table[i].dir, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
                         continue;
 
@@ -94,10 +93,9 @@ int base_filesystem_create(const char *root, uid_t uid, gid_t gid) {
                                 return -errno;
                         }
 
-                        if (uid_is_valid(uid) || gid_is_valid(gid)) {
+                        if (uid_is_valid(uid) || gid_is_valid(gid))
                                 if (fchownat(fd, table[i].dir, uid, gid, AT_SYMLINK_NOFOLLOW) < 0)
                                         return log_error_errno(errno, "Failed to chown symlink at %s/%s: %m", root, table[i].dir);
-                        }
 
                         continue;
                 }
@@ -114,10 +112,9 @@ int base_filesystem_create(const char *root, uid_t uid, gid_t gid) {
                         return -errno;
                 }
 
-                if (uid != UID_INVALID || gid != UID_INVALID) {
+                if (uid != UID_INVALID || gid != UID_INVALID)
                         if (fchownat(fd, table[i].dir, uid, gid, AT_SYMLINK_NOFOLLOW) < 0)
                                 return log_error_errno(errno, "Failed to chown directory at %s/%s: %m", root, table[i].dir);
-                }
         }
 
         return 0;
index 10239142af30898fc556b476fa553868d10fc530..a8a34521fd640c24c1a816e39c8424e4769f9f86 100644 (file)
 #include "memory-util.h"
 #include "missing_syscall.h"
 #include "path-util.h"
+#include "string-table.h"
+
+static const char *const bpf_cgroup_attach_type_table[__MAX_BPF_ATTACH_TYPE] = {
+        [BPF_CGROUP_INET_INGRESS] =     "ingress",
+        [BPF_CGROUP_INET_EGRESS] =      "egress",
+        [BPF_CGROUP_INET_SOCK_CREATE] = "sock_create",
+        [BPF_CGROUP_SOCK_OPS] =         "sock_ops",
+        [BPF_CGROUP_DEVICE] =           "device",
+        [BPF_CGROUP_INET4_BIND] =       "bind4",
+        [BPF_CGROUP_INET6_BIND] =       "bind6",
+        [BPF_CGROUP_INET4_CONNECT] =    "connect4",
+        [BPF_CGROUP_INET6_CONNECT] =    "connect6",
+        [BPF_CGROUP_INET4_POST_BIND] =  "post_bind4",
+        [BPF_CGROUP_INET6_POST_BIND] =  "post_bind6",
+        [BPF_CGROUP_UDP4_SENDMSG] =     "sendmsg4",
+        [BPF_CGROUP_UDP6_SENDMSG] =     "sendmsg6",
+        [BPF_CGROUP_SYSCTL] =           "sysctl",
+        [BPF_CGROUP_UDP4_RECVMSG] =     "recvmsg4",
+        [BPF_CGROUP_UDP6_RECVMSG] =     "recvmsg6",
+        [BPF_CGROUP_GETSOCKOPT] =       "getsockopt",
+        [BPF_CGROUP_SETSOCKOPT] =       "setsockopt",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bpf_cgroup_attach_type, int);
+
+ /* struct bpf_prog_info info must be initialized since its value is both input and output
+  * for BPF_OBJ_GET_INFO_BY_FD syscall. */
+static int bpf_program_get_info_by_fd(int prog_fd, struct bpf_prog_info *info, uint32_t info_len) {
+        union bpf_attr attr;
+
+        /* Explicitly memset to zero since some compilers may produce non-zero-initialized padding when
+         * structured initialization is used.
+         * Refer to https://github.com/systemd/systemd/issues/18164
+         */
+        zero(attr);
+        attr.info.bpf_fd = prog_fd;
+        attr.info.info_len = info_len;
+        attr.info.info = PTR_TO_UINT64(info);
+
+        if (bpf(BPF_OBJ_GET_INFO_BY_FD, &attr, sizeof(attr)) < 0)
+                return -errno;
+
+        return 0;
+}
 
 int bpf_program_new(uint32_t prog_type, BPFProgram **ret) {
         _cleanup_(bpf_program_unrefp) BPFProgram *p = NULL;
@@ -28,6 +72,38 @@ int bpf_program_new(uint32_t prog_type, BPFProgram **ret) {
         return 0;
 }
 
+int bpf_program_new_from_bpffs_path(const char *path, BPFProgram **ret) {
+        _cleanup_(bpf_program_unrefp) BPFProgram *p = NULL;
+        struct bpf_prog_info info = {};
+        int r;
+
+        assert(path);
+        assert(ret);
+
+        p = new(BPFProgram, 1);
+        if (!p)
+                return -ENOMEM;
+
+        *p = (BPFProgram) {
+                .prog_type = BPF_PROG_TYPE_UNSPEC,
+                .n_ref = 1,
+                .kernel_fd = -1,
+        };
+
+        r = bpf_program_load_from_bpf_fs(p, path);
+        if (r < 0)
+                return r;
+
+        r = bpf_program_get_info_by_fd(p->kernel_fd, &info, sizeof(info));
+        if (r < 0)
+                return r;
+
+        p->prog_type = info.type;
+        *ret = TAKE_PTR(p);
+
+        return 0;
+}
+
 static BPFProgram *bpf_program_free(BPFProgram *p) {
         assert(p);
 
@@ -254,3 +330,31 @@ int bpf_map_lookup_element(int fd, const void *key, void *value) {
 
         return 0;
 }
+
+int bpf_program_pin(int prog_fd, const char *bpffs_path) {
+        union bpf_attr attr;
+
+        zero(attr);
+        attr.pathname = PTR_TO_UINT64((void *) bpffs_path);
+        attr.bpf_fd = prog_fd;
+
+        if (bpf(BPF_OBJ_PIN, &attr, sizeof(attr)) < 0)
+                return -errno;
+
+        return 0;
+}
+
+int bpf_program_get_id_by_fd(int prog_fd, uint32_t *ret_id) {
+        struct bpf_prog_info info = {};
+        int r;
+
+        assert(ret_id);
+
+        r = bpf_program_get_info_by_fd(prog_fd, &info, sizeof(info));
+        if (r < 0)
+                return r;
+
+        *ret_id = info.id;
+
+        return 0;
+};
index eef77f9d8e1a6dde7c7be9bf836ce8f9eabc3998..86fd338c93c44d61a18d4c792bcff75e84060dc5 100644 (file)
@@ -26,8 +26,9 @@ struct BPFProgram {
 };
 
 int bpf_program_new(uint32_t prog_type, BPFProgram **ret);
-BPFProgram *bpf_program_unref(BPFProgram *p);
+int bpf_program_new_from_bpffs_path(const char *path, BPFProgram **ret);
 BPFProgram *bpf_program_ref(BPFProgram *p);
+BPFProgram *bpf_program_unref(BPFProgram *p);
 
 int bpf_program_add_instructions(BPFProgram *p, const struct bpf_insn *insn, size_t count);
 int bpf_program_load_kernel(BPFProgram *p, char *log_buf, size_t log_size);
@@ -35,9 +36,14 @@ int bpf_program_load_from_bpf_fs(BPFProgram *p, const char *path);
 
 int bpf_program_cgroup_attach(BPFProgram *p, int type, const char *path, uint32_t flags);
 int bpf_program_cgroup_detach(BPFProgram *p);
+int bpf_program_pin(int prog_fd, const char *bpffs_path);
+int bpf_program_get_id_by_fd(int prog_fd, uint32_t *ret_id);
 
 int bpf_map_new(enum bpf_map_type type, size_t key_size, size_t value_size, size_t max_entries, uint32_t flags);
 int bpf_map_update_element(int fd, const void *key, void *value);
 int bpf_map_lookup_element(int fd, const void *key, void *value);
 
+int bpf_cgroup_attach_type_from_string(const char *str) _pure_;
+const char *bpf_cgroup_attach_type_to_string(int attach_type) _const_;
+
 DEFINE_TRIVIAL_CLEANUP_FUNC(BPFProgram*, bpf_program_unref);
index 19500a552d7ef9b6d2ec3c5a09949f75f5eba32e..14a4a4cfd6bac8380a687f6b29b02cf8afcf1c0a 100644 (file)
@@ -17,7 +17,7 @@ int bus_message_read_ifindex(sd_bus_message *message, sd_bus_error *error, int *
                 return r;
 
         if (ifindex <= 0)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
 
         *ret = ifindex;
 
@@ -62,7 +62,7 @@ int bus_message_read_in_addr_auto(sd_bus_message *message, sd_bus_error *error,
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
 
         if (sz != FAMILY_ADDRESS_SIZE(family))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
 
         if (ret_family)
                 *ret_family = family;
@@ -98,8 +98,11 @@ static int bus_message_read_dns_one(
         if (r < 0)
                 return r;
 
-        if (!dns_server_address_valid(family, &a))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNS server address");
+        if (!dns_server_address_valid(family, &a)) {
+                r = sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNS server address");
+                assert(r < 0);
+                return r;
+        }
 
         if (extended) {
                 r = sd_bus_message_read(message, "q", &port);
index 84d4729334c682d91da077b3b6936a1c79c1fc87..eb28c359244f971ac5cdbe6fccb5df3a717c0732 100644 (file)
@@ -842,6 +842,26 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
                 return 1;
         }
 
+        if (streq(field, "BPFProgram")) {
+                if (isempty(eq))
+                        r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0);
+                else {
+                        _cleanup_free_ char *word = NULL;
+
+                        r = extract_first_word(&eq, &word, ":", 0);
+                        if (r == -ENOMEM)
+                                return log_oom();
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to parse %s: %m", field);
+
+                        r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, word, eq);
+                }
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                return 1;
+        }
+
         return 0;
 }
 
index 9dfa1907511d16d3c0f4941328be424397c63cd8..fa4079cff7717bbeb63a521959c4ef08b6fce57e 100644 (file)
@@ -300,7 +300,8 @@ int config_parse(
 
                 (void) stat_warn_permissions(filename, &st);
                 mtime = timespec_load(&st.st_mtim);
-        }
+        } else
+                mtime = 0;
 
         for (;;) {
                 _cleanup_free_ char *buf = NULL;
index 70739412a2fc8e0fbbef2c5de106ba1e120cc763..ce8a683bd68d97d8c1b4966dc69b0a75ab20fa9b 100644 (file)
@@ -127,33 +127,58 @@ static int enumerator_for_parent(sd_device *d, sd_device_enumerator **ret) {
         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, blkid_partition pp) {
+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;
-        const char *ss, *v;
+        sd_device *parent;
 
         assert(d);
+        assert(expected_parent);
         assert(pp);
 
-        r = sd_device_get_subsystem(d, &ss);
+        r = sd_device_get_subsystem(d, &v);
         if (r < 0)
                 return r;
-        if (!streq(ss, "block"))
+        if (!streq(v, "block"))
                 return false;
 
-        r = sd_device_get_sysattr_value(d, "partition", &v);
-        if (r == -ENOENT ||        /* Not a partition device */
-            ERRNO_IS_PRIVILEGE(r)) /* Not ready to access? */
+        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 */
+
+        r = sd_device_get_sysattr_value(d, "partition", &v);
         if (r < 0)
                 return r;
         r = safe_atoi(v, &partno);
@@ -219,7 +244,7 @@ static int find_partition(
                 return r;
 
         FOREACH_DEVICE(e, q) {
-                r = device_is_partition(q, pp);
+                r = device_is_partition(q, parent, pp);
                 if (r < 0)
                         return r;
                 if (r > 0) {
@@ -242,9 +267,7 @@ static inline void wait_data_done(struct wait_data *d) {
 }
 
 static int device_monitor_handler(sd_device_monitor *monitor, sd_device *device, void *userdata) {
-        const char *parent1_path, *parent2_path;
         struct wait_data *w = userdata;
-        sd_device *pp;
         int r;
 
         assert(w);
@@ -252,22 +275,7 @@ static int device_monitor_handler(sd_device_monitor *monitor, sd_device *device,
         if (device_for_action(device, SD_DEVICE_REMOVE))
                 return 0;
 
-        r = sd_device_get_parent(device, &pp);
-        if (r < 0)
-                return 0; /* Doesn't have a parent? No relevant to us */
-
-        r = sd_device_get_syspath(pp, &parent1_path); /* Check parent of device of this action */
-        if (r < 0)
-                goto finish;
-
-        r = sd_device_get_syspath(w->parent_device, &parent2_path); /* Check parent of device we are looking for */
-        if (r < 0)
-                goto finish;
-
-        if (!path_equal(parent1_path, parent2_path))
-                return 0; /* Has a different parent than what we need, not interesting to us */
-
-        r = device_is_partition(device, w->blkidp);
+        r = device_is_partition(device, w->parent_device, w->blkidp);
         if (r < 0)
                 goto finish;
         if (r == 0) /* Not the one we need */
@@ -313,6 +321,14 @@ static int wait_for_partition_device(
         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;
@@ -486,7 +502,8 @@ int dissect_image(
 #ifdef GPT_USR_NATIVE
         sd_id128_t usr_uuid = SD_ID128_NULL, usr_verity_uuid = SD_ID128_NULL;
 #endif
-        bool is_gpt, is_mbr, generic_rw, multiple_generic = false;
+        bool is_gpt, is_mbr, multiple_generic = false,
+                generic_rw = false;  /* initialize to appease gcc */
         _cleanup_(sd_device_unrefp) sd_device *d = NULL;
         _cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
         _cleanup_(blkid_free_probep) blkid_probe b = NULL;
@@ -494,7 +511,7 @@ int dissect_image(
         sd_id128_t generic_uuid = SD_ID128_NULL;
         const char *pttype = NULL, *sysname = NULL;
         blkid_partlist pl;
-        int r, generic_nr, n_partitions;
+        int r, generic_nr = -1, n_partitions;
         struct stat st;
         usec_t deadline;
 
@@ -1202,6 +1219,7 @@ int dissect_image(
                                         return -ENOMEM;
                         }
 
+                        assert(generic_nr >= 0);
                         m->partitions[PARTITION_ROOT] = (DissectedPartition) {
                                 .found = true,
                                 .rw = generic_rw,
index 982c61d8fbd81627bd70bdb219b1628074769608..d53a394895aae835f1334fe137ed2e67619aace9 100644 (file)
@@ -102,9 +102,9 @@ int fw_iptables_add_masquerade(
         if (!source || source_prefixlen == 0)
                 return -EINVAL;
 
-        h = iptc_init("nat");
-        if (!h)
-                return -errno;
+        r = fw_iptables_init_nat(&h);
+        if (r < 0)
+                return r;
 
         sz = XT_ALIGN(sizeof(struct ipt_entry)) +
              XT_ALIGN(sizeof(struct ipt_entry_target)) +
@@ -192,9 +192,9 @@ int fw_iptables_add_local_dnat(
         if (remote_port <= 0)
                 return -EINVAL;
 
-        h = iptc_init("nat");
-        if (!h)
-                return -errno;
+        r = fw_iptables_init_nat(&h);
+        if (r < 0)
+                return r;
 
         sz = XT_ALIGN(sizeof(struct ipt_entry)) +
              XT_ALIGN(sizeof(struct ipt_entry_match)) +
@@ -348,3 +348,16 @@ int fw_iptables_add_local_dnat(
 
         return 0;
 }
+
+int fw_iptables_init_nat(struct xtc_handle **ret) {
+        _cleanup_(iptc_freep) struct xtc_handle *h = NULL;
+
+        h = iptc_init("nat");
+        if (!h)
+                return log_debug_errno(errno, "Failed to init \"nat\" table: %s", iptc_strerror(errno));
+
+        if (ret)
+                *ret = TAKE_PTR(h);
+
+        return 0;
+}
index 07e2d0bbd3dc35db035eaf22afd3b393bf6f56f3..14f5a35a878efe89a3c2e395299015be452cec7c 100644 (file)
@@ -46,6 +46,7 @@ int fw_nftables_add_local_dnat(
                 const union in_addr_union *previous_remote);
 
 #if HAVE_LIBIPTC
+struct xtc_handle;
 
 int fw_iptables_add_masquerade(
                 bool add,
@@ -61,4 +62,6 @@ int fw_iptables_add_local_dnat(
                 const union in_addr_union *remote,
                 uint16_t remote_port,
                 const union in_addr_union *previous_remote);
+
+int fw_iptables_init_nat(struct xtc_handle **ret);
 #endif
index 6bbc8bd509e1dfc9b0562b5b3336bcfbaa331e3b..abc4bb36516c45f87b02eca5484442642e33dfbb 100644 (file)
@@ -783,19 +783,17 @@ int table_update(Table *t, TableCell *cell, TableDataType type, const void *data
 }
 
 int table_add_many_internal(Table *t, TableDataType first_type, ...) {
-        TableDataType type;
-        va_list ap;
         TableCell *last_cell = NULL;
+        va_list ap;
         int r;
 
         assert(t);
         assert(first_type >= 0);
         assert(first_type < _TABLE_DATA_TYPE_MAX);
 
-        type = first_type;
-
         va_start(ap, first_type);
-        for (;;) {
+
+        for (TableDataType type = first_type;; type = va_arg(ap, TableDataType)) {
                 const void *data;
                 union {
                         uint64_t size;
@@ -968,43 +966,43 @@ int table_add_many_internal(Table *t, TableDataType first_type, ...) {
                         size_t w = va_arg(ap, size_t);
 
                         r = table_set_minimum_width(t, last_cell, w);
-                        break;
+                        goto check;
                 }
 
                 case TABLE_SET_MAXIMUM_WIDTH: {
                         size_t w = va_arg(ap, size_t);
                         r = table_set_maximum_width(t, last_cell, w);
-                        break;
+                        goto check;
                 }
 
                 case TABLE_SET_WEIGHT: {
                         unsigned w = va_arg(ap, unsigned);
                         r = table_set_weight(t, last_cell, w);
-                        break;
+                        goto check;
                 }
 
                 case TABLE_SET_ALIGN_PERCENT: {
                         unsigned p = va_arg(ap, unsigned);
                         r = table_set_align_percent(t, last_cell, p);
-                        break;
+                        goto check;
                 }
 
                 case TABLE_SET_ELLIPSIZE_PERCENT: {
                         unsigned p = va_arg(ap, unsigned);
                         r = table_set_ellipsize_percent(t, last_cell, p);
-                        break;
+                        goto check;
                 }
 
                 case TABLE_SET_COLOR: {
                         const char *c = va_arg(ap, const char*);
                         r = table_set_color(t, last_cell, c);
-                        break;
+                        goto check;
                 }
 
                 case TABLE_SET_RGAP_COLOR: {
                         const char *c = va_arg(ap, const char*);
                         r = table_set_rgap_color(t, last_cell, c);
-                        break;
+                        goto check;
                 }
 
                 case TABLE_SET_BOTH_COLORS: {
@@ -1017,19 +1015,19 @@ int table_add_many_internal(Table *t, TableDataType first_type, ...) {
                         }
 
                         r = table_set_rgap_color(t, last_cell, c);
-                        break;
+                        goto check;
                 }
 
                 case TABLE_SET_URL: {
                         const char *u = va_arg(ap, const char*);
                         r = table_set_url(t, last_cell, u);
-                        break;
+                        goto check;
                 }
 
                 case TABLE_SET_UPPERCASE: {
                         int u = va_arg(ap, int);
                         r = table_set_uppercase(t, last_cell, u);
-                        break;
+                        goto check;
                 }
 
                 case _TABLE_DATA_TYPE_MAX:
@@ -1041,15 +1039,12 @@ int table_add_many_internal(Table *t, TableDataType first_type, ...) {
                         assert_not_reached("Uh? Unexpected data type.");
                 }
 
-                if (type < _TABLE_DATA_TYPE_MAX)
-                        r = table_add_cell(t, &last_cell, type, data);
-
+                r = table_add_cell(t, &last_cell, type, data);
+        check:
                 if (r < 0) {
                         va_end(ap);
                         return r;
                 }
-
-                type = va_arg(ap, TableDataType);
         }
 }
 
index df520ab89ed31ec015026eb4f4fcf73da08d9736..82c6625e56a6c4dd46ea9182fcea473c6de467d1 100644 (file)
@@ -13,6 +13,7 @@ static const NamingScheme naming_schemes[] = {
         { "v243", NAMING_V243 },
         { "v245", NAMING_V245 },
         { "v247", NAMING_V247 },
+        { "v249", NAMING_V249 },
         /* … add more schemes here, as the logic to name devices is updated … */
 };
 
index 28cd4e41f23c0e3aef1f82b301847bec5e5a5211..f719744d568524592a7fbb35524412b878006e39 100644 (file)
@@ -32,6 +32,7 @@ typedef enum NamingSchemeFlags {
         NAMING_LABEL_NOPREFIX      = 1 << 7, /* Don't prepend ID_NET_LABEL_ONBOARD with interface type prefix */
         NAMING_NSPAWN_LONG_HASH    = 1 << 8, /* Shorten nspawn interfaces by including 24bit hash, instead of simple truncation  */
         NAMING_BRIDGE_NO_SLOT      = 1 << 9, /* Don't use PCI hotplug slot information if the corresponding device is a PCI bridge */
+        NAMING_SLOT_FUNCTION_ID    = 1 << 10, /* Use function_id if present to identify PCI hotplug slots */
 
         /* And now the masks that combine the features above */
         NAMING_V238 = 0,
@@ -41,6 +42,7 @@ typedef enum NamingSchemeFlags {
         NAMING_V243 = NAMING_V241 | NAMING_NETDEVSIM | NAMING_LABEL_NOPREFIX,
         NAMING_V245 = NAMING_V243 | NAMING_NSPAWN_LONG_HASH,
         NAMING_V247 = NAMING_V245 | NAMING_BRIDGE_NO_SLOT,
+        NAMING_V249 = NAMING_V247 | NAMING_SLOT_FUNCTION_ID,
 
         _NAMING_SCHEME_FLAGS_INVALID = -EINVAL,
 } NamingSchemeFlags;
index 4ea72a8b2b0e441e6712bbedc784c0a072a71c6d..bb47ae5e873844b4137cae8b2844e116ccf286f3 100644 (file)
@@ -46,7 +46,7 @@ int rsa_pkey_to_suitable_key_size(
                 size_t *ret_suitable_key_size) {
 
         size_t suitable_key_size;
-        RSA *rsa;
+        const RSA *rsa;
         int bits;
 
         assert_se(pkey);
index 4fa1effb2d3be3878ce56f9fde225757596b1a75..aff45ed868c426d1c7f071ea9f22cabba7f5647c 100644 (file)
@@ -31,7 +31,7 @@ bool pkcs11_uri_valid(const char *uri) {
         if (isempty(p))
                 return false;
 
-        if (!in_charset(p, ALPHANUMERICAL "-_?;&%="))
+        if (!in_charset(p, ALPHANUMERICAL ".~/-_?;&%="))
                 return false;
 
         return true;
index 0f02f327601171d77aa690ca01063984aff4a668..137ba77b3a6ea700396cce26608e02f230ee7734 100644 (file)
@@ -280,7 +280,7 @@ static int guess_type(const char **name, char ***prefixes, bool *is_collection,
 int conf_files_cat(const char *root, const char *name) {
         _cleanup_strv_free_ char **dirs = NULL, **files = NULL;
         _cleanup_free_ char *path = NULL;
-        char **prefixes, **prefix;
+        char **prefix, **prefixes = NULL; /* explicit initialization to appease gcc */
         bool is_collection;
         const char *extension;
         char **t;
@@ -289,6 +289,8 @@ int conf_files_cat(const char *root, const char *name) {
         r = guess_type(&name, &prefixes, &is_collection, &extension);
         if (r < 0)
                 return r;
+        assert(prefixes);
+        assert(extension);
 
         STRV_FOREACH(prefix, prefixes) {
                 assert(endswith(*prefix, "/"));
index 6b9ff8531bbe171a68a0cfa6b0c71fb55aa8aacb..79ac640672563291d9f9f644afdb7763c3f25b36 100644 (file)
@@ -110,7 +110,7 @@ int print_qrcode(FILE *out, const char *header, const char *string) {
         if (r < 0)
                 return r;
 
-        qr = sym_QRcode_encodeString(string, 0, QR_ECLEVEL_L, QR_MODE_8, 0);
+        qr = sym_QRcode_encodeString(string, 0, QR_ECLEVEL_L, QR_MODE_8, 1);
         if (!qr)
                 return -ENOMEM;
 
index cea51482deec43476c37f4fc0b913fff59dd9dfa..37f83306dba87f8794040f1f408709e93b200869 100644 (file)
@@ -324,7 +324,7 @@ static bool location_is_resume_device(const HibernateLocation *location, dev_t s
 int find_hibernate_location(HibernateLocation **ret_hibernate_location) {
         _cleanup_fclose_ FILE *f = NULL;
         _cleanup_(hibernate_location_freep) HibernateLocation *hibernate_location = NULL;
-        dev_t sys_resume;
+        dev_t sys_resume = 0; /* Unnecessary initialization to appease gcc */
         uint64_t sys_offset = 0;
         bool resume_match = false;
         int r;
index 8a0f45c2db764f2ff5415cc9a4b572c6de9918b8..4d17f3c96a2238ea92bc93e24c0ae9057e34e44f 100644 (file)
@@ -686,6 +686,10 @@ int tpm2_unseal(
 
         assert(pcr_mask < (UINT32_C(1) << TPM2_PCRS_MAX)); /* Support 24 PCR banks */
 
+        r = dlopen_tpm2();
+        if (r < 0)
+                return log_error_errno(r, "TPM2 support is not installed.");
+
         /* So here's what we do here: We connect to the TPM2 chip. As we do when sealing we generate a
          * "primary" key on the TPM2 chip, with the same parameters as well as a PCR-bound policy
          * session. Given we pass the same parameters, this will result in the same "primary" key, and same
index 6ed72075ba5beda6ac98bb2dbcaad0f96c19fcd4..a271082ac33a9dca7c05e37c37919e2bda9839ac 100644 (file)
@@ -448,13 +448,16 @@ static int varlink_write(Varlink *v) {
         assert(v->fd >= 0);
 
         /* We generally prefer recv()/send() (mostly because of MSG_NOSIGNAL) but also want to be compatible
-         * with non-socket IO, hence fall back automatically */
-        if (!v->prefer_read_write) {
+         * with non-socket IO, hence fall back automatically.
+         *
+         * Use a local variable to help gcc figure out that we set 'n' in all cases. */
+        bool prefer_write = v->prefer_read_write;
+        if (!prefer_write) {
                 n = send(v->fd, v->output_buffer + v->output_buffer_index, v->output_buffer_size, MSG_DONTWAIT|MSG_NOSIGNAL);
                 if (n < 0 && errno == ENOTSOCK)
-                        v->prefer_read_write = true;
+                        prefer_write = v->prefer_read_write = true;
         }
-        if (v->prefer_read_write)
+        if (prefer_write)
                 n = write(v->fd, v->output_buffer + v->output_buffer_index, v->output_buffer_size);
         if (n < 0) {
                 if (errno == EAGAIN)
@@ -531,12 +534,13 @@ static int varlink_read(Varlink *v) {
 
         rs = v->input_buffer_allocated - (v->input_buffer_index + v->input_buffer_size);
 
-        if (!v->prefer_read_write) {
+        bool prefer_read = v->prefer_read_write;
+        if (!prefer_read) {
                 n = recv(v->fd, v->input_buffer + v->input_buffer_index + v->input_buffer_size, rs, MSG_DONTWAIT);
                 if (n < 0 && errno == ENOTSOCK)
-                        v->prefer_read_write = true;
+                        prefer_read = v->prefer_read_write = true;
         }
-        if (v->prefer_read_write)
+        if (prefer_read)
                 n = read(v->fd, v->input_buffer + v->input_buffer_index + v->input_buffer_size, rs);
         if (n < 0) {
                 if (errno == EAGAIN)
index 15e396ebd7a38301a4812776b992ac6fd0d1f738..28dd25b523dffb5e6d0887e39cbaaef9be1aa775 100644 (file)
@@ -80,7 +80,7 @@ int logind_reboot(enum action a) {
                 return 0;
 
         SET_FLAG(flags, SD_LOGIND_ROOT_CHECK_INHIBITORS, arg_check_inhibitors > 0);
-        SET_FLAG(flags, SD_LOGIND_KEXEC_REBOOT, a == ACTION_KEXEC);
+        SET_FLAG(flags, SD_LOGIND_REBOOT_VIA_KEXEC, a == ACTION_KEXEC);
 
         method_with_flags = strjoina(actions[a].method, "WithFlags");
 
index c3c81f03fbd0b1241ed7a3fa43f0fecb51cdcbe9..2fe3d8c509e2b994ed8e2bf69b7055e31849586e 100644 (file)
@@ -1694,6 +1694,23 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
 
                         return 1;
 
+                } else if (streq(name, "BPFProgram")) {
+                        const char *a, *p;
+
+                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        while ((r = sd_bus_message_read(m, "(ss)", &a, &p)) > 0)
+                                bus_print_property_valuef(name, expected_value, value, "%s:%s", a, p);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        r = sd_bus_message_exit_container(m);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        return 1;
                 }
 
                 break;
index c40e807212d9d48bddd41ee929bc74e410307069..096b8ada200e9cb9b47dd7114ee05d35f148076e 100644 (file)
@@ -307,7 +307,9 @@ int start_unit(int argc, char *argv[], void *userdata) {
                                 method = verb_to_method(argv[0]);
                                 job_type = verb_to_job_type(argv[0]);
                                 mode = arg_job_mode;
-                        }
+                        } else
+                                method = job_type = mode = NULL;
+
                         one_name = NULL;
                 }
         } else {
index 310fcaa278a62dae6396c16830e64d631c4679fa..e760e03f35a9b413f5f5193a41c9e5e55f8bfb4e 100644 (file)
@@ -136,6 +136,8 @@ int sd_device_monitor_stop(sd_device_monitor *m);
 
 int sd_device_monitor_filter_add_match_subsystem_devtype(sd_device_monitor *m, const char *subsystem, const char *devtype);
 int sd_device_monitor_filter_add_match_tag(sd_device_monitor *m, const char *tag);
+int sd_device_monitor_filter_add_match_sysattr(sd_device_monitor *m, const char *sysattr, const char *value, int match);
+int sd_device_monitor_filter_add_match_parent(sd_device_monitor *m, sd_device *device, int match);
 int sd_device_monitor_filter_update(sd_device_monitor *m);
 int sd_device_monitor_filter_remove(sd_device_monitor *m);
 
index 5abf9a406c07aa3f152fcf3911cc36a2f945cbc1..9cf36d896b28aa6be6d31d26850dc89b0b38047a 100644 (file)
@@ -46,36 +46,36 @@ typedef enum sd_dhcp_lease_server_type_t {
         _SD_ENUM_FORCE_S64(DHCP_LEASE_SERVER_TYPE),
 } sd_dhcp_lease_server_type_t;
 
-int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr);
-int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime);
-int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1);
-int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2);
-int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr);
-int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr);
-int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr);
-int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr);
-int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr);
-int sd_dhcp_lease_get_servers(sd_dhcp_lease *lease, sd_dhcp_lease_server_type_t what, const struct in_addr **addr);
-int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr);
-int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr);
-int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **addr);
-int sd_dhcp_lease_get_pop3(sd_dhcp_lease *lease, const struct in_addr **addr);
-int sd_dhcp_lease_get_smtp(sd_dhcp_lease *lease, const struct in_addr **addr);
-int sd_dhcp_lease_get_lpr(sd_dhcp_lease *lease, const struct in_addr **addr);
-int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu);
-int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname);
-int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains);
-int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname);
-int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path);
-int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, sd_dhcp_route ***routes);
-int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len);
-int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len);
-int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **timezone);
+int sd_dhcp_lease_get_address(const sd_dhcp_lease *lease, struct in_addr *addr);
+int sd_dhcp_lease_get_lifetime(const sd_dhcp_lease *lease, uint32_t *lifetime);
+int sd_dhcp_lease_get_t1(const sd_dhcp_lease *lease, uint32_t *t1);
+int sd_dhcp_lease_get_t2(const sd_dhcp_lease *lease, uint32_t *t2);
+int sd_dhcp_lease_get_broadcast(const sd_dhcp_lease *lease, struct in_addr *addr);
+int sd_dhcp_lease_get_netmask(const sd_dhcp_lease *lease, struct in_addr *addr);
+int sd_dhcp_lease_get_router(const sd_dhcp_lease *lease, const struct in_addr **addr);
+int sd_dhcp_lease_get_next_server(const sd_dhcp_lease *lease, struct in_addr *addr);
+int sd_dhcp_lease_get_server_identifier(const sd_dhcp_lease *lease, struct in_addr *addr);
+int sd_dhcp_lease_get_servers(const sd_dhcp_lease *lease, sd_dhcp_lease_server_type_t what, const struct in_addr **addr);
+int sd_dhcp_lease_get_dns(const sd_dhcp_lease *lease, const struct in_addr **addr);
+int sd_dhcp_lease_get_ntp(const sd_dhcp_lease *lease, const struct in_addr **addr);
+int sd_dhcp_lease_get_sip(const sd_dhcp_lease *lease, const struct in_addr **addr);
+int sd_dhcp_lease_get_pop3(const sd_dhcp_lease *lease, const struct in_addr **addr);
+int sd_dhcp_lease_get_smtp(const sd_dhcp_lease *lease, const struct in_addr **addr);
+int sd_dhcp_lease_get_lpr(const sd_dhcp_lease *lease, const struct in_addr **addr);
+int sd_dhcp_lease_get_mtu(const sd_dhcp_lease *lease, uint16_t *mtu);
+int sd_dhcp_lease_get_domainname(const sd_dhcp_lease *lease, const char **domainname);
+int sd_dhcp_lease_get_search_domains(const sd_dhcp_lease *lease, char ***domains);
+int sd_dhcp_lease_get_hostname(const sd_dhcp_lease *lease, const char **hostname);
+int sd_dhcp_lease_get_root_path(const sd_dhcp_lease *lease, const char **root_path);
+int sd_dhcp_lease_get_routes(const sd_dhcp_lease *lease, sd_dhcp_route ***routes);
+int sd_dhcp_lease_get_vendor_specific(const sd_dhcp_lease *lease, const void **data, size_t *data_len);
+int sd_dhcp_lease_get_client_id(const sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len);
+int sd_dhcp_lease_get_timezone(const sd_dhcp_lease *lease, const char **timezone);
 
-int sd_dhcp_route_get_destination(sd_dhcp_route *route, struct in_addr *destination);
-int sd_dhcp_route_get_destination_prefix_length(sd_dhcp_route *route, uint8_t *length);
-int sd_dhcp_route_get_gateway(sd_dhcp_route *route, struct in_addr *gateway);
-int sd_dhcp_route_get_option(sd_dhcp_route *route);
+int sd_dhcp_route_get_destination(const sd_dhcp_route *route, struct in_addr *destination);
+int sd_dhcp_route_get_destination_prefix_length(const sd_dhcp_route *route, uint8_t *length);
+int sd_dhcp_route_get_gateway(const sd_dhcp_route *route, struct in_addr *gateway);
+int sd_dhcp_route_get_option(const sd_dhcp_route *route);
 
 _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_lease, sd_dhcp_lease_unref);
 
index 0488baba82090e61a798311003f5ad4621f72bb6..e077c8e03f29c2d3f0c1d8f127ca3cb0719207c8 100644 (file)
@@ -158,7 +158,10 @@ tests += [
 
         [['src/test/test-fstab-util.c']],
 
-        [['src/test/test-random-util.c']],
+        [['src/test/test-random-util.c'],
+         [],
+         [libm],
+         [], '', 'timeout=120'],
 
         [['src/test/test-format-table.c']],
 
@@ -321,6 +324,12 @@ tests += [
           libblkid],
          core_includes],
 
+        [['src/test/test-bpf-foreign-programs.c'],
+         [libcore,
+          libshared],
+         [],
+         core_includes],
+
         [['src/test/test-watch-pid.c'],
          [libcore,
           libshared],
diff --git a/src/test/test-bpf-foreign-programs.c b/src/test/test-bpf-foreign-programs.c
new file mode 100644 (file)
index 0000000..e703924
--- /dev/null
@@ -0,0 +1,332 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <fcntl.h>
+#include <linux/bpf_insn.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include "bpf-foreign.h"
+#include "load-fragment.h"
+#include "manager.h"
+#include "process-util.h"
+#include "rlimit-util.h"
+#include "rm-rf.h"
+#include "service.h"
+#include "tests.h"
+#include "unit.h"
+#include "virt.h"
+
+struct Test {
+        const char *option_name;
+        enum bpf_prog_type prog_type;
+        enum bpf_attach_type attach_type;
+        const char *bpffs_path;
+};
+
+typedef struct Test Test;
+
+#define BPFFS_PATH(prog_suffix) ("/sys/fs/bpf/test-bpf-foreing-" # prog_suffix)
+static const Test single_prog[] = {
+        {
+                .option_name = "BPFProgram",
+                .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
+                .attach_type = BPF_CGROUP_INET_INGRESS,
+                .bpffs_path = BPFFS_PATH("trivial-skb"),
+        },
+};
+static const Test path_split_test[] = {
+        {
+                .option_name = "BPFProgram",
+                .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
+                .attach_type = BPF_CGROUP_INET_INGRESS,
+                .bpffs_path = BPFFS_PATH("path:split:test"),
+        },
+};
+
+static const Test same_prog_same_hook[] = {
+        {
+                .option_name = "BPFProgram",
+                .prog_type = BPF_PROG_TYPE_CGROUP_SOCK,
+                .attach_type = BPF_CGROUP_INET_SOCK_CREATE,
+                .bpffs_path = BPFFS_PATH("trivial-sock"),
+        },
+        {
+                .option_name = "BPFProgram",
+                .prog_type = BPF_PROG_TYPE_CGROUP_SOCK,
+                .attach_type = BPF_CGROUP_INET_SOCK_CREATE,
+                .bpffs_path = BPFFS_PATH("trivial-sock"),
+        }
+};
+
+static const Test multi_prog_same_hook[] = {
+        {
+                .option_name = "BPFProgram",
+                .prog_type = BPF_PROG_TYPE_CGROUP_SOCK,
+                .attach_type = BPF_CGROUP_INET_SOCK_CREATE,
+                .bpffs_path = BPFFS_PATH("trivial-sock-0"),
+        },
+        {
+                .option_name = "BPFProgram",
+                .prog_type = BPF_PROG_TYPE_CGROUP_SOCK,
+                .attach_type = BPF_CGROUP_INET_SOCK_CREATE,
+                .bpffs_path = BPFFS_PATH("trivial-sock-1"),
+        }
+};
+
+static const Test same_prog_multi_hook[] = {
+        {
+                .option_name = "BPFProgram",
+                .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
+                .attach_type = BPF_CGROUP_INET_INGRESS,
+                .bpffs_path = BPFFS_PATH("trivial-skb"),
+        },
+        {
+                .option_name = "BPFProgram",
+                .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
+                .attach_type = BPF_CGROUP_INET_EGRESS,
+                .bpffs_path = BPFFS_PATH("trivial-skb"),
+        }
+};
+
+static const Test same_prog_multi_option_0[] = {
+        {
+                .option_name = "BPFProgram",
+                .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
+                .attach_type = BPF_CGROUP_INET_INGRESS,
+                .bpffs_path = BPFFS_PATH("trivial-skb"),
+        },
+        {
+                .option_name = "IPIngressFilterPath",
+                .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
+                .attach_type = BPF_CGROUP_INET_INGRESS,
+                .bpffs_path = BPFFS_PATH("trivial-skb"),
+        }
+};
+
+static const Test same_prog_multi_option_1[] = {
+        {
+                .option_name = "IPEgressFilterPath",
+                .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
+                .attach_type = BPF_CGROUP_INET_EGRESS,
+                .bpffs_path = BPFFS_PATH("trivial-skb"),
+        },
+        {
+                .option_name = "BPFProgram",
+                .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
+                .attach_type = BPF_CGROUP_INET_EGRESS,
+                .bpffs_path = BPFFS_PATH("trivial-skb"),
+        }
+};
+#undef BPFFS_PATH
+
+static int bpf_foreign_test_to_string(enum bpf_attach_type attach_type, const char *bpffs_path, char **ret_str) {
+        const char *s = NULL;
+
+        assert_se(bpffs_path);
+        assert_se(ret_str);
+
+        assert_se(s = bpf_cgroup_attach_type_to_string(attach_type));
+        assert_se(*ret_str = strjoin(s, ":", bpffs_path));
+
+        return 0;
+}
+
+static char **unlink_paths_and_free(char **paths) {
+        char **i;
+
+        STRV_FOREACH(i, paths)
+                (void) unlink(*i);
+
+        return strv_free(paths);
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(char **, unlink_paths_and_free);
+
+static int pin_programs(Unit *u, CGroupContext *cc, const Test *test_suite, size_t test_suite_size, char ***paths_ret) {
+        _cleanup_(unlink_paths_and_freep) char **bpffs_paths = NULL;
+        static const struct bpf_insn trivial[] = {
+                BPF_MOV64_IMM(BPF_REG_0, 0),
+                BPF_EXIT_INSN()
+        };
+        char log_buf[0xffff];
+        int r;
+
+        assert_se(paths_ret);
+
+        for (size_t i = 0; i < test_suite_size; i++) {
+                _cleanup_(bpf_program_unrefp) BPFProgram *prog = NULL;
+                _cleanup_free_ char *str = NULL;
+
+                r = bpf_foreign_test_to_string(test_suite[i].attach_type, test_suite[i].bpffs_path, &str);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to convert program to string");
+
+                r = bpf_program_new(test_suite[i].prog_type, &prog);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to create program '%s'", str);
+
+                r = bpf_program_add_instructions(prog, trivial, ELEMENTSOF(trivial));
+                if (r < 0)
+                        return log_error_errno(r, "Failed to add trivial instructions for '%s'", str);
+
+                r = bpf_program_load_kernel(prog, log_buf, ELEMENTSOF(log_buf));
+                if (r < 0)
+                        return log_error_errno(r, "Failed to load BPF program '%s'", str);
+
+                if (strv_contains(bpffs_paths, test_suite[i].bpffs_path))
+                        continue;
+
+                r = strv_extend(&bpffs_paths, test_suite[i].bpffs_path);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to put path into a vector: %m");
+
+                r = bpf_program_pin(prog->kernel_fd, test_suite[i].bpffs_path);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to pin BPF program '%s'", str);
+        }
+
+        *paths_ret = TAKE_PTR(bpffs_paths);
+        return 0;
+}
+
+static int test_bpf_cgroup_programs(Manager *m, const char *unit_name, const Test *test_suite, size_t test_suite_size) {
+        _cleanup_(unlink_paths_and_freep) char **bpffs_paths = NULL;
+        _cleanup_(unit_freep) Unit *u = NULL;
+        CGroupContext *cc = NULL;
+        int cld_code, r;
+
+        assert_se(u = unit_new(m, sizeof(Service)));
+        assert_se(unit_add_name(u, unit_name) == 0);
+        assert_se(cc = unit_get_cgroup_context(u));
+
+        r = pin_programs(u, cc, test_suite, test_suite_size, &bpffs_paths);
+        if (r < 0)
+                return log_error_errno(r, "Failed to pin programs: %m");
+
+        for (size_t i = 0; i < test_suite_size; i++) {
+                if (streq(test_suite[i].option_name, "BPFProgram")) {
+                        _cleanup_free_ char *option = NULL;
+                        r = bpf_foreign_test_to_string(test_suite[i].attach_type, test_suite[i].bpffs_path, &option);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to compose option string: %m");
+                        r = config_parse_bpf_foreign_program(
+                                        u->id, "filename", 1, "Service", 1, test_suite[i].option_name, 0, option, cc, u);
+
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to parse option string '%s': %m", option);
+                } else if (STR_IN_SET(test_suite[i].option_name, "IPIngressFilterPath", "IPEgressFilterPath")) {
+                        const char *option = test_suite[i].bpffs_path;
+                        void *paths = NULL;
+
+                        if (streq(test_suite[i].option_name, "IPIngressFilterPath"))
+                                paths = &cc->ip_filters_ingress;
+                        else
+                                paths = &cc->ip_filters_egress;
+
+                        r = config_parse_ip_filter_bpf_progs(
+                                        u->id, "filename", 1, "Service", 1, test_suite[i].option_name, 0, option, paths, u);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to parse option string '%s': %m", option);
+                }
+        }
+
+        r = config_parse_exec(
+                        u->id,
+                        "filename",
+                        1,
+                        "Service",
+                        1,
+                        "ExecStart",
+                        SERVICE_EXEC_START,
+                        "-/bin/ping -c 5 127.0.0.1 -W 1",
+                        SERVICE(u)->exec_command,
+                        u);
+        if (r < 0)
+                return log_error_errno(r, "Failed to parse ExecStart");
+
+        SERVICE(u)->type = SERVICE_ONESHOT;
+        u->load_state = UNIT_LOADED;
+
+        r = unit_start(u);
+        if (r < 0)
+                return log_error_errno(r, "Unit start failed %m");
+
+        while (!IN_SET(SERVICE(u)->state, SERVICE_DEAD, SERVICE_FAILED)) {
+                r = sd_event_run(m->event, UINT64_MAX);
+                if (r < 0)
+                        return log_error_errno(errno, "Event run failed %m");
+        }
+
+        cld_code = SERVICE(u)->exec_command[SERVICE_EXEC_START]->exec_status.code;
+        if (cld_code != CLD_EXITED)
+                return log_error_errno(SYNTHETIC_ERRNO(EBUSY),
+                                "ExecStart didn't exited, code='%s'", sigchld_code_to_string(cld_code));
+
+        if (SERVICE(u)->state != SERVICE_DEAD)
+                return log_error_errno(SYNTHETIC_ERRNO(EBUSY), "Service is not dead");
+
+        return r;
+}
+
+int main(int argc, char *argv[]) {
+        _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
+        _cleanup_(manager_freep) Manager *m = NULL;
+        _cleanup_free_ char *unit_dir = NULL;
+        struct rlimit rl;
+        int r;
+
+        test_setup_logging(LOG_DEBUG);
+
+        if (detect_container() > 0)
+                return log_tests_skipped("test-bpf fails inside LXC and Docker containers: https://github.com/systemd/systemd/issues/9666");
+
+        if (getuid() != 0)
+                return log_tests_skipped("not running as root");
+
+        assert_se(getrlimit(RLIMIT_MEMLOCK, &rl) >= 0);
+        rl.rlim_cur = rl.rlim_max = MAX(rl.rlim_max, CAN_MEMLOCK_SIZE);
+        (void) setrlimit_closest(RLIMIT_MEMLOCK, &rl);
+
+        if (!can_memlock())
+                return log_tests_skipped("Can't use mlock(), skipping.");
+
+        r = cg_all_unified();
+        if (r <= 0)
+                return log_tests_skipped_errno(r, "Unified hierarchy is required, skipping.");
+
+        r = enter_cgroup_subroot(NULL);
+        if (r == -ENOMEDIUM)
+                return log_tests_skipped("cgroupfs not available");
+
+        assert_se(get_testdata_dir("units", &unit_dir) >= 0);
+        assert_se(set_unit_path(unit_dir) >= 0);
+        assert_se(runtime_dir = setup_fake_runtime_dir());
+
+        assert_se(manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0);
+        assert_se(manager_startup(m, NULL, NULL) >= 0);
+
+        assert_se(test_bpf_cgroup_programs(m,
+                                "single_prog.service", single_prog, ELEMENTSOF(single_prog)) >= 0);
+        assert_se(test_bpf_cgroup_programs(m,
+                                "multi_prog_same_hook.service",
+                                multi_prog_same_hook, ELEMENTSOF(multi_prog_same_hook)) >= 0);
+        assert_se(test_bpf_cgroup_programs(m,
+                                "same_prog_multi_hook.service",
+                                same_prog_multi_hook, ELEMENTSOF(same_prog_multi_hook)) >= 0);
+        assert_se(test_bpf_cgroup_programs(m,
+                                "same_prog_multi_option_0.service",
+                                same_prog_multi_option_0, ELEMENTSOF(same_prog_multi_option_0)) >= 0);
+        assert_se(test_bpf_cgroup_programs(m,
+                                "same_prog_multi_option_1.service",
+                                same_prog_multi_option_1, ELEMENTSOF(same_prog_multi_option_1)) >= 0);
+        assert_se(test_bpf_cgroup_programs(m,
+                                "same_prog_same_hook.service",
+                                same_prog_same_hook,
+                                ELEMENTSOF(same_prog_same_hook)) >= 0);
+        assert_se(test_bpf_cgroup_programs(m,
+                                "path_split_test.service",
+                                path_split_test,
+                                ELEMENTSOF(path_split_test)) >= 0);
+        return 0;
+}
index 0ff56070b163fb25b4f1188641f826f135bbc25f..5fa8fe242ef4ee11f2cd8a6641dbcad65c7d3451 100644 (file)
@@ -103,22 +103,15 @@ static int setup_tests(bool *run_ambient) {
 
         nobody = getpwnam(NOBODY_USER_NAME);
         if (!nobody)
-                return log_error_errno(SYNTHETIC_ERRNO(ENOENT), "Could not find nobody user: %m");
+                return log_warning_errno(SYNTHETIC_ERRNO(ENOENT), "Couldn't find 'nobody' user: %m");
 
         test_uid = nobody->pw_uid;
         test_gid = nobody->pw_gid;
 
-        *run_ambient = false;
-
         r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
-
-        /* There's support for PR_CAP_AMBIENT if the prctl() call
-         * succeeded or error code was something else than EINVAL. The
-         * EINVAL check should be good enough to rule out false
-         * positives. */
-
-        if (r >= 0 || errno != EINVAL)
-                *run_ambient = true;
+        /* There's support for PR_CAP_AMBIENT if the prctl() call succeeded or error code was something else
+         * than EINVAL. The EINVAL check should be good enough to rule out false positives. */
+        *run_ambient = r >= 0 || errno != EINVAL;
 
         return 0;
 }
@@ -249,7 +242,7 @@ static void test_ensure_cap_64bit(void) {
 }
 
 int main(int argc, char *argv[]) {
-        bool run_ambient;
+        bool run_ambient = false;  /* avoid false maybe-uninitialized warning */
 
         test_setup_logging(LOG_INFO);
 
index b53e327c63d302e5d6937e5aaae073a0777e1ee8..d721946f713efa10b0c3fb8081c1573a25909d48 100644 (file)
@@ -140,7 +140,7 @@ static void test_cg_mask_to_string_one(CGroupMask mask, const char *t) {
 
 static void test_cg_mask_to_string(void) {
         test_cg_mask_to_string_one(0, NULL);
-        test_cg_mask_to_string_one(_CGROUP_MASK_ALL, "cpu cpuacct cpuset io blkio memory devices pids bpf-firewall bpf-devices");
+        test_cg_mask_to_string_one(_CGROUP_MASK_ALL, "cpu cpuacct cpuset io blkio memory devices pids bpf-firewall bpf-devices bpf-foreign");
         test_cg_mask_to_string_one(CGROUP_MASK_CPU, "cpu");
         test_cg_mask_to_string_one(CGROUP_MASK_CPUACCT, "cpuacct");
         test_cg_mask_to_string_one(CGROUP_MASK_CPUSET, "cpuset");
index f1085266df23c80babb8b848b3a5e13656348a85..391968463f26df24369b6771d21b1df03855dbcd 100644 (file)
@@ -428,6 +428,20 @@ static void test_extract_first_word(void) {
         assert_se(streq(t, "c"));
         free(t);
         assert_se(p == NULL);
+
+        p = original = "foobar=\"waldo\"maldo, baldo";
+        assert_se(extract_first_word(&p, &t, "=\", ", 0) > 0);
+        assert_se(streq(t, "foobar"));
+        free(t);
+        assert_se(extract_first_word(&p, &t, "=\", ", 0) > 0);
+        assert_se(streq(t, "waldo"));
+        free(t);
+        assert_se(extract_first_word(&p, &t, "=\", ", 0) > 0);
+        assert_se(streq(t, "maldo"));
+        free(t);
+        assert_se(extract_first_word(&p, &t, "=\", ", 0) > 0);
+        assert_se(streq(t, "baldo"));
+        free(t);
 }
 
 static void test_extract_first_word_and_warn(void) {
index dfde01a678899a4fc3b22a68afb0c51cce5df99a..d2843cfab73da20a52234a7f98f53e327f9efad8 100644 (file)
@@ -61,6 +61,13 @@ static bool test_v4(FirewallContext *ctx) {
 
         log_info("/* %s(backend=%s) */", __func__, firewall_backend_to_string(ctx->backend));
 
+#if HAVE_LIBIPTC
+        if (ctx->backend == FW_BACKEND_IPTABLES && fw_iptables_init_nat(NULL) < 0) {
+                log_debug("iptables backend is used, but nat table is not enabled, skipping tests");
+                return false;
+        }
+#endif
+
         assert_se(fw_add_masquerade(&ctx, true, AF_INET, NULL, 0) == -EINVAL);
         assert_se(fw_add_masquerade(&ctx, true, AF_INET, parse_addr("10.1.2.0", &u), 0) == -EINVAL);
 
index b49b0ae9081691cdcfb559e1bdd32e4ad0d93c14..1572483602c38dfcf21074b1964213b90f954deb 100644 (file)
@@ -113,6 +113,11 @@ static void test_path(void) {
         assert_se(!path_equal_ptr("/a", "/b"));
         assert_se(!path_equal_ptr("/a", NULL));
         assert_se(!path_equal_ptr(NULL, "/a"));
+
+        assert_se(path_equal_filename("/a/c", "/b/c"));
+        assert_se(path_equal_filename("/a", "/a"));
+        assert_se(!path_equal_filename("/a/b", "/a/c"));
+        assert_se(!path_equal_filename("/b", "/c"));
 }
 
 static void test_path_equal_root(void) {
index fb08f9ad260867ec101e1bb1632657665e9e329a..4cab8acbd9c64b2f6ba1180e8a29f27d073b27e0 100644 (file)
@@ -96,21 +96,17 @@ static int print_status_info(const StatusInfo *i) {
         } else
                 log_warning("Could not get time from timedated and not operating locally, ignoring.");
 
-        if (have_time)
-                n = strftime(a, sizeof a, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm));
-
+        n = have_time ? strftime(a, sizeof a, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm)) : 0;
         r = table_add_many(table,
                            TABLE_STRING, "Local time:",
-                           TABLE_STRING, have_time && n > 0 ? a : "n/a");
+                           TABLE_STRING, n > 0 ? a : "n/a");
         if (r < 0)
                 return table_log_add_error(r);
 
-        if (have_time)
-                n = strftime(a, sizeof a, "%a %Y-%m-%d %H:%M:%S UTC", gmtime_r(&sec, &tm));
-
+        n = have_time ? strftime(a, sizeof a, "%a %Y-%m-%d %H:%M:%S UTC", gmtime_r(&sec, &tm)) : 0;
         r = table_add_many(table,
                            TABLE_STRING, "Universal time:",
-                           TABLE_STRING, have_time && n > 0 ? a : "n/a");
+                           TABLE_STRING, n > 0 ? a : "n/a");
         if (r < 0)
                 return table_log_add_error(r);
 
@@ -119,26 +115,23 @@ static int print_status_info(const StatusInfo *i) {
 
                 rtc_sec = (time_t) (i->rtc_time / USEC_PER_SEC);
                 n = strftime(a, sizeof a, "%a %Y-%m-%d %H:%M:%S", gmtime_r(&rtc_sec, &tm));
-        }
-
+        } else
+                n = 0;
         r = table_add_many(table,
                            TABLE_STRING, "RTC time:",
-                           TABLE_STRING, i->rtc_time > 0 && n > 0 ? a : "n/a");
+                           TABLE_STRING, n > 0 ? a : "n/a");
         if (r < 0)
                 return table_log_add_error(r);
 
-        if (have_time)
-                n = strftime(a, sizeof a, "%Z, %z", localtime_r(&sec, &tm));
-
         r = table_add_cell(table, NULL, TABLE_STRING, "Time zone:");
         if (r < 0)
                 return table_log_add_error(r);
 
-        r = table_add_cell_stringf(table, NULL, "%s (%s)", strna(i->timezone), have_time && n > 0 ? a : "n/a");
+        n = have_time ? strftime(a, sizeof a, "%Z, %z", localtime_r(&sec, &tm)) : 0;
+        r = table_add_cell_stringf(table, NULL, "%s (%s)", strna(i->timezone), n > 0 ? a : "n/a");
         if (r < 0)
                 return table_log_add_error(r);
 
-
         /* Restore the $TZ */
         r = set_unset_env("TZ", old_tz, true);
         if (r < 0)
index 567244dc244ede65bc89285c27dd7ef85ba2e0a9..452c38e0de094efc2fd047c8e218fa112982c015 100644 (file)
@@ -801,6 +801,7 @@ static int method_set_local_rtc(sd_bus_message *m, void *userdata, sd_bus_error
 
 static int method_set_time(sd_bus_message *m, void *userdata, sd_bus_error *error) {
         sd_bus *bus = sd_bus_message_get_bus(m);
+        char buf[FORMAT_TIMESTAMP_MAX];
         int relative, interactive, r;
         Context *c = userdata;
         int64_t utc;
@@ -886,7 +887,7 @@ static int method_set_time(sd_bus_message *m, void *userdata, sd_bus_error *erro
         log_struct(LOG_INFO,
                    "MESSAGE_ID=" SD_MESSAGE_TIME_CHANGE_STR,
                    "REALTIME="USEC_FMT, timespec_load(&ts),
-                   LOG_MESSAGE("Changed local time to %s", ctime(&ts.tv_sec)));
+                   LOG_MESSAGE("Changed local time to %s", strnull(format_timestamp(buf, sizeof(buf), timespec_load(&ts)))));
 
         return sd_bus_reply_method_return(m, NULL);
 }
index f11b4eed7cc91135d97bc9427dccdc21790b94db..b6de1e74b210d2a692693ad1588f7371fa5bdc5d 100644 (file)
@@ -1656,10 +1656,9 @@ static int create_directory_or_subvolume(const char *path, mode_t mode, bool sub
                         return log_error_errno(r, "%s does not exist and cannot be created as the file system is read-only.", path);
                 if (k < 0)
                         return log_error_errno(k, "Failed to check if %s exists: %m", path);
-                if (!k) {
-                        log_warning("\"%s\" already exists and is not a directory.", path);
-                        return -EEXIST;
-                }
+                if (!k)
+                        return log_warning_errno(SYNTHETIC_ERRNO(EEXIST),
+                                                 "\"%s\" already exists and is not a directory.", path);
 
                 *creation = CREATION_EXISTING;
         } else
@@ -1742,10 +1741,10 @@ static int empty_directory(Item *i, const char *path) {
         }
         if (r < 0)
                 return log_error_errno(r, "is_dir() failed on path %s: %m", path);
-        if (r == 0)
-                return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
-                                       "'%s' already exists and is not a directory.",
-                                       path);
+        if (r == 0) {
+                log_warning("\"%s\" already exists and is not a directory.", path);
+                return 0;
+        }
 
         return path_set_perms(i, path);
 }
@@ -1804,7 +1803,7 @@ static int create_device(Item *i, mode_t file_type) {
                                         return log_error_errno(r, "Failed to create device node \"%s\": %m", i->path);
                                 creation = CREATION_FORCE;
                         } else {
-                                log_debug("%s is not a device node.", i->path);
+                                log_warning("\"%s\" already exists is not a device node.", i->path);
                                 return 0;
                         }
                 } else
@@ -2575,7 +2574,9 @@ static int patch_var_run(const char *fname, unsigned line, char **path) {
         /* Also log about this briefly. We do so at LOG_NOTICE level, as we fixed up the situation automatically, hence
          * there's no immediate need for action by the user. However, in the interest of making things less confusing
          * to the user, let's still inform the user that these snippets should really be updated. */
-        log_syntax(NULL, LOG_NOTICE, fname, line, 0, "Line references path below legacy directory /var/run/, updating %s → %s; please update the tmpfiles.d/ drop-in file accordingly.", *path, n);
+        log_syntax(NULL, LOG_NOTICE, fname, line, 0,
+                   "Line references path below legacy directory /var/run/, updating %s → %s; please update the tmpfiles.d/ drop-in file accordingly.",
+                   *path, n);
 
         free_and_replace(*path, n);
 
@@ -3186,7 +3187,7 @@ static int read_config_file(char **config_dirs, const char *fn, bool ignore_enoe
         _cleanup_fclose_ FILE *_f = NULL;
         unsigned v = 0;
         FILE *f;
-        Item *i;
+        ItemArray *ia;
         int r = 0;
 
         assert(fn);
@@ -3239,31 +3240,41 @@ static int read_config_file(char **config_dirs, const char *fn, bool ignore_enoe
         }
 
         /* we have to determine age parameter for each entry of type X */
-        ORDERED_HASHMAP_FOREACH(i, globs) {
-                Item *j, *candidate_item = NULL;
-
-                if (i->type != IGNORE_DIRECTORY_PATH)
-                        continue;
+        ORDERED_HASHMAP_FOREACH(ia, globs)
+                for (size_t ni = 0; ni < ia->n_items; ni++) {
+                        ItemArray *ja;
+                        Item *i = ia->items + ni, *candidate_item = NULL;
 
-                ORDERED_HASHMAP_FOREACH(j, items) {
-                        if (!IN_SET(j->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA))
+                        if (i->type != IGNORE_DIRECTORY_PATH)
                                 continue;
 
-                        if (path_equal(j->path, i->path)) {
-                                candidate_item = j;
-                                break;
-                        }
+                        ORDERED_HASHMAP_FOREACH(ja, items)
+                                for (size_t nj = 0; nj < ja->n_items; nj++) {
+                                        Item *j = ja->items + nj;
 
-                        if ((!candidate_item && path_startswith(i->path, j->path)) ||
-                            (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
-                                candidate_item = j;
-                }
+                                        if (!IN_SET(j->type, CREATE_DIRECTORY,
+                                                             TRUNCATE_DIRECTORY,
+                                                             CREATE_SUBVOLUME,
+                                                             CREATE_SUBVOLUME_INHERIT_QUOTA,
+                                                             CREATE_SUBVOLUME_NEW_QUOTA))
+                                                continue;
+
+                                        if (path_equal(j->path, i->path)) {
+                                                candidate_item = j;
+                                                break;
+                                        }
 
-                if (candidate_item && candidate_item->age_set) {
-                        i->age = candidate_item->age;
-                        i->age_set = true;
+                                        if (candidate_item
+                                            ? (path_startswith(j->path, candidate_item->path) && fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)
+                                            : path_startswith(i->path, j->path) != NULL)
+                                                candidate_item = j;
+                                }
+
+                        if (candidate_item && candidate_item->age_set) {
+                                i->age = candidate_item->age;
+                                i->age_set = true;
+                        }
                 }
-        }
 
         if (ferror(f)) {
                 log_error_errno(errno, "Failed to read from file %s: %m", fn);
index 0c4a17c456d15f3b1f79fd8605114d36eb9d953f..2f07a2d99fa4a19e109300b548fc6751206b6ccf 100644 (file)
 #include "alloc-util.h"
 #include "build.h"
 #include "device-nodes.h"
+#include "extract-word.h"
 #include "fd-util.h"
+#include "fileio.h"
 #include "scsi_id.h"
 #include "string-util.h"
+#include "strv.h"
 #include "strxcpyx.h"
 #include "udev-util.h"
 
@@ -90,50 +93,6 @@ static void set_type(const char *from, char *to, size_t len) {
         strscpy(to, len, type);
 }
 
-/*
- * get_value:
- *
- * buf points to an '=' followed by a quoted string ("foo") or a string ending
- * with a space or ','.
- *
- * Return a pointer to the NUL terminated string, returns NULL if no
- * matches.
- */
-static char *get_value(char **buffer) {
-        static const char *quote_string = "\"\n";
-        static const char *comma_string = ",\n";
-        char *val;
-        const char *end;
-
-        if (**buffer == '"') {
-                /*
-                 * skip leading quote, terminate when quote seen
-                 */
-                (*buffer)++;
-                end = quote_string;
-        } else
-                end = comma_string;
-        val = strsep(buffer, end);
-        if (val && end == quote_string)
-                /*
-                 * skip trailing quote
-                 */
-                (*buffer)++;
-
-        while (isspace(**buffer))
-                (*buffer)++;
-
-        return val;
-}
-
-static int argc_count(char *opts) {
-        int i = 0;
-        while (*opts != '\0')
-                if (*opts++ == ' ')
-                        i++;
-        return i;
-}
-
 /*
  * get_file_options:
  *
@@ -145,14 +104,10 @@ static int argc_count(char *opts) {
  */
 static int get_file_options(const char *vendor, const char *model,
                             int *argc, char ***newargv) {
-        _cleanup_free_ char *buffer = NULL;
+        _cleanup_free_ char *vendor_in = NULL, *model_in = NULL, *options_in = NULL; /* read in from file */
+        _cleanup_strv_free_ char **options_argv = NULL;
         _cleanup_fclose_ FILE *f;
-        char *buf;
-        char *str1;
-        char *vendor_in, *model_in, *options_in; /* read in from file */
-        int lineno;
-        int c;
-        int retval = 0;
+        int lineno, r;
 
         f = fopen(config_file, "re");
         if (!f) {
@@ -164,28 +119,21 @@ static int get_file_options(const char *vendor, const char *model,
                 }
         }
 
-        /*
-         * Allocate a buffer rather than put it on the stack so we can
-         * keep it around to parse any options (any allocated newargv
-         * points into this buffer for its strings).
-         */
-        buffer = malloc(MAX_BUFFER_LEN);
-        if (!buffer)
-                return log_oom();
-
         *newargv = NULL;
         lineno = 0;
         for (;;) {
+                _cleanup_free_ char *buffer = NULL, *key = NULL, *value = NULL;
+                const char *buf;
+
                 vendor_in = model_in = options_in = NULL;
 
-                buf = fgets(buffer, MAX_BUFFER_LEN, f);
-                if (!buf)
+                r = read_line(f, MAX_BUFFER_LEN, &buffer);
+                if (r < 0)
+                        return log_error_errno(r, "read_line() on line %d of %s failed: %m", lineno, config_file);
+                if (r == 0)
                         break;
+                buf = buffer;
                 lineno++;
-                if (buf[strlen(buffer) - 1] != '\n') {
-                        log_error("Config file line %d too long", lineno);
-                        break;
-                }
 
                 while (isspace(*buf))
                         buf++;
@@ -198,44 +146,36 @@ static int get_file_options(const char *vendor, const char *model,
                 if (*buf == '#')
                         continue;
 
-                str1 = strsep(&buf, "=");
-                if (str1 && strcaseeq(str1, "VENDOR")) {
-                        str1 = get_value(&buf);
-                        if (!str1) {
-                                retval = log_oom();
-                                break;
-                        }
-                        vendor_in = str1;
-
-                        str1 = strsep(&buf, "=");
-                        if (str1 && strcaseeq(str1, "MODEL")) {
-                                str1 = get_value(&buf);
-                                if (!str1) {
-                                        retval = log_oom();
-                                        break;
-                                }
-                                model_in = str1;
-                                str1 = strsep(&buf, "=");
-                        }
-                }
+                r = extract_many_words(&buf, "=\",\n", 0, &key, &value, NULL);
+                if (r < 2)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Error parsing config file line %d '%s'", lineno, buffer);
 
-                if (str1 && strcaseeq(str1, "OPTIONS")) {
-                        str1 = get_value(&buf);
-                        if (!str1) {
-                                retval = log_oom();
-                                break;
+                if (strcaseeq(key, "VENDOR")) {
+                        vendor_in = TAKE_PTR(value);
+
+                        key = mfree(key);
+                        r = extract_many_words(&buf, "=\",\n", 0, &key, &value, NULL);
+                        if (r < 2)
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Error parsing config file line %d '%s'", lineno, buffer);
+
+                        if (strcaseeq(key, "MODEL")) {
+                                model_in = TAKE_PTR(value);
+
+                                key = mfree(key);
+                                r = extract_many_words(&buf, "=\",\n", 0, &key, &value, NULL);
+                                if (r < 2)
+                                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Error parsing config file line %d '%s'", lineno, buffer);
                         }
-                        options_in = str1;
                 }
 
+                if (strcaseeq(key, "OPTIONS"))
+                        options_in = TAKE_PTR(value);
+
                 /*
                  * Only allow: [vendor=foo[,model=bar]]options=stuff
                  */
-                if (!options_in || (!vendor_in && model_in)) {
-                        log_error("Error parsing config file line %d '%s'", lineno, buffer);
-                        retval = -1;
-                        break;
-                }
+                if (!options_in || (!vendor_in && model_in))
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Error parsing config file line %d '%s'", lineno, buffer);
                 if (!vendor) {
                         if (!vendor_in)
                                 break;
@@ -251,39 +191,30 @@ static int get_file_options(const char *vendor, const char *model,
                                  */
                                 break;
                 }
-        }
 
-        if (retval == 0) {
-                if (vendor_in != NULL || model_in != NULL ||
-                    options_in != NULL) {
-                        /*
-                         * Something matched. Allocate newargv, and store
-                         * values found in options_in.
-                         */
-                        strcpy(buffer, options_in);
-                        c = argc_count(buffer) + 2;
-                        *newargv = calloc(c, sizeof(**newargv));
-                        if (!*newargv)
-                                retval = log_oom();
-                        else {
-                                *argc = c;
-                                c = 0;
-                                /*
-                                 * argv[0] at 0 is skipped by getopt, but
-                                 * store the buffer address there for
-                                 * later freeing
-                                 */
-                                (*newargv)[c] = buffer;
-                                for (c = 1; c < *argc; c++)
-                                        (*newargv)[c] = strsep(&buffer, " \t");
-                                buffer = NULL;
-                        }
-                } else {
-                        /* No matches  */
-                        retval = 1;
-                }
+                vendor_in = mfree(vendor_in);
+                model_in = mfree(model_in);
+                options_in = mfree(options_in);
+
         }
-        return retval;
+
+        if (vendor_in == NULL && model_in == NULL && options_in == NULL)
+                return 1; /* No matches  */
+
+        /*
+        * Something matched. Allocate newargv, and store
+        * values found in options_in.
+        */
+        options_argv = strv_split(options_in, " \t");
+        if (!options_argv)
+                return log_oom();
+        r = strv_prepend(&options_argv, ""); /* getopt skips over argv[0] */
+        if (r < 0)
+                return r;
+        *newargv = TAKE_PTR(options_argv);
+        *argc = strv_length(*newargv);
+
+        return 0;
 }
 
 static void help(void) {
@@ -391,9 +322,9 @@ static int set_options(int argc, char **argv,
 }
 
 static int per_dev_options(struct scsi_id_device *dev_scsi, int *good_bad, int *page_code) {
+        _cleanup_strv_free_ char **newargv = NULL;
         int retval;
         int newargc;
-        char **newargv = NULL;
         int option;
 
         *good_bad = all_good;
@@ -436,10 +367,6 @@ static int per_dev_options(struct scsi_id_device *dev_scsi, int *good_bad, int *
                 }
         }
 
-        if (newargv) {
-                free(newargv[0]);
-                free(newargv);
-        }
         return retval;
 }
 
@@ -543,10 +470,10 @@ out:
 }
 
 int main(int argc, char **argv) {
+        _cleanup_strv_free_ char **newargv = NULL;
         int retval = 0;
         char maj_min_dev[MAX_PATH_LEN];
         int newargc;
-        char **newargv = NULL;
 
         log_set_target(LOG_TARGET_AUTO);
         udev_parse_config();
@@ -585,10 +512,6 @@ int main(int argc, char **argv) {
         retval = scsi_id(maj_min_dev);
 
 exit:
-        if (newargv) {
-                free(newargv[0]);
-                free(newargv);
-        }
         log_close();
         return retval;
 }
index 872833ebbc17a256feac8a1c5139e8bbd5862581..088bfe38d9ef23d72e8ac1aa61b53f3530d9b4e0 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/pci_regs.h>
 
 #include "alloc-util.h"
+#include "device-util.h"
 #include "dirent-util.h"
 #include "fd-util.h"
 #include "fileio.h"
@@ -262,18 +263,60 @@ static bool is_pci_bridge(sd_device *dev) {
         return strneq(p + 2, "04", 2);
 }
 
+static int parse_hotplug_slot_from_function_id(sd_device *dev, const char *slots, uint32_t *ret) {
+        uint64_t function_id;
+        char path[PATH_MAX];
+        const char *attr;
+        int r;
+
+        /* The <sysname>/function_id attribute is unique to the s390 PCI driver. If present, we know
+         * that the slot's directory name for this device is /sys/bus/pci/XXXXXXXX/ where XXXXXXXX is
+         * the fixed length 8 hexadecimal character string representation of function_id. Therefore we
+         * can short cut here and just check for the existence of the slot directory. As this directory
+         * has to exist, we're emitting a debug message for the unlikely case it's not found. Note that
+         * the domain part doesn't belong to the slot name here because there's a 1-to-1 relationship
+         * between PCI function and its hotplug slot. */
+
+        assert(dev);
+        assert(slots);
+        assert(ret);
+
+        if (!naming_scheme_has(NAMING_SLOT_FUNCTION_ID))
+                return 0;
+
+        if (sd_device_get_sysattr_value(dev, "function_id", &attr) < 0)
+                return 0;
+
+        r = safe_atou64(attr, &function_id);
+        if (r < 0)
+                return log_device_debug_errno(dev, r, "Failed to parse function_id, ignoring: %s", attr);
+
+        if (function_id <= 0 || function_id > UINT32_MAX)
+                return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EINVAL),
+                                              "Invalid function id (0x%"PRIx64"), ignoring.",
+                                              function_id);
+
+        if (!snprintf_ok(path, sizeof path, "%s/%08"PRIx64, slots, function_id))
+                return log_device_debug_errno(dev, SYNTHETIC_ERRNO(ENAMETOOLONG),
+                                              "PCI slot path is too long, ignoring.");
+
+        if (access(path, F_OK) < 0)
+                return log_device_debug_errno(dev, errno, "Cannot access %s, ignoring: %m", path);
+
+        *ret = (uint32_t) function_id;
+        return 1;
+}
+
 static int dev_pci_slot(sd_device *dev, struct netnames *names) {
-        unsigned long dev_port = 0;
-        unsigned domain, bus, slot, func;
-        int hotplug_slot = -1;
-        size_t l;
-        char *s;
         const char *sysname, *attr, *port_name = NULL, *syspath;
         _cleanup_(sd_device_unrefp) sd_device *pci = NULL;
-        sd_device *hotplug_slot_dev;
-        char slots[PATH_MAX];
         _cleanup_closedir_ DIR *dir = NULL;
-        struct dirent *dent;
+        unsigned domain, bus, slot, func;
+        sd_device *hotplug_slot_dev;
+        unsigned long dev_port = 0;
+        uint32_t hotplug_slot = 0;
+        char slots[PATH_MAX], *s;
+        size_t l;
         int r;
 
         r = sd_device_get_sysname(names->pcidev, &sysname);
@@ -342,18 +385,29 @@ static int dev_pci_slot(sd_device *dev, struct netnames *names) {
 
         hotplug_slot_dev = names->pcidev;
         while (hotplug_slot_dev) {
-                if (sd_device_get_sysname(hotplug_slot_dev, &sysname) < 0)
-                        continue;
+                struct dirent *dent;
+
+                r = parse_hotplug_slot_from_function_id(hotplug_slot_dev, slots, &hotplug_slot);
+                if (r < 0)
+                        return 0;
+                if (r > 0) {
+                        domain = 0; /* See comments in parse_hotplug_slot_from_function_id(). */
+                        break;
+                }
+
+                r = sd_device_get_sysname(hotplug_slot_dev, &sysname);
+                if (r < 0)
+                        return log_device_debug_errno(hotplug_slot_dev, r, "Failed to get sysname: %m");
 
                 FOREACH_DIRENT_ALL(dent, dir, break) {
-                        int i;
-                        char str[PATH_MAX];
                         _cleanup_free_ char *address = NULL;
+                        char str[PATH_MAX];
+                        uint32_t i;
 
                         if (dot_or_dot_dot(dent->d_name))
                                 continue;
 
-                        r = safe_atoi(dent->d_name, &i);
+                        r = safe_atou32(dent->d_name, &i);
                         if (r < 0 || i <= 0)
                                 continue;
 
@@ -368,12 +422,12 @@ static int dev_pci_slot(sd_device *dev, struct netnames *names) {
                                  * devices that will try to claim the same index and that would create name
                                  * collision. */
                                 if (naming_scheme_has(NAMING_BRIDGE_NO_SLOT) && is_pci_bridge(hotplug_slot_dev))
-                                        hotplug_slot = 0;
+                                        return 0;
 
                                 break;
                         }
                 }
-                if (hotplug_slot >= 0)
+                if (hotplug_slot > 0)
                         break;
                 if (sd_device_get_parent_with_subsystem_devtype(hotplug_slot_dev, "pci", NULL, &hotplug_slot_dev) < 0)
                         break;
@@ -385,7 +439,7 @@ static int dev_pci_slot(sd_device *dev, struct netnames *names) {
                 l = sizeof(names->pci_slot);
                 if (domain > 0)
                         l = strpcpyf(&s, l, "P%d", domain);
-                l = strpcpyf(&s, l, "s%d", hotplug_slot);
+                l = strpcpyf(&s, l, "s%"PRIu32, hotplug_slot);
                 if (func > 0 || is_pci_multifunction(names->pcidev))
                         l = strpcpyf(&s, l, "f%d", func);
                 if (port_name)
@@ -945,7 +999,7 @@ static int builtin_net_id(sd_device *dev, int argc, char *argv[], bool test) {
                         udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
 
                 if (names.pci_slot[0] &&
-                    snprintf(str, sizeof str, "%s%s%s", prefix, names.pci_slot, names.bcma_core))
+                    snprintf_ok(str, sizeof str, "%s%s%s", prefix, names.pci_slot, names.bcma_core))
                         udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str);
                 return 0;
         }
index a0848ef6723deea89c9cf30b24424b266a797a06..28b97fadb08767de6aa85dcaffce2d4977e3ca30 100755 (executable)
@@ -16,4 +16,4 @@ NSPAWN_TIMEOUT=20
 # only found from the console during the poweroff.
 rm -f /tmp/honorfirstshutdown.log >/dev/null
 
-do_test "$@" 52 > /tmp/honorfirstshutdown.log
+do_test "$@" 52 >/tmp/honorfirstshutdown.log
diff --git a/test/fuzz/fuzz-unit-file/directives-all.service b/test/fuzz/fuzz-unit-file/directives-all.service
new file mode 100644 (file)
index 0000000..310dbd6
--- /dev/null
@@ -0,0 +1,949 @@
+service
+Accept=
+AccuracySec=
+After=
+Alias=
+AllowedCPUs=
+AllowedMemoryNodes=
+AllowIsolate=
+Also=
+AmbientCapabilities=
+AssertACPower=
+AssertArchitecture=
+AssertCapability=
+AssertControlGroupController=
+AssertDirectoryNotEmpty=
+AssertFileIsExecutable=
+AssertFileNotEmpty=
+AssertFirstBoot=
+AssertGroup=
+AssertHost=
+AssertKernelCommandLine=
+AssertKernelVersion=
+AssertNeedsUpdate=
+AssertPathExists=
+AssertPathExistsGlob=
+AssertPathIsDirectory=
+AssertPathIsMountPoint=
+AssertPathIsReadWrite=
+AssertPathIsSymbolicLink=
+AssertSecurity=
+AssertUser=
+AssertVirtualization=
+Backlog=
+Before=
+BindIPv6Only=
+BindPaths=
+BindReadOnlyPaths=
+BindToDevice=
+BindsTo=
+BlockIOAccounting=
+BlockIODeviceWeight=
+BlockIOReadBandwidth=
+BlockIOWeight=
+BlockIOWriteBandwidth=
+Broadcast=
+BusName=
+CoredumpFilter=
+CPUAccounting=
+CPUQuota=
+CPUShares=
+CPUWeight=
+CapabilityBoundingSet=
+CollectMode=
+ConditionACPower=
+ConditionArchitecture=
+ConditionCapability=
+ConditionControlGroupController=
+ConditionDirectoryNotEmpty=
+ConditionFileIsExecutable=
+ConditionFileNotEmpty=
+ConditionFirstBoot=
+ConditionGroup=
+ConditionHost=
+ConditionKernelCommandLine=
+ConditionKernelVersion=
+ConditionNeedsUpdate=
+ConditionPathExists=
+ConditionPathExistsGlob=
+ConditionPathIsDirectory=
+ConditionPathIsMountPoint=
+ConditionPathIsReadWrite=
+ConditionPathIsSymbolicLink=
+ConditionSecurity=
+ConditionUser=
+ConditionVirtualization=
+Conflicts=
+DefaultDependencies=
+DefaultInstance=
+DeferAcceptSec=
+Delegate=
+Description=
+DeviceAllow=
+DevicePolicy=
+DirectoryMode=
+DirectoryNotEmpty=
+Documentation=
+DynamicUser=
+ExecPaths=
+ExecReload=
+ExecCondition=
+ExecStart=
+ExecStartPost=
+ExecStartPre=
+ExecStop=
+ExecStopPost=
+ExecStopPre=
+ExitType=
+FailureAction=
+FileDescriptorName=
+FileDescriptorStoreMax=
+ForceUnmount=
+FreeBind=
+Group=
+GuessMainPID=
+IOAccounting=
+IODeviceWeight=
+IOReadBandwidthMax=
+IOReadIOPSMax=
+IOWeight=
+IOWriteBandwidthMax=
+IOWriteIOPSMax=
+IPAccounting=
+IPAddressAllow=
+IPAddressDeny=
+IPCNamespacePath=
+IPTOS=
+IPTTL=
+IgnoreOnIsolate=
+JobRunningTimeoutSec=
+JobTimeoutAction=
+JobTimeoutRebootArgument=
+JobTimeoutSec=
+JoinsNamespaceOf=
+KeepAlive=
+KeepAliveIntervalSec=
+KeepAliveProbes=
+KeepAliveTimeSec=
+KillMode=
+KillSignal=
+LazyUnmount=
+ListenDatagram=
+ListenFIFO=
+ListenMessageQueue=
+#ListenNetlink=
+ListenSequentialPacket=
+ListenSpecial=
+ListenStream=
+ListenUSBFunction=
+MakeDirectory=
+Mark=
+MaxConnections=
+MaxConnectionsPerSource=
+ManagedOOMSwap=
+ManagedOOMMemoryPressure=
+ManagedOOMMemoryPressureLimitPercent=
+ManagedOOMPreference=
+MemoryAccounting=
+MemoryHigh=
+MemoryLimit=
+MemoryLow=
+MemoryMax=
+MemorySwapMax=
+MessageQueueMaxMessages=
+MessageQueueMessageSize=
+MountAPIVFS=
+NetworkNamespacePath=
+NoDelay=
+NoExecPaths=
+NoNewPrivileges=
+NonBlocking=
+NotifyAccess=
+OnActiveSec=
+OnBootSec=
+OnCalendar=
+OnFailure=
+OnFailureJobMode=
+OnStartupSec=
+OnUnitActiveSec=
+OnUnitInactiveSec=
+Options=
+PAMName=
+PIDFile=
+PartOf=
+PassCredentials=
+PassSecurity=
+PassPacketInfo=
+PathChanged=
+PathExists=
+PathExistsGlob=
+PathModified=
+PermissionsStartOnly=
+Persistent=
+PipeSize=
+Priority=
+PropagatesReloadTo=
+RandomizedDelaySec=
+FixedRandomDelay=
+RebootArgument=
+ReceiveBuffer=
+RefuseManualStart=
+RefuseManualStop=
+ReloadPropagatedFrom=
+RemainAfterElapse=
+RemainAfterExit=
+RemoveOnStop=
+RequiredBy=
+Requires=
+RequiresMountsFor=
+Requisite=
+Restart=
+RestartForceExitStatus=
+RestartKillSignal=
+RestartPreventExitStatus=
+RestartSec=
+ReusePort=
+RootDirectory=
+RootDirectoryStartOnly=
+RootImage=
+RootHash=
+RootHashSignature=
+RootVerity=
+ExtensionImages=
+RuntimeMaxSec=
+SELinuxContextFromNet=
+SecureBits=
+SendBuffer=
+SendSIGHUP=
+SendSIGKILL=
+Service=
+Slice=
+SloppyOptions=
+SmackLabel=
+SmackLabelIPIn=
+SmackLabelIPOut=
+SocketGroup=
+SocketMode=
+SocketProtocol=
+SocketUser=
+Sockets=
+SourcePath=
+StartLimitAction=
+StartLimitBurst=
+StartLimitIntervalSec=
+StartupBlockIOWeight=
+StartupCPUShares=
+StartupCPUWeight=
+StartupIOWeight=
+StopWhenUnneeded=
+SuccessAction=
+SuccessExitStatus=
+SupplementaryGroups=
+Symlinks=
+TCPCongestion=
+TasksAccounting=
+TasksMax=
+TimeoutIdleSec=
+TimeoutSec=
+TimeoutStartSec=
+TimeoutStopSec=
+TimeoutAbortSec=
+Transparent=
+TriggerLimitBurst=
+TriggerLimitIntervalSec=
+Type=
+USBFunctionDescriptors=
+USBFunctionStrings=
+Unit=
+User=
+WakeSystem=
+WantedBy=
+Wants=
+WatchdogSec=
+What=
+Where=
+WorkingDirectory=
+Writable=
+fsck.mode=
+fsck.repair=
+fstab=
+locale.LANG=
+locale.LANGUAGE=
+locale.LC_ADDRESS=
+locale.LC_COLLATE=
+locale.LC_CTYPE=
+locale.LC_IDENTIFICATION=
+locale.LC_MEASUREMENT=
+locale.LC_MESSAGES=
+locale.LC_MONETARY=
+locale.LC_NAME=
+locale.LC_NUMERIC=
+locale.LC_PAPER=
+locale.LC_TELEPHONE=
+locale.LC_TIME=
+luks.crypttab=
+luks.key=
+luks.name=
+luks.options=
+luks.uuid=
+luks=
+modules_load=
+mount.usr=
+mount.usrflags=
+mount.usrfstype=
+net.ifnames=
+plymouth.enable=
+quotacheck.mode=
+rd.fstab=
+rd.luks.crypttab=
+rd.luks.key=
+rd.luks.name=
+rd.luks.options=
+rd.luks.uuid=
+rd.luks=
+rd.modules_load=
+rd.systemd.gpt_auto=
+rd.systemd.unit=
+rd.systemd.verity=
+rd.udev.children_max=
+rd.udev.event_timeout=
+rd.udev.exec_delay=
+rd.udev.log_level=
+resume=
+resumeflags=
+root=
+rootflags=
+rootfstype=
+roothash=
+systemd.default_standard_error=
+systemd.default_standard_output=
+systemd.default_timeout_start_sec=
+systemd.firstboot=
+systemd.gpt_auto=
+systemd.journald.forward_to_console=
+systemd.journald.forward_to_kmsg=
+systemd.journald.forward_to_syslog=
+systemd.journald.forward_to_wall=
+systemd.log_level=
+systemd.log_location=
+systemd.log_target=
+systemd.machine_id=
+systemd.mask=
+systemd.restore_state=
+systemd.service_watchdogs=
+systemd.setenv=
+systemd.unit=
+systemd.verity=
+systemd.verity_root_data=
+systemd.verity_root_hash=
+systemd.verity_root_options=
+systemd.volatile=
+systemd.wants=
+systemd.watchdog_device=
+udev.children_max=
+udev.event_timeout=
+udev.exec_delay=
+udev.log_level=
+vconsole.font=
+vconsole.font_map=
+vconsole.font_unimap=
+vconsole.keymap=
+vconsole.keymap_toggle=
+ID_MODEL=
+ID_MODEL_FROM_DATABASE=
+SYSTEMD_ALIAS=
+SYSTEMD_MOUNT_OPTIONS=
+SYSTEMD_MOUNT_WHERE=
+SYSTEMD_READY=
+SYSTEMD_USER_WANTS=
+SYSTEMD_WANTS=
+link_priority=
+static_node=
+string_escape=
+ARP=
+ARPAllTargets=
+ARPIPTargets=
+ARPIntervalSec=
+ARPValidate=
+ActiveSlave=
+AdSelect=
+Address=
+AddressAutoconfiguration=
+AgeingTimeSec=
+Alias=
+AllSlavesActive=
+AllowLocalRemote=
+AllowPortToBeRoot=
+AllowedIPs=
+Anonymize=
+Architecture=
+AutoJoin=
+AutoNegotiation=
+BindCarrier=
+BitsPerSecond=
+Bond=
+Bridge=
+Broadcast=
+Cache=
+CacheFromLocalhost=
+ClientIdentifier=
+ConfigureWithoutCarrier=
+CopyDSCP=
+Cost=
+CriticalConnection=
+DHCP=
+DHCPServer=
+DNS=
+DNSLifetimeSec=
+DNSSEC=
+DNSSECNegativeTrustAnchors=
+DNSStubListener=
+DNSStubListenerExtra=
+DUIDRawData=
+DUIDType=
+DefaultLeaseTimeSec=
+DefaultPVID=
+Description=
+Destination=
+DestinationPort=
+DiscoverPathMTU=
+Domains=
+DownDelaySec=
+Driver=
+Duplex=
+DuplicateAddressDetection=
+EgressUntagged=
+EmitDNS=
+EmitDomains=
+EmitLLDP=
+EmitNTP=
+EmitRouter=
+EmitTimezone=
+EncapsulationLimit=
+Endpoint=
+FDBAgeingSec=
+FailOverMACPolicy=
+FallbackDNS=
+FallbackNTP=
+FastLeave=
+FirewallMark=
+Flags=
+FlowLabel=
+ForwardDelaySec=
+From=
+FwMark=
+GVRP=
+Gateway=
+GatewayOnLink=
+GenericReceiveOffload=
+GenericSegmentationOffload=
+GratuitousARP=
+Group=
+GroupForwardMask=
+GroupPolicyExtension=
+HairPin=
+MulticastToUnicast=
+HelloTimeSec=
+HomeAddress=
+Host=
+Hostname=
+IAID=
+IPForward=
+IPMasquerade=
+IPv4LLRoute=
+IPv4ProxyARP=
+IPv6AcceptRA=
+IPv6DuplicateAddressDetection=
+IPv6FlowLabel=
+IPv6HopLimit=
+IPv6Preference=
+IPv6PrefixDelegation=
+IPv6PrivacyExtensions=
+IPv6ProxyNDP=
+IPv6ProxyNDPAddress=
+IPv6Token=
+Id=
+IncomingInterface=
+Independent=
+InitialAdvertisedReceiveWindow=
+InitialCongestionWindow=
+InputKey=
+InvertRule=
+KernelCommandLine=
+KernelVersion=
+Key=
+Kind=
+L2MissNotification=
+L3MissNotification=
+LACPTransmitRate=
+LLDP=
+LLMNR=
+Label=
+LargeReceiveOffload=
+LearnPacketIntervalSec=
+LinkLocalAddressing=
+ListenPort=
+Local=
+LooseBinding=
+MACAddress=
+MACAddressPolicy=
+MACVLAN=
+MIIMonitorSec=
+MTUBytes=
+MVRP=
+MacLearning=
+ManageTemporaryAddress=
+Managed=
+MaxAgeSec=
+MaxLeaseTimeSec=
+MaximumFDBEntries=
+Metric=
+MinLinks=
+Mode=
+MultiQueue=
+MulticastDNS=
+MulticastQuerier=
+MulticastSnooping=
+NTP=
+Name=
+NamePolicy=
+OnLink=
+OneQueue=
+OriginalName=
+OtherInformation=
+OutgoingInterface=
+OutputKey=
+PVID=
+PacketInfo=
+PacketsPerSlave=
+Path=
+Peer=
+PersistentKeepalive=
+PollIntervalMaxSec=
+PollIntervalMinSec=
+PoolOffset=
+PoolSize=
+Port=
+PortRange=
+PreferredLifetime=
+PreferredLifetimeSec=
+PreferredSource=
+Prefix=
+PrefixRoute=
+PresharedKey=
+PrimaryReselectPolicy=
+PrimarySlave=
+Priority=
+PrivateKey=
+Protocol=
+PublicKey=
+QuickAck=
+RapidCommit=
+ReduceARPProxy=
+Remote=
+RemoteChecksumRx=
+RemoteChecksumTx=
+ReorderHeader=
+RequestBroadcast=
+RequiredForOnline=
+ResendIGMP=
+RootDistanceMaxSec=
+RouteMetric=
+RouteShortCircuit=
+RouteTable=
+RouterLifetimeSec=
+RouterPreference=
+STP=
+Scope=
+SendHostname=
+Source=
+SuppressPrefixLength=
+TCP6SegmentationOffload=
+TCPSegmentationOffload=
+TOS=
+TTL=
+Table=
+Timezone=
+To=
+TransmitHashPolicy=
+Tunnel=
+TxtData=
+TxtText=
+Type=
+TypeOfService=
+UDP6ZeroChecksumRx=
+UDP6ZeroChecksumTx=
+UDPChecksum=
+UDPSegmentationOffload=
+UnicastFlood=
+Unmanaged=
+UpDelaySec=
+UseBPDU=
+UseDNS=
+UseDomains=
+UseHostname=
+UseMTU=
+UseNTP=
+UseRoutes=
+UseTimezone=
+User=
+VLAN=
+VLANFiltering=
+VLANId=
+VNetHeader=
+VRF=
+VXLAN=
+ValidLifetimeSec=
+VendorClassIdentifier=
+Virtualization=
+WakeOnLan=
+Weight=
+CODE_FILE=
+CODE_FUNC=
+CODE_LINE=
+COREDUMP_UNIT=
+COREDUMP_USER_UNIT=
+ERRNO=
+MESSAGE=
+MESSAGE_ID=
+OBJECT_AUDIT_LOGINUID=
+OBJECT_AUDIT_SESSION=
+OBJECT_CMDLINE=
+OBJECT_COMM=
+OBJECT_EXE=
+OBJECT_GID=
+OBJECT_PID=
+OBJECT_SYSTEMD_CGROUP=
+OBJECT_SYSTEMD_OWNER_UID=
+OBJECT_SYSTEMD_SESSION=
+OBJECT_SYSTEMD_UNIT=
+OBJECT_SYSTEMD_USER_UNIT=
+OBJECT_UID=
+PRIORITY=
+SYSLOG_FACILITY=
+SYSLOG_IDENTIFIER=
+SYSLOG_PID=
+_AUDIT_LOGINUID=
+_AUDIT_SESSION=
+_BOOT_ID=
+_CAP_EFFECTIVE=
+_CMDLINE=
+_COMM=
+_EXE=
+_GID=
+_HOSTNAME=
+_KERNEL_DEVICE=
+_KERNEL_SUBSYSTEM=
+_LINE_BREAK=
+_MACHINE_ID=
+_PID=
+_SELINUX_CONTEXT=
+_SOURCE_REALTIME_TIMESTAMP=
+_STREAM_ID=
+_SYSTEMD_CGROUP=
+_SYSTEMD_INVOCATION_ID=
+_SYSTEMD_OWNER_UID=
+_SYSTEMD_SESSION=
+_SYSTEMD_SLICE=
+_SYSTEMD_UNIT=
+_SYSTEMD_USER_UNIT=
+_TRANSPORT=
+_UDEV_DEVLINK=
+_UDEV_DEVNODE=
+_UDEV_SYSNAME=
+_UID=
+__CURSOR=
+__MONOTONIC_TIMESTAMP=
+__REALTIME_TIMESTAMP=
+class=
+type=
+cipher=
+hash=
+header=
+key-slot=
+keyfile-offset=
+keyfile-size=
+offset=
+size=
+skip=
+tcrypt-keyfile=
+timeout=
+tries=
+x-systemd.after=
+x-systemd.before=
+x-systemd.device-timeout=
+x-systemd.idle-timeout=
+x-systemd.mount-timeout=
+x-systemd.requires-mounts-for=
+x-systemd.requires=
+CPUAffinity=
+CapabilityBoundingSet=
+CrashChangeVT=
+CrashReboot=
+CrashShell=
+CtrlAltDelBurstAction=
+DefaultBlockIOAccounting=
+DefaultCPUAccounting=
+DefaultEnvironment=
+DefaultIPAccounting=
+DefaultLimitAS=
+DefaultLimitCORE=
+DefaultLimitCPU=
+DefaultLimitDATA=
+DefaultLimitFSIZE=
+DefaultLimitLOCKS=
+DefaultLimitMEMLOCK=
+DefaultLimitMSGQUEUE=
+DefaultLimitNICE=
+DefaultLimitNOFILE=
+DefaultLimitNPROC=
+DefaultLimitRSS=
+DefaultLimitRTPRIO=
+DefaultLimitRTTIME=
+DefaultLimitSIGPENDING=
+DefaultLimitSTACK=
+DefaultMemoryAccounting=
+DefaultRestartSec=
+DefaultStandardError=
+DefaultStandardOutput=
+DefaultStartLimitBurst=
+DefaultStartLimitIntervalSec=
+DefaultTasksAccounting=
+DefaultTasksMax=
+DefaultTimeoutStartSec=
+DefaultTimeoutStopSec=
+DefaultTimeoutAbortSec=
+DefaultTimerAccuracySec=
+DumpCore=
+HibernateMode=
+HibernateState=
+HybridSleepMode=
+HybridSleepState=
+LogColor=
+LogLevel=
+LogLocation=
+LogTarget=
+RuntimeWatchdogSec=
+ShowStatus=
+RebootWatchdogSec=
+ShutdownWatchdogSec=
+KExecWatchdogSec=
+SuspendMode=
+SuspendState=
+SystemCallArchitectures=
+TimerSlackNSec=
+WatchdogDevice=
+-N=
+-c=
+-e=
+-t=
+ANSI_COLOR=
+AppArmorProfile=
+BUG_REPORT_URL=
+BUILD_ID=
+Bind=
+BindReadOnly=
+Boot=
+Bridge=
+CHASSIS=
+CPE_NAME=
+CPUAffinity=
+CPUSchedulingPolicy=
+CPUSchedulingPriority=
+CPUSchedulingResetOnFork=
+CacheDirectory=
+CacheDirectoryMode=
+Capability=
+Compress=
+ConfigurationDirectory=
+ConfigurationDirectoryMode=
+DEPLOYMENT=
+DropCapability=
+Environment=
+EnvironmentFile=
+ExternalSizeMax=
+FONT=
+FONT_MAP=
+FONT_UNIMAP=
+ForwardToConsole=
+ForwardToKMsg=
+ForwardToSyslog=
+ForwardToWall=
+HOME_URL=
+HandleHibernateKey=
+HandleLidSwitch=
+HandleLidSwitchDocked=
+HandleLidSwitchExternalPower=
+HandlePowerKey=
+HandleSuspendKey=
+HibernateKeyIgnoreInhibited=
+HoldoffTimeoutSec=
+ICON_NAME=
+ID=
+ID_LIKE=
+IOSchedulingClass=
+IOSchedulingPriority=
+IPVLAN=
+IdleAction=
+IdleActionSec=
+IgnoreSIGPIPE=
+InaccessiblePaths=
+InhibitDelayMaxSec=
+InhibitorsMax=
+Interface=
+JournalSizeMax=
+KEYMAP=
+KEYMAP_TOGGLE=
+KeepFree=
+KeyringMode=
+ProtectProc=
+ProcSubset=
+KillExcludeUsers=
+KillOnlyUsers=
+KillSignal=
+WatchdogSignal=
+KillUserProcesses=
+LOCATION=
+LidSwitchIgnoreInhibited=
+LimitAS=
+LimitCORE=
+LimitCPU=
+LimitDATA=
+LimitFSIZE=
+LimitLOCKS=
+LimitMEMLOCK=
+LimitMSGQUEUE=
+LimitNICE=
+LimitNOFILE=
+LimitNPROC=
+LimitRSS=
+LimitRTPRIO=
+LimitRTTIME=
+LimitSIGPENDING=
+LimitSTACK=
+LineMax=
+LockPersonality=
+LogExtraFields=
+LogLevelMax=
+LogRateLimitIntervalSec=
+LogRateLimitBurst=
+LogsDirectory=
+LogsDirectoryMode=
+MACVLAN=
+MachineID=
+MaxFileSec=
+MaxLevelConsole=
+MaxLevelKMsg=
+MaxLevelStore=
+MaxLevelSyslog=
+MaxLevelWall=
+MaxRetentionSec=
+MaxUse=
+MemoryDenyWriteExecute=
+MountFlags=
+NAME=
+NAutoVTs=
+Nice=
+NoNewPrivileges=
+NotifyReady=
+OOMScoreAdjust=
+Overlay=
+OverlayReadOnly=
+PRETTY_HOSTNAME=
+PRETTY_NAME=
+PRIVACY_POLICY_URL=
+Parameters=
+PassEnvironment=
+Personality=
+PivotRoot=
+Port=
+PowerKeyIgnoreInhibited=
+Private=
+PrivateIPC=
+PrivateDevices=
+PrivateNetwork=
+PrivateTmp=
+PrivateUsers=
+PrivateUsersChown=
+ProcessSizeMax=
+ProcessTwo=
+ProtectControlGroups=
+ProtectHome=
+ProtectKernelModules=
+ProtectKernelTunables=
+ProtectSystem=
+RateLimitBurst=
+RateLimitIntervalSec=
+ReadKMsg=
+ReadOnly=
+ReadOnlyPaths=
+ReadWriteOnly=
+ReadWritePaths=
+RemoveIPC=
+ReserveVT=
+RestrictAddressFamilies=
+RestrictNamespaces=
+RestrictRealtime=
+RestrictSUIDSGID=
+RuntimeDirectory=
+RuntimeDirectoryInodesMax=
+RuntimeDirectoryMode=
+RuntimeDirectoryPreserve=
+RuntimeDirectorySize=
+RuntimeKeepFree=
+RuntimeMaxFileSize=
+RuntimeMaxFiles=
+RuntimeMaxUse=
+SELinuxContext=
+SUPPORT_URL=
+Seal=
+ServerCertificateFile=
+ServerKeyFile=
+SessionsMax=
+SmackProcessLabel=
+SplitMode=
+StandardError=
+StandardInput=
+StandardInputData=
+StandardInputText=
+StandardOutput=
+StateDirectory=
+StateDirectoryMode=
+Storage=
+SuspendKeyIgnoreInhibited=
+SyncIntervalSec=
+SyslogFacility=
+SyslogIdentifier=
+SyslogLevel=
+SyslogLevelPrefix=
+SystemCallArchitectures=
+SystemCallErrorNumber=
+SystemCallFilter=
+SystemKeepFree=
+SystemMaxFileSize=
+SystemMaxFiles=
+SystemMaxUse=
+TTYPath=
+TTYReset=
+TTYVHangup=
+TTYVTDisallocate=
+TemporaryFileSystem=
+TimerSlackNSec=
+TrustedCertificateFile=
+UMask=
+URL=
+UnsetEnvironment=
+User=
+UserTasksMax=
+UtmpIdentifier=
+UtmpMode=
+VARIANT=
+VARIANT_ID=
+VERSION=
+VERSION_CODENAME=
+VERSION_ID=
+VirtualEthernet=
+VirtualEthernetExtra=
+Volatile=
+WorkingDirectory=
+Zone=
diff --git a/test/fuzz/fuzz-unit-file/directives.automount b/test/fuzz/fuzz-unit-file/directives.automount
new file mode 100644 (file)
index 0000000..70772ba
--- /dev/null
@@ -0,0 +1,5 @@
+automount
+[Automount]
+DirectoryMode=
+TimeoutIdleSec=
+Where=
diff --git a/test/fuzz/fuzz-unit-file/directives.mount b/test/fuzz/fuzz-unit-file/directives.mount
new file mode 100644 (file)
index 0000000..f1a8d19
--- /dev/null
@@ -0,0 +1,204 @@
+mount
+[Mount]
+AllowedCPUs=
+AllowedMemoryNodes=
+AmbientCapabilities=
+AppArmorProfile=
+BPFProgram=
+BindPaths=
+BindReadOnlyPaths=
+BlockIOAccounting=
+BlockIODeviceWeight=
+BlockIOReadBandwidth=
+BlockIOWeight=
+BlockIOWriteBandwidth=
+CPUAccounting=
+CPUAffinity=
+CPUQuota=
+CPUQuotaPeriodSec=
+CPUSchedulingPolicy=
+CPUSchedulingPriority=
+CPUSchedulingResetOnFork=
+CPUShares=
+CPUWeight=
+CacheDirectory=
+CacheDirectoryMode=
+Capabilities=
+CapabilityBoundingSet=
+ConfigurationDirectory=
+ConfigurationDirectoryMode=
+CoredumpFilter=
+DefaultMemoryLow=
+DefaultMemoryMin=
+Delegate=
+DeviceAllow=
+DevicePolicy=
+DirectoryMode=
+DisableControllers=
+DynamicUser=
+Environment=
+EnvironmentFile=
+ExecPaths=
+ExtensionImages=
+FinalKillSignal=
+ForceUnmount=
+Group=
+IOAccounting=
+IODeviceLatencyTargetSec=
+IODeviceWeight=
+IOReadBandwidthMax=
+IOReadIOPSMax=
+IOSchedulingClass=
+IOSchedulingPriority=
+IOWeight=
+IOWriteBandwidthMax=
+IOWriteIOPSMax=
+IPAccounting=
+IPAddressAllow=
+IPAddressDeny=
+IPCNamespacePath=
+IPEgressFilterPath=
+IPIngressFilterPath=
+IgnoreSIGPIPE=
+InaccessibleDirectories=
+InaccessiblePaths=
+KeyringMode=
+KillMode=
+KillSignal=
+LazyUnmount=
+LimitAS=
+LimitCORE=
+LimitCPU=
+LimitDATA=
+LimitFSIZE=
+LimitLOCKS=
+LimitMEMLOCK=
+LimitMSGQUEUE=
+LimitNICE=
+LimitNOFILE=
+LimitNPROC=
+LimitRSS=
+LimitRTPRIO=
+LimitRTTIME=
+LimitSIGPENDING=
+LimitSTACK=
+LoadCredential=
+LockPersonality=
+LogExtraFields=
+LogLevelMax=
+LogNamespace=
+LogRateLimitBurst=
+LogRateLimitIntervalSec=
+LogsDirectory=
+LogsDirectoryMode=
+ManagedOOMMemoryPressure=
+ManagedOOMMemoryPressureLimit=
+ManagedOOMPreference=
+ManagedOOMSwap=
+MemoryAccounting=
+MemoryDenyWriteExecute=
+MemoryHigh=
+MemoryLimit=
+MemoryLow=
+MemoryMax=
+MemoryMin=
+MemorySwapMax=
+MountAPIVFS=
+MountFlags=
+MountImages=
+NUMAMask=
+NUMAPolicy=
+NetClass=
+NetworkNamespacePath=
+Nice=
+NoExecPaths=
+NoNewPrivileges=
+OOMScoreAdjust=
+Options=
+PAMName=
+PassEnvironment=
+Personality=
+PrivateDevices=
+PrivateIPC=
+PrivateMounts=
+PrivateNetwork=
+PrivateTmp=
+PrivateUsers=
+ProcSubset=
+ProtectClock=
+ProtectControlGroups=
+ProtectHome=
+ProtectHostname=
+ProtectKernelLogs=
+ProtectKernelModules=
+ProtectKernelTunables=
+ProtectProc=
+ProtectSystem=
+ReadOnlyDirectories=
+ReadOnlyPaths=
+ReadWriteDirectories=
+ReadWriteOnly=
+ReadWritePaths=
+RemoveIPC=
+RestartKillSignal=
+RestrictAddressFamilies=
+RestrictNamespaces=
+RestrictRealtime=
+RestrictSUIDSGID=
+RootDirectory=
+RootHash=
+RootHashSignature=
+RootImage=
+RootImageOptions=
+RootVerity=
+RuntimeDirectory=
+RuntimeDirectoryMode=
+RuntimeDirectoryPreserve=
+SELinuxContext=
+SecureBits=
+SendSIGHUP=
+SendSIGKILL=
+SetCredential=
+Slice=
+SloppyOptions=
+SmackProcessLabel=
+StandardError=
+StandardInput=
+StandardInputData=
+StandardInputText=
+StandardOutput=
+StartupBlockIOWeight=
+StartupCPUShares=
+StartupCPUWeight=
+StartupIOWeight=
+StateDirectory=
+StateDirectoryMode=
+SupplementaryGroups=
+SyslogFacility=
+SyslogIdentifier=
+SyslogLevel=
+SyslogLevelPrefix=
+SystemCallArchitectures=
+SystemCallErrorNumber=
+SystemCallFilter=
+SystemCallLog=
+TTYPath=
+TTYReset=
+TTYVHangup=
+TTYVTDisallocate=
+TasksAccounting=
+TasksMax=
+TemporaryFileSystem=
+TimeoutCleanSec=
+TimeoutSec=
+TimerSlackNSec=
+Type=
+UMask=
+UnsetEnvironment=
+User=
+UtmpIdentifier=
+UtmpMode=
+WatchdogSignal=
+What=
+Where=
+WorkingDirectory=
diff --git a/test/fuzz/fuzz-unit-file/directives.path b/test/fuzz/fuzz-unit-file/directives.path
new file mode 100644 (file)
index 0000000..213beff
--- /dev/null
@@ -0,0 +1,10 @@
+path
+[Path]
+DirectoryMode=
+DirectoryNotEmpty=
+MakeDirectory=
+PathChanged=
+PathExists=
+PathExistsGlob=
+PathModified=
+Unit=
index d0e194c3715be51691814816dd4ff4e3da001922..97ca9b47aa08ca20228fa5d0522545655dfd2d59 100644 (file)
@@ -1,2 +1,62 @@
 scope
+[Scope]
+AllowedCPUs=
+AllowedMemoryNodes=
+BPFProgram=
+BlockIOAccounting=
+BlockIODeviceWeight=
+BlockIOReadBandwidth=
+BlockIOWeight=
+BlockIOWriteBandwidth=
+CPUAccounting=
+CPUQuota=
+CPUQuotaPeriodSec=
+CPUShares=
+CPUWeight=
+DefaultMemoryLow=
+DefaultMemoryMin=
+Delegate=
+DeviceAllow=
+DevicePolicy=
+DisableControllers=
+FinalKillSignal=
+IOAccounting=
+IODeviceLatencyTargetSec=
+IODeviceWeight=
+IOReadBandwidthMax=
+IOReadIOPSMax=
+IOWeight=
+IOWriteBandwidthMax=
+IOWriteIOPSMax=
+IPAccounting=
+IPAddressAllow=
+IPAddressDeny=
+IPEgressFilterPath=
+IPIngressFilterPath=
+KillMode=
+KillSignal=
+ManagedOOMMemoryPressure=
+ManagedOOMMemoryPressureLimit=
+ManagedOOMPreference=
+ManagedOOMSwap=
+MemoryAccounting=
+MemoryHigh=
+MemoryLimit=
+MemoryLow=
+MemoryMax=
+MemoryMin=
+MemorySwapMax=
+NetClass=
+RestartKillSignal=
 RuntimeMaxSec=
+SendSIGHUP=
+SendSIGKILL=
+Slice=
+StartupBlockIOWeight=
+StartupCPUShares=
+StartupCPUWeight=
+StartupIOWeight=
+TasksAccounting=
+TasksMax=
+TimeoutStopSec=
+WatchdogSignal=
index 310dbd6add2be3b09e1e344f122a1b677511bd29..c2069c1a785c51a1190684d24fbdc0573d46b66f 100644 (file)
@@ -1,18 +1,14 @@
 service
-Accept=
-AccuracySec=
+[Unit]
 After=
-Alias=
-AllowedCPUs=
-AllowedMemoryNodes=
 AllowIsolate=
-Also=
-AmbientCapabilities=
 AssertACPower=
 AssertArchitecture=
+AssertCPUs=
 AssertCapability=
 AssertControlGroupController=
 AssertDirectoryNotEmpty=
+AssertEnvironment=
 AssertFileIsExecutable=
 AssertFileNotEmpty=
 AssertFirstBoot=
@@ -20,42 +16,30 @@ AssertGroup=
 AssertHost=
 AssertKernelCommandLine=
 AssertKernelVersion=
+AssertMemory=
 AssertNeedsUpdate=
 AssertPathExists=
 AssertPathExistsGlob=
 AssertPathIsDirectory=
+AssertPathIsEncrypted=
 AssertPathIsMountPoint=
 AssertPathIsReadWrite=
 AssertPathIsSymbolicLink=
 AssertSecurity=
 AssertUser=
 AssertVirtualization=
-Backlog=
+BPFProgram=
 Before=
-BindIPv6Only=
-BindPaths=
-BindReadOnlyPaths=
-BindToDevice=
+BindTo=
 BindsTo=
-BlockIOAccounting=
-BlockIODeviceWeight=
-BlockIOReadBandwidth=
-BlockIOWeight=
-BlockIOWriteBandwidth=
-Broadcast=
-BusName=
-CoredumpFilter=
-CPUAccounting=
-CPUQuota=
-CPUShares=
-CPUWeight=
-CapabilityBoundingSet=
 CollectMode=
 ConditionACPower=
 ConditionArchitecture=
+ConditionCPUs=
 ConditionCapability=
 ConditionControlGroupController=
 ConditionDirectoryNotEmpty=
+ConditionEnvironment=
 ConditionFileIsExecutable=
 ConditionFileNotEmpty=
 ConditionFirstBoot=
@@ -63,10 +47,12 @@ ConditionGroup=
 ConditionHost=
 ConditionKernelCommandLine=
 ConditionKernelVersion=
+ConditionMemory=
 ConditionNeedsUpdate=
 ConditionPathExists=
 ConditionPathExistsGlob=
 ConditionPathIsDirectory=
+ConditionPathIsEncrypted=
 ConditionPathIsMountPoint=
 ConditionPathIsReadWrite=
 ConditionPathIsSymbolicLink=
@@ -75,736 +61,124 @@ ConditionUser=
 ConditionVirtualization=
 Conflicts=
 DefaultDependencies=
-DefaultInstance=
-DeferAcceptSec=
-Delegate=
 Description=
-DeviceAllow=
-DevicePolicy=
-DirectoryMode=
-DirectoryNotEmpty=
 Documentation=
-DynamicUser=
-ExecPaths=
-ExecReload=
-ExecCondition=
-ExecStart=
-ExecStartPost=
-ExecStartPre=
-ExecStop=
-ExecStopPost=
-ExecStopPre=
-ExitType=
 FailureAction=
-FileDescriptorName=
-FileDescriptorStoreMax=
-ForceUnmount=
-FreeBind=
-Group=
-GuessMainPID=
-IOAccounting=
-IODeviceWeight=
-IOReadBandwidthMax=
-IOReadIOPSMax=
-IOWeight=
-IOWriteBandwidthMax=
-IOWriteIOPSMax=
-IPAccounting=
-IPAddressAllow=
-IPAddressDeny=
-IPCNamespacePath=
-IPTOS=
-IPTTL=
+FailureActionExitStatus=
 IgnoreOnIsolate=
+IgnoreOnSnapshot=
 JobRunningTimeoutSec=
 JobTimeoutAction=
 JobTimeoutRebootArgument=
 JobTimeoutSec=
 JoinsNamespaceOf=
-KeepAlive=
-KeepAliveIntervalSec=
-KeepAliveProbes=
-KeepAliveTimeSec=
-KillMode=
-KillSignal=
-LazyUnmount=
-ListenDatagram=
-ListenFIFO=
-ListenMessageQueue=
-#ListenNetlink=
-ListenSequentialPacket=
-ListenSpecial=
-ListenStream=
-ListenUSBFunction=
-MakeDirectory=
-Mark=
-MaxConnections=
-MaxConnectionsPerSource=
-ManagedOOMSwap=
-ManagedOOMMemoryPressure=
-ManagedOOMMemoryPressureLimitPercent=
-ManagedOOMPreference=
-MemoryAccounting=
-MemoryHigh=
-MemoryLimit=
-MemoryLow=
-MemoryMax=
-MemorySwapMax=
-MessageQueueMaxMessages=
-MessageQueueMessageSize=
-MountAPIVFS=
-NetworkNamespacePath=
-NoDelay=
-NoExecPaths=
-NoNewPrivileges=
-NonBlocking=
-NotifyAccess=
-OnActiveSec=
-OnBootSec=
-OnCalendar=
 OnFailure=
+OnFailureIsolate=
 OnFailureJobMode=
-OnStartupSec=
-OnUnitActiveSec=
-OnUnitInactiveSec=
-Options=
-PAMName=
-PIDFile=
 PartOf=
-PassCredentials=
-PassSecurity=
-PassPacketInfo=
-PathChanged=
-PathExists=
-PathExistsGlob=
-PathModified=
-PermissionsStartOnly=
-Persistent=
-PipeSize=
-Priority=
+PropagateReloadFrom=
+PropagateReloadTo=
 PropagatesReloadTo=
-RandomizedDelaySec=
-FixedRandomDelay=
 RebootArgument=
-ReceiveBuffer=
 RefuseManualStart=
 RefuseManualStop=
 ReloadPropagatedFrom=
-RemainAfterElapse=
-RemainAfterExit=
-RemoveOnStop=
-RequiredBy=
 Requires=
 RequiresMountsFor=
+RequiresOverridable=
 Requisite=
-Restart=
-RestartForceExitStatus=
-RestartKillSignal=
-RestartPreventExitStatus=
-RestartSec=
-ReusePort=
-RootDirectory=
-RootDirectoryStartOnly=
-RootImage=
-RootHash=
-RootHashSignature=
-RootVerity=
-ExtensionImages=
-RuntimeMaxSec=
-SELinuxContextFromNet=
-SecureBits=
-SendBuffer=
-SendSIGHUP=
-SendSIGKILL=
-Service=
-Slice=
-SloppyOptions=
-SmackLabel=
-SmackLabelIPIn=
-SmackLabelIPOut=
-SocketGroup=
-SocketMode=
-SocketProtocol=
-SocketUser=
-Sockets=
+RequisiteOverridable=
 SourcePath=
 StartLimitAction=
 StartLimitBurst=
+StartLimitInterval=
 StartLimitIntervalSec=
-StartupBlockIOWeight=
-StartupCPUShares=
-StartupCPUWeight=
-StartupIOWeight=
 StopWhenUnneeded=
 SuccessAction=
-SuccessExitStatus=
-SupplementaryGroups=
-Symlinks=
-TCPCongestion=
-TasksAccounting=
-TasksMax=
-TimeoutIdleSec=
-TimeoutSec=
-TimeoutStartSec=
-TimeoutStopSec=
-TimeoutAbortSec=
-Transparent=
-TriggerLimitBurst=
-TriggerLimitIntervalSec=
-Type=
-USBFunctionDescriptors=
-USBFunctionStrings=
-Unit=
-User=
-WakeSystem=
-WantedBy=
+SuccessActionExitStatus=
 Wants=
-WatchdogSec=
-What=
-Where=
-WorkingDirectory=
-Writable=
-fsck.mode=
-fsck.repair=
-fstab=
-locale.LANG=
-locale.LANGUAGE=
-locale.LC_ADDRESS=
-locale.LC_COLLATE=
-locale.LC_CTYPE=
-locale.LC_IDENTIFICATION=
-locale.LC_MEASUREMENT=
-locale.LC_MESSAGES=
-locale.LC_MONETARY=
-locale.LC_NAME=
-locale.LC_NUMERIC=
-locale.LC_PAPER=
-locale.LC_TELEPHONE=
-locale.LC_TIME=
-luks.crypttab=
-luks.key=
-luks.name=
-luks.options=
-luks.uuid=
-luks=
-modules_load=
-mount.usr=
-mount.usrflags=
-mount.usrfstype=
-net.ifnames=
-plymouth.enable=
-quotacheck.mode=
-rd.fstab=
-rd.luks.crypttab=
-rd.luks.key=
-rd.luks.name=
-rd.luks.options=
-rd.luks.uuid=
-rd.luks=
-rd.modules_load=
-rd.systemd.gpt_auto=
-rd.systemd.unit=
-rd.systemd.verity=
-rd.udev.children_max=
-rd.udev.event_timeout=
-rd.udev.exec_delay=
-rd.udev.log_level=
-resume=
-resumeflags=
-root=
-rootflags=
-rootfstype=
-roothash=
-systemd.default_standard_error=
-systemd.default_standard_output=
-systemd.default_timeout_start_sec=
-systemd.firstboot=
-systemd.gpt_auto=
-systemd.journald.forward_to_console=
-systemd.journald.forward_to_kmsg=
-systemd.journald.forward_to_syslog=
-systemd.journald.forward_to_wall=
-systemd.log_level=
-systemd.log_location=
-systemd.log_target=
-systemd.machine_id=
-systemd.mask=
-systemd.restore_state=
-systemd.service_watchdogs=
-systemd.setenv=
-systemd.unit=
-systemd.verity=
-systemd.verity_root_data=
-systemd.verity_root_hash=
-systemd.verity_root_options=
-systemd.volatile=
-systemd.wants=
-systemd.watchdog_device=
-udev.children_max=
-udev.event_timeout=
-udev.exec_delay=
-udev.log_level=
-vconsole.font=
-vconsole.font_map=
-vconsole.font_unimap=
-vconsole.keymap=
-vconsole.keymap_toggle=
-ID_MODEL=
-ID_MODEL_FROM_DATABASE=
-SYSTEMD_ALIAS=
-SYSTEMD_MOUNT_OPTIONS=
-SYSTEMD_MOUNT_WHERE=
-SYSTEMD_READY=
-SYSTEMD_USER_WANTS=
-SYSTEMD_WANTS=
-link_priority=
-static_node=
-string_escape=
-ARP=
-ARPAllTargets=
-ARPIPTargets=
-ARPIntervalSec=
-ARPValidate=
-ActiveSlave=
-AdSelect=
-Address=
-AddressAutoconfiguration=
-AgeingTimeSec=
+[Install]
 Alias=
-AllSlavesActive=
-AllowLocalRemote=
-AllowPortToBeRoot=
-AllowedIPs=
-Anonymize=
-Architecture=
-AutoJoin=
-AutoNegotiation=
-BindCarrier=
-BitsPerSecond=
-Bond=
-Bridge=
-Broadcast=
-Cache=
-CacheFromLocalhost=
-ClientIdentifier=
-ConfigureWithoutCarrier=
-CopyDSCP=
-Cost=
-CriticalConnection=
-DHCP=
-DHCPServer=
-DNS=
-DNSLifetimeSec=
-DNSSEC=
-DNSSECNegativeTrustAnchors=
-DNSStubListener=
-DNSStubListenerExtra=
-DUIDRawData=
-DUIDType=
-DefaultLeaseTimeSec=
-DefaultPVID=
-Description=
-Destination=
-DestinationPort=
-DiscoverPathMTU=
-Domains=
-DownDelaySec=
-Driver=
-Duplex=
-DuplicateAddressDetection=
-EgressUntagged=
-EmitDNS=
-EmitDomains=
-EmitLLDP=
-EmitNTP=
-EmitRouter=
-EmitTimezone=
-EncapsulationLimit=
-Endpoint=
-FDBAgeingSec=
-FailOverMACPolicy=
-FallbackDNS=
-FallbackNTP=
-FastLeave=
-FirewallMark=
-Flags=
-FlowLabel=
-ForwardDelaySec=
-From=
-FwMark=
-GVRP=
-Gateway=
-GatewayOnLink=
-GenericReceiveOffload=
-GenericSegmentationOffload=
-GratuitousARP=
-Group=
-GroupForwardMask=
-GroupPolicyExtension=
-HairPin=
-MulticastToUnicast=
-HelloTimeSec=
-HomeAddress=
-Host=
-Hostname=
-IAID=
-IPForward=
-IPMasquerade=
-IPv4LLRoute=
-IPv4ProxyARP=
-IPv6AcceptRA=
-IPv6DuplicateAddressDetection=
-IPv6FlowLabel=
-IPv6HopLimit=
-IPv6Preference=
-IPv6PrefixDelegation=
-IPv6PrivacyExtensions=
-IPv6ProxyNDP=
-IPv6ProxyNDPAddress=
-IPv6Token=
-Id=
-IncomingInterface=
-Independent=
-InitialAdvertisedReceiveWindow=
-InitialCongestionWindow=
-InputKey=
-InvertRule=
-KernelCommandLine=
-KernelVersion=
-Key=
-Kind=
-L2MissNotification=
-L3MissNotification=
-LACPTransmitRate=
-LLDP=
-LLMNR=
-Label=
-LargeReceiveOffload=
-LearnPacketIntervalSec=
-LinkLocalAddressing=
-ListenPort=
-Local=
-LooseBinding=
-MACAddress=
-MACAddressPolicy=
-MACVLAN=
-MIIMonitorSec=
-MTUBytes=
-MVRP=
-MacLearning=
-ManageTemporaryAddress=
-Managed=
-MaxAgeSec=
-MaxLeaseTimeSec=
-MaximumFDBEntries=
-Metric=
-MinLinks=
-Mode=
-MultiQueue=
-MulticastDNS=
-MulticastQuerier=
-MulticastSnooping=
-NTP=
-Name=
-NamePolicy=
-OnLink=
-OneQueue=
-OriginalName=
-OtherInformation=
-OutgoingInterface=
-OutputKey=
-PVID=
-PacketInfo=
-PacketsPerSlave=
-Path=
-Peer=
-PersistentKeepalive=
-PollIntervalMaxSec=
-PollIntervalMinSec=
-PoolOffset=
-PoolSize=
-Port=
-PortRange=
-PreferredLifetime=
-PreferredLifetimeSec=
-PreferredSource=
-Prefix=
-PrefixRoute=
-PresharedKey=
-PrimaryReselectPolicy=
-PrimarySlave=
-Priority=
-PrivateKey=
-Protocol=
-PublicKey=
-QuickAck=
-RapidCommit=
-ReduceARPProxy=
-Remote=
-RemoteChecksumRx=
-RemoteChecksumTx=
-ReorderHeader=
-RequestBroadcast=
-RequiredForOnline=
-ResendIGMP=
-RootDistanceMaxSec=
-RouteMetric=
-RouteShortCircuit=
-RouteTable=
-RouterLifetimeSec=
-RouterPreference=
-STP=
-Scope=
-SendHostname=
-Source=
-SuppressPrefixLength=
-TCP6SegmentationOffload=
-TCPSegmentationOffload=
-TOS=
-TTL=
-Table=
-Timezone=
-To=
-TransmitHashPolicy=
-Tunnel=
-TxtData=
-TxtText=
-Type=
-TypeOfService=
-UDP6ZeroChecksumRx=
-UDP6ZeroChecksumTx=
-UDPChecksum=
-UDPSegmentationOffload=
-UnicastFlood=
-Unmanaged=
-UpDelaySec=
-UseBPDU=
-UseDNS=
-UseDomains=
-UseHostname=
-UseMTU=
-UseNTP=
-UseRoutes=
-UseTimezone=
-User=
-VLAN=
-VLANFiltering=
-VLANId=
-VNetHeader=
-VRF=
-VXLAN=
-ValidLifetimeSec=
-VendorClassIdentifier=
-Virtualization=
-WakeOnLan=
-Weight=
-CODE_FILE=
-CODE_FUNC=
-CODE_LINE=
-COREDUMP_UNIT=
-COREDUMP_USER_UNIT=
-ERRNO=
-MESSAGE=
-MESSAGE_ID=
-OBJECT_AUDIT_LOGINUID=
-OBJECT_AUDIT_SESSION=
-OBJECT_CMDLINE=
-OBJECT_COMM=
-OBJECT_EXE=
-OBJECT_GID=
-OBJECT_PID=
-OBJECT_SYSTEMD_CGROUP=
-OBJECT_SYSTEMD_OWNER_UID=
-OBJECT_SYSTEMD_SESSION=
-OBJECT_SYSTEMD_UNIT=
-OBJECT_SYSTEMD_USER_UNIT=
-OBJECT_UID=
-PRIORITY=
-SYSLOG_FACILITY=
-SYSLOG_IDENTIFIER=
-SYSLOG_PID=
-_AUDIT_LOGINUID=
-_AUDIT_SESSION=
-_BOOT_ID=
-_CAP_EFFECTIVE=
-_CMDLINE=
-_COMM=
-_EXE=
-_GID=
-_HOSTNAME=
-_KERNEL_DEVICE=
-_KERNEL_SUBSYSTEM=
-_LINE_BREAK=
-_MACHINE_ID=
-_PID=
-_SELINUX_CONTEXT=
-_SOURCE_REALTIME_TIMESTAMP=
-_STREAM_ID=
-_SYSTEMD_CGROUP=
-_SYSTEMD_INVOCATION_ID=
-_SYSTEMD_OWNER_UID=
-_SYSTEMD_SESSION=
-_SYSTEMD_SLICE=
-_SYSTEMD_UNIT=
-_SYSTEMD_USER_UNIT=
-_TRANSPORT=
-_UDEV_DEVLINK=
-_UDEV_DEVNODE=
-_UDEV_SYSNAME=
-_UID=
-__CURSOR=
-__MONOTONIC_TIMESTAMP=
-__REALTIME_TIMESTAMP=
-class=
-type=
-cipher=
-hash=
-header=
-key-slot=
-keyfile-offset=
-keyfile-size=
-offset=
-size=
-skip=
-tcrypt-keyfile=
-timeout=
-tries=
-x-systemd.after=
-x-systemd.before=
-x-systemd.device-timeout=
-x-systemd.idle-timeout=
-x-systemd.mount-timeout=
-x-systemd.requires-mounts-for=
-x-systemd.requires=
-CPUAffinity=
-CapabilityBoundingSet=
-CrashChangeVT=
-CrashReboot=
-CrashShell=
-CtrlAltDelBurstAction=
-DefaultBlockIOAccounting=
-DefaultCPUAccounting=
-DefaultEnvironment=
-DefaultIPAccounting=
-DefaultLimitAS=
-DefaultLimitCORE=
-DefaultLimitCPU=
-DefaultLimitDATA=
-DefaultLimitFSIZE=
-DefaultLimitLOCKS=
-DefaultLimitMEMLOCK=
-DefaultLimitMSGQUEUE=
-DefaultLimitNICE=
-DefaultLimitNOFILE=
-DefaultLimitNPROC=
-DefaultLimitRSS=
-DefaultLimitRTPRIO=
-DefaultLimitRTTIME=
-DefaultLimitSIGPENDING=
-DefaultLimitSTACK=
-DefaultMemoryAccounting=
-DefaultRestartSec=
-DefaultStandardError=
-DefaultStandardOutput=
-DefaultStartLimitBurst=
-DefaultStartLimitIntervalSec=
-DefaultTasksAccounting=
-DefaultTasksMax=
-DefaultTimeoutStartSec=
-DefaultTimeoutStopSec=
-DefaultTimeoutAbortSec=
-DefaultTimerAccuracySec=
-DumpCore=
-HibernateMode=
-HibernateState=
-HybridSleepMode=
-HybridSleepState=
-LogColor=
-LogLevel=
-LogLocation=
-LogTarget=
-RuntimeWatchdogSec=
-ShowStatus=
-RebootWatchdogSec=
-ShutdownWatchdogSec=
-KExecWatchdogSec=
-SuspendMode=
-SuspendState=
-SystemCallArchitectures=
-TimerSlackNSec=
-WatchdogDevice=
--N=
--c=
--e=
--t=
-ANSI_COLOR=
+Also=
+DefaultInstance=
+RequiredBy=
+WantedBy=
+[Service]
+AllowedCPUs=
+AllowedMemoryNodes=
+AmbientCapabilities=
 AppArmorProfile=
-BUG_REPORT_URL=
-BUILD_ID=
-Bind=
-BindReadOnly=
-Boot=
-Bridge=
-CHASSIS=
-CPE_NAME=
+BindPaths=
+BindReadOnlyPaths=
+BlockIOAccounting=
+BlockIODeviceWeight=
+BlockIOReadBandwidth=
+BlockIOWeight=
+BlockIOWriteBandwidth=
+BusName=
+BusPolicy=
+CPUAccounting=
 CPUAffinity=
+CPUQuota=
+CPUQuotaPeriodSec=
 CPUSchedulingPolicy=
 CPUSchedulingPriority=
 CPUSchedulingResetOnFork=
+CPUShares=
+CPUWeight=
 CacheDirectory=
 CacheDirectoryMode=
-Capability=
-Compress=
+Capabilities=
+CapabilityBoundingSet=
 ConfigurationDirectory=
 ConfigurationDirectoryMode=
-DEPLOYMENT=
-DropCapability=
+CoredumpFilter=
+DefaultMemoryLow=
+DefaultMemoryMin=
+Delegate=
+DeviceAllow=
+DevicePolicy=
+DisableControllers=
+DynamicUser=
 Environment=
 EnvironmentFile=
-ExternalSizeMax=
-FONT=
-FONT_MAP=
-FONT_UNIMAP=
-ForwardToConsole=
-ForwardToKMsg=
-ForwardToSyslog=
-ForwardToWall=
-HOME_URL=
-HandleHibernateKey=
-HandleLidSwitch=
-HandleLidSwitchDocked=
-HandleLidSwitchExternalPower=
-HandlePowerKey=
-HandleSuspendKey=
-HibernateKeyIgnoreInhibited=
-HoldoffTimeoutSec=
-ICON_NAME=
-ID=
-ID_LIKE=
+ExecCondition=
+ExecPaths=
+ExecReload=
+ExecStart=
+ExecStartPost=
+ExecStartPre=
+ExecStop=
+ExecStopPost=
+ExitType=
+ExtensionImages=
+FailureAction=
+FileDescriptorStoreMax=
+FinalKillSignal=
+Group=
+GuessMainPID=
+IOAccounting=
+IODeviceLatencyTargetSec=
+IODeviceWeight=
+IOReadBandwidthMax=
+IOReadIOPSMax=
 IOSchedulingClass=
 IOSchedulingPriority=
-IPVLAN=
-IdleAction=
-IdleActionSec=
+IOWeight=
+IOWriteBandwidthMax=
+IOWriteIOPSMax=
+IPAccounting=
+IPAddressAllow=
+IPAddressDeny=
+IPCNamespacePath=
+IPEgressFilterPath=
+IPIngressFilterPath=
 IgnoreSIGPIPE=
+InaccessibleDirectories=
 InaccessiblePaths=
-InhibitDelayMaxSec=
-InhibitorsMax=
-Interface=
-JournalSizeMax=
-KEYMAP=
-KEYMAP_TOGGLE=
-KeepFree=
 KeyringMode=
-ProtectProc=
-ProcSubset=
-KillExcludeUsers=
-KillOnlyUsers=
+KillMode=
 KillSignal=
-WatchdogSignal=
-KillUserProcesses=
-LOCATION=
-LidSwitchIgnoreInhibited=
 LimitAS=
 LimitCORE=
 LimitCPU=
@@ -821,97 +195,114 @@ LimitRTPRIO=
 LimitRTTIME=
 LimitSIGPENDING=
 LimitSTACK=
-LineMax=
+LoadCredential=
 LockPersonality=
 LogExtraFields=
 LogLevelMax=
-LogRateLimitIntervalSec=
+LogNamespace=
 LogRateLimitBurst=
+LogRateLimitIntervalSec=
 LogsDirectory=
 LogsDirectoryMode=
-MACVLAN=
-MachineID=
-MaxFileSec=
-MaxLevelConsole=
-MaxLevelKMsg=
-MaxLevelStore=
-MaxLevelSyslog=
-MaxLevelWall=
-MaxRetentionSec=
-MaxUse=
+ManagedOOMMemoryPressure=
+ManagedOOMMemoryPressureLimit=
+ManagedOOMPreference=
+ManagedOOMSwap=
+MemoryAccounting=
 MemoryDenyWriteExecute=
+MemoryHigh=
+MemoryLimit=
+MemoryLow=
+MemoryMax=
+MemoryMin=
+MemorySwapMax=
+MountAPIVFS=
 MountFlags=
-NAME=
-NAutoVTs=
+MountImages=
+NUMAMask=
+NUMAPolicy=
+NetClass=
+NetworkNamespacePath=
 Nice=
+NoExecPaths=
 NoNewPrivileges=
-NotifyReady=
+NonBlocking=
+NotifyAccess=
+OOMPolicy=
 OOMScoreAdjust=
-Overlay=
-OverlayReadOnly=
-PRETTY_HOSTNAME=
-PRETTY_NAME=
-PRIVACY_POLICY_URL=
-Parameters=
+PAMName=
+PIDFile=
 PassEnvironment=
+PermissionsStartOnly=
 Personality=
-PivotRoot=
-Port=
-PowerKeyIgnoreInhibited=
-Private=
-PrivateIPC=
 PrivateDevices=
+PrivateIPC=
+PrivateMounts=
 PrivateNetwork=
 PrivateTmp=
 PrivateUsers=
-PrivateUsersChown=
-ProcessSizeMax=
-ProcessTwo=
+ProcSubset=
+ProtectClock=
 ProtectControlGroups=
 ProtectHome=
+ProtectHostname=
+ProtectKernelLogs=
 ProtectKernelModules=
 ProtectKernelTunables=
+ProtectProc=
 ProtectSystem=
-RateLimitBurst=
-RateLimitIntervalSec=
-ReadKMsg=
-ReadOnly=
+ReadOnlyDirectories=
 ReadOnlyPaths=
-ReadWriteOnly=
+ReadWriteDirectories=
 ReadWritePaths=
+RebootArgument=
+RemainAfterExit=
 RemoveIPC=
-ReserveVT=
+Restart=
+RestartForceExitStatus=
+RestartKillSignal=
+RestartPreventExitStatus=
+RestartSec=
 RestrictAddressFamilies=
 RestrictNamespaces=
 RestrictRealtime=
 RestrictSUIDSGID=
+RootDirectory=
+RootDirectoryStartOnly=
+RootHash=
+RootHashSignature=
+RootImage=
+RootImageOptions=
+RootVerity=
 RuntimeDirectory=
-RuntimeDirectoryInodesMax=
 RuntimeDirectoryMode=
 RuntimeDirectoryPreserve=
-RuntimeDirectorySize=
-RuntimeKeepFree=
-RuntimeMaxFileSize=
-RuntimeMaxFiles=
-RuntimeMaxUse=
+RuntimeMaxSec=
 SELinuxContext=
-SUPPORT_URL=
-Seal=
-ServerCertificateFile=
-ServerKeyFile=
-SessionsMax=
+SecureBits=
+SendSIGHUP=
+SendSIGKILL=
+SetCredential=
+Slice=
 SmackProcessLabel=
-SplitMode=
+Sockets=
 StandardError=
 StandardInput=
 StandardInputData=
 StandardInputText=
 StandardOutput=
+StartLimitAction=
+StartLimitBurst=
+StartLimitInterval=
+StartupBlockIOWeight=
+StartupCPUShares=
+StartupCPUWeight=
+StartupIOWeight=
 StateDirectory=
 StateDirectoryMode=
-Storage=
-SuspendKeyIgnoreInhibited=
-SyncIntervalSec=
+SuccessExitStatus=
+SupplementaryGroups=
+SysVStartPriority=
 SyslogFacility=
 SyslogIdentifier=
 SyslogLevel=
@@ -919,31 +310,30 @@ SyslogLevelPrefix=
 SystemCallArchitectures=
 SystemCallErrorNumber=
 SystemCallFilter=
-SystemKeepFree=
-SystemMaxFileSize=
-SystemMaxFiles=
-SystemMaxUse=
+SystemCallLog=
 TTYPath=
 TTYReset=
 TTYVHangup=
 TTYVTDisallocate=
+TasksAccounting=
+TasksMax=
 TemporaryFileSystem=
+TimeoutAbortSec=
+TimeoutCleanSec=
+TimeoutSec=
+TimeoutStartFailureMode=
+TimeoutStartSec=
+TimeoutStopFailureMode=
+TimeoutStopSec=
 TimerSlackNSec=
-TrustedCertificateFile=
+Type=
 UMask=
-URL=
+USBFunctionDescriptors=
+USBFunctionStrings=
 UnsetEnvironment=
 User=
-UserTasksMax=
 UtmpIdentifier=
 UtmpMode=
-VARIANT=
-VARIANT_ID=
-VERSION=
-VERSION_CODENAME=
-VERSION_ID=
-VirtualEthernet=
-VirtualEthernetExtra=
-Volatile=
+WatchdogSec=
+WatchdogSignal=
 WorkingDirectory=
-Zone=
diff --git a/test/fuzz/fuzz-unit-file/directives.slice b/test/fuzz/fuzz-unit-file/directives.slice
new file mode 100644 (file)
index 0000000..b96d062
--- /dev/null
@@ -0,0 +1,53 @@
+slice
+[Slice]
+AllowedCPUs=
+AllowedMemoryNodes=
+BPFProgram=
+BlockIOAccounting=
+BlockIODeviceWeight=
+BlockIOReadBandwidth=
+BlockIOWeight=
+BlockIOWriteBandwidth=
+CPUAccounting=
+CPUQuota=
+CPUQuotaPeriodSec=
+CPUShares=
+CPUWeight=
+DefaultMemoryLow=
+DefaultMemoryMin=
+Delegate=
+DeviceAllow=
+DevicePolicy=
+DisableControllers=
+IOAccounting=
+IODeviceLatencyTargetSec=
+IODeviceWeight=
+IOReadBandwidthMax=
+IOReadIOPSMax=
+IOWeight=
+IOWriteBandwidthMax=
+IOWriteIOPSMax=
+IPAccounting=
+IPAddressAllow=
+IPAddressDeny=
+IPEgressFilterPath=
+IPIngressFilterPath=
+ManagedOOMMemoryPressure=
+ManagedOOMMemoryPressureLimit=
+ManagedOOMPreference=
+ManagedOOMSwap=
+MemoryAccounting=
+MemoryHigh=
+MemoryLimit=
+MemoryLow=
+MemoryMax=
+MemoryMin=
+MemorySwapMax=
+NetClass=
+Slice=
+StartupBlockIOWeight=
+StartupCPUShares=
+StartupCPUWeight=
+StartupIOWeight=
+TasksAccounting=
+TasksMax=
diff --git a/test/fuzz/fuzz-unit-file/directives.socket b/test/fuzz/fuzz-unit-file/directives.socket
new file mode 100644 (file)
index 0000000..79e04a2
--- /dev/null
@@ -0,0 +1,254 @@
+socket
+[Socket]
+Accept=
+AllowedCPUs=
+AllowedMemoryNodes=
+AmbientCapabilities=
+AppArmorProfile=
+BPFProgram=
+Backlog=
+BindIPv6Only=
+BindPaths=
+BindReadOnlyPaths=
+BindToDevice=
+BlockIOAccounting=
+BlockIODeviceWeight=
+BlockIOReadBandwidth=
+BlockIOWeight=
+BlockIOWriteBandwidth=
+Broadcast=
+CPUAccounting=
+CPUAffinity=
+CPUQuota=
+CPUQuotaPeriodSec=
+CPUSchedulingPolicy=
+CPUSchedulingPriority=
+CPUSchedulingResetOnFork=
+CPUShares=
+CPUWeight=
+CacheDirectory=
+CacheDirectoryMode=
+Capabilities=
+CapabilityBoundingSet=
+ConfigurationDirectory=
+ConfigurationDirectoryMode=
+CoredumpFilter=
+DefaultMemoryLow=
+DefaultMemoryMin=
+DeferAcceptSec=
+Delegate=
+DeviceAllow=
+DevicePolicy=
+DirectoryMode=
+DisableControllers=
+DynamicUser=
+Environment=
+EnvironmentFile=
+ExecPaths=
+ExecStartPost=
+ExecStartPre=
+ExecStopPost=
+ExecStopPre=
+ExtensionImages=
+FileDescriptorName=
+FinalKillSignal=
+FlushPending=
+FreeBind=
+Group=
+IOAccounting=
+IODeviceLatencyTargetSec=
+IODeviceWeight=
+IOReadBandwidthMax=
+IOReadIOPSMax=
+IOSchedulingClass=
+IOSchedulingPriority=
+IOWeight=
+IOWriteBandwidthMax=
+IOWriteIOPSMax=
+IPAccounting=
+IPAddressAllow=
+IPAddressDeny=
+IPCNamespacePath=
+IPEgressFilterPath=
+IPIngressFilterPath=
+IPTOS=
+IPTTL=
+IgnoreSIGPIPE=
+InaccessibleDirectories=
+InaccessiblePaths=
+KeepAlive=
+KeepAliveIntervalSec=
+KeepAliveProbes=
+KeepAliveTimeSec=
+KeyringMode=
+KillMode=
+KillSignal=
+LimitAS=
+LimitCORE=
+LimitCPU=
+LimitDATA=
+LimitFSIZE=
+LimitLOCKS=
+LimitMEMLOCK=
+LimitMSGQUEUE=
+LimitNICE=
+LimitNOFILE=
+LimitNPROC=
+LimitRSS=
+LimitRTPRIO=
+LimitRTTIME=
+LimitSIGPENDING=
+LimitSTACK=
+ListenDatagram=
+ListenFIFO=
+ListenMessageQueue=
+ListenNetlink=
+ListenSequentialPacket=
+ListenSpecial=
+ListenStream=
+ListenUSBFunction=
+LoadCredential=
+LockPersonality=
+LogExtraFields=
+LogLevelMax=
+LogNamespace=
+LogRateLimitBurst=
+LogRateLimitIntervalSec=
+LogsDirectory=
+LogsDirectoryMode=
+ManagedOOMMemoryPressure=
+ManagedOOMMemoryPressureLimit=
+ManagedOOMPreference=
+ManagedOOMSwap=
+Mark=
+MaxConnections=
+MaxConnectionsPerSource=
+MemoryAccounting=
+MemoryDenyWriteExecute=
+MemoryHigh=
+MemoryLimit=
+MemoryLow=
+MemoryMax=
+MemoryMin=
+MemorySwapMax=
+MessageQueueMaxMessages=
+MessageQueueMessageSize=
+MountAPIVFS=
+MountFlags=
+MountImages=
+NUMAMask=
+NUMAPolicy=
+NetClass=
+NetworkNamespacePath=
+Nice=
+NoDelay=
+NoExecPaths=
+NoNewPrivileges=
+OOMScoreAdjust=
+PAMName=
+PassCredentials=
+PassEnvironment=
+PassPacketInfo=
+PassSecurity=
+Personality=
+PipeSize=
+Priority=
+PrivateDevices=
+PrivateIPC=
+PrivateMounts=
+PrivateNetwork=
+PrivateTmp=
+PrivateUsers=
+ProcSubset=
+ProtectClock=
+ProtectControlGroups=
+ProtectHome=
+ProtectHostname=
+ProtectKernelLogs=
+ProtectKernelModules=
+ProtectKernelTunables=
+ProtectProc=
+ProtectSystem=
+ReadOnlyDirectories=
+ReadOnlyPaths=
+ReadWriteDirectories=
+ReadWritePaths=
+ReceiveBuffer=
+RemoveIPC=
+RemoveOnStop=
+RestartKillSignal=
+RestrictAddressFamilies=
+RestrictNamespaces=
+RestrictRealtime=
+RestrictSUIDSGID=
+ReusePort=
+RootDirectory=
+RootHash=
+RootHashSignature=
+RootImage=
+RootImageOptions=
+RootVerity=
+RuntimeDirectory=
+RuntimeDirectoryMode=
+RuntimeDirectoryPreserve=
+SELinuxContext=
+SELinuxContextFromNet=
+SecureBits=
+SendBuffer=
+SendSIGHUP=
+SendSIGKILL=
+Service=
+SetCredential=
+Slice=
+SmackLabel=
+SmackLabelIPIn=
+SmackLabelIPOut=
+SmackProcessLabel=
+SocketGroup=
+SocketMode=
+SocketProtocol=
+SocketUser=
+StandardError=
+StandardInput=
+StandardInputData=
+StandardInputText=
+StandardOutput=
+StartupBlockIOWeight=
+StartupCPUShares=
+StartupCPUWeight=
+StartupIOWeight=
+StateDirectory=
+StateDirectoryMode=
+SupplementaryGroups=
+Symlinks=
+SyslogFacility=
+SyslogIdentifier=
+SyslogLevel=
+SyslogLevelPrefix=
+SystemCallArchitectures=
+SystemCallErrorNumber=
+SystemCallFilter=
+SystemCallLog=
+TCPCongestion=
+TTYPath=
+TTYReset=
+TTYVHangup=
+TTYVTDisallocate=
+TasksAccounting=
+TasksMax=
+TemporaryFileSystem=
+TimeoutCleanSec=
+TimeoutSec=
+TimerSlackNSec=
+Timestamping=
+Transparent=
+TriggerLimitBurst=
+TriggerLimitIntervalSec=
+UMask=
+UnsetEnvironment=
+User=
+UtmpIdentifier=
+UtmpMode=
+WatchdogSignal=
+WorkingDirectory=
+Writable=
diff --git a/test/fuzz/fuzz-unit-file/directives.swap b/test/fuzz/fuzz-unit-file/directives.swap
new file mode 100644 (file)
index 0000000..c3b63aa
--- /dev/null
@@ -0,0 +1,198 @@
+swap
+[Swap]
+AllowedCPUs=
+AllowedMemoryNodes=
+AmbientCapabilities=
+AppArmorProfile=
+BPFProgram=
+BindPaths=
+BindReadOnlyPaths=
+BlockIOAccounting=
+BlockIODeviceWeight=
+BlockIOReadBandwidth=
+BlockIOWeight=
+BlockIOWriteBandwidth=
+CPUAccounting=
+CPUAffinity=
+CPUQuota=
+CPUQuotaPeriodSec=
+CPUSchedulingPolicy=
+CPUSchedulingPriority=
+CPUSchedulingResetOnFork=
+CPUShares=
+CPUWeight=
+CacheDirectory=
+CacheDirectoryMode=
+Capabilities=
+CapabilityBoundingSet=
+ConfigurationDirectory=
+ConfigurationDirectoryMode=
+CoredumpFilter=
+DefaultMemoryLow=
+DefaultMemoryMin=
+Delegate=
+DeviceAllow=
+DevicePolicy=
+DisableControllers=
+DynamicUser=
+Environment=
+EnvironmentFile=
+ExecPaths=
+ExtensionImages=
+FinalKillSignal=
+Group=
+IOAccounting=
+IODeviceLatencyTargetSec=
+IODeviceWeight=
+IOReadBandwidthMax=
+IOReadIOPSMax=
+IOSchedulingClass=
+IOSchedulingPriority=
+IOWeight=
+IOWriteBandwidthMax=
+IOWriteIOPSMax=
+IPAccounting=
+IPAddressAllow=
+IPAddressDeny=
+IPCNamespacePath=
+IPEgressFilterPath=
+IPIngressFilterPath=
+IgnoreSIGPIPE=
+InaccessibleDirectories=
+InaccessiblePaths=
+KeyringMode=
+KillMode=
+KillSignal=
+LimitAS=
+LimitCORE=
+LimitCPU=
+LimitDATA=
+LimitFSIZE=
+LimitLOCKS=
+LimitMEMLOCK=
+LimitMSGQUEUE=
+LimitNICE=
+LimitNOFILE=
+LimitNPROC=
+LimitRSS=
+LimitRTPRIO=
+LimitRTTIME=
+LimitSIGPENDING=
+LimitSTACK=
+LoadCredential=
+LockPersonality=
+LogExtraFields=
+LogLevelMax=
+LogNamespace=
+LogRateLimitBurst=
+LogRateLimitIntervalSec=
+LogsDirectory=
+LogsDirectoryMode=
+ManagedOOMMemoryPressure=
+ManagedOOMMemoryPressureLimit=
+ManagedOOMPreference=
+ManagedOOMSwap=
+MemoryAccounting=
+MemoryDenyWriteExecute=
+MemoryHigh=
+MemoryLimit=
+MemoryLow=
+MemoryMax=
+MemoryMin=
+MemorySwapMax=
+MountAPIVFS=
+MountFlags=
+MountImages=
+NUMAMask=
+NUMAPolicy=
+NetClass=
+NetworkNamespacePath=
+Nice=
+NoExecPaths=
+NoNewPrivileges=
+OOMScoreAdjust=
+Options=
+PAMName=
+PassEnvironment=
+Personality=
+Priority=
+PrivateDevices=
+PrivateIPC=
+PrivateMounts=
+PrivateNetwork=
+PrivateTmp=
+PrivateUsers=
+ProcSubset=
+ProtectClock=
+ProtectControlGroups=
+ProtectHome=
+ProtectHostname=
+ProtectKernelLogs=
+ProtectKernelModules=
+ProtectKernelTunables=
+ProtectProc=
+ProtectSystem=
+ReadOnlyDirectories=
+ReadOnlyPaths=
+ReadWriteDirectories=
+ReadWritePaths=
+RemoveIPC=
+RestartKillSignal=
+RestrictAddressFamilies=
+RestrictNamespaces=
+RestrictRealtime=
+RestrictSUIDSGID=
+RootDirectory=
+RootHash=
+RootHashSignature=
+RootImage=
+RootImageOptions=
+RootVerity=
+RuntimeDirectory=
+RuntimeDirectoryMode=
+RuntimeDirectoryPreserve=
+SELinuxContext=
+SecureBits=
+SendSIGHUP=
+SendSIGKILL=
+SetCredential=
+Slice=
+SmackProcessLabel=
+StandardError=
+StandardInput=
+StandardInputData=
+StandardInputText=
+StandardOutput=
+StartupBlockIOWeight=
+StartupCPUShares=
+StartupCPUWeight=
+StartupIOWeight=
+StateDirectory=
+StateDirectoryMode=
+SupplementaryGroups=
+SyslogFacility=
+SyslogIdentifier=
+SyslogLevel=
+SyslogLevelPrefix=
+SystemCallArchitectures=
+SystemCallErrorNumber=
+SystemCallFilter=
+SystemCallLog=
+TTYPath=
+TTYReset=
+TTYVHangup=
+TTYVTDisallocate=
+TasksAccounting=
+TasksMax=
+TemporaryFileSystem=
+TimeoutCleanSec=
+TimeoutSec=
+TimerSlackNSec=
+UMask=
+UnsetEnvironment=
+User=
+UtmpIdentifier=
+UtmpMode=
+WatchdogSignal=
+What=
+WorkingDirectory=
diff --git a/test/fuzz/fuzz-unit-file/directives.timer b/test/fuzz/fuzz-unit-file/directives.timer
new file mode 100644 (file)
index 0000000..40075cf
--- /dev/null
@@ -0,0 +1,17 @@
+timer
+[Timer]
+AccuracySec=
+FixedRandomDelay=
+OnActiveSec=
+OnBootSec=
+OnCalendar=
+OnClockChange=
+OnStartupSec=
+OnTimezoneChange=
+OnUnitActiveSec=
+OnUnitInactiveSec=
+Persistent=
+RandomizedDelaySec=
+RemainAfterElapse=
+Unit=
+WakeSystem=
diff --git a/test/fuzz/fuzz-unit-file/github-19178 b/test/fuzz/fuzz-unit-file/github-19178
new file mode 100644 (file)
index 0000000..982c344
--- /dev/null
@@ -0,0 +1,3 @@
+service
+[Service]
+LoadCredential=passwd.hashed-password.root
diff --git a/test/fuzz/fuzz-unit-file/oss-fuzz-32991 b/test/fuzz/fuzz-unit-file/oss-fuzz-32991
new file mode 100644 (file)
index 0000000..6305b2a
Binary files /dev/null and b/test/fuzz/fuzz-unit-file/oss-fuzz-32991 differ
index 8983bb056b23457d6ff0891ab5f44f86f1d690ac..2118bfc2a661c0f022f2489b007f9b23a740a7a1 100644 (file)
@@ -2,8 +2,8 @@
 Description=Test for StandardOutput=append:
 
 [Service]
-ExecStartPre=sh -c 'printf "hello\n" > /tmp/test-exec-standardoutput-output'
-ExecStartPre=sh -c 'printf "hello\nhello\n" > /tmp/test-exec-standardoutput-expected'
+ExecStartPre=sh -c 'printf "hello\n" >/tmp/test-exec-standardoutput-output'
+ExecStartPre=sh -c 'printf "hello\nhello\n" >/tmp/test-exec-standardoutput-expected'
 StandardInput=data
 StandardInputText=hello
 StandardOutput=append:/tmp/test-exec-standardoutput-output
index 71e2604b942ca26b8a742e7e6dd42036a9a4d140..8d484a456e6b4eec1901de9b9969b213d329d067 100644 (file)
@@ -2,8 +2,8 @@
 Description=Test for StandardOutput=file:
 
 [Service]
-ExecStartPre=sh -c 'printf "nooo\nhello\n" > /tmp/test-exec-standardoutput-output'
-ExecStartPre=sh -c 'printf "hello\nello\n" > /tmp/test-exec-standardoutput-expected'
+ExecStartPre=sh -c 'printf "nooo\nhello\n" >/tmp/test-exec-standardoutput-output'
+ExecStartPre=sh -c 'printf "hello\nello\n" >/tmp/test-exec-standardoutput-expected'
 StandardInput=data
 StandardInputText=hello
 StandardOutput=file:/tmp/test-exec-standardoutput-output
index 4b4bb87b758bb97a4ba2ba68fe58ee8c05dfe313..8d6ea2769fed3fa9e80db45a8fe04eb0a608fb9e 100644 (file)
@@ -2,8 +2,8 @@
 Description=Test for StandardOutput=truncate:
 
 [Service]
-ExecStartPre=sh -c 'printf "hello\n" > /tmp/test-exec-standardoutput-output'
-ExecStartPre=sh -c 'printf "hi\n" > /tmp/test-exec-standardoutput-expected'
+ExecStartPre=sh -c 'printf "hello\n" >/tmp/test-exec-standardoutput-output'
+ExecStartPre=sh -c 'printf "hi\n" >/tmp/test-exec-standardoutput-expected'
 StandardInput=data
 StandardInputText=hi
 StandardOutput=truncate:/tmp/test-exec-standardoutput-output
index 6b94058fd366a989544f5acf97b1406d70162389..063a6096fdcdd0df36365910088a265b4a0a7fd5 100644 (file)
@@ -503,13 +503,13 @@ install_verity_minimal() {
         ln -s ../usr/lib/os-release $initdir/etc/os-release
         touch $initdir/etc/machine-id $initdir/etc/resolv.conf
         touch $initdir/opt/some_file
-        echo MARKER=1 >> $initdir/usr/lib/os-release
-        echo -e "[Service]\nExecStartPre=cat /usr/lib/os-release\nExecStart=sleep 120" > $initdir/usr/lib/systemd/system/app0.service
+        echo MARKER=1 >>$initdir/usr/lib/os-release
+        echo -e "[Service]\nExecStartPre=cat /usr/lib/os-release\nExecStart=sleep 120" >$initdir/usr/lib/systemd/system/app0.service
         cp $initdir/usr/lib/systemd/system/app0.service $initdir/usr/lib/systemd/system/app0-foo.service
 
         mksquashfs $initdir $oldinitdir/usr/share/minimal_0.raw
         veritysetup format $oldinitdir/usr/share/minimal_0.raw $oldinitdir/usr/share/minimal_0.verity | \
-            grep '^Root hash:' | cut -f2 | tr -d '\n' > $oldinitdir/usr/share/minimal_0.roothash
+            grep '^Root hash:' | cut -f2 | tr -d '\n' >$oldinitdir/usr/share/minimal_0.roothash
 
         sed -i "s/MARKER=1/MARKER=2/g" $initdir/usr/lib/os-release
         rm $initdir/usr/lib/systemd/system/app0-foo.service
@@ -517,7 +517,7 @@ install_verity_minimal() {
 
         mksquashfs $initdir $oldinitdir/usr/share/minimal_1.raw
         veritysetup format $oldinitdir/usr/share/minimal_1.raw $oldinitdir/usr/share/minimal_1.verity | \
-            grep '^Root hash:' | cut -f2 | tr -d '\n' > $oldinitdir/usr/share/minimal_1.roothash
+            grep '^Root hash:' | cut -f2 | tr -d '\n' >$oldinitdir/usr/share/minimal_1.roothash
 
         # Rolling distros like Arch do not set VERSION_ID
         local version_id=""
@@ -527,42 +527,42 @@ install_verity_minimal() {
 
         export initdir=$TESTDIR/app0
         mkdir -p $initdir/usr/lib/extension-release.d $initdir/usr/lib/systemd/system $initdir/opt
-        grep "^ID=" $os_release > $initdir/usr/lib/extension-release.d/extension-release.app0
-        echo "${version_id}" >> $initdir/usr/lib/extension-release.d/extension-release.app0
-        cat <<EOF > $initdir/usr/lib/systemd/system/app0.service
+        grep "^ID=" $os_release >$initdir/usr/lib/extension-release.d/extension-release.app0
+        echo "${version_id}" >>$initdir/usr/lib/extension-release.d/extension-release.app0
+        cat <<EOF >$initdir/usr/lib/systemd/system/app0.service
 [Service]
 Type=oneshot
 RemainAfterExit=yes
 ExecStart=/opt/script0.sh
 EOF
-        cat <<EOF > $initdir/opt/script0.sh
+        cat <<EOF >$initdir/opt/script0.sh
 #!/bin/bash
 set -e
 test -e /usr/lib/os-release
 cat /usr/lib/extension-release.d/extension-release.app0
 EOF
         chmod +x $initdir/opt/script0.sh
-        echo MARKER=1 > $initdir/usr/lib/systemd/system/some_file
+        echo MARKER=1 >$initdir/usr/lib/systemd/system/some_file
         mksquashfs $initdir $oldinitdir/usr/share/app0.raw
 
         export initdir=$TESTDIR/app1
         mkdir -p $initdir/usr/lib/extension-release.d $initdir/usr/lib/systemd/system $initdir/opt
-        grep "^ID=" $os_release > $initdir/usr/lib/extension-release.d/extension-release.app1
-        echo "${version_id}" >> $initdir/usr/lib/extension-release.d/extension-release.app1
-        cat <<EOF > $initdir/usr/lib/systemd/system/app1.service
+        grep "^ID=" $os_release >$initdir/usr/lib/extension-release.d/extension-release.app1
+        echo "${version_id}" >>$initdir/usr/lib/extension-release.d/extension-release.app1
+        cat <<EOF >$initdir/usr/lib/systemd/system/app1.service
 [Service]
 Type=oneshot
 RemainAfterExit=yes
 ExecStart=/opt/script1.sh
 EOF
-        cat <<EOF > $initdir/opt/script1.sh
+        cat <<EOF >$initdir/opt/script1.sh
 #!/bin/bash
 set -e
 test -e /usr/lib/os-release
 cat /usr/lib/extension-release.d/extension-release.app1
 EOF
         chmod +x $initdir/opt/script1.sh
-        echo MARKER=1 > $initdir/usr/lib/systemd/system/other_file
+        echo MARKER=1 >$initdir/usr/lib/systemd/system/other_file
         mksquashfs $initdir $oldinitdir/usr/share/app1.raw
     )
 }
@@ -700,7 +700,7 @@ if [[ "$ASAN_COMPILER" == "clang" ]]; then
   # Let's add the ASan DSO's path to the dynamic linker's cache. This is pretty
   # unnecessary for gcc & libasan, however, for clang this is crucial, as its
   # runtime ASan DSO is in a non-standard (library) path.
-  echo "${ASAN_RT_PATH%/*}" > /etc/ld.so.conf.d/asan-path-override.conf
+  echo "${ASAN_RT_PATH%/*}" >/etc/ld.so.conf.d/asan-path-override.conf
   ldconfig
 fi
 echo DefaultEnvironment=\$DEFAULT_ENVIRONMENT >>/etc/systemd/system.conf
@@ -741,7 +741,7 @@ printf "[Service]\nEnvironment=ASAN_OPTIONS=leak_check_at_exit=false\n" >/etc/sy
 # they're uninstrumented (like dmsetup). Let's add a simple rule which sets
 # LD_PRELOAD to the ASan RT library to fix this.
 mkdir -p /etc/udev/rules.d
-cat > /etc/udev/rules.d/00-set-LD_PRELOAD.rules << INNER_EOF
+cat >/etc/udev/rules.d/00-set-LD_PRELOAD.rules <<INNER_EOF
 SUBSYSTEM=="block", ENV{LD_PRELOAD}="$ASAN_RT_PATH"
 INNER_EOF
 chmod 0644 /etc/udev/rules.d/00-set-LD_PRELOAD.rules
@@ -856,9 +856,9 @@ install_systemd() {
     [[ "$LOOKS_LIKE_SUSE" ]] && setup_suse
 
     # enable debug logging in PID1
-    echo LogLevel=debug >> $initdir/etc/systemd/system.conf
+    echo LogLevel=debug >>$initdir/etc/systemd/system.conf
     # store coredumps in journal
-    echo Storage=journal >> $initdir/etc/systemd/coredump.conf
+    echo Storage=journal >>$initdir/etc/systemd/coredump.conf
 }
 
 get_ldpath() {
@@ -1174,12 +1174,12 @@ install_config_files() {
     inst_any /etc/os-release /usr/lib/os-release
     inst /etc/localtime
     # we want an empty environment
-    > $initdir/etc/environment
-    > $initdir/etc/machine-id
-    > $initdir/etc/resolv.conf
+    >$initdir/etc/environment
+    >$initdir/etc/machine-id
+    >$initdir/etc/resolv.conf
 
     # set the hostname
-    echo systemd-testsuite > $initdir/etc/hostname
+    echo systemd-testsuite >$initdir/etc/hostname
 
     # let's set up just one image with the traditional verbose output
     if [ ${IMAGE_NAME} != "basic" ]; then
@@ -1202,9 +1202,9 @@ install_debug_tools() {
         # Set default TERM from vt220 to linux, so at least basic key shortcuts work
         local _getty_override="$initdir/etc/systemd/system/serial-getty@.service.d"
         mkdir -p "$_getty_override"
-        echo -e "[Service]\nEnvironment=TERM=linux" > "$_getty_override/default-TERM.conf"
+        echo -e "[Service]\nEnvironment=TERM=linux" >"$_getty_override/default-TERM.conf"
 
-        cat > "$initdir/etc/motd" << EOF
+        cat >"$initdir/etc/motd" <<EOF
 To adjust the terminal size use:
     export COLUMNS=xx
     export LINES=yy
@@ -1246,7 +1246,7 @@ install_dbus() {
 
     # setup policy for Type=dbus test
     mkdir -p $initdir/etc/dbus-1/system.d
-    cat > $initdir/etc/dbus-1/system.d/systemd.test.ExecStopPost.conf <<EOF
+    cat >$initdir/etc/dbus-1/system.d/systemd.test.ExecStopPost.conf <<EOF
 <?xml version="1.0"?>
 <!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
         "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
@@ -1987,7 +1987,7 @@ install_kmod_with_fw() {
     fi
 
     [ -d "$initdir/.kernelmodseen" ] && \
-        > "$initdir/.kernelmodseen/${1##*/}"
+        >"$initdir/.kernelmodseen/${1##*/}"
 
     inst_simple "$1" "/lib/modules/$KERNEL_VER/${1##*/lib/modules/$KERNEL_VER/}" \
         || return $?
@@ -2059,11 +2059,11 @@ filter_kernel_modules_by_path () (
     for _modname in $(eval $_filtercmd); do
         case $_modname in
             *.ko) "$2" "$_modname" && echo "$_modname";;
-            *.ko.gz) gzip -dc "$_modname" > $initdir/$$.ko
+            *.ko.gz) gzip -dc "$_modname" >$initdir/$$.ko
                 $2 $initdir/$$.ko && echo "$_modname"
                 rm -f $initdir/$$.ko
                 ;;
-            *.ko.xz) xz -dc "$_modname" > $initdir/$$.ko
+            *.ko.xz) xz -dc "$_modname" >$initdir/$$.ko
                 $2 $initdir/$$.ko && echo "$_modname"
                 rm -f $initdir/$$.ko
                 ;;
@@ -2276,7 +2276,7 @@ test_setup() {
         fi
 
         local hook_defined=1
-        if declare -f -F test_append_files > /dev/null; then
+        if declare -f -F test_append_files >/dev/null; then
             hook_defined=$?
         fi
 
index facf5577be10ba31d8e5887c6b8eb1b648bf6880..766a454d6a2e66aec54c5b61b23c385243067893 100644 (file)
@@ -7,4 +7,4 @@ After=testsuite-28-pre.service
 [Service]
 Type=oneshot
 ExecStart=test -f /tmp/test-specifier-j-%j
-ExecStart=sh -c 'echo OK > /testok'
+ExecStart=sh -c 'echo OK >/testok'
index 9cccf1b6c161ec5199a69cb14f19ab13cc4997fa..e10bf561105d400d52dd90426c631048c9920aa4 100755 (executable)
@@ -3,7 +3,7 @@ set -ex
 set -o pipefail
 
 if ! test -x /usr/lib/systemd/tests/testdata/units/test-honor-first-shutdown.sh ; then
-        echo "honor-first-shutdown script not found - FAIL" > /testok
+        echo "honor-first-shutdown script not found - FAIL" >/testok
         exit 0
 fi
 
@@ -13,6 +13,6 @@ systemd-analyze log-target console
 systemctl enable test-honor-first-shutdown.service
 systemctl start test-honor-first-shutdown.service
 
-echo OK > /testok
+echo OK >/testok
 
 exit 0
index 85efeeb741c3428736606145841984f1f569ccb6..5a2dadd6b83d73e8759f63c0253717aae2de1ecf 100755 (executable)
@@ -6,9 +6,9 @@ set -ex
 
 systemctl start --no-block hello-after-sleep.target
 
-systemctl list-jobs > /root/list-jobs.txt
+systemctl list-jobs >/root/list-jobs.txt
 while ! grep 'sleep\.service.*running' /root/list-jobs.txt; do
-    systemctl list-jobs > /root/list-jobs.txt
+    systemctl list-jobs >/root/list-jobs.txt
 done
 
 grep 'hello\.service.*waiting' /root/list-jobs.txt
@@ -19,20 +19,20 @@ systemctl start --job-mode=ignore-dependencies hello
 END_SEC=$(date -u '+%s')
 ELAPSED=$(($END_SEC-$START_SEC))
 
-[ "$ELAPSED" -lt 3 ]
+test "$ELAPSED" -lt 3
 
 # sleep should still be running, hello not.
-systemctl list-jobs > /root/list-jobs.txt
+systemctl list-jobs >/root/list-jobs.txt
 grep 'sleep\.service.*running' /root/list-jobs.txt
 grep 'hello\.service' /root/list-jobs.txt && exit 1
 systemctl stop sleep.service hello-after-sleep.target
 
 # Some basic testing that --show-transaction does something useful
-! systemctl is-active systemd-importd
+systemctl is-active systemd-importd && { echo 'unexpected success'; exit 1; }
 systemctl -T start systemd-importd
 systemctl is-active systemd-importd
 systemctl --show-transaction stop systemd-importd
-! systemctl is-active systemd-importd
+systemctl is-active systemd-importd && { echo 'unexpected success'; exit 1; }
 
 # Test for a crash when enqueuing a JOB_NOP when other job already exists
 systemctl start --no-block hello-after-sleep.target
@@ -58,13 +58,13 @@ systemctl stop --job-mode=replace-irreversibly unstoppable.service
 systemctl start unstoppable.service
 
 # Test waiting for a started unit(s) to terminate again
-cat <<EOF >  /run/systemd/system/wait2.service
+cat <<EOF >/run/systemd/system/wait2.service
 [Unit]
 Description=Wait for 2 seconds
 [Service]
 ExecStart=/bin/sh -ec 'sleep 2'
 EOF
-cat <<EOF >  /run/systemd/system/wait5fail.service
+cat <<EOF >/run/systemd/system/wait5fail.service
 [Unit]
 Description=Wait for 5 seconds and fail
 [Service]
@@ -80,7 +80,7 @@ ELAPSED=$(($END_SEC-$START_SEC))
 
 # wait5fail fails, so systemctl should fail
 START_SEC=$(date -u '+%s')
-! systemctl start --wait wait2.service wait5fail.service || exit 1
+systemctl start --wait wait2.service wait5fail.service && { echo 'unexpected success'; exit 1; }
 END_SEC=$(date -u '+%s')
 ELAPSED=$(($END_SEC-$START_SEC))
 [[ "$ELAPSED" -ge 5 ]] && [[ "$ELAPSED" -le 7 ]] || exit 1
index 3dce73b778250854dbde499123242101931540c5..a2a1292380818f67c726472a1e325856778eed83 100755 (executable)
@@ -59,19 +59,19 @@ journalctl -b -o export --output-fields=MESSAGE,FOO --output-fields=PRIORITY,MES
 grep -q '^__CURSOR=' /output
 grep -q '^MESSAGE=foo$' /output
 grep -q '^PRIORITY=6$' /output
-! grep -q '^FOO=' /output
-! grep -q '^SYSLOG_FACILITY=' /output
+grep '^FOO=' /output && { echo 'unexpected success'; exit 1; }
+grep '^SYSLOG_FACILITY=' /output && { echo 'unexpected success'; exit 1; }
 
 # `-b all` negates earlier use of -b (-b and -m are otherwise exclusive)
-journalctl -b -1 -b all -m > /dev/null
+journalctl -b -1 -b all -m >/dev/null
 
 # -b always behaves like -b0
-journalctl -q -b-1 -b0 | head -1 > /expected
-journalctl -q -b-1 -b  | head -1 > /output
+journalctl -q -b-1 -b0 | head -1 >/expected
+journalctl -q -b-1 -b  | head -1 >/output
 cmp /expected /output
 # ... even when another option follows (both of these should fail due to -m)
-{ journalctl -ball -b0 -m 2>&1 || :; } | head -1 > /expected
-{ journalctl -ball -b  -m 2>&1 || :; } | head -1 > /output
+{ journalctl -ball -b0 -m 2>&1 || :; } | head -1 >/expected
+{ journalctl -ball -b  -m 2>&1 || :; } | head -1 >/output
 cmp /expected /output
 
 # https://github.com/systemd/systemd/issues/13708
index b5888a255bca165f8dd94917342987a19f2e2d3a..7e7b0ec25a0f9566989f0023204a66376c0bec17 100755 (executable)
@@ -14,7 +14,7 @@ SocketGroup=adm
 SocketMode=0660
 EOF
 
-cat <<'EOF' > /run/systemd/system/test12@.service
+cat <<'EOF' >/run/systemd/system/test12@.service
 [Unit]
 Description=Test service
 [Service]
index 1844323d2f17f40ac5e339f1190a4ef9be71fd6c..3e66aa9d547db6ad3bac36e890c6b6fcf770703c 100755 (executable)
@@ -51,9 +51,9 @@ function check_norbind {
     local _root="/var/lib/machines/testsuite-13.norbind-path"
     rm -rf "$_root"
     mkdir -p /tmp/binddir/subdir
-    echo -n "outer" > /tmp/binddir/subdir/file
+    echo -n "outer" >/tmp/binddir/subdir/file
     mount -t tmpfs tmpfs /tmp/binddir/subdir
-    echo -n "inner" > /tmp/binddir/subdir/file
+    echo -n "inner" >/tmp/binddir/subdir/file
     /usr/lib/systemd/tests/testdata/create-busybox-container "$_root"
     systemd-nspawn $SUSE_OPTS--register=no -D "$_root" --bind=/tmp/binddir:/mnt:norbind /bin/sh -c 'CONTENT=$(cat /mnt/subdir/file); if [[ $CONTENT != "outer" ]]; then echo "*** unexpected content: $CONTENT"; return 1; fi'
 }
@@ -73,7 +73,7 @@ if [ -n "${VERSION_ID:+set}" ] && [ "${VERSION_ID}" != "${container_host_version
 if [ -n "${BUILD_ID:+set}" ] && [ "${BUILD_ID}" != "${container_host_build_id}" ]; then exit 1; fi
 if [ -n "${VARIANT_ID:+set}" ] && [ "${VARIANT_ID}" != "${container_host_variant_id}" ]; then exit 1; fi
 cd /tmp; (cd /run/host; md5sum os-release) | md5sum -c
-if echo test >> /run/host/os-release; then exit 1; fi
+if echo test >>/run/host/os-release; then exit 1; fi
 '
 
     local _os_release_source="/etc/os-release"
@@ -82,7 +82,7 @@ if echo test >> /run/host/os-release; then exit 1; fi
     elif [ -L "${_os_release_source}" ] && rm /etc/os-release; then
         # Ensure that /etc always wins if available
         cp /usr/lib/os-release /etc
-        echo MARKER=1 >> /etc/os-release
+        echo MARKER=1 >>/etc/os-release
     fi
 
     systemd-nspawn $SUSE_OPTS--register=no -D /testsuite-13.nc-container --bind="${_os_release_source}":/tmp/os-release /bin/sh -x -e -c "$_cmd"
@@ -96,7 +96,7 @@ if echo test >> /run/host/os-release; then exit 1; fi
 function check_machinectl_bind {
     local _cmd='for i in $(seq 1 20); do if test -f /tmp/marker; then exit 0; fi; sleep 0.5; done; exit 1;'
 
-    cat <<EOF > /run/systemd/system/nspawn_machinectl_bind.service
+    cat <<EOF >/run/systemd/system/nspawn_machinectl_bind.service
 [Service]
 Type=notify
 ExecStart=systemd-nspawn $SUSE_OPTS -D /testsuite-13.nc-container --notify-ready=no /bin/sh -x -e -c "$_cmd"
index 23a39bf09014cd1721a25b83c88d9cda0940dce7..fc392c584dcff186f5ce90c7d51000a9e22ac857 100755 (executable)
@@ -165,7 +165,7 @@ test_hierarchical_dropins () {
         echo "
 [Service]
 ExecCondition=/bin/echo $dropin
-        " > /usr/lib/systemd/system/$dropin/override.conf
+        " >/usr/lib/systemd/system/$dropin/override.conf
         systemctl daemon-reload
         check_ok a-b-c ExecCondition "/bin/echo $dropin"
     done
index 573ad4107916b84ce20b2658fc3c1011c83f4271..8be27d95073e627ea150bbc0a006daeefb6b158b 100755 (executable)
@@ -19,7 +19,7 @@ while : ; do
     sleep .5
 done
 
-cat > /run/udev/rules.d/50-testsuite.rules <<EOF
+cat >/run/udev/rules.d/50-testsuite.rules <<EOF
 ACTION!="remove", SUBSYSTEM=="block", KERNEL=="sda", ENV{SYSTEMD_WANTS}="foobar.service"
 EOF
 udevadm control --reload
@@ -36,7 +36,7 @@ while : ; do
     sleep .5
 done
 
-cat > /run/udev/rules.d/50-testsuite.rules <<EOF
+cat >/run/udev/rules.d/50-testsuite.rules <<EOF
 ACTION!="remove", SUBSYSTEM=="block", KERNEL=="sda", ENV{SYSTEMD_WANTS}="waldo.service"
 EOF
 udevadm control --reload
index c21fcc781b29af7ed8387103d6059510e9decc7f..5c77ab4b6a12861fe610b7c39e6d8a9680a7b67a 100755 (executable)
@@ -4,7 +4,7 @@ set -o pipefail
 
 mkdir -p /run/udev/rules.d/
 
-cat > /run/udev/rules.d/50-testsuite.rules <<EOF
+cat >/run/udev/rules.d/50-testsuite.rules <<EOF
 ACTION=="remove", GOTO="lo_end"
 
 SUBSYSTEM=="net", KERNEL=="lo", TAG+="systemd", ENV{SYSTEMD_ALIAS}+="/sys/subsystem/net/devices/lo"
index 02ac2176b5ad944d3367a3222cd0fb63ecc50689..e5178ce554371c32b302ec24f6cb025367e2ea31 100755 (executable)
@@ -7,9 +7,9 @@ test_rule="/run/udev/rules.d/49-test.rules"
 setup() {
     mkdir -p "${test_rule%/*}"
     cp -f /etc/udev/udev.conf /etc/udev/udev.conf.bckp
-    echo 'KERNEL=="lo", SUBSYSTEM=="net", PROGRAM=="/bin/sleep 60"' > "${test_rule}"
-    echo "event_timeout=30" >> /etc/udev/udev.conf
-    echo "timeout_signal=SIGABRT" >> /etc/udev/udev.conf
+    echo 'KERNEL=="lo", SUBSYSTEM=="net", PROGRAM=="/bin/sleep 60"' >"${test_rule}"
+    echo "event_timeout=30" >>/etc/udev/udev.conf
+    echo "timeout_signal=SIGABRT" >>/etc/udev/udev.conf
 
     systemctl restart systemd-udevd.service
 }
@@ -25,7 +25,7 @@ teardown() {
 run_test() {
     since="$(date +%T)"
 
-    echo add > /sys/class/net/lo/uevent
+    echo add >/sys/class/net/lo/uevent
 
     for n in {1..20}; do
         sleep 5
index c799936c0a3b04c61e1f1788f1d83aeba16d39e4..b33d47ef6de315b0cb1641811ea8e96910384780 100755 (executable)
@@ -4,14 +4,11 @@ set -o pipefail
 
 mkdir -p /run/udev/rules.d/
 
-! test -f /run/udev/tags/added/c1:3 &&
-    ! test -f /run/udev/tags/changed/c1:3 &&
-    udevadm info /dev/null | grep -q -v 'E: TAGS=.*:added:.*' &&
-    udevadm info /dev/null | grep -q -v 'E: CURRENT_TAGS=.*:added:.*' &&
-    udevadm info /dev/null | grep -q -v 'E: TAGS=.*:changed:.*' &&
-    udevadm info /dev/null | grep -q -v 'E: CURRENT_TAGS=.*:changed:.*'
+test ! -f /run/udev/tags/added/c1:3
+test ! -f /run/udev/tags/changed/c1:3
+udevadm info /dev/null | grep -E 'E: (TAGS|CURRENT_TAGS)=.*:(added|changed):' && exit 1
 
-cat > /run/udev/rules.d/50-testsuite.rules <<EOF
+cat >/run/udev/rules.d/50-testsuite.rules <<EOF
 ACTION=="add", SUBSYSTEM=="mem", KERNEL=="null", TAG+="added"
 ACTION=="change", SUBSYSTEM=="mem", KERNEL=="null", TAG+="changed"
 EOF
@@ -19,45 +16,39 @@ EOF
 udevadm control --reload
 udevadm trigger -c add /dev/null
 
-while : ; do
-    test -f /run/udev/tags/added/c1:3 &&
-        ! test -f /run/udev/tags/changed/c1:3 &&
-        udevadm info /dev/null | grep -q 'E: TAGS=.*:added:.*' &&
-        udevadm info /dev/null | grep -q 'E: CURRENT_TAGS=.*:added:.*' &&
-        udevadm info /dev/null | grep -q -v 'E: TAGS=.*:changed:.*' &&
-        udevadm info /dev/null | grep -q -v 'E: CURRENT_TAGS=.*:changed:.*' &&
-        break
-
+while   test ! -f /run/udev/tags/added/c1:3 ||
+        test -f /run/udev/tags/changed/c1:3 ||
+        ! udevadm info /dev/null | grep -q 'E: TAGS=.*:added:.*' ||
+        ! udevadm info /dev/null | grep -q 'E: CURRENT_TAGS=.*:added:.*' ||
+        udevadm info /dev/null | grep -q 'E: TAGS=.*:changed:.*' ||
+        udevadm info /dev/null | grep -q 'E: CURRENT_TAGS=.*:changed:.*'
+do
     sleep .5
 done
 
 udevadm control --reload
 udevadm trigger -c change /dev/null
 
-while : ; do
-    test -f /run/udev/tags/added/c1:3 &&
-        test -f /run/udev/tags/changed/c1:3 &&
-        udevadm info /dev/null | grep -q 'E: TAGS=.*:added:.*' &&
-        udevadm info /dev/null | grep -q -v 'E: CURRENT_TAGS=.*:added:.*' &&
-        udevadm info /dev/null | grep -q 'E: TAGS=.*:changed:.*' &&
-        udevadm info /dev/null | grep -q 'E: CURRENT_TAGS=.*:changed:.*' &&
-        break
-
+while   test ! -f /run/udev/tags/added/c1:3 ||
+        test ! -f /run/udev/tags/changed/c1:3 ||
+        ! udevadm info /dev/null | grep -q 'E: TAGS=.*:added:.*' ||
+        udevadm info /dev/null | grep -q 'E: CURRENT_TAGS=.*:added:.*' ||
+        ! udevadm info /dev/null | grep -q 'E: TAGS=.*:changed:.*' ||
+        ! udevadm info /dev/null | grep -q 'E: CURRENT_TAGS=.*:changed:.*'
+do
     sleep .5
 done
 
 udevadm control --reload
 udevadm trigger -c add /dev/null
 
-while : ; do
-    test -f /run/udev/tags/added/c1:3 &&
-        test -f /run/udev/tags/changed/c1:3 &&
-        udevadm info /dev/null | grep -q 'E: TAGS=.*:added:.*' &&
-        udevadm info /dev/null | grep -q 'E: CURRENT_TAGS=.*:added:.*' &&
-        udevadm info /dev/null | grep -q 'E: TAGS=.*:changed:.*' &&
-        udevadm info /dev/null | grep -q -v 'E: CURRENT_TAGS=.*:changed:.*' &&
-        break
-
+while   test ! -f /run/udev/tags/added/c1:3 ||
+        test ! -f /run/udev/tags/changed/c1:3 ||
+        ! udevadm info /dev/null | grep -q 'E: TAGS=.*:added:.*' ||
+        ! udevadm info /dev/null | grep -q 'E: CURRENT_TAGS=.*:added:.*' ||
+        ! udevadm info /dev/null | grep -q 'E: TAGS=.*:changed:.*' ||
+        udevadm info /dev/null | grep -q 'E: CURRENT_TAGS=.*:changed:.*'
+do
     sleep .5
 done
 
index 0991ec9d590d71d26d32284a793b998e2bc4aea5..1e7f7f41b0a5d0de7f4fa95d540e802a7bc0ab1f 100755 (executable)
@@ -4,7 +4,7 @@ set -o pipefail
 
 mkdir -p /run/udev/rules.d/
 
-cat > /run/udev/rules.d/50-testsuite.rules <<EOF
+cat >/run/udev/rules.d/50-testsuite.rules <<EOF
 SUBSYSTEM=="mem", KERNEL=="null", OPTIONS="log_level=debug"
 ACTION=="add", SUBSYSTEM=="mem", KERNEL=="null", IMPORT{program}="/bin/echo -e HOGE=aa\\\\x20\\\\x20\\\\x20bb\nFOO=\\\\x20aaa\\\\x20\n\n\n"
 EOF
index e471cda51b58e46940c25cc6e17757919483c7f1..c4e3ca211081aeadcbc03e601b4fd40b2e5c3883 100755 (executable)
@@ -3,13 +3,13 @@ set -ex
 set -o pipefail
 
 systemd-run --wait -p FailureAction=poweroff true
-! systemd-run --wait -p SuccessAction=poweroff false
+systemd-run --wait -p SuccessAction=poweroff false && { echo 'unexpected success'; exit 1; }
 
 if ! test -f /firstphase ; then
-    echo OK > /firstphase
+    echo OK >/firstphase
     systemd-run --wait -p SuccessAction=reboot true
 else
-    echo OK > /testok
+    echo OK >/testok
     systemd-run --wait -p FailureAction=poweroff false
 fi
 
index 57831c267f6d976237913c2c1229a7fdb1c559d7..dea2f4ba1f7f834863ff75197fe443895bad0360 100755 (executable)
@@ -34,6 +34,6 @@ else
     echo "Skipping TEST-19-DELEGATE, as the kernel doesn't actually support cgroup v2" >&2
 fi
 
-echo OK > /testok
+echo OK >/testok
 
 exit 0
index d94f6b2afbcbbfcb22cc4c89624215ad738eaa46..6003e4f1813be4b865df6efd62be25d9d5b1d196 100755 (executable)
@@ -71,7 +71,7 @@ disown
 sleep infinity &
 disown
 
-echo \$MAINPID > /run/mainpidsh/pid
+echo \$MAINPID >/run/mainpidsh/pid
 EOF
 chmod +x /tmp/test20-mainpid.sh
 
@@ -95,7 +95,7 @@ disown
 sleep infinity &
 disown
 
-echo \$MAINPID > /run/mainpidsh2/pid
+echo \$MAINPID >/run/mainpidsh2/pid
 chown 1001:1001 /run/mainpidsh2/pid
 EOF
 chmod +x /tmp/test20-mainpid2.sh
@@ -126,14 +126,24 @@ test -f /run/mainpidsh3/pid
 EOF
 chmod 755 /dev/shm/test20-mainpid3.sh
 
-# This has to fail, as we shouldn't accept the dangerous PID file, and then inotify-wait on it to be corrected which we never do
-! systemd-run --unit=test20-mainpidsh3.service -p StandardOutput=tty -p StandardError=tty -p Type=forking -p RuntimeDirectory=mainpidsh3 -p PIDFile=/run/mainpidsh3/pid -p DynamicUser=1 -p TimeoutStartSec=2s /dev/shm/test20-mainpid3.sh
+# This has to fail, as we shouldn't accept the dangerous PID file, and then
+# inotify-wait on it to be corrected which we never do.
+systemd-run --unit=test20-mainpidsh3.service \
+            -p StandardOutput=tty \
+            -p StandardError=tty \
+            -p Type=forking \
+            -p RuntimeDirectory=mainpidsh3 \
+            -p PIDFile=/run/mainpidsh3/pid \
+            -p DynamicUser=1 \
+            -p TimeoutStartSec=2s \
+            /dev/shm/test20-mainpid3.sh \
+    && { echo 'unexpected success'; exit 1; }
 
 # Test that this failed due to timeout, and not some other error
-test `systemctl show -P Result test20-mainpidsh3.service` = timeout
+test $(systemctl show -P Result test20-mainpidsh3.service) = timeout
 
 systemd-analyze log-level info
 
-echo OK > /testok
+echo OK >/testok
 
 exit 0
index d233e37fb2177c39cdff4fb86d71fd2ddf621d09..b10b5aaa1aa7c0ce8b999c37475960628ba241ca 100755 (executable)
@@ -10,4 +10,4 @@ rm -fr /tmp/test
 
 echo "e /tmp/test - root root 1d" | systemd-tmpfiles --create -
 
-! test -e /tmp/test
+test ! -e /tmp/test
index d1bf1ea04b9d77c8a12b54443c524a3c45cd3c0e..c337cd6e05b829125d595e0cfa1b137091380a86 100755 (executable)
@@ -63,7 +63,7 @@ e     /tmp/e/1     0755 daemon daemon - -
 e     /tmp/e/2/*   0755 daemon daemon - -
 EOF
 
-! test -d /tmp/e/1
+test ! -d /tmp/e/1
 
 test -d /tmp/e/2
 test $(stat -c %U:%G:%a /tmp/e/2) = "root:root:777"
@@ -80,7 +80,7 @@ chmod 777 /tmp/e/3/d*
 touch /tmp/e/3/f1
 chmod 644 /tmp/e/3/f1
 
-systemd-tmpfiles --create - <<EOF
+systemd-tmpfiles --create - <<EOF
 e     /tmp/e/3/*   0755 daemon daemon - -
 EOF
 
@@ -115,7 +115,7 @@ test $(stat -c %U:%G:%a /tmp/C/1/f1) = "daemon:daemon:755"
 test -d /tmp/C/2
 test $(stat -c %U:%G:%a /tmp/C/2/f1) = "daemon:daemon:755"
 
-systemd-tmpfiles --create - <<EOF
+systemd-tmpfiles --create - <<EOF
 C     /tmp/C/3    0755 daemon daemon - /tmp/C/3-origin
 EOF
 
index 8d009fb5bb96bde6e73d39fa73e101033951d171..c905784bee4a4ead748177ff1647d86279b2861a 100755 (executable)
@@ -19,7 +19,7 @@ f     /tmp/f/2    0644 - - - This string should be written
 EOF
 
 ### '1' should exist and be empty
-test -f /tmp/f/1; ! test -s /tmp/f/1
+test -f /tmp/f/1; test ! -s /tmp/f/1
 test $(stat -c %U:%G:%a /tmp/f/1) = "root:root:644"
 
 test $(stat -c %U:%G:%a /tmp/f/2) = "root:root:644"
@@ -31,7 +31,7 @@ f     /tmp/f/1    0666 daemon daemon - This string should not be written
 EOF
 
 # file should be empty
-! test -s /tmp/f/1
+test ! -s /tmp/f/1
 test $(stat -c %U:%G:%a /tmp/f/1) = "daemon:daemon:666"
 
 ### But we shouldn't try to set perms on an existing file which is not a
@@ -39,7 +39,7 @@ test $(stat -c %U:%G:%a /tmp/f/1) = "daemon:daemon:666"
 mkfifo /tmp/f/fifo
 chmod 644 /tmp/f/fifo
 
-! systemd-tmpfiles --create - <<EOF
+systemd-tmpfiles --create - <<EOF && { echo 'unexpected success'; exit 1; }
 f     /tmp/f/fifo    0666 daemon daemon - This string should not be written
 EOF
 
@@ -50,11 +50,11 @@ test $(stat -c %U:%G:%a /tmp/f/fifo) = "root:root:644"
 ln -s missing /tmp/f/dangling
 ln -s /tmp/file-owned-by-root /tmp/f/symlink
 
-! systemd-tmpfiles --create - <<EOF
+systemd-tmpfiles --create - <<EOF && { echo 'unexpected success'; exit 1; }
 f     /tmp/f/dangling    0644 daemon daemon - -
 f     /tmp/f/symlink     0644 daemon daemon - -
 EOF
-! test -e /tmp/f/missing
+test ! -e /tmp/f/missing
 test $(stat -c %U:%G:%a /tmp/file-owned-by-root) = "root:root:644"
 
 ### Handle read-only filesystem gracefully: we shouldn't fail if the target
@@ -70,27 +70,27 @@ mount -o bind,ro /tmp/f/rw-fs /tmp/f/ro-fs
 systemd-tmpfiles --create - <<EOF
 f     /tmp/f/ro-fs/foo    0644 - - - - This string should not be written
 EOF
-test -f /tmp/f/ro-fs/foo; ! test -s /tmp/f/ro-fs/foo
+test -f /tmp/f/ro-fs/foo; test ! -s /tmp/f/ro-fs/foo
 
-! systemd-tmpfiles --create - <<EOF
+systemd-tmpfiles --create - <<EOF && { echo 'unexpected success'; exit 1; }
 f     /tmp/f/ro-fs/foo    0666 - - - -
 EOF
 test $(stat -c %U:%G:%a /tmp/f/fifo) = "root:root:644"
 
-! systemd-tmpfiles --create - <<EOF
+systemd-tmpfiles --create - <<EOF && { echo 'unexpected success'; exit 1; }
 f     /tmp/f/ro-fs/bar    0644 - - - -
 EOF
-! test -e /tmp/f/ro-fs/bar
+test ! -e /tmp/f/ro-fs/bar
 
 ### 'f' shouldn't follow unsafe paths.
 mkdir /tmp/f/daemon
 ln -s /root /tmp/f/daemon/unsafe-symlink
 chown -R --no-dereference daemon:daemon /tmp/f/daemon
 
-! systemd-tmpfiles --create - <<EOF
+systemd-tmpfiles --create - <<EOF && { echo 'unexpected success'; exit 1; }
 f     /tmp/f/daemon/unsafe-symlink/exploit    0644 daemon daemon - -
 EOF
-! test -e /tmp/f/daemon/unsafe-symlink/exploit
+test ! -e /tmp/f/daemon/unsafe-symlink/exploit
 
 #
 # 'F'
@@ -105,10 +105,10 @@ F     /tmp/F/truncated              0666 daemon daemon - -
 F     /tmp/F/truncated-with-content 0666 daemon daemon - new content
 EOF
 
-test -f /tmp/F/created; ! test -s /tmp/F/created
+test -f /tmp/F/created; test ! -s /tmp/F/created
 test -f /tmp/F/created-with-content
 test "$(< /tmp/F/created-with-content)" = "new content"
-test -f /tmp/F/truncated; ! test -s /tmp/F/truncated
+test -f /tmp/F/truncated; test ! -s /tmp/F/truncated
 test $(stat -c %U:%G:%a /tmp/F/truncated) = "daemon:daemon:666"
 test -s /tmp/F/truncated-with-content
 test $(stat -c %U:%G:%a /tmp/F/truncated-with-content) = "daemon:daemon:666"
@@ -117,7 +117,7 @@ test $(stat -c %U:%G:%a /tmp/F/truncated-with-content) = "daemon:daemon:666"
 ### unspecified in the other cases.
 mkfifo /tmp/F/fifo
 
-! systemd-tmpfiles --create - <<EOF
+systemd-tmpfiles --create - <<EOF && { echo 'unexpected success'; exit 1; }
 F     /tmp/F/fifo                0644 - - - -
 EOF
 
@@ -127,11 +127,11 @@ test -p /tmp/F/fifo
 ln -s missing /tmp/F/dangling
 ln -s /tmp/file-owned-by-root /tmp/F/symlink
 
-! systemd-tmpfiles --create - <<EOF
+systemd-tmpfiles --create - <<EOF && { echo 'unexpected success'; exit 1; }
 f     /tmp/F/dangling    0644 daemon daemon - -
 f     /tmp/F/symlink     0644 daemon daemon - -
 EOF
-! test -e /tmp/F/missing
+test ! -e /tmp/F/missing
 test $(stat -c %U:%G:%a /tmp/file-owned-by-root) = "root:root:644"
 
 ### Handle read-only filesystem gracefully: we shouldn't fail if the target
@@ -147,40 +147,41 @@ mount -o bind,ro /tmp/F/rw-fs /tmp/F/ro-fs
 systemd-tmpfiles --create - <<EOF
 F     /tmp/F/ro-fs/foo    0644 - - - -
 EOF
-test -f /tmp/F/ro-fs/foo; ! test -s /tmp/F/ro-fs/foo
+test -f /tmp/F/ro-fs/foo; test ! -s /tmp/F/ro-fs/foo
 
 echo "truncating is not allowed anymore" >/tmp/F/rw-fs/foo
-! systemd-tmpfiles --create - <<EOF
+systemd-tmpfiles --create - <<EOF && { echo 'unexpected success'; exit 1; }
 F     /tmp/F/ro-fs/foo    0644 - - - -
 EOF
 
-! systemd-tmpfiles --create - <<EOF
+systemd-tmpfiles --create - <<EOF && { echo 'unexpected success'; exit 1; }
 F     /tmp/F/ro-fs/foo    0644 - - - - This string should not be written
 EOF
-test -f /tmp/F/ro-fs/foo; ! test -s /tmp/F/ro-fs/foo
+test -f /tmp/F/ro-fs/foo
+grep -q 'truncating is not allowed' /tmp/F/ro-fs/foo
 
 # Trying to change the perms should fail.
 >/tmp/F/rw-fs/foo
-! systemd-tmpfiles --create - <<EOF
+systemd-tmpfiles --create - <<EOF && { echo 'unexpected success'; exit 1; }
 F     /tmp/F/ro-fs/foo    0666 - - - -
 EOF
 test $(stat -c %U:%G:%a /tmp/F/ro-fs/foo) = "root:root:644"
 
 ### Try to create a new file.
-! systemd-tmpfiles --create - <<EOF
+systemd-tmpfiles --create - <<EOF && { echo 'unexpected success'; exit 1; }
 F     /tmp/F/ro-fs/bar    0644 - - - -
 EOF
-! test -e /tmp/F/ro-fs/bar
+test ! -e /tmp/F/ro-fs/bar
 
 ### 'F' shouldn't follow unsafe paths.
 mkdir /tmp/F/daemon
 ln -s /root /tmp/F/daemon/unsafe-symlink
 chown -R --no-dereference daemon:daemon /tmp/F/daemon
 
-! systemd-tmpfiles --create - <<EOF
+systemd-tmpfiles --create - <<EOF && { echo 'unexpected success'; exit 1; }
 F     /tmp/F/daemon/unsafe-symlink/exploit    0644 daemon daemon - -
 EOF
-! test -e /tmp/F/daemon/unsafe-symlink/exploit
+test ! -e /tmp/F/daemon/unsafe-symlink/exploit
 
 #
 # 'w'
@@ -191,10 +192,10 @@ touch /tmp/w/overwritten
 systemd-tmpfiles --create - <<EOF
 w     /tmp/w/unexistent    0644 - - - new content
 EOF
-! test -e /tmp/w/unexistent
+test ! -e /tmp/w/unexistent
 
 ### no argument given -> fails.
-! systemd-tmpfiles --create - <<EOF
+systemd-tmpfiles --create - <<EOF && { echo 'unexpected success'; exit 1; }
 w     /tmp/w/unexistent    0644 - - - -
 EOF
 
@@ -230,7 +231,7 @@ mkdir /tmp/w/daemon
 ln -s /root /tmp/w/daemon/unsafe-symlink
 chown -R --no-dereference daemon:daemon /tmp/w/daemon
 
-! systemd-tmpfiles --create - <<EOF
+systemd-tmpfiles --create - <<EOF && { echo 'unexpected success'; exit 1; }
 f     /tmp/w/daemon/unsafe-symlink/exploit    0644 daemon daemon - -
 EOF
-! test -e /tmp/w/daemon/unsafe-symlink/exploit
+test ! -e /tmp/w/daemon/unsafe-symlink/exploit
index f916086b1edf47f59e82a5887cfa42282b411bc5..fc90ab4dc7fcce8464d226d12a6e16bf6afe612b 100755 (executable)
@@ -17,8 +17,8 @@ EOF
 test -p /tmp/p/fifo1
 test $(stat -c %U:%G:%a /tmp/p/fifo1) = "root:root:666"
 
-# it should refuse to overwrite an existing file
-systemd-tmpfiles --create - <<EOF
+# Refuse to overwrite an existing file. Error is not propagated.
+systemd-tmpfiles --create - <<EOF
 p     /tmp/p/f1    0666 - - - -
 EOF
 
index cd65ba6726508ef4ee8de1c072956f8f12c49148..8ce0a08f68a8f442c5844a20495383b68c6c578e 100755 (executable)
@@ -18,8 +18,8 @@ test -d /var/tmp/foobar-test-06
 test -d /var/tmp/foobar-test-06/important
 
 test_snippet --remove
-! test -f /var/tmp/foobar-test-06
-! test -f /var/tmp/foobar-test-06/important
+test ! -f /var/tmp/foobar-test-06
+test ! -f /var/tmp/foobar-test-06/important
 
 test_snippet --create
 test -d /var/tmp/foobar-test-06
@@ -35,4 +35,4 @@ test -f /var/tmp/foobar-test-06/something-else
 test_snippet --create --remove
 test -d /var/tmp/foobar-test-06
 test -d /var/tmp/foobar-test-06/important
-! test -f /var/tmp/foobar-test-06/something-else
+test ! -f /var/tmp/foobar-test-06/something-else
index 39c04b925cf67645ca32fb7dcd4f7ddd8328af90..74286a33057b2668ae9f274743ed823e7cb0780f 100755 (executable)
@@ -16,8 +16,8 @@ r /tmp/test-prefix
 r /tmp/test-prefix/file
 EOF
 
-! test -f /tmp/test-prefix/file
-! test -f /tmp/test-prefix
+test ! -f /tmp/test-prefix/file
+test ! -f /tmp/test-prefix
 
 mkdir /tmp/test-prefix
 touch /tmp/test-prefix/file
@@ -27,5 +27,5 @@ r /tmp/test-prefix/file
 r /tmp/test-prefix
 EOF
 
-! test -f /tmp/test-prefix/file
-! test -f /tmp/test-prefix
+test ! -f /tmp/test-prefix/file
+test ! -f /tmp/test-prefix
index e7bf0447839fefdbe11957b1fa70ea16cc2a07c0..01d3bdb50cfbe72b46222966f9287ed1bbfa4ccb 100755 (executable)
@@ -22,10 +22,12 @@ test -d /tmp/root/test2
 # Verify the command fails to write to a root-owned subdirectory under an
 # unprivileged user's directory when it's not part of the prefix, as expected
 # by the unsafe_transition function.
-! echo 'd /tmp/user/root/test' | systemd-tmpfiles --create -
-! test -e /tmp/user/root/test
-! echo 'd /user/root/test' | systemd-tmpfiles --root=/tmp --create -
-! test -e /tmp/user/root/test
+echo 'd /tmp/user/root/test' | systemd-tmpfiles --create - \
+    && { echo 'unexpected success'; exit 1; }
+test ! -e /tmp/user/root/test
+echo 'd /user/root/test' | systemd-tmpfiles --root=/tmp --create - \
+    && { echo 'unexpected success'; exit 1; }
+test ! -e /tmp/user/root/test
 
 # Verify the above works when all user-owned directories are in the prefix.
 echo 'd /test' | systemd-tmpfiles --root=/tmp/user/root --create -
diff --git a/test/units/testsuite-22.11.sh b/test/units/testsuite-22.11.sh
new file mode 100755 (executable)
index 0000000..21ef210
--- /dev/null
@@ -0,0 +1,141 @@
+#! /bin/bash
+
+set -e
+set -x
+
+rm -fr /tmp/x
+mkdir  /tmp/x
+
+#
+# 'x'
+#
+mkdir -p /tmp/x/{1,2}
+touch /tmp/x/1/{x1,x2} /tmp/x/2/{y1,y2} /tmp/x/{z1,z2}
+
+systemd-tmpfiles --clean - <<EOF
+d /tmp/x - - - 0
+x /tmp/x/1
+EOF
+
+find /tmp/x | sort
+test -d /tmp/x/1
+test -f /tmp/x/1/x1
+test -f /tmp/x/1/x2
+test ! -d /tmp/x/2
+test ! -f /tmp/x/2/x1
+test ! -f /tmp/x/2/x2
+test ! -f /tmp/x/z1
+test ! -f /tmp/x/z2
+
+#
+# 'X'
+#
+
+mkdir -p /tmp/x/{1,2}
+touch /tmp/x/1/{x1,x2} /tmp/x/2/{y1,y2} /tmp/x/{z1,z2}
+
+systemd-tmpfiles --clean - <<EOF
+d /tmp/x - - - 0
+X /tmp/x/1
+EOF
+
+find /tmp/x | sort
+test -d /tmp/x/1
+test ! -f /tmp/x/1/x1
+test ! -f /tmp/x/1/x2
+test ! -d /tmp/x/2
+test ! -f /tmp/x/2/x1
+test ! -f /tmp/x/2/x2
+test ! -f /tmp/x/z1
+test ! -f /tmp/x/z2
+
+#
+# 'x' with glob
+#
+
+mkdir -p /tmp/x/{1,2}
+touch /tmp/x/1/{x1,x2} /tmp/x/2/{y1,y2} /tmp/x/{z1,z2}
+
+systemd-tmpfiles --clean - <<EOF
+d /tmp/x - - - 0
+x /tmp/x/[1345]
+x /tmp/x/z*
+EOF
+
+find /tmp/x | sort
+test -d /tmp/x/1
+test -f /tmp/x/1/x1
+test -f /tmp/x/1/x2
+test ! -d /tmp/x/2
+test ! -f /tmp/x/2/x1
+test ! -f /tmp/x/2/x2
+test -f /tmp/x/z1
+test -f /tmp/x/z2
+
+#
+# 'X' with glob
+#
+
+mkdir -p /tmp/x/{1,2}
+touch /tmp/x/1/{x1,x2} /tmp/x/2/{y1,y2} /tmp/x/{z1,z2}
+
+systemd-tmpfiles --clean - <<EOF
+d /tmp/x - - - 0
+X /tmp/x/[1345]
+X /tmp/x/?[12]
+EOF
+
+find /tmp/x | sort
+test -d /tmp/x/1
+test ! -f /tmp/x/1/x1
+test ! -f /tmp/x/1/x2
+test ! -d /tmp/x/2
+test ! -f /tmp/x/2/x1
+test ! -f /tmp/x/2/x2
+test -f /tmp/x/z1
+test -f /tmp/x/z2
+
+#
+# 'x' with 'r'
+#
+
+mkdir -p /tmp/x/{1,2}/a
+touch /tmp/x/1/a/{x1,x2} /tmp/x/2/a/{y1,y2}
+
+systemd-tmpfiles --clean - <<EOF
+# x/X is not supposed to influence r
+x /tmp/x/1/a
+X /tmp/x/2/a
+r /tmp/x/1
+r /tmp/x/2
+EOF
+
+find /tmp/x | sort
+test -d /tmp/x/1
+test -d /tmp/x/1/a
+test -f /tmp/x/1/a/x1
+test -f /tmp/x/1/a/x2
+test -f /tmp/x/2/a/y1
+test -f /tmp/x/2/a/y2
+
+#
+# 'x' with 'R'
+#
+
+mkdir -p /tmp/x/{1,2}/a
+touch /tmp/x/1/a/{x1,x2} /tmp/x/2/a/{y1,y2}
+
+systemd-tmpfiles --remove - <<EOF
+# X is not supposed to influence R
+X /tmp/x/1/a
+X /tmp/x/2/a
+R /tmp/x/1
+EOF
+
+find /tmp/x | sort
+test ! -d /tmp/x/1
+test ! -d /tmp/x/1/a
+test ! -f /tmp/x/1/a/x1
+test ! -f /tmp/x/1/a/x2
+test -f /tmp/x/2/a/y1
+test -f /tmp/x/2/a/y2
index 5e2966f848e0cd60013146a4400023455794cc1c..a21523756230184e2507a0d2c49d2ff3bb572325 100755 (executable)
@@ -16,8 +16,8 @@ systemd-run --unit=three -p Type=simple /tmp/brokenbinary
 
 # And now, do the same with Type=exec, where the latter two should fail
 systemd-run --unit=four -p Type=exec /bin/sleep infinity
-! systemd-run --unit=five -p Type=exec -p User=idontexist /bin/sleep infinity
-! systemd-run --unit=six -p Type=exec /tmp/brokenbinary
+systemd-run --unit=five -p Type=exec -p User=idontexist /bin/sleep infinity && { echo 'unexpected success'; exit 1; }
+systemd-run --unit=six -p Type=exec /tmp/brokenbinary && { echo 'unexpected success'; exit 1; }
 
 systemd-run --unit=seven -p KillSignal=SIGTERM -p RestartKillSignal=SIGINT -p Type=exec /bin/sleep infinity
 # Both TERM and SIGINT happen to have the same number on all architectures
@@ -29,6 +29,6 @@ systemctl stop seven.service
 
 systemd-analyze log-level info
 
-echo OK > /testok
+echo OK >/testok
 
 exit 0
index e3dd43add38d95d6e891a47afd5ab7d35e586b6c..d4d2e0f9532b30a53e05a346a04f68e4f2e0a023 100755 (executable)
@@ -34,8 +34,8 @@ cmp /var/tmp/testimage.raw /var/lib/machines/testimage3.raw
 
 # Test removal
 machinectl remove testimage
-! test -f /var/lib/machines/testimage.raw
-! machinectl image-status testimage
+test ! -f /var/lib/machines/testimage.raw
+machinectl image-status testimage && { echo 'unexpected success'; exit 1; }
 
 # Test export of clone
 machinectl export-raw testimage3 /var/tmp/testimage3.raw
@@ -46,8 +46,8 @@ rm /var/tmp/testimage3.raw
 machinectl rename testimage3 testimage4
 test -f /var/lib/machines/testimage4.raw
 machinectl image-status testimage4
-! test -f /var/lib/machines/testimage3.raw
-! machinectl image-status testimage3
+test ! -f /var/lib/machines/testimage3.raw
+machinectl image-status testimage3 && { echo 'unexpected success'; exit 1; }
 cmp /var/tmp/testimage.raw /var/lib/machines/testimage4.raw
 
 # Test export of rename
@@ -57,8 +57,8 @@ rm /var/tmp/testimage4.raw
 
 # Test removal
 machinectl remove testimage4
-! test -f /var/lib/machines/testimage4.raw
-! machinectl image-status testimage4
+test ! -f /var/lib/machines/testimage4.raw
+machinectl image-status testimage4 && { echo 'unexpected success'; exit 1; }
 
 # → And now, let's test directory trees ← #
 
@@ -67,7 +67,7 @@ mkdir /var/tmp/scratch
 mv /var/tmp/testimage.raw /var/tmp/scratch/
 touch /var/tmp/scratch/anotherfile
 mkdir /var/tmp/scratch/adirectory
-echo "piep" > /var/tmp/scratch/adirectory/athirdfile
+echo "piep" >/var/tmp/scratch/adirectory/athirdfile
 
 # Test import-fs
 machinectl import-fs /var/tmp/scratch/
@@ -90,8 +90,8 @@ diff -r /var/tmp/scratch/ /var/lib/machines/scratch2
 
 # Test removal
 machinectl remove scratch
-! test -f /var/lib/machines/scratch
-! machinectl image-status scratch
+test ! -f /var/lib/machines/scratch
+machinectl image-status scratchi && { echo 'unexpected success'; exit 1; }
 
 # Test clone
 machinectl clone scratch2 scratch3
@@ -103,21 +103,21 @@ diff -r /var/tmp/scratch/ /var/lib/machines/scratch3
 
 # Test removal
 machinectl remove scratch2
-! test -f /var/lib/machines/scratch2
-! machinectl image-status scratch2
+test ! -f /var/lib/machines/scratch2
+machinectl image-status scratch2 && { echo 'unexpected success'; exit 1; }
 
 # Test rename
 machinectl rename scratch3 scratch4
 test -d /var/lib/machines/scratch4
 machinectl image-status scratch4
-! test -f /var/lib/machines/scratch3
-! machinectl image-status scratch3
+test ! -f /var/lib/machines/scratch3
+machinectl image-status scratch3 && { echo 'unexpected success'; exit 1; }
 diff -r /var/tmp/scratch/ /var/lib/machines/scratch4
 
 # Test removal
 machinectl remove scratch4
-! test -f /var/lib/machines/scratch4
-! machinectl image-status scratch4
+test ! -f /var/lib/machines/scratch4
+machinectl image-status scratch4 && { echo 'unexpected success'; exit 1; }
 
 # Test import-tar hyphen/stdin pipe behavior
 cat /var/tmp/scratch.tar.gz | machinectl import-tar - scratch5
@@ -135,9 +135,9 @@ rm -rf /var/tmp/scratch
 
 # Test removal
 machinectl remove scratch5
-! test -f /var/lib/machines/scratch5
-! machinectl image-status scratch5
+test ! -f /var/lib/machines/scratch5
+machinectl image-status scratch5 && { echo 'unexpected success'; exit 1; }
 
-echo OK > /testok
+echo OK >/testok
 
 exit 0
index 89c0937c8dafc7dbba060a787c3db1749ab9b982..9c1abc5916186b83639dd96ca26158c68174d3ad 100755 (executable)
@@ -22,10 +22,10 @@ systemctl show-environment | grep -q '^FOO=BAR$'
 systemctl unset-environment FOO PATH
 
 # Check that one is gone and the other reverted to the built-in
-! (systemctl show-environment | grep -q '^FOO=$')
-! (systemctl show-environment | grep -q '^PATH=.*testaddition$')
+systemctl show-environment | grep '^FOO=$' && exit 1
+systemctl show-environment | grep '^PATH=.*testaddition$' && exit 1
 systemctl show-environment | grep -q '^PATH='
 
-echo OK > /testok
+echo OK >/testok
 
 exit 0
index 2e55c275bf1d8443cc60fbbf50117aa60819e082..4e91aa73363ed2ff776c035e281e547f2a8c728c 100755 (executable)
@@ -93,6 +93,6 @@ umount /tmp/overlay
 umount /tmp/rootdir
 umount /tmp/app1
 
-echo OK > /testok
+echo OK >/testok
 
 exit 0
index a507ffcd7bcee21ecc33617ebb0faeba39ac1c9f..cb3b46d2cbea58432c711a0f20ef9199008a2849 100755 (executable)
@@ -13,19 +13,19 @@ timedatectl set-time 1980-10-15
 systemd-run --on-timezone-change touch /tmp/timezone-changed
 systemd-run --on-clock-change touch /tmp/clock-changed
 
-! test -f /tmp/timezone-changed
-! test -f /tmp/clock-changed
+test ! -f /tmp/timezone-changed
+test ! -f /tmp/clock-changed
 
 timedatectl set-timezone Europe/Kiev
 
-while ! test -f /tmp/timezone-changed ; do sleep .5 ; done
+while test ! -f /tmp/timezone-changed ; do sleep .5 ; done
 
 timedatectl set-time 2018-1-1
 
-while ! test -f /tmp/clock-changed ; do sleep .5 ; done
+while test ! -f /tmp/clock-changed ; do sleep .5 ; done
 
 systemd-analyze log-level info
 
-echo OK > /testok
+echo OK >/testok
 
 exit 0
index fcff82d804804673f5fb4b5013c7d14e019e4b30..42873bfd833a88166bdcb84f667ae13ea7b73057 100755 (executable)
@@ -6,5 +6,5 @@ if journalctl -b -t systemd --grep '\.device: Changed plugged -> dead'; then
     exit 1
 fi
 
-echo OK > /testok
+echo OK >/testok
 exit 0
index 0a6ee57b99867cfa7f62c7a8c20d824073cf145e..929c76062be8f1d6fd2bbd5e56301dbf6e94eb3c 100755 (executable)
@@ -4,7 +4,7 @@
 set -ex
 set -o pipefail
 
-cat > /etc/systemd/system/testservice.service <<EOF
+cat >/etc/systemd/system/testservice.service <<EOF
 [Service]
 ConfigurationDirectory=testservice
 RuntimeDirectory=testservice
@@ -18,11 +18,11 @@ EOF
 
 systemctl daemon-reload
 
-! test -e /etc/testservice
-! test -e /run/testservice
-! test -e /var/lib/testservice
-! test -e /var/cache/testservice
-! test -e /var/log/testservice
+test ! -e /etc/testservice
+test ! -e /run/testservice
+test ! -e /var/lib/testservice
+test ! -e /var/cache/testservice
+test ! -e /var/log/testservice
 
 systemctl start testservice
 
@@ -32,7 +32,7 @@ test -d /var/lib/testservice
 test -d /var/cache/testservice
 test -d /var/log/testservice
 
-! systemctl clean testservice
+systemctl clean testservice && { echo 'unexpected success'; exit 1; }
 
 systemctl stop testservice
 
@@ -44,7 +44,7 @@ test -d /var/log/testservice
 
 systemctl clean testservice --what=configuration
 
-! test -e /etc/testservice
+test ! -e /etc/testservice
 test -d /run/testservice
 test -d /var/lib/testservice
 test -d /var/cache/testservice
@@ -52,29 +52,29 @@ test -d /var/log/testservice
 
 systemctl clean testservice
 
-! test -e /etc/testservice
-! test -e /run/testservice
+test ! -e /etc/testservice
+test ! -e /run/testservice
 test -d /var/lib/testservice
-! test -e /var/cache/testservice
+test ! -e /var/cache/testservice
 test -d /var/log/testservice
 
 systemctl clean testservice --what=logs
 
-! test -e /etc/testservice
-! test -e /run/testservice
+test ! -e /etc/testservice
+test ! -e /run/testservice
 test -d /var/lib/testservice
-! test -e /var/cache/testservice
-! test -e /var/log/testservice
+test ! -e /var/cache/testservice
+test ! -e /var/log/testservice
 
 systemctl clean testservice --what=all
 
-! test -e /etc/testservice
-! test -e /run/testservice
-! test -e /var/lib/testservice
-! test -e /var/cache/testservice
-! test -e /var/log/testservice
+test ! -e /etc/testservice
+test ! -e /run/testservice
+test ! -e /var/lib/testservice
+test ! -e /var/cache/testservice
+test ! -e /var/log/testservice
 
-cat > /etc/systemd/system/testservice.service <<EOF
+cat >/etc/systemd/system/testservice.service <<EOF
 [Service]
 DynamicUser=yes
 ConfigurationDirectory=testservice
@@ -89,11 +89,11 @@ EOF
 
 systemctl daemon-reload
 
-! test -e /etc/testservice
-! test -e /run/testservice
-! test -e /var/lib/testservice
-! test -e /var/cache/testservice
-! test -e /var/log/testservice
+test ! -e /etc/testservice
+test ! -e /run/testservice
+test ! -e /var/lib/testservice
+test ! -e /var/cache/testservice
+test ! -e /var/log/testservice
 
 systemctl restart testservice
 
@@ -107,7 +107,7 @@ test -L /var/lib/testservice
 test -L /var/cache/testservice
 test -L /var/log/testservice
 
-! systemctl clean testservice
+systemctl clean testservice && { echo 'unexpected success'; exit 1; }
 
 systemctl stop testservice
 
@@ -123,7 +123,7 @@ test -L /var/log/testservice
 
 systemctl clean testservice --what=configuration
 
-! test -d /etc/testservice
+test ! -d /etc/testservice
 test -d /run/private/testservice
 test -d /var/lib/private/testservice
 test -d /var/cache/private/testservice
@@ -135,41 +135,41 @@ test -L /var/log/testservice
 
 systemctl clean testservice
 
-! test -d /etc/testservice
-! test -d /run/private/testservice
+test ! -d /etc/testservice
+test ! -d /run/private/testservice
 test -d /var/lib/private/testservice
-! test -d /var/cache/private/testservice
+test ! -d /var/cache/private/testservice
 test -d /var/log/private/testservice
-! test -L /run/testservice
+test ! -L /run/testservice
 test -L /var/lib/testservice
-! test -L /var/cache/testservice
+test ! -L /var/cache/testservice
 test -L /var/log/testservice
 
 systemctl clean testservice --what=logs
 
-! test -d /etc/testservice
-! test -d /run/private/testservice
+test ! -d /etc/testservice
+test ! -d /run/private/testservice
 test -d /var/lib/private/testservice
-! test -d /var/cache/private/testservice
-! test -d /var/log/private/testservice
-! test -L /run/testservice
+test ! -d /var/cache/private/testservice
+test ! -d /var/log/private/testservice
+test ! -L /run/testservice
 test -L /var/lib/testservice
-! test -L /var/cache/testservice
-! test -L /var/log/testservice
+test ! -L /var/cache/testservice
+test ! -L /var/log/testservice
 
 systemctl clean testservice --what=all
 
-! test -d /etc/testservice
-! test -d /run/private/testservice
-! test -d /var/lib/private/testservice
-! test -d /var/cache/private/testservice
-! test -d /var/log/private/testservice
-! test -L /run/testservice
-! test -L /var/lib/testservice
-! test -L /var/cache/testservice
-! test -L /var/log/testservice
-
-cat > /etc/systemd/system/tmp-hoge.mount <<EOF
+test ! -d /etc/testservice
+test ! -d /run/private/testservice
+test ! -d /var/lib/private/testservice
+test ! -d /var/cache/private/testservice
+test ! -d /var/log/private/testservice
+test ! -L /run/testservice
+test ! -L /var/lib/testservice
+test ! -L /var/cache/testservice
+test ! -L /var/log/testservice
+
+cat >/etc/systemd/system/tmp-hoge.mount <<EOF
 [Mount]
 What=tmpfs
 Type=tmpfs
@@ -182,11 +182,11 @@ EOF
 
 systemctl daemon-reload
 
-! test -e /etc/hoge
-! test -e /run/hoge
-! test -e /var/lib/hoge
-! test -e /var/cache/hoge
-! test -e /var/log/hoge
+test ! -e /etc/hoge
+test ! -e /run/hoge
+test ! -e /var/lib/hoge
+test ! -e /var/cache/hoge
+test ! -e /var/log/hoge
 
 systemctl start tmp-hoge.mount
 
@@ -196,7 +196,7 @@ test -d /var/lib/hoge
 test -d /var/cache/hoge
 test -d /var/log/hoge
 
-! systemctl clean tmp-hoge.mount
+systemctl clean tmp-hoge.mount && { echo 'unexpected success'; exit 1; }
 
 test -d /etc/hoge
 test -d /run/hoge
@@ -207,44 +207,44 @@ test -d /var/log/hoge
 systemctl stop tmp-hoge.mount
 
 test -d /etc/hoge
-! test -d /run/hoge
+test ! -d /run/hoge
 test -d /var/lib/hoge
 test -d /var/cache/hoge
 test -d /var/log/hoge
 
 systemctl clean tmp-hoge.mount --what=configuration
 
-! test -d /etc/hoge
-! test -d /run/hoge
+test ! -d /etc/hoge
+test ! -d /run/hoge
 test -d /var/lib/hoge
 test -d /var/cache/hoge
 test -d /var/log/hoge
 
 systemctl clean tmp-hoge.mount
 
-! test -d /etc/hoge
-! test -d /run/hoge
+test ! -d /etc/hoge
+test ! -d /run/hoge
 test -d /var/lib/hoge
-! test -d /var/cache/hoge
+test ! -d /var/cache/hoge
 test -d /var/log/hoge
 
 systemctl clean tmp-hoge.mount --what=logs
 
-! test -d /etc/hoge
-! test -d /run/hoge
+test ! -d /etc/hoge
+test ! -d /run/hoge
 test -d /var/lib/hoge
-! test -d /var/cache/hoge
-! test -d /var/log/hoge
+test ! -d /var/cache/hoge
+test ! -d /var/log/hoge
 
 systemctl clean tmp-hoge.mount --what=all
 
-! test -d /etc/hoge
-! test -d /run/hoge
-! test -d /var/lib/hoge
-! test -d /var/cache/hoge
-! test -d /var/log/hoge
+test ! -d /etc/hoge
+test ! -d /run/hoge
+test ! -d /var/lib/hoge
+test ! -d /var/cache/hoge
+test ! -d /var/log/hoge
 
-cat > /etc/systemd/system/testservice.socket <<EOF
+cat >/etc/systemd/system/testservice.socket <<EOF
 [Socket]
 ListenSequentialPacket=/run/testservice.socket
 RemoveOnStop=yes
@@ -258,62 +258,62 @@ EOF
 
 systemctl daemon-reload
 
-! test -e /etc/testsocket
-! test -e /run/testsocket
-! test -e /var/lib/testsocket
-! test -e /var/cache/testsocket
-! test -e /var/log/testsocket
+test ! -e /etc/testsocket
+test ! -e /run/testsocket
+test ! -e /var/lib/testsocket
+test ! -e /var/cache/testsocket
+test ! -e /var/log/testsocket
 
 systemctl start testservice.socket
 
 test -d /etc/testsocket
-test -d /run/testsocket
+test -d /run/testsocket
 test -d /var/lib/testsocket
 test -d /var/cache/testsocket
 test -d /var/log/testsocket
 
-! systemctl clean testservice.socket
+systemctl clean testservice.socket && { echo 'unexpected success'; exit 1; }
 
 systemctl stop testservice.socket
 
 test -d /etc/testsocket
-! test -d /run/testsocket
+test ! -d /run/testsocket
 test -d /var/lib/testsocket
 test -d /var/cache/testsocket
 test -d /var/log/testsocket
 
 systemctl clean testservice.socket --what=configuration
 
-! test -e /etc/testsocket
-! test -d /run/testsocket
+test ! -e /etc/testsocket
+test ! -d /run/testsocket
 test -d /var/lib/testsocket
 test -d /var/cache/testsocket
 test -d /var/log/testsocket
 
 systemctl clean testservice.socket
 
-! test -e /etc/testsocket
-! test -e /run/testsocket
+test ! -e /etc/testsocket
+test ! -e /run/testsocket
 test -d /var/lib/testsocket
-! test -e /var/cache/testsocket
+test ! -e /var/cache/testsocket
 test -d /var/log/testsocket
 
 systemctl clean testservice.socket --what=logs
 
-! test -e /etc/testsocket
-! test -e /run/testsocket
+test ! -e /etc/testsocket
+test ! -e /run/testsocket
 test -d /var/lib/testsocket
-! test -e /var/cache/testsocket
-! test -e /var/log/testsocket
+test ! -e /var/cache/testsocket
+test ! -e /var/log/testsocket
 
 systemctl clean testservice.socket --what=all
 
-! test -e /etc/testsocket
-! test -e /run/testsocket
-! test -e /var/lib/testsocket
-! test -e /var/cache/testsocket
-! test -e /var/log/testsocket
+test ! -e /etc/testsocket
+test ! -e /run/testsocket
+test ! -e /var/lib/testsocket
+test ! -e /var/cache/testsocket
+test ! -e /var/log/testsocket
 
-echo OK > /testok
+echo OK >/testok
 
 exit 0
index 6d9488688a1bb4554923154641e6e98e65a714fa..ca54a01f403894defed71ba567db2f187f469b66 100755 (executable)
@@ -9,38 +9,41 @@ systemd-analyze log-target console
 
 systemd-run --wait -p DynamicUser=0 -p StateDirectory=zzz touch /var/lib/zzz/test
 systemd-run --wait -p DynamicUser=0 -p StateDirectory=zzz test -f /var/lib/zzz/test
-! systemd-run --wait -p DynamicUser=0 -p StateDirectory=zzz test -f /var/lib/zzz/test-missing
+systemd-run --wait -p DynamicUser=0 -p StateDirectory=zzz test -f /var/lib/zzz/test-missing \
+    && { echo 'unexpected success'; exit 1; }
 
 test -d /var/lib/zzz
-! test -L /var/lib/zzz
-! test -e /var/lib/private/zzz
+test ! -L /var/lib/zzz
+test ! -e /var/lib/private/zzz
 test -f /var/lib/zzz/test
-! test -f /var/lib/zzz/test-missing
+test ! -f /var/lib/zzz/test-missing
 
 # Convert to DynamicUser=1
 
 systemd-run --wait -p DynamicUser=1 -p StateDirectory=zzz test -f /var/lib/zzz/test
-! systemd-run --wait -p DynamicUser=1 -p StateDirectory=zzz test -f /var/lib/zzz/test-missing
+systemd-run --wait -p DynamicUser=1 -p StateDirectory=zzz test -f /var/lib/zzz/test-missing \
+    && { echo 'unexpected success'; exit 1; }
 
 test -L /var/lib/zzz
 test -d /var/lib/private/zzz
 
 test -f /var/lib/zzz/test
-! test -f /var/lib/zzz/test-missing
+test ! -f /var/lib/zzz/test-missing
 
 # Convert back
 
 systemd-run --wait -p DynamicUser=0 -p StateDirectory=zzz test -f /var/lib/zzz/test
-! systemd-run --wait -p DynamicUser=0 -p StateDirectory=zzz test -f /var/lib/zzz/test-missing
+systemd-run --wait -p DynamicUser=0 -p StateDirectory=zzz test -f /var/lib/zzz/test-missing \
+    && { echo 'unexpected success'; exit 1; }
 
 test -d /var/lib/zzz
-! test -L /var/lib/zzz
-! test -e /var/lib/private/zzz
+test ! -L /var/lib/zzz
+test ! -e /var/lib/private/zzz
 test -f /var/lib/zzz/test
-! test -f /var/lib/zzz/test-missing
+test ! -f /var/lib/zzz/test-missing
 
 systemd-analyze log-level info
 
-echo OK > /testok
+echo OK >/testok
 
 exit 0
index f5579ce8255ff21997db22f3df9cc5cf23cf6f73..3decf4b3f33ddc84aee5ea027d3b721f2ea0dfca 100755 (executable)
@@ -55,7 +55,7 @@ stopJournalctl() {
     # the --sync wait until the synchronization is complete
     echo "Force journald to write all queued messages"
     journalctl --sync
-    journalctl -u $unit --cursor-file="$journalCursorFile" > "$journalLog"
+    journalctl -u $unit --cursor-file="$journalCursorFile" >"$journalLog"
 }
 
 checkNUMA() {
@@ -64,21 +64,21 @@ checkNUMA() {
 }
 
 writePID1NUMAPolicy() {
-    echo [Manager] > $confDir/numa.conf
-    echo NUMAPolicy=$1 >> $confDir/numa.conf
-    echo NUMAMask=$2>> $confDir/numa.conf
+    echo [Manager] >$confDir/numa.conf
+    echo NUMAPolicy=$1 >>$confDir/numa.conf
+    echo NUMAMask=$2 >>$confDir/numa.conf
 }
 
 writeTestUnit() {
     mkdir -p $testUnitFile.d/
-    echo [Service] > $testUnitFile
-    echo ExecStart=/bin/sleep 3600 >> $testUnitFile
+    echo [Service] >$testUnitFile
+    echo ExecStart=/bin/sleep 3600 >>$testUnitFile
 }
 
 writeTestUnitNUMAPolicy() {
-    echo [Service] > $testUnitNUMAConf
-    echo NUMAPolicy=$1 >> $testUnitNUMAConf
-    echo NUMAMask=$2>> $testUnitNUMAConf
+    echo [Service] >$testUnitNUMAConf
+    echo NUMAPolicy=$1 >>$testUnitNUMAConf
+    echo NUMAMask=$2 >>$testUnitNUMAConf
     systemctl daemon-reload
 }
 
@@ -115,13 +115,13 @@ pid1StopUnit() {
 
 systemctlCheckNUMAProperties() {
     local LOGFILE="$(mktemp)"
-    systemctl show -p NUMAPolicy $1 > "$LOGFILE"
+    systemctl show -p NUMAPolicy $1 >"$LOGFILE"
     grep "NUMAPolicy=$2" "$LOGFILE"
 
-    > "$LOGFILE"
+    >"$LOGFILE"
 
     if [ -n "$3" ]; then
-        systemctl show -p NUMAMask $1 > "$LOGFILE"
+        systemctl show -p NUMAMask $1 >"$LOGFILE"
         grep "NUMAMask=$3" "$LOGFILE"
     fi
 }
@@ -281,7 +281,7 @@ else
 
     echo "Unit file CPUAffinity=NUMA support"
     writeTestUnitNUMAPolicy "bind" "0"
-    echo "CPUAffinity=numa" >> $testUnitNUMAConf
+    echo "CPUAffinity=numa" >>$testUnitNUMAConf
     systemctl daemon-reload
     systemctl start $testUnit
     systemctlCheckNUMAProperties $testUnit "bind" "0"
@@ -336,6 +336,6 @@ systemctl daemon-reload
 
 systemd-analyze log-level info
 
-echo OK > /testok
+echo OK >/testok
 
 exit 0
index 32a9dd8694e03c7bfe5f5a16eacba6f38a439980..3ae0cb32fe166084805706ef53f98dd790fa3d6a 100755 (executable)
@@ -12,8 +12,8 @@ touch /tmp/aaa/bbb
 systemctl restart tmp-aaa.mount
 
 test -e /run/hoge/foo
-! test -e /tmp/aaa/bbb
+test ! -e /tmp/aaa/bbb
 
-echo OK > /testok
+echo OK >/testok
 
 exit 0
index 18b7bd6dcee27b0b8f3c8564f20c1747cf927461..707fd8a86466105a59c2de360c1ea9a4c8f903df 100755 (executable)
@@ -245,7 +245,7 @@ test_preserve_state() {
     echo "Test that freezer state is preserved when recursive freezing is initiated from outside (e.g. by manager up the tree):"
 
     echo -n "  - freeze from outside: "
-    echo 1 > /sys/fs/cgroup/"${slice}"/cgroup.freeze
+    echo 1 >/sys/fs/cgroup/"${slice}"/cgroup.freeze
     # Give kernel some time to freeze the slice
     sleep 1
 
@@ -259,7 +259,7 @@ test_preserve_state() {
     echo "[ OK ]"
 
     echo -n "  - thaw from outside: "
-    echo 0 > /sys/fs/cgroup/"${slice}"/cgroup.freeze
+    echo 0 >/sys/fs/cgroup/"${slice}"/cgroup.freeze
     sleep 1
 
     check_freezer_state "${unit}" "running"
@@ -271,8 +271,8 @@ test_preserve_state() {
     echo -n "  - thaw from outside while inner service is frozen: "
     systemctl freeze "$unit"
     check_freezer_state "${unit}" "frozen"
-    echo 1 > /sys/fs/cgroup/"${slice}"/cgroup.freeze
-    echo 0 > /sys/fs/cgroup/"${slice}"/cgroup.freeze
+    echo 1 >/sys/fs/cgroup/"${slice}"/cgroup.freeze
+    echo 0 >/sys/fs/cgroup/"${slice}"/cgroup.freeze
     check_freezer_state "${slice}" "running"
     check_freezer_state "${unit}" "frozen"
     echo "[ OK ]"
@@ -293,5 +293,5 @@ test -e /sys/fs/cgroup/system.slice/cgroup.freeze && {
     test_preserve_state
 }
 
-echo OK > /testok
+echo OK >/testok
 exit 0
index eb7363fa6a2bb182998dc9b92b60763e3069eb6c..5c0680878f352c2329dce336eeb066f58ccb7ded 100755 (executable)
@@ -11,7 +11,7 @@ SERVICE_PATH="$(mktemp /etc/systemd/system/execreloadXXX.service)"
 SERVICE_NAME="${SERVICE_PATH##*/}"
 
 echo "[#1] Failing ExecReload= should not kill the service"
-cat > "$SERVICE_PATH" << EOF
+cat >"$SERVICE_PATH" <<EOF
 [Service]
 ExecStart=/bin/sleep infinity
 ExecReload=/bin/false
@@ -21,13 +21,13 @@ systemctl daemon-reload
 systemctl start $SERVICE_NAME
 systemctl status $SERVICE_NAME
 # The reload SHOULD fail but SHOULD NOT affect the service state
-! systemctl reload $SERVICE_NAME
+systemctl reload $SERVICE_NAME && { echo 'unexpected success'; exit 1; }
 systemctl status $SERVICE_NAME
 systemctl stop $SERVICE_NAME
 
 
 echo "[#2] Failing ExecReload= should not kill the service (multiple ExecReload=)"
-cat > "$SERVICE_PATH" << EOF
+cat >"$SERVICE_PATH" <<EOF
 [Service]
 ExecStart=/bin/sleep infinity
 ExecReload=/bin/true
@@ -39,12 +39,12 @@ systemctl daemon-reload
 systemctl start $SERVICE_NAME
 systemctl status $SERVICE_NAME
 # The reload SHOULD fail but SHOULD NOT affect the service state
-! systemctl reload $SERVICE_NAME
+systemctl reload $SERVICE_NAME && { echo 'unexpected success'; exit 1; }
 systemctl status $SERVICE_NAME
 systemctl stop $SERVICE_NAME
 
 echo "[#3] Failing ExecReload=- should not affect reload's exit code"
-cat > "$SERVICE_PATH" << EOF
+cat >"$SERVICE_PATH" <<EOF
 [Service]
 ExecStart=/bin/sleep infinity
 ExecReload=-/bin/false
@@ -59,6 +59,6 @@ systemctl stop $SERVICE_NAME
 
 systemd-analyze log-level info
 
-echo OK > /testok
+echo OK >/testok
 
 exit 0
index 957d22031a9416a94e293901ee375845bc9482e9..7593401369eef8d07b47021bf995a407b9032646 100755 (executable)
@@ -41,6 +41,6 @@ done
 
 systemd-analyze log-level info
 
-echo OK > /testok
+echo OK >/testok
 
 exit 0
index 81fa1716f14bbf749ae811a0a76ead4696dd01f0..0a43f8ba57412a0ed908f93c2c500ec72c449c49 100755 (executable)
@@ -9,7 +9,8 @@ systemd-analyze log-level debug
 systemd-analyze log-target console
 
 # test one: Restart=on-failure should restart the service
-! systemd-run --unit=one -p Type=oneshot -p Restart=on-failure /bin/bash -c "exit 1"
+systemd-run --unit=one -p Type=oneshot -p Restart=on-failure /bin/bash -c "exit 1" \
+    && { echo 'unexpected success'; exit 1; }
 
 for ((secs=0; secs<$MAX_SECS; secs++)); do
   [[ "$(systemctl show one.service -P NRestarts)" -le 0 ]] || break
@@ -25,7 +26,13 @@ TMP_FILE="/tmp/test-41-oneshot-restart-test"
 
 # test two: make sure StartLimitBurst correctly limits the number of restarts
 # and restarts execution of the unit from the first ExecStart=
-! systemd-run --unit=two -p StartLimitIntervalSec=120 -p StartLimitBurst=3 -p Type=oneshot -p Restart=on-failure -p ExecStart="/bin/bash -c \"printf a >>  $TMP_FILE\"" /bin/bash -c "exit 1"
+systemd-run --unit=two \
+            -p StartLimitIntervalSec=120 \
+            -p StartLimitBurst=3 \
+            -p Type=oneshot \
+            -p Restart=on-failure \
+            -p ExecStart="/bin/bash -c \"printf a >>  $TMP_FILE\"" /bin/bash -c "exit 1" \
+    && { echo 'unexpected success'; exit 1; }
 
 # wait for at least 3 restarts
 for ((secs=0; secs<$MAX_SECS; secs++)); do
@@ -44,6 +51,6 @@ fi
 
 systemd-analyze log-level info
 
-echo OK > /testok
+echo OK >/testok
 
 exit 0
index 154398dd662e8a68c4c0b7823eb47403d5229515..ca13c5dec5cab036070318298af3db78e9e98300 100755 (executable)
@@ -6,16 +6,18 @@ systemd-analyze log-level debug
 systemd-run --unit=simple1.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=simple -p ExecStopPost='/bin/touch /run/simple1' true
 test -f /run/simple1
 
-! systemd-run --unit=simple2.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=simple -p ExecStopPost='/bin/touch /run/simple2' false
+systemd-run --unit=simple2.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=simple -p ExecStopPost='/bin/touch /run/simple2' false \
+    && { echo 'unexpected success'; exit 1; }
 test -f /run/simple2
 
 systemd-run --unit=exec1.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=exec -p ExecStopPost='/bin/touch /run/exec1' sleep 1
 test -f /run/exec1
 
-! systemd-run --unit=exec2.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=exec -p ExecStopPost='/bin/touch /run/exec2' sh -c 'sleep 1; false'
+systemd-run --unit=exec2.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=exec -p ExecStopPost='/bin/touch /run/exec2' sh -c 'sleep 1; false' \
+    && { echo 'unexpected success'; exit 1; }
 test -f /run/exec2
 
-cat > /tmp/forking1.sh <<EOF
+cat >/tmp/forking1.sh <<EOF
 #!/usr/bin/env bash
 
 set -eux
@@ -31,7 +33,7 @@ chmod +x /tmp/forking1.sh
 systemd-run --unit=forking1.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=forking -p NotifyAccess=exec -p ExecStopPost='/bin/touch /run/forking1' /tmp/forking1.sh
 test -f /run/forking1
 
-cat > /tmp/forking2.sh <<EOF
+cat >/tmp/forking2.sh <<EOF
 #!/usr/bin/env bash
 
 set -eux
@@ -44,13 +46,15 @@ systemd-notify MAINPID=\$MAINPID
 EOF
 chmod +x /tmp/forking2.sh
 
-! systemd-run --unit=forking2.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=forking -p NotifyAccess=exec -p ExecStopPost='/bin/touch /run/forking2' /tmp/forking2.sh
+systemd-run --unit=forking2.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=forking -p NotifyAccess=exec -p ExecStopPost='/bin/touch /run/forking2' /tmp/forking2.sh \
+    && { echo 'unexpected success'; exit 1; }
 test -f /run/forking2
 
 systemd-run --unit=oneshot1.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=oneshot -p ExecStopPost='/bin/touch /run/oneshot1' true
 test -f /run/oneshot1
 
-! systemd-run --unit=oneshot2.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=oneshot -p ExecStopPost='/bin/touch /run/oneshot2' false
+systemd-run --unit=oneshot2.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=oneshot -p ExecStopPost='/bin/touch /run/oneshot2' false \
+    && { echo 'unexpected success'; exit 1; }
 test -f /run/oneshot2
 
 systemd-run --unit=dbus1.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=dbus -p BusName=systemd.test.ExecStopPost -p ExecStopPost='/bin/touch /run/dbus1' \
@@ -58,10 +62,10 @@ systemd-run --unit=dbus1.service --wait -p StandardOutput=tty -p StandardError=t
     || :
 test -f /run/dbus1
 
-systemd-run --unit=dbus2.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=dbus -p BusName=systemd.test.ExecStopPost -p ExecStopPost='/bin/touch /run/dbus2' true
+systemd-run --unit=dbus2.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=dbus -p BusName=systemd.test.ExecStopPost -p ExecStopPost='/bin/touch /run/dbus2' true
 test -f /run/dbus2
 
-cat > /tmp/notify1.sh <<EOF
+cat >/tmp/notify1.sh <<EOF
 #!/usr/bin/env bash
 
 set -eux
@@ -73,17 +77,19 @@ chmod +x /tmp/notify1.sh
 systemd-run --unit=notify1.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=notify -p ExecStopPost='/bin/touch /run/notify1' /tmp/notify1.sh
 test -f /run/notify1
 
-! systemd-run --unit=notify2.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=notify -p ExecStopPost='/bin/touch /run/notify2' true
+systemd-run --unit=notify2.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=notify -p ExecStopPost='/bin/touch /run/notify2' true \
+    && { echo 'unexpected success'; exit 1; }
 test -f /run/notify2
 
 systemd-run --unit=idle1.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=idle -p ExecStopPost='/bin/touch /run/idle1' true
 test -f /run/idle1
 
-! systemd-run --unit=idle2.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=idle -p ExecStopPost='/bin/touch /run/idle2' false
+systemd-run --unit=idle2.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=idle -p ExecStopPost='/bin/touch /run/idle2' false \
+     && { echo 'unexpected success'; exit 1; }
 test -f /run/idle2
 
 systemd-analyze log-level info
 
-echo OK > /testok
+echo OK >/testok
 
 exit 0
index ec84868a21271cbc07591c636b359c286925cdb3..f3c0ca4fd223dccc9827f4557a1a28cc88f0f0b1 100755 (executable)
@@ -34,9 +34,10 @@ test -e /home/testuser/works.txt
 runas testuser systemd-run --wait --user --unit=test-protect-home-read-only \
     -p PrivateUsers=yes -p ProtectHome=read-only \
     -P bash -c '
-        test -e /home/testuser/works.txt
-        ! touch /home/testuser/blocked.txt
-    '
+        test -e /home/testuser/works.txt || exit 10
+        touch /home/testuser/blocked.txt && exit 11
+    ' \
+        && { echo 'unexpected success'; exit 1; }
 test ! -e /home/testuser/blocked.txt
 
 # Check that tmpfs hides the whole directory
@@ -57,12 +58,13 @@ runas testuser systemd-run --wait --user --unit=test-protect-home-yes \
 # namespace (no CAP_SETGID in the parent namespace to write the additional
 # mapping of the user supplied group and thus cannot change groups to an
 # unmapped group ID)
-runas testuser systemd-run --wait --user --unit=test-group-fail \
+runas testuser systemd-run --wait --user --unit=test-group-fail \
     -p PrivateUsers=yes -p Group=daemon \
-    -P true
+    -P true \
+    && { echo 'unexpected success'; exit 1; }
 
 systemd-analyze log-level info
 
-echo OK > /testok
+echo OK >/testok
 
 exit 0
index 97541634d05b8a816f234f1d4e79422c8bf175cb..0badb7112591ec322c92349280fce5814e3df789 100755 (executable)
@@ -6,14 +6,14 @@ systemd-analyze log-level debug
 systemd-run -p LogNamespace=foobar echo "hello world"
 
 journalctl --namespace=foobar --sync
-journalctl --namespace=foobar > /tmp/hello-world
-journalctl /tmp/no-hello-world
+journalctl -o cat --namespace=foobar >/tmp/hello-world
+journalctl -o cat >/tmp/no-hello-world
 
-grep "hello world" /tmp/hello-world
-! grep "hello world" /tmp/no-hello-world
+grep "^hello world$" /tmp/hello-world
+grep "^hello world$" /tmp/no-hello-world && { echo 'unexpected success'; exit 1; }
 
 systemd-analyze log-level info
 
-echo OK > /testok
+echo OK >/testok
 
 exit 0
index 00bbdf507e62f79b4a4c2878dacbeebfe50fe2bd..d3f0f710434f54314155e8c1e27893580ce45ce2 100755 (executable)
@@ -4,22 +4,21 @@ set -o pipefail
 
 # Check if homectl is installed, and if it isn't bail out early instead of failing
 if ! test -x /usr/bin/homectl ; then
-        echo OK > /testok
+        echo OK >/testok
         exit 0
 fi
 
 inspect() {
-        # As updating disk-size-related attributes can take some time on
-        # some filesystems, let's drop these fields before comparing the
-        # outputs to avoid unexpected fails. To see the full outputs of both
-        # homectl & userdbctl (for debugging purposes) drop the fields just
-        # before the comparison.
-        homectl inspect $1 | tee /tmp/a
-        userdbctl user $1 | tee /tmp/b
-
-        local PATTERN='/^\s*Disk (Size|Free|Floor|Ceiling):/d'
-        diff <(sed -r "$PATTERN" /tmp/a) <(sed -r "$PATTERN" /tmp/b)
-        rm /tmp/a /tmp/b
+    # As updating disk-size-related attributes can take some time on some
+    # filesystems, let's drop these fields before comparing the outputs to
+    # avoid unexpected fails. To see the full outputs of both homectl &
+    # userdbctl (for debugging purposes) drop the fields just before the
+    # comparison.
+    homectl inspect $1 | tee /tmp/a
+    userdbctl user $1 | tee /tmp/b
+
+    diff -I '/^\s*Disk (Size|Free|Floor|Ceiling):/' /tmp/{a,b}
+    rm /tmp/{a,b}
 }
 
 systemd-analyze log-level debug
@@ -66,16 +65,20 @@ inspect test-user
 PASSWORD=xEhErW0ndafV4s homectl deactivate test-user
 inspect test-user
 
-! PASSWORD=xEhErW0ndafV4s homectl with test-user -- test -f /home/test-user/xyz
+PASSWORD=xEhErW0ndafV4s homectl with test-user -- test ! -f /home/test-user/xyz
+PASSWORD=xEhErW0ndafV4s homectl with test-user -- test -f /home/test-user/xyz \
+    && { echo 'unexpected success'; exit 1; }
 PASSWORD=xEhErW0ndafV4s homectl with test-user -- touch /home/test-user/xyz
 PASSWORD=xEhErW0ndafV4s homectl with test-user -- test -f /home/test-user/xyz
 PASSWORD=xEhErW0ndafV4s homectl with test-user -- rm /home/test-user/xyz
-! PASSWORD=xEhErW0ndafV4s homectl with test-user -- test -f /home/test-user/xyz
+PASSWORD=xEhErW0ndafV4s homectl with test-user -- test ! -f /home/test-user/xyz
+PASSWORD=xEhErW0ndafV4s homectl with test-user -- test -f /home/test-user/xyz \
+    && { echo 'unexpected success'; exit 1; }
 
 homectl remove test-user
 
 systemd-analyze log-level info
 
-echo OK > /testok
+echo OK >/testok
 
 exit 0
index 8c34289c529602223d99fe854fb6d9e1232d28c7..b008f52e9521e33cd2c8988b026efa298e240fcd 100755 (executable)
@@ -1,5 +1,5 @@
 #!/usr/bin/env bash
 
 sleep infinity &
-echo $! > /leakedtestpid
+echo $! >/leakedtestpid
 wait $!
index 50034cf3d9a5e9af2c6ccfd1cfbcf60a79d21ebc..f8529083a2b23fdfcc7359ac157d218dc261063b 100755 (executable)
@@ -20,6 +20,6 @@ ps -p "$leaked_pid" && exit 42
 
 systemd-analyze log-level info
 
-echo OK > /testok
+echo OK >/testok
 
 exit 0
index 03231e71b183b3f1f76fac1d1bd641ad9b98404e..ea84b1d72325d25ae214eb67651dcacebd3fb76a 100755 (executable)
@@ -3,7 +3,7 @@
 # ex: ts=8 sw=4 sts=4 et filetype=sh
 set -ex
 
-cat > /run/systemd/system/testservice-48.target <<EOF
+cat >/run/systemd/system/testservice-48.target <<EOF
 [Unit]
 Wants=testservice-48.service
 EOF
@@ -23,7 +23,7 @@ systemctl start testservice-48.target
 # May 07 23:12:20 systemd-testsuite testsuite-48.sh[53]: ef53
 sleep 3.1
 
-cat > /run/systemd/system/testservice-48.service <<EOF
+cat >/run/systemd/system/testservice-48.service <<EOF
 [Service]
 ExecStart=/bin/sleep infinity
 EOF
@@ -39,7 +39,7 @@ systemctl daemon-reload
 
 sleep 3.1
 
-cat > /run/systemd/system/testservice-48.service <<EOF
+cat >/run/systemd/system/testservice-48.service <<EOF
 [Service]
 ExecStart=/bin/sleep infinity
 EOF
@@ -61,7 +61,7 @@ systemctl daemon-reload
 
 sleep 3.1
 
-cat > /run/systemd/system/testservice-48.target <<EOF
+cat >/run/systemd/system/testservice-48.target <<EOF
 [Unit]
 Conflicts=shutdown.target
 Wants=testservice-48.service
@@ -71,7 +71,7 @@ systemctl daemon-reload
 
 systemctl start testservice-48.target
 
-cat > /run/systemd/system/testservice-48.service <<EOF
+cat >/run/systemd/system/testservice-48.service <<EOF
 [Service]
 ExecStart=/bin/sleep infinity
 EOF
@@ -80,6 +80,6 @@ systemctl restart testservice-48.target
 
 systemctl is-active testservice-48.service
 
-echo OK > /testok
+echo OK >/testok
 
 exit 0
index 07bb20d99c67f5f39e77f62099bc9216e6ad85df..f92280f884bedabca0dbaeb22caf512af91f8f95 100755 (executable)
@@ -1,7 +1,7 @@
 #!/usr/bin/env bash
 set -ex
 
-echo "MARKER_FIXED" > /run/testservice-49-fixed
+echo "MARKER_FIXED" >/run/testservice-49-fixed
 mkdir -p /run/inaccessible
 
 systemctl start testsuite-49-namespaced.service
@@ -11,7 +11,7 @@ set +e
 systemctl bind --mkdir testsuite-49-namespaced.service /run/testservice-49-fixed /run/inaccessible/testfile_fixed && exit 1
 set -e
 
-echo "MARKER_RUNTIME" > /run/testservice-49-runtime
+echo "MARKER_RUNTIME" >/run/testservice-49-runtime
 
 systemctl bind --mkdir testsuite-49-namespaced.service /run/testservice-49-runtime /tmp/testfile_runtime
 
@@ -38,6 +38,6 @@ set +e
 systemctl is-active testsuite-49-non-namespaced.service && exit 1
 set -e
 
-echo OK > /testok
+echo OK >/testok
 
 exit 0
index e2d8ef6da23693b543f702ab7fba4220e5ccafa2..b3c120d9a6491d9324ff478d89b0880db28b3685 100755 (executable)
@@ -32,13 +32,13 @@ os_release=$(test -e /etc/os-release && echo /etc/os-release || echo /usr/lib/os
 
 systemd-dissect --json=short ${image}.raw | grep -q -F '{"rw":"ro","designator":"root","partition_uuid":null,"partition_label":null,"fstype":"squashfs","architecture":null,"verity":"external"'
 systemd-dissect ${image}.raw | grep -q -F "MARKER=1"
-systemd-dissect ${image}.raw | grep -q -F -f $os_release
+systemd-dissect ${image}.raw | grep -q -F -f <(sed 's/"//g' $os_release)
 
 mv ${image}.verity ${image}.fooverity
 mv ${image}.roothash ${image}.foohash
 systemd-dissect --json=short ${image}.raw --root-hash=${roothash} --verity-data=${image}.fooverity | grep -q -F '{"rw":"ro","designator":"root","partition_uuid":null,"partition_label":null,"fstype":"squashfs","architecture":null,"verity":"external"'
 systemd-dissect ${image}.raw --root-hash=${roothash} --verity-data=${image}.fooverity | grep -q -F "MARKER=1"
-systemd-dissect ${image}.raw --root-hash=${roothash} --verity-data=${image}.fooverity | grep -q -F -f $os_release
+systemd-dissect ${image}.raw --root-hash=${roothash} --verity-data=${image}.fooverity | grep -q -F -f <(sed 's/"//g' $os_release)
 mv ${image}.fooverity ${image}.verity
 mv ${image}.foohash ${image}.roothash
 
@@ -130,7 +130,7 @@ VERITY_UUID=$(systemd-id128 -u show $(tail -c 32 ${image}.roothash) -u | tail -n
 systemd-dissect --json=short --root-hash ${roothash} ${image}.gpt | grep -q '{"rw":"ro","designator":"root","partition_uuid":"'$ROOT_UUID'","partition_label":"Root Partition","fstype":"squashfs","architecture":"'$architecture'","verity":"yes","node":'
 systemd-dissect --json=short --root-hash ${roothash} ${image}.gpt | grep -q '{"rw":"ro","designator":"root-verity","partition_uuid":"'$VERITY_UUID'","partition_label":"Verity Partition","fstype":"DM_verity_hash","architecture":"'$architecture'","verity":null,"node":'
 systemd-dissect --root-hash ${roothash} ${image}.gpt | grep -q -F "MARKER=1"
-systemd-dissect --root-hash ${roothash} ${image}.gpt | grep -q -F -f $os_release
+systemd-dissect --root-hash ${roothash} ${image}.gpt | grep -q -F -f <(sed 's/"//g' $os_release)
 
 systemd-dissect --root-hash ${roothash} --mount ${image}.gpt ${image_dir}/mount
 cat ${image_dir}/mount/usr/lib/os-release | grep -q -F -f $os_release
@@ -207,7 +207,7 @@ grep -F "squashfs" ${image_dir}/result/c | grep -q -F -v "nosuid"
 
 # Adding a new mounts at runtime works if the unit is in the active state,
 # so use Type=notify to make sure there's no race condition in the test
-cat > /run/systemd/system/testservice-50d.service <<EOF
+cat >/run/systemd/system/testservice-50d.service <<EOF
 [Service]
 RuntimeMaxSec=300
 Type=notify
index aabc56f3481fa6885cc8c44b69921ae5c8ed519b..d145d7e33ec498628fa08d2d4758ea3b39fca54e 100755 (executable)
@@ -10,22 +10,24 @@ systemd-run -p LoadCredential=passwd:/etc/passwd \
             -p DynamicUser=1 \
             --wait \
             --pipe \
-            cat '${CREDENTIALS_DIRECTORY}/passwd' '${CREDENTIALS_DIRECTORY}/shadow' '${CREDENTIALS_DIRECTORY}/dog' > /tmp/ts54-concat
+            cat '${CREDENTIALS_DIRECTORY}/passwd' '${CREDENTIALS_DIRECTORY}/shadow' '${CREDENTIALS_DIRECTORY}/dog' >/tmp/ts54-concat
 ( cat /etc/passwd /etc/shadow && echo -n wuff ) | cmp /tmp/ts54-concat
 rm /tmp/ts54-concat
 
 # Verify that the creds are immutable
-systemd-run -p LoadCredential=passwd:/etc/passwd \
+systemd-run -p LoadCredential=passwd:/etc/passwd \
             -p DynamicUser=1 \
             --wait \
-            touch '${CREDENTIALS_DIRECTORY}/passwd'
-! systemd-run -p LoadCredential=passwd:/etc/passwd \
+            touch '${CREDENTIALS_DIRECTORY}/passwd' \
+    && { echo 'unexpected success'; exit 1; }
+systemd-run -p LoadCredential=passwd:/etc/passwd \
             -p DynamicUser=1 \
             --wait \
-            rm '${CREDENTIALS_DIRECTORY}/passwd'
+            rm '${CREDENTIALS_DIRECTORY}/passwd' \
+    && { echo 'unexpected success'; exit 1; }
 
 systemd-analyze log-level info
 
-echo OK > /testok
+echo OK >/testok
 
 exit 0
index f7896ada4274c3d53a5138b345acd121db6d66dd..d73f4b1e7ae21b76e9a5000e345c1116a61b6bf4 100755 (executable)
@@ -6,19 +6,19 @@ systemd-analyze log-level debug
 systemd-analyze log-target console
 
 # Loose checks to ensure the environment has the necessary features for systemd-oomd
-[[ -e /proc/pressure ]] || echo "no PSI" >> /skipped
+[[ -e /proc/pressure ]] || echo "no PSI" >>/skipped
 cgroup_type=$(stat -fc %T /sys/fs/cgroup/)
 if [[ "$cgroup_type" != *"cgroup2"* ]] && [[ "$cgroup_type" != *"0x63677270"* ]]; then
-    echo "no cgroup2" >> /skipped
+    echo "no cgroup2" >>/skipped
 fi
 if [ ! -f /usr/lib/systemd/systemd-oomd ] && [ ! -f /lib/systemd/systemd-oomd ]; then
-    echo "no oomd" >> /skipped
+    echo "no oomd" >>/skipped
 fi
 [[ -e /skipped ]] && exit 0 || true
 
 rm -rf /etc/systemd/system/testsuite-55-testbloat.service.d
 
-echo "DefaultMemoryPressureDurationSec=5s" >> /etc/systemd/oomd.conf
+echo "DefaultMemoryPressureDurationSec=5s" >>/etc/systemd/oomd.conf
 
 systemctl start testsuite-55-testchill.service
 systemctl start testsuite-55-testbloat.service
@@ -47,8 +47,8 @@ if setfattr -n user.xattr_test -v 1 /sys/fs/cgroup/; then
     sleep 120 # wait for systemd-oomd kill cool down and elevated memory pressure to come down
 
     mkdir -p /etc/systemd/system/testsuite-55-testbloat.service.d/
-    echo "[Service]" > /etc/systemd/system/testsuite-55-testbloat.service.d/override.conf
-    echo "ManagedOOMPreference=avoid" >> /etc/systemd/system/testsuite-55-testbloat.service.d/override.conf
+    echo "[Service]" >/etc/systemd/system/testsuite-55-testbloat.service.d/override.conf
+    echo "ManagedOOMPreference=avoid" >>/etc/systemd/system/testsuite-55-testbloat.service.d/override.conf
 
     systemctl daemon-reload
     systemctl start testsuite-55-testchill.service
@@ -71,6 +71,6 @@ fi
 
 systemd-analyze log-level info
 
-echo OK > /testok
+echo OK >/testok
 
 exit 0
index 9de03e1dea4f73e873d77c58e08af663b47eb479..079da072015a666c9e20c90332c77a22d3c6e511 100755 (executable)
@@ -29,11 +29,13 @@ systemd-run --wait --unit=one -p ExitType=cgroup /tmp/test56-exit-cgroup.sh
 systemd-run --wait --unit=two -p ExitType=cgroup -p ExecCondition=true /tmp/test56-exit-cgroup.sh
 
 # false exec condition: systemd-run should exit immediately with status code: 1
-! systemd-run --wait --unit=three -p ExitType=cgroup -p ExecCondition=false /tmp/test56-exit-cgroup.sh
+systemd-run --wait --unit=three -p ExitType=cgroup -p ExecCondition=false /tmp/test56-exit-cgroup.sh \
+    && { echo 'unexpected success'; exit 1; }
 
 # service should exit uncleanly
 (sleep 1; systemctl kill --signal 9 four) &
-! systemd-run --wait --unit=four -p ExitType=cgroup /tmp/test56-exit-cgroup.sh
+systemd-run --wait --unit=four -p ExitType=cgroup /tmp/test56-exit-cgroup.sh \
+    && { echo 'unexpected success'; exit 1; }
 
 
 # Multiple level process tree, parent process exits quickly
@@ -55,7 +57,8 @@ systemd-run --wait --unit=five -p ExitType=cgroup /tmp/test56-exit-cgroup-parent
 
 # service should exit uncleanly
 (sleep 1; systemctl kill --signal 9 six) &
-! systemd-run --wait --unit=six -p ExitType=cgroup /tmp/test56-exit-cgroup-parentless.sh
+systemd-run --wait --unit=six -p ExitType=cgroup /tmp/test56-exit-cgroup-parentless.sh \
+    && { echo 'unexpected success'; exit 1; }
 
 
 # Multiple level process tree, parent process exits uncleanly but last process exits cleanly
@@ -85,10 +88,11 @@ EOF
 chmod +x /tmp/test56-exit-cgroup-unclean.sh
 
 # service should exit uncleanly after 1 second
-! systemd-run --wait --unit=eight -p ExitType=cgroup /tmp/test56-exit-cgroup-unclean.sh
+systemd-run --wait --unit=eight -p ExitType=cgroup /tmp/test56-exit-cgroup-unclean.sh \
+    && { echo 'unexpected success'; exit 1; }
 
 systemd-analyze log-level info
 
-echo OK > /testok
+echo OK >/testok
 
 exit 0
index 1d11fa98a16f324ab7f1e790a3917049ea3b3d62..2274d36e6016b8e234131e9f784ed643b0520bd5 100755 (executable)
@@ -1,37 +1,71 @@
 #!/usr/bin/env bash
 # SPDX-License-Identifier: LGPL-2.1-or-later
-set -e
+set -eu
 
-which perl &>/dev/null || exit 77
+SOURCE_ROOT="${1:?Missing argument: project source root}"
+BUILD_ROOT="${2:?Missing argument: project build root}"
+
+command -v gawk &>/dev/null || exit 77
 
 function generate_directives() {
-    perl -aF'/[\s,]+/' -ne '
-        if (my ($s, $d) = ($F[0] =~ /^([^\s\.]+)\.([^\s\.]+)$/)) { $d{$s}{"$d="} = 1; }
-        END { while (my ($key, $value) = each %d) {
-            printf "[%s]\n%s\n", $key, join("\n", keys(%$value))
-        }}' "$1"
+    gawk -v sec_rx="${2:-""}" -v unit_type="${3:-""}" '
+    match($0, /^([^ \t\.]+)\.([^ \t\.,]+)/, m) {
+        # res[section][directive] = 1
+        res[m[1]][m[2]] = 1;
+    }
+    END {
+        if (unit_type)
+            print unit_type
+
+        for (section in res) {
+            if (sec_rx && section !~ sec_rx)
+                continue
+
+            print "[" section "]";
+            for (directive in res[section]) {
+                print directive "=";
+            }
+        }
+    }
+    ' "$1"
 }
 
 ret=0
 if ! diff \
-     <(generate_directives "$1"/src/network/networkd-network-gperf.gperf | sort) \
-     <(cat "$1"/test/fuzz/fuzz-network-parser/directives.network | sort); then
+     <(generate_directives "$SOURCE_ROOT"/src/network/networkd-network-gperf.gperf | sort) \
+     <(sort "$SOURCE_ROOT"/test/fuzz/fuzz-network-parser/directives.network); then
     echo "Looks like test/fuzz/fuzz-network-parser/directives.network hasn't been updated"
     ret=1
 fi
 
 if ! diff \
-     <(generate_directives "$1"/src/network/netdev/netdev-gperf.gperf | sort) \
-     <(cat "$1"/test/fuzz/fuzz-netdev-parser/directives.netdev | sort); then
+     <(generate_directives "$SOURCE_ROOT"/src/network/netdev/netdev-gperf.gperf | sort) \
+     <(sort "$SOURCE_ROOT"/test/fuzz/fuzz-netdev-parser/directives.netdev); then
     echo "Looks like test/fuzz/fuzz-netdev-parser/directives.netdev hasn't been updated"
     ret=1
 fi
 
 if ! diff \
-     <(generate_directives "$1"/src/udev/net/link-config-gperf.gperf | sort) \
-     <(cat "$1"/test/fuzz/fuzz-link-parser/directives.link | sort) ; then
+     <(generate_directives "$SOURCE_ROOT"/src/udev/net/link-config-gperf.gperf | sort) \
+     <(sort "$SOURCE_ROOT"/test/fuzz/fuzz-link-parser/directives.link) ; then
     echo "Looks like test/fuzz/fuzz-link-parser/directives.link hasn't been updated"
     ret=1
 fi
 
+for section in Automount Mount Path Scope Slice Socket Swap Timer; do
+    if ! diff \
+         <(generate_directives "$BUILD_ROOT"/src/core/load-fragment-gperf.gperf "$section" "${section,,}" | sort) \
+         <(sort "$SOURCE_ROOT/test/fuzz/fuzz-unit-file/directives.${section,,}") ; then
+        echo "Looks like test/fuzz/fuzz-unit-file/directives.${section,,} hasn't been updated"
+        ret=1
+    fi
+done
+
+if ! diff \
+     <(generate_directives "$BUILD_ROOT"/src/core/load-fragment-gperf.gperf "(Service|Unit|Install)" "service" | sort) \
+     <(sort "$SOURCE_ROOT/test/fuzz/fuzz-unit-file/directives.service") ; then
+    echo "Looks like test/fuzz/fuzz-unit-file/directives.service hasn't been updated"
+    ret=1
+fi
+
 exit $ret
index 0d0eeea7530524b0349b11935d83a6752498aa45..15463760c6796d6f93670bb25e3be6bbc8515c6d 100644 (file)
@@ -209,7 +209,8 @@ in_units = [
         ['systemd-networkd.service',             'ENABLE_NETWORKD'],
         ['systemd-networkd-wait-online.service', 'ENABLE_NETWORKD'],
         ['systemd-nspawn@.service',              ''],
-        ['systemd-oomd.service',                 'ENABLE_OOMD'],
+        ['systemd-oomd.service',                 'ENABLE_OOMD',
+         'dbus-org.freedesktop.oom1.service'],
         ['systemd-portabled.service',            'ENABLE_PORTABLED',
          'dbus-org.freedesktop.portable1.service'],
         ['systemd-userdbd.service',              'ENABLE_USERDB'],
index 9369b73ae27fefc63f6e9a172baad8cfb0f4e9f6..98206a9d0643d4b17bee90ee29ce69006fa5313c 100644 (file)
@@ -9,5 +9,5 @@
 
 [Unit]
 Description=Cryptsetup Units Slice
-Documentation=man:systemd.special(7)
+Documentation=man:systemd-cryptsetup@.service(8)
 DefaultDependencies=no
index 2e57b064c183d9a2219fa97829109d458578bd17..70bc67e1d63d2fb98001faa5e5c043c74af68f81 100644 (file)
@@ -29,10 +29,12 @@ StandardError=tty
 # Optionally, pick up basic fields from credentials passed to the service
 # manager. This is useful for importing this data from nspawn's
 # --set-credential= switch.
-LoadCredential=passwd.hashed-password.root
-LoadCredential=passwd.plaintext-password.root
-LoadCredential=passwd.shell.root
-LoadCredential=firstboot.locale
-LoadCredential=firstboot.locale-messages
-LoadCredential=firstboot.keymap
-LoadCredential=firstboot.timezone
+# FIXME: temporarily disabled as it causes asserts on v247/v248, see:
+# https://github.com/systemd/systemd/issues/19178
+#LoadCredential=passwd.hashed-password.root
+#LoadCredential=passwd.plaintext-password.root
+#LoadCredential=passwd.shell.root
+#LoadCredential=firstboot.locale
+#LoadCredential=firstboot.locale-messages
+#LoadCredential=firstboot.keymap
+#LoadCredential=firstboot.timezone
index 47373307b32a527bf9cb0caf9232afe11c3a4938..460ff387f25d2517ec9831e4145071560715cc97 100644 (file)
@@ -25,6 +25,8 @@ TimeoutSec=90s
 # Optionally, pick up a root password and shell for the root user from a
 # credential passed to the service manager. This is useful for importing this
 # data from nspawn's --set-credential= switch.
-LoadCredential=passwd.hashed-password.root
-LoadCredential=passwd.plaintext-password.root
-LoadCredential=passwd.shell.root
+# FIXME: temporarily disabled as it causes asserts on v247/v248, see:
+# https://github.com/systemd/systemd/issues/19178
+#LoadCredential=passwd.hashed-password.root
+#LoadCredential=passwd.plaintext-password.root
+#LoadCredential=passwd.shell.root