]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #24420 from keszybz/mouse-power
authorLennart Poettering <lennart@poettering.net>
Wed, 24 Aug 2022 08:16:14 +0000 (10:16 +0200)
committerGitHub <noreply@github.com>
Wed, 24 Aug 2022 08:16:14 +0000 (10:16 +0200)
Rework on_ac_power()

102 files changed:
.github/workflows/build_test.sh
.github/workflows/build_test.yml
.github/workflows/mkosi.yml
.lgtm/cpp-queries/PotentiallyDangerousFunction.ql
TODO
docs/CODING_STYLE.md
man/bootctl.xml
man/check-os-release.py
man/crypttab.xml
man/journalctl.xml
man/machinectl.xml
man/org.freedesktop.import1.xml
man/org.freedesktop.login1.xml
man/org.freedesktop.systemd1.xml
man/repart.d.xml
man/sd_bus_add_match.xml
man/sd_bus_enqueue_for_read.xml
man/sd_pid_get_owner_uid.xml
man/systemd-analyze.xml
man/systemd-ask-password.xml
man/systemd-cat.xml
man/systemd-debug-generator.xml
man/systemd-detect-virt.xml
man/systemd-nspawn.xml
man/systemd-run.xml
man/systemd.exec.xml
man/systemd.journal-fields.xml
man/systemd.network.xml
man/systemd.path.xml
man/systemd.service.xml
man/systemd.timer.xml
man/systemd.unit.xml
mkosi.build
mkosi.default.d/10-systemd.conf
mkosi.default.d/arch/10-mkosi.arch
mkosi.default.d/centos_epel/10-mkosi.centos_epel
mkosi.default.d/debian/10-mkosi.debian
mkosi.default.d/fedora/10-mkosi.fedora
mkosi.default.d/opensuse/10-mkosi.opensuse
mkosi.default.d/ubuntu/10-mkosi.ubuntu
mkosi.postinst
src/analyze/analyze-verify-util.c
src/basic/glob-util.c
src/basic/glob-util.h
src/basic/mkdir.c
src/basic/path-util.c
src/basic/path-util.h
src/basic/virt.c
src/basic/virt.h
src/boot/bless-boot.c
src/boot/efi/meson.build
src/boot/measure.c
src/core/automount.c
src/core/dbus-job.c
src/core/dbus-unit.c
src/core/dbus-util.c
src/core/dbus-util.h
src/core/execute.c
src/core/job.c
src/core/job.h
src/core/mount.c
src/core/path.c
src/core/path.h
src/core/service.c
src/core/timer.c
src/core/timer.h
src/core/unit.c
src/core/unit.h
src/dissect/dissect.c
src/home/homed-home.c
src/home/homework-luks.c
src/import/export-raw.c
src/journal/journald-server.c
src/journal/journald-server.h
src/libsystemd/sd-bus/bus-kernel.c
src/libsystemd/sd-bus/test-bus-watch-bind.c
src/libsystemd/sd-journal/sd-journal.c
src/machine/machine-dbus.c
src/shared/find-esp.c
src/shared/install.c
src/shared/sleep-config.c
src/shared/sleep-config.h
src/sleep/sleep.c
src/systemctl/systemctl-edit.c
src/systemctl/systemctl-show.c
src/test/test-bpf-devices.c
src/test/test-bpf-firewall.c
src/test/test-bpf-foreign-programs.c
src/test/test-bpf-lsm.c
src/test/test-execute.c
src/test/test-glob-util.c
src/test/test-path.c
src/test/test-socket-bind.c
test/TEST-63-PATH/Makefile [moved from test/TEST-63-ISSUE-17433/Makefile with 100% similarity]
test/TEST-63-PATH/test.sh [moved from test/TEST-63-ISSUE-17433/test.sh with 100% similarity]
test/testsuite-63.units/test63-glob.path [new file with mode: 0644]
test/testsuite-63.units/test63-glob.service [new file with mode: 0644]
test/testsuite-63.units/test63.service
test/units/testsuite-07.sh
test/units/testsuite-50.sh
test/units/testsuite-63.service
test/units/testsuite-63.sh [new file with mode: 0755]

index 4e6f6a1af1ba0ecb6b81cb7ba4bd958cda02a34e..b60db29efcb3bdeb4544171094c192ca1c1e36d3 100755 (executable)
@@ -45,6 +45,7 @@ PACKAGES=(
     libxkbcommon-dev
     libxtables-dev
     libzstd-dev
+    mold
     mount
     net-tools
     perl
@@ -121,27 +122,28 @@ ninja --version
 for args in "${ARGS[@]}"; do
     SECONDS=0
 
-    # meson fails with
-    #   src/boot/efi/meson.build:52: WARNING: Not using lld as efi-ld, falling back to bfd
-    #   src/boot/efi/meson.build:52:16: ERROR: Fatal warnings enabled, aborting
-    # when LINKER is set to lld so let's just not turn meson warnings into errors with lld
-    # to make sure that the build systemd can pick up the correct efi-ld linker automatically.
-
     # The install_tag feature introduced in 0.60 causes meson to fail with fatal-meson-warnings
     # "Project targeting '>= 0.53.2' but tried to use feature introduced in '0.60.0': install_tag arg in custom_target"
     # It can be safely removed from the CI since it isn't actually used anywhere to test anything.
     find . -type f -name meson.build -exec sed -i '/install_tag/d' '{}' '+'
-    if [[ "$LINKER" != lld ]]; then
-        additional_meson_args="--fatal-meson-warnings"
+
+    # mold < 1.1 does not support LTO.
+    if dpkg --compare-versions "$(dpkg-query --showformat='${Version}' --show mold)" ge 1.1; then
+        fatal "Newer mold version detected, please remove this workaround."
+    elif [[ "$args" == *"-Db_lto=true"* ]]; then
+        LD="gold"
+    else
+        LD="$LINKER"
     fi
+
     info "Checking build with $args"
     # shellcheck disable=SC2086
     if ! AR="$AR" \
-         CC="$CC" CC_LD="$LINKER" CFLAGS="-Werror" \
-         CXX="$CXX" CXX_LD="$LINKER" CXXFLAGS="-Werror" \
+         CC="$CC" CC_LD="$LD" CFLAGS="-Werror" \
+         CXX="$CXX" CXX_LD="$LD" CXXFLAGS="-Werror" \
          meson -Dtests=unsafe -Dslow-tests=true -Dfuzz-tests=true --werror \
-               -Dnobody-group=nogroup $additional_meson_args \
-               -Dcryptolib="${CRYPTOLIB:?}" $args build; then
+               -Dnobody-group=nogroup -Dcryptolib="${CRYPTOLIB:?}" \
+               $args build; then
 
         cat build/meson-logs/meson-log.txt
         fatal "meson failed with $args"
index 9a0f8f9bd324798897915726f951df08c9a06137..cd6937e390245ce5a002662dde3b8fc88834014b 100644 (file)
@@ -27,7 +27,7 @@ jobs:
         env:
           - { COMPILER: "gcc",   COMPILER_VERSION: "11", LINKER: "bfd",  CRYPTOLIB: "gcrypt"  }
           - { COMPILER: "gcc",   COMPILER_VERSION: "12", LINKER: "gold", CRYPTOLIB: "openssl" }
-          - { COMPILER: "clang", COMPILER_VERSION: "13", LINKER: "gold", CRYPTOLIB: "gcrypt"  }
+          - { COMPILER: "clang", COMPILER_VERSION: "13", LINKER: "mold", CRYPTOLIB: "gcrypt"  }
           - { COMPILER: "clang", COMPILER_VERSION: "14", LINKER: "lld",  CRYPTOLIB: "openssl" }
           - { COMPILER: "clang", COMPILER_VERSION: "15", LINKER: "bfd",  CRYPTOLIB: "auto"    }
     env: ${{ matrix.env }}
index fa0a22a577c11bb66ae6fe07af6aaad0cdb6a4ee..c2c12f33931a37a7230e57ba424fbec15401ce8c 100644 (file)
@@ -44,8 +44,6 @@ jobs:
             release: rawhide
           - distro: opensuse
             release: tumbleweed
-          - distro: centos_epel
-            release: 8-stream
           - distro: centos_epel
             release: 9-stream
 
index 39e8dddd13a07219bedb768edf2ee8e74d0f31de..63fd14e75f611cfa0a7ab2686b17f1e18d6a9c93 100644 (file)
@@ -46,6 +46,9 @@ predicate potentiallyDangerousFunction(Function f, string message) {
   ) or (
     f.getQualifiedName() = "accept" and
     message = "Call to accept() is not O_CLOEXEC-safe. Use accept4() instead."
+  ) or (
+    f.getQualifiedName() = "dirname" and
+    message = "Call dirname() is icky. Use path_extract_directory() instead."
   )
 }
 
diff --git a/TODO b/TODO
index 309c51b756e0ba0835a95d3ca31db8774b3134f9..46ab894b2a7bdd4292ba1fc20598db6727b1998e 100644 (file)
--- a/TODO
+++ b/TODO
@@ -77,6 +77,11 @@ Janitorial Clean-ups:
 * rework mount.c and swap.c to follow proper state enumeration/deserialization
   semantics, like we do for device.c now
 
+* get rid of prefix_roota() and similar, only use chase_symlinks() and related
+  calls instead.
+
+* get rid of basename() and replace by path_extract_filename()
+
 Deprecations and removals:
 
 * Remove any support for booting without /usr pre-mounted in the initrd entirely.
index b7e700237ad98b5f4297f4e8287c9ec05b0cef50..ac35dc38d56f037e70838644d1be4c7735b23fcf 100644 (file)
@@ -667,11 +667,11 @@ SPDX-License-Identifier: LGPL-2.1-or-later
   process, please use `_exit()` instead of `exit()`, so that the exit handlers
   are not run.
 
-- We never use the POSIX version of `basename()` (which glibc defines in
-  `libgen.h`), only the GNU version (which glibc defines in `string.h`).  The
-  only reason to include `libgen.h` is because `dirname()` is needed. Every
-  time you need that please immediately undefine `basename()`, and add a
-  comment about it, so that no code ever ends up using the POSIX version!
+- Do not use `basename()` or `dirname()`. The semantics in corner cases are
+  full of pitfalls, and the fact that there are two quite different versions of
+  `basename()` (one POSIX and one GNU, of which the latter is much more useful)
+  doesn't make it bette either. Use path_extract_filename() and
+  path_extract_directory() instead.
 
 - Never use `FILENAME_MAX`. Use `PATH_MAX` instead (for checking maximum size
   of paths) and `NAME_MAX` (for checking maximum size of filenames).
index 85820ff6068243a92aa1e8fa5090e34d0f7d3dd0..d7eea90a979e654554ebef3290e562a86983f9c3 100644 (file)
       <varlistentry>
         <term><option>--image=<replaceable>image</replaceable></option></term>
 
-        <listitem><para>Takes a path to a disk image file or block device node. If specified all operations
-        are applied to file system in the indicated disk image. This is similar to <option>--root=</option>
-        but operates on file systems stored in disk images or block devices. The disk image should either
-        contain just a file system or a set of file systems within a GPT partition table, following the
-        <ulink url="https://systemd.io/DISCOVERABLE_PARTITIONS">Discoverable Partitions
+        <listitem><para>Takes a path to a disk image file or block device node. If specified, all operations
+        are applied to file system in the indicated disk image. This option is similar to
+        <option>--root=</option>, but operates on file systems stored in disk images or block devices. The
+        disk image should either contain just a file system or a set of file systems within a GPT partition
+        table, following the <ulink url="https://systemd.io/DISCOVERABLE_PARTITIONS">Discoverable Partitions
         Specification</ulink>. For further information on supported disk images, see
         <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
         switch of the same name.</para></listitem>
         Specification Type #2 entries should be placed in the directory <literal>$(bootctl
         -x)/EFI/Linux/</literal>.</para>
 
-        <para>Note that this option (similar to the <option>--print-booth-path</option> option mentioned
+        <para>Note that this option (similarly to the <option>--print-booth-path</option> option mentioned
         above), is available independently from the boot loader used, i.e. also without
         <command>systemd-boot</command> being installed.</para></listitem>
       </varlistentry>
 
         <para>If set to <option>os-id</option> the entries are named after the OS ID of the running system,
         i.e. the <varname>ID=</varname> field of
-        <citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-        (e.g. <literal>fedora</literal>). Similar, if set to <option>os-image-id</option> the entries are
-        named after the OS image ID of the running system, i.e. the <varname>IMAGE_ID=</varname> field of
+        <citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry> (e.g.
+        <literal>fedora</literal>). Similarly, if set to <option>os-image-id</option> the entries are named
+        after the OS image ID of the running system, i.e. the <varname>IMAGE_ID=</varname> field of
         <filename>os-release</filename> (e.g. <literal>vendorx-cashier-system</literal>).</para>
 
         <para>If set to <option>auto</option> (the default), the <filename>/etc/kernel/entry-token</filename>
index 91a5494b4a1835a687d67f136dff0bbc4adaf21b..1a57c7a20d0eee80d2a8d196282b88a90b55c9b0 100644 (file)
@@ -17,7 +17,8 @@ def read_os_release():
         line = line.rstrip()
         if not line or line.startswith('#'):
             continue
-        if m := re.match(r'([A-Z][A-Z_0-9]+)=(.*)', line):
+        m = re.match(r'([A-Z][A-Z_0-9]+)=(.*)', line)
+        if m:
             name, val = m.groups()
             if val and val[0] in '"\'':
                 val = ast.literal_eval(val)
index a296949595ec47fce822d02b7d697deb604248db..0469d365ef76869595ba90b33d48184fcac8febc 100644 (file)
       then decrypted by the PKCS#11 token with an RSA key stored on it, and then used to unlock the encrypted
       volume. Use the <option>pkcs11-uri=</option> option described below to use this mechanism.</para></listitem>
 
-      <listitem><para>Similar, the key may be acquired via a FIDO2 compatible hardware security token (which
-      must implement the "hmac-secret" extension). In this case a (during enrollment) randomly generated key
-      is stored on disk/removable media, acquired via <constant>AF_UNIX</constant>, or stored in the LUKS2
-      JSON token metadata header. The random key is hashed via a keyed hash function (HMAC) on the FIDO2
-      token, using a secret key stored on the token that never leaves it. The resulting hash value is then
-      used as key to unlock the encrypted volume. Use the <option>fido2-device=</option> option described
-      below to use this mechanism.</para></listitem>
-
-      <listitem><para>Similar, the key may be acquired via a TPM2 security chip. In this case a (during
+      <listitem><para>Similarly, the key may be acquired via a FIDO2 compatible hardware security token
+      (which must implement the "hmac-secret" extension). In this case a key generated randomly during
+      enrollment is stored on disk/removable media, acquired via <constant>AF_UNIX</constant>, or stored in
+      the LUKS2 JSON token metadata header. The random key is hashed via a keyed hash function (HMAC) on the
+      FIDO2 token, using a secret key stored on the token that never leaves it. The resulting hash value is
+      then used as key to unlock the encrypted volume. Use the <option>fido2-device=</option> option
+      described below to use this mechanism.</para></listitem>
+
+      <listitem><para>Similarly, the key may be acquired via a TPM2 security chip. In this case a (during
       enrollment) randomly generated key â€” encrypted by an asymmetric key derived from the TPM2 chip's seed
       key â€” is stored on disk/removable media, acquired via <constant>AF_UNIX</constant>, or stored in the
       LUKS2 JSON token metadata header. Use the <option>tpm2-device=</option> option described below to use
     project='man-pages'><refentrytitle>unix</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
     details. The source socket name is chosen according the following format:</para>
 
-    <programlisting><constant>NUL</constant> <replaceable>RANDOM</replaceable> <literal>/cryptsetup/</literal> <replaceable>VOLUME</replaceable></programlisting>
+    <programlisting><constant>NUL</constant> <replaceable>RANDOM</replaceable> /cryptsetup/ <replaceable>VOLUME</replaceable></programlisting>
 
     <para>In other words: a <constant>NUL</constant> byte (as required for abstract namespace sockets),
     followed by a random string (consisting of alphanumeric characters only), followed by the literal
     string <literal>/cryptsetup/</literal>, followed by the name of the volume to acquire they key
-    for. Example (for a volume <literal>myvol</literal>):</para>
+    for. For example, for the volume <literal>myvol</literal>:</para>
 
-    <example><programlisting>\0d7067f78d9827418/cryptsetup/myvol</programlisting></example>
+    <programlisting>\0d7067f78d9827418/cryptsetup/myvol</programlisting>
 
     <para>Services listening on the <constant>AF_UNIX</constant> stream socket may query the source socket
     name with <citerefentry
     project='man-pages'><refentrytitle>getpeername</refentrytitle><manvolnum>2</manvolnum></citerefentry>,
-    and use it to determine which key to send, allowing a single listening socket to serve keys for a
-    multitude of volumes. If the PKCS#11 logic is used (see above) the socket source name is picked in
-    identical fashion, except that the literal string <literal>/cryptsetup-pkcs11/</literal> is used (similar
-    for FIDO2: <literal>/cryptsetup-fido2/</literal> and TPM2: <literal>/cryptsetup-tpm2/</literal>). This is
-    done so that services providing key material know that not a secret key is requested but an encrypted key
-    that will be decrypted via the PKCS#11/FIDO2/TPM2 logic to acquire the final secret key.</para>
+    and use this to determine which key to send, allowing a single listening socket to serve keys for
+    multiple volumes. If the PKCS#11 logic is used (see above), the socket source name is picked in similar
+    fashion, except that the literal string <literal>/cryptsetup-pkcs11/</literal> is used. And similarly for
+    FIDO2 (<literal>/cryptsetup-fido2/</literal>) and TPM2 (<literal>/cryptsetup-tpm2/</literal>). A diffent
+    path component is used so that services providing key material know that the secret key was not requested
+    directly, but instead an encrypted key that will be decrypted via the PKCS#11/FIDO2/TPM2 logic to acquire
+    the final secret key.</para>
   </refsect1>
 
   <refsect1>
index 97b781a4c7ff9b9b1dcf22c8bb4f001e6b6ccaf7..fb7da5446e2d0b7fe7d154ecdd18b45d81b13ed7 100644 (file)
         <term><option>--image=<replaceable>IMAGE</replaceable></option></term>
 
         <listitem><para>Takes a path to a disk image file or block device node. If specified,
-        <command>journalctl</command> will operate on the file system in the indicated disk image. This is
-        similar to <option>--root=</option> but operates on file systems stored in disk images or block
-        devices, thus providing an easy way to extract log data from disk images. The disk image should
+        <command>journalctl</command> will operate on the file system in the indicated disk image. This
+        option is similar to <option>--root=</option>, but operates on file systems stored in disk images or
+        block devices, thus providing an easy way to extract log data from disk images. The disk image should
         either contain just a file system or a set of file systems within a GPT partition table, following
         the <ulink url="https://systemd.io/DISCOVERABLE_PARTITIONS">Discoverable Partitions
         Specification</ulink>. For further information on supported disk images, see
 
           <varlistentry>
             <term><option>with-unit</option></term>
-            <listitem><para>similar to short-full, but prefixes the unit and user unit names instead of the
-            traditional syslog identifier. Useful when using templated instances, as it will include the
-            arguments in the unit names.</para></listitem>
+            <listitem><para>similar to <option>short-full</option>, but prefixes the unit and user unit names
+            instead of the traditional syslog identifier. Useful when using templated instances, as it will
+            include the arguments in the unit names.</para></listitem>
           </varlistentry>
         </variablelist></listitem>
       </varlistentry>
       <varlistentry>
         <term><option>--smart-relinquish-var</option></term>
 
-        <listitem><para>Similar to <option>--relinquish-var</option> but executes no operation if the root
-        file system and <filename>/var/lib/journal/</filename> reside on the same mount point. This
-        operation is used during system shutdown in order to make the journal daemon stop writing data to
-        <filename>/var/log/journal/</filename> in case that directory is located on a mount point that
-        needs to be unmounted.</para></listitem>
+        <listitem><para>Similar to <option>--relinquish-var</option>, but executes no operation if the root
+        file system and <filename>/var/lib/journal/</filename> reside on the same mount point. This operation
+        is used during system shutdown in order to make the journal daemon stop writing data to
+        <filename>/var/log/journal/</filename> in case that directory is located on a mount point that needs
+        to be unmounted.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index 5bc82e5d1a741f6fbfeb0b56eb05fdb5f37cd8e8..1b39e42e3867762f6355cbad2294e751a491b4f0 100644 (file)
         the machine name is specified as the empty string, or the
         special machine name <literal>.host</literal> (see below) is
         specified, the connection is made to the local host
-        instead. This works similar to <command>login</command> but
+        instead. This works similarly to <command>login</command>, but
         immediately invokes a user process. This command runs the
         specified executable with the specified arguments, or the
         default shell for the user if none is specified, or
         <para>Note that <command>machinectl shell</command> does not propagate the exit code/status of the invoked
         shell process. Use <command>systemd-run</command> instead if that information is required (see below).</para>
 
-        <para>When using the <command>shell</command> command without
-        arguments, (thus invoking the executed shell or command on the
-        local host), it is in many ways similar to a <citerefentry
-        project='die-net'><refentrytitle>su</refentrytitle><manvolnum>1</manvolnum></citerefentry>
-        session, but, unlike <command>su</command>, completely isolates
-        the new session from the originating session, so that it
-        shares no process or session properties, and is in a clean and
-        well-defined state. It will be tracked in a new utmp, login,
-        audit, security and keyring session, and will not inherit any
-        environment variables or resource limits, among other
-        properties.</para>
-
-        <para>Note that <citerefentry><refentrytitle>systemd-run</refentrytitle><manvolnum>1</manvolnum></citerefentry>
-        with its <option>--machine=</option> switch may be used in place of the <command>machinectl shell</command>
-        command, and allows non-interactive operation, more detailed and low-level configuration of the invoked unit,
-        as well as access to runtime and exit code/status information of the invoked shell process. In particular, use
-        <command>systemd-run</command>'s <option>--wait</option> switch to propagate exit status information of the
-        invoked process. Use <command>systemd-run</command>'s <option>--pty</option> switch for acquiring an
-        interactive shell, similar to <command>machinectl shell</command>. In general, <command>systemd-run</command>
-        is preferable for scripting purposes. However, note that <command>systemd-run</command> might require higher
-        privileges than <command>machinectl shell</command>.</para></listitem>
+        <para>Using the <command>shell</command> command without arguments (thus invoking the executed shell
+        or command on the local host), is in many ways similar to a <citerefentry
+        project='die-net'><refentrytitle>su</refentrytitle><manvolnum>1</manvolnum></citerefentry> session,
+        but, unlike <command>su</command>, completely isolates the new session from the originating session,
+        so that it shares no process or session properties and is in a clean well-defined state. It will be
+        tracked in a new utmp, login, audit, security, and keyring sessions, and will not inherit any
+        environment variables or resource limits, among other properties.</para>
+
+        <para>Note that
+        <citerefentry><refentrytitle>systemd-run</refentrytitle><manvolnum>1</manvolnum></citerefentry> with
+        its <option>--machine=</option> switch may be used in place of the <command>machinectl
+        shell</command> command, and allows non-interactive operation, more detailed and low-level
+        configuration of the invoked unit, as well as access to runtime and exit code/status information of
+        the invoked shell process. In particular, use <command>systemd-run</command>'s
+        <option>--wait</option> switch to propagate exit status information of the invoked process. Use
+        <command>systemd-run</command>'s <option>--pty</option> switch to acquire an interactive shell,
+        similarly to <command>machinectl shell</command>. In general, <command>systemd-run</command> is
+        preferable for scripting purposes. However, note that <command>systemd-run</command> might require
+        higher privileges than <command>machinectl shell</command>.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><command>enable</command> <replaceable>NAME</replaceable>…</term>
         <term><command>disable</command> <replaceable>NAME</replaceable>…</term>
 
-        <listitem><para>Enable or disable a container as a system
-        service to start at system boot, using
+        <listitem><para>Enable or disable a container as a system service to start at system boot, using
         <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
-        This enables or disables
-        <filename>systemd-nspawn@.service</filename>, instantiated for
-        the specified machine name, similar to the effect of
-        <command>systemctl enable</command> or <command>systemctl
+        This enables or disables <filename>systemd-nspawn@.service</filename>, instantiated for the specified
+        machine name, similarly to the effect of <command>systemctl enable</command> or <command>systemctl
         disable</command> on the service name.</para></listitem>
       </varlistentry>
 
         machine name. To omit creation of the local, writable copy
         pass <literal>-</literal> as local machine name.</para>
 
-        <para>Similar to the behavior of <command>pull-tar</command>,
-        the read-only image is prefixed with
-        <filename>.raw-</filename>, and thus not shown by
-        <command>list-images</command>, unless <option>--all</option>
-        is passed.</para>
+        <para>Similarly to the behavior of <command>pull-tar</command>, the read-only image is prefixed with
+        <filename>.raw-</filename>, and thus not shown by <command>list-images</command>, unless
+        <option>--all</option> is passed.</para>
 
         <para>Note that pressing C-c during execution of this command
         will not abort the download. Use
         <term><command>import-fs</command> <replaceable>DIRECTORY</replaceable> [<replaceable>NAME</replaceable>]</term>
 
         <listitem><para>Imports a container image stored in a local directory into
-        <filename>/var/lib/machines/</filename>, operates similar to <command>import-tar</command> or
-        <command>import-raw</command>, but the first argument is the source directory. If supported, this command will
-        create btrfs snapshot or subvolume for the new image.</para></listitem>
+        <filename>/var/lib/machines/</filename>, operates similarly to <command>import-tar</command> or
+        <command>import-raw</command>, but the first argument is the source directory. If supported, this
+        command will create a btrfs snapshot or subvolume for the new image.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index 5be21dad6cd5683c56ff9b91edaef85cc985d04c..62d753e00981097cab5800394f1a78412561f1a5 100644 (file)
@@ -183,14 +183,14 @@ node /org/freedesktop/import1 {
       specified file descriptor will be a tar file in case of <function>ExportTar()</function> or a raw disk
       image in case of <function>ExportRaw()</function>. Note that currently raw disk images may not be
       exported as tar files, and vice versa. This restriction might be lifted eventually. The method
-      returns a transfer identifier and object path for cancelling or tracking the export operation, similar
+      returns a transfer identifier and object path for cancelling or tracking the export operation, similarly
       to <function>ImportTar()</function> or <function>ImportRaw()</function> as described above.</para>
 
       <para><function>PullTar()</function> and <function>PullRaw()</function> may be used to download, verify
       and import a system image from a URL. They take an URL argument which should point to a tar or
       raw file on the <literal>http://</literal> or <literal>https://</literal> protocols, possibly
       compressed with xz, bzip2 or gzip. The second argument is a local name for the image. It should be
-      suitable as a hostname, similar to the matching argument of the <function>ImportTar()</function> and
+      suitable as a hostname, similarly to the matching argument of the <function>ImportTar()</function> and
       <function>ImportRaw()</function> methods above. The third argument indicates the verification mode for
       the image. It may be one of <literal>no</literal>, <literal>checksum</literal>,
       <literal>signature</literal>. <literal>no</literal> turns off any kind of verification of the image;
index 4cc9f2789193b0827b1f2b9f22c3c2a7b10e80c7..dc67e0100904adef982b71525f0ebde025449326 100644 (file)
@@ -873,8 +873,9 @@ node /org/freedesktop/login1/seat/seat0 {
     <refsect2>
       <title>Methods</title>
 
-      <para><function>Terminate()</function> and <function>ActivateSession()</function> work similar to
-      TerminateSeat(), ActivationSessionOnSeat() on the Manager object.</para>
+      <para><function>Terminate()</function> and <function>ActivateSession()</function> work similarly to
+      <function>TerminateSeat()</function> and <function>ActivationSessionOnSeat()</function> on the Manager
+      object.</para>
 
       <para><function>SwitchTo()</function> switches to the session on the virtual terminal
       <varname>vtnr</varname>. <function>SwitchToNext()</function> and
@@ -907,8 +908,8 @@ node /org/freedesktop/login1/seat/seat0 {
       encoded in a structure consisting of the ID and the object path.</para>
 
       <para>The <varname>IdleHint</varname>, <varname>IdleSinceHint</varname>, and
-      <varname>IdleSinceHintMonotonic</varname> properties encode the idle state, similar to the ones exposed
-      on the <interfacename>Manager</interfacename> object, but specific for this seat.</para>
+      <varname>IdleSinceHintMonotonic</varname> properties encode the idle state, similarly to the ones
+      exposed on the <interfacename>Manager</interfacename> object, but specific for this seat.</para>
     </refsect2>
   </refsect1>
 
@@ -1000,7 +1001,7 @@ node /org/freedesktop/login1/user/_1000 {
     <refsect2>
       <title>Methods</title>
 
-      <para><function>Terminate()</function> and <function>Kill()</function> work similar to the
+      <para><function>Terminate()</function> and <function>Kill()</function> work similarly to the
       <function>TerminateUser()</function> and <function>KillUser()</function> methods on the manager
       object.</para>
     </refsect2>
@@ -1050,8 +1051,8 @@ node /org/freedesktop/login1/user/_1000 {
       user. Each structure consists of the ID and object path.</para>
 
       <para>The <varname>IdleHint</varname>, <varname>IdleSinceHint</varname>, and
-      <varname>IdleSinceHintMonotonic</varname> properties encode the idle hint state of the user, similar to
-      the <interfacename>Manager</interfacename>'s properties, but specific for this user.</para>
+      <varname>IdleSinceHintMonotonic</varname> properties encode the idle hint state of the user, similarly
+      to the <interfacename>Manager</interfacename>'s properties, but specific for this user.</para>
 
       <para>The <varname>Linger</varname> property shows whether lingering is enabled for this user.</para>
     </refsect2>
index 120ffbc8ef08edd43ab0d37f2f4416057f2285ae..689ca3ec88fc14cd6e70acee7fcf22376f30f6d9 100644 (file)
@@ -1898,6 +1898,7 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
       readonly s CollectMode = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly as Refs = ['...', ...];
+      readonly a(ss) ActivationDetails = [...];
   };
   interface org.freedesktop.DBus.Peer { ... };
   interface org.freedesktop.DBus.Introspectable { ... };
@@ -2229,6 +2230,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <variablelist class="dbus-property" generated="True" extra-ref="Refs"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="ActivationDetails"/>
+
     <!--End of Autogenerated section-->
 
     <refsect2>
@@ -2406,6 +2409,18 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
       <para><varname>Transient</varname> contains a boolean that indicates whether the unit was created as a
       transient unit (i.e. via <function>CreateTransientUnit()</function> on the manager object).</para>
+
+      <para><varname>ActivationDetails</varname> contains a list of string pairs, key and value, that
+      describe the event that caused the unit to be activated, if any. The key describes the information
+      (e.g.: <varname>trigger_unit</varname>, with value <varname>foo.service</varname>). This is only filled
+      in if the unit was triggered by a <varname>Path</varname> or <varname>Timer</varname> unit, and it is
+      only provided in a best effort fashion: it is not guaranteed to be set, and it is not guaranteed to be
+      the only trigger. It is only guaranteed to be a valid trigger that caused the activation job to be
+      enqueued and complete successfully. The key value pairs correspond (in lowercase) to the environment
+      variables described in the <literal>Environment Variables Set on Triggered Units</literal> section in
+      <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
+      Note that new key value pair may be added at any time in future versions. Existing entries will not be
+      removed.</para>
     </refsect2>
 
     <refsect2>
@@ -10650,6 +10665,8 @@ node /org/freedesktop/systemd1/job/666 {
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s JobType = '...';
       readonly s State = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+      readonly a(ss) ActivationDetails = [...];
   };
   interface org.freedesktop.DBus.Peer { ... };
   interface org.freedesktop.DBus.Introspectable { ... };
@@ -10681,6 +10698,8 @@ node /org/freedesktop/systemd1/job/666 {
 
     <variablelist class="dbus-property" generated="True" extra-ref="State"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="ActivationDetails"/>
+
     <!--End of Autogenerated section-->
 
     <refsect2>
@@ -10709,6 +10728,9 @@ node /org/freedesktop/systemd1/job/666 {
       <para><varname>State</varname> refers to the job's state and is one of <literal>waiting</literal> and
       <literal>running</literal>. The former indicates that a job is currently queued but has not begun to
       execute yet. The latter indicates that a job is currently being executed.</para>
+
+      <para><varname>ActivationDetails</varname> has the same content as the property of the same name under
+      the <varname>org.freedesktop.systemd1.Unit</varname> interface.</para>
     </refsect2>
   </refsect1>
 
index 93c85b613800f03a564fadb2542845b33a15eb34..d9ec521160ba7f3e39ddb1a3fbf5c50700e4169f 100644 (file)
       <varlistentry>
         <term><varname>PaddingWeight=</varname></term>
 
-        <listitem><para>Similar to <varname>Weight=</varname> but sets a weight for the free space after the
+        <listitem><para>Similar to <varname>Weight=</varname>, but sets a weight for the free space after the
         partition (the "padding"). When distributing available space the weights of all partitions and all
         defined padding is summed, and then each partition and padding gets the fraction defined by its
         weight. Defaults to 0, i.e. by default no padding is applied.</para>
 
         <para>This option has no effect if the partition already exists.</para>
 
-        <para>Similar to the behaviour of <varname>CopyBlocks=</varname> the file system is formatted before
-        the partition is created, ensuring that the partition only ever exists with a fully initialized
-        file system.</para>
+        <para>Similarly to the behaviour of <varname>CopyBlocks=</varname>, the file system is formatted
+        before the partition is created, ensuring that the partition only ever exists with a fully
+        initialized file system.</para>
 
         <para>This option cannot be combined with <varname>CopyBlocks=</varname>.</para></listitem>
       </varlistentry>
index 3de7a6a53ebad9a18cc3c62a540f3d824475ac03..429a2fd412ad577a88ecada4a6e9bf8297785c3e 100644 (file)
@@ -99,7 +99,7 @@
     synchronously when connected to a bus broker, i.e. the call sends a control message requested the match to be added
     to the broker and waits until the broker confirms the match has been installed successfully.</para>
 
-    <para><function>sd_bus_add_match_async()</function> operates very similar to
+    <para><function>sd_bus_add_match_async()</function> operates very similarly to
     <function>sd_bus_add_match()</function>, however it installs the match asynchronously, in a non-blocking
     fashion: a request is sent to the broker, but the call does not wait for a response. The
     <parameter>install_callback</parameter> function is called when the response is later received, with the response
index 82b91cbe3c72f9feab12b1de5713b838120751dc..9bdf4981950e7b8059300cf8e0379b3b2e017821 100644 (file)
@@ -39,7 +39,7 @@
     <title>Description</title>
 
     <para><function>sd_bus_enqueue_for_read()</function> may be used to re-enqueue an incoming bus message on
-    the local read queue, so that it is processed and dispatched locally again, similar to how an incoming
+    the local read queue, so that it is processed and dispatched locally again, similarly to how an incoming
     message from the peer is processed. Takes a bus connection object and the message to enqueue. A reference
     is taken of the message and the caller's reference thus remains in possession of the caller. The message
     is enqueued at the end of the queue, thus will be dispatched after all other already queued messages are
index 3e30acad8db7bf5274b78557d6b6a2f673ae0312..c516083a5b9303447714f1a6146695e9b67de69c 100644 (file)
     <function>sd_peer_get_machine_name()</function>,
     <function>sd_peer_get_slice()</function>,
     <function>sd_peer_get_user_slice()</function> and
-    <function>sd_peer_get_cgroup()</function> calls operate similar to
-    their PID counterparts, but operate on a connected AF_UNIX socket
-    and retrieve information about the connected peer process. Note
-    that these fields are retrieved via <filename>/proc/</filename>,
-    and hence are not suitable for authorization purposes, as they are
-    subject to races.</para>
+    <function>sd_peer_get_cgroup()</function> calls operate similarly to their PID counterparts, but accept a
+    connected <constant>AF_UNIX</constant> socket and retrieve information about the connected peer process.
+    Note that these fields are retrieved via <filename>/proc/</filename>, and hence are not suitable for
+    authorization purposes, as they are subject to races.</para>
   </refsect1>
 
   <refsect1>
index 8061743c567195551cc052e56fc97b0a09fd0cc5..5789b61a0a352766da4e290101620ca3642a6899 100644 (file)
@@ -215,7 +215,7 @@ multi-user.target reached after 47.820s in userspace
       <replaceable>UNIT</replaceable>s or for the default target otherwise). The time after the unit is
       active or started is printed after the "@" character. The time the unit takes to start is printed after
       the "+" character. Note that the output might be misleading as the initialization of services might
-      depend on socket activation and because of the parallel execution of units. Also, similar to the
+      depend on socket activation and because of the parallel execution of units. Also, similarly to the
       <command>blame</command> command, this only takes into account the time units spent in
       <literal>activating</literal> state, and hence does not cover units that never went through an
       <literal>activating</literal> state (such as device units that transition directly from
index 97735eb65719f1a93d4cfa41f1492073ed0311f0..27f77751fef9574dc40387841a10b70eb1ff9713 100644 (file)
       <varlistentry>
         <term><option>-n</option></term>
 
-        <listitem><para>By default, when writing the acquired password to standard output it is suffixed by a
-        newline character. This may be turned off with the <option>-n</option> switch, similar to the switch
-        of the same name of the <citerefentry
+        <listitem><para>By default, when the acquired password is written to standard output it is suffixed
+        by a newline character. This may be turned off with the <option>-n</option> switch, similarly to the
+        switch of the same name of the <citerefentry
         project='man-pages'><refentrytitle>echo</refentrytitle><manvolnum>1</manvolnum></citerefentry>
         command.</para></listitem>
       </varlistentry>
index aff295bd8717dfb041d221397164827e8f7eee09..a4b6139a8cd467ff40862cff938fbf27490520b2 100644 (file)
       <varlistentry>
         <term><option>--level-prefix=</option></term>
 
-        <listitem><para>Controls whether lines read are parsed for
-        syslog priority level prefixes. If enabled (the default), a
-        line prefixed with a priority prefix such as
-        <literal>&lt;5&gt;</literal> is logged at priority 5
-        (<literal>notice</literal>), and similar for the other
-        priority levels. Takes a boolean argument.</para></listitem>
+        <listitem><para>Controls whether lines read are parsed for syslog priority level prefixes. If enabled
+        (the default), a line prefixed with a priority prefix such as <literal>&lt;5&gt;</literal> is logged
+        at priority 5 (<literal>notice</literal>), and similarly for the other priority levels. Takes a
+        boolean argument.</para></listitem>
       </varlistentry>
 
     </variablelist>
       <programlisting># ls | systemd-cat</programlisting>
     </example>
 
-    <para>Even though the two examples have very similar effects the
-    first is preferable since only one process is running at a time,
-    and both stdout and stderr are captured while in the second
-    example, only stdout is captured.</para>
+    <para>Even though the two examples have very similar effects, the first is preferable, since only one
+    process is running at a time and both stdout and stderr are captured, while in the second example, only
+    stdout is captured.</para>
   </refsect1>
 
   <refsect1>
index 81d1efb446dbca5de280feebe178e9c8e17cfda2..65de9caa9a3d846675b64c7762d37016968c735d 100644 (file)
@@ -37,7 +37,7 @@
 
     <para>If the <option>systemd.mask=</option> or <option>rd.systemd.mask=</option>
     option is specified and followed by a unit name, this unit is
-    masked for the runtime (i.e. for this session - from boot to shutdown), similar to the effect of
+    masked for the runtime (i.e. for this session â€” from boot to shutdown), similarly to the effect of
     <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
     <command>mask</command> command. This is useful to boot with
     certain units removed from the initial boot transaction for
index 8ac4de4047e970cabdbc41932ace3b8c4dbc6085..a8c089d0b515ed6b7678dfbd00ec35ff216b55b4 100644 (file)
@@ -62,7 +62,7 @@
         </thead>
         <tbody>
           <row>
-            <entry valign="top" morerows="14">VM</entry>
+            <entry valign="top" morerows="15">VM</entry>
             <entry><varname>qemu</varname></entry>
             <entry>QEMU software virtualization, without KVM</entry>
           </row>
             <entry><ulink url="https://projectacrn.org">ACRN hypervisor</ulink></entry>
           </row>
 
+          <row>
+            <entry><varname>apple</varname></entry>
+            <entry><ulink url="https://developer.apple.com/documentation/virtualization">Apple Virtualization.framework</ulink></entry>
+          </row>
+
           <row>
             <entry valign="top" morerows="9">Container</entry>
             <entry><varname>openvz</varname></entry>
index 975ddd0be33566200bc9b1795656bb999dc548bb..a5058a781131f1fcc904b153f4a23a4a3aa4ae9d 100644 (file)
         <listitem><para>Set a unit property on the scope unit to register for the machine. This applies only if the
         machine is run in its own scope unit, i.e. if <option>--keep-unit</option> isn't used. Takes unit property
         assignments in the same format as <command>systemctl set-property</command>. This is useful to set memory
-        limits and similar for container.</para>
+        limits and similar for the container.</para>
         </listitem>
       </varlistentry>
 
           the UID/GID range is automatically chosen. As first step, the file owner UID/GID of the root
           directory of the container's directory tree is read, and it is checked that no other container is
           currently using it. If this check is successful, the UID/GID range determined this way is used,
-          similar to the behavior if <literal>yes</literal> is specified. If the check is not successful (and
-          thus the UID/GID range indicated in the root directory's file owner is already used elsewhere) a
-          new â€“ currently unused â€“ UID/GID range of 65536 UIDs/GIDs is randomly chosen between the host
+          similarly to the behavior if <literal>yes</literal> is specified. If the check is not successful
+          (and thus the UID/GID range indicated in the root directory's file owner is already used elsewhere)
+          new â€“ currently unused â€“ UID/GID range of 65536 UIDs/GIDs is randomly chosen between the host
           UID/GIDs of 524288 and 1878982656, always starting at a multiple of 65536, and, if possible,
           consistently hashed from the machine name. This setting implies
           <option>--private-users-ownership=auto</option> (see below), which possibly has the effect that the
@@ -1235,8 +1235,8 @@ After=sys-subsystem-net-devices-ens1.device</programlisting>
 
         <para>If set to <literal>copy-host</literal>, the <filename>/etc/resolv.conf</filename> file from the
         host is copied into the container, unless the file exists already and is not a regular file (e.g. a
-        symlink). Similar, if <literal>replace-host</literal> is used the file is copied, replacing any
-        existing inode, including symlinks. Similar, if <literal>bind-host</literal> is used, the file is
+        symlink). Similarly, if <literal>replace-host</literal> is used the file is copied, replacing any
+        existing inode, including symlinks. Similarly, if <literal>bind-host</literal> is used, the file is
         bind mounted from the host into the container.</para>
 
         <para>If set to <literal>copy-static</literal>, <literal>replace-static</literal> or
index ab1fb8256718f1a3390c167b0723c08a15137193..faf88d560a7141d4689812a63834b86a3cec6ffe 100644 (file)
     command has begun execution (unless <option>--no-block</option> or <option>--wait</option> are specified, see
     below).</para>
 
-    <para>If a command is run as transient scope unit, it will be executed by <command>systemd-run</command> itself as
-    parent process and will thus inherit the execution environment of the caller. However, the processes of the command
-    are managed by the service manager similar to normal services, and will show up in the output of <command>systemctl
-    list-units</command>. Execution in this case is synchronous, and will return only when the command finishes. This
-    mode is enabled via the <option>--scope</option> switch (see below). </para>
+    <para>If a command is run as transient scope unit, it will be executed by <command>systemd-run</command>
+    itself as parent process and will thus inherit the execution environment of the caller. However, the
+    processes of the command are managed by the service manager similarly to normal services, and will show
+    up in the output of <command>systemctl list-units</command>. Execution in this case is synchronous, and
+    will return only when the command finishes. This mode is enabled via the <option>--scope</option> switch
+    (see below). </para>
 
     <para>If a command is run with path, socket, or timer options such as <option>--on-calendar=</option> (see below),
     a transient path, socket, or timer unit is created alongside the service unit for the specified command. Only the
         <term><option>--same-dir</option></term>
         <term><option>-d</option></term>
 
-        <listitem><para>Similar to <option>--working-directory=</option> but uses the current working directory of the
-        caller for the service to execute.</para></listitem>
+        <listitem><para>Similar to <option>--working-directory=</option>, but uses the current working
+        directory of the caller for the service to execute.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><option>--socket-property=</option></term>
         <term><option>--timer-property=</option></term>
 
-        <listitem><para>Sets a property on the path, socket, or timer unit that is created. This option is similar to
-        <option>--property=</option> but applies to the transient path, socket, or timer unit rather than the
-        transient service unit created. This option takes an assignment in the same format as
+        <listitem><para>Sets a property on the path, socket, or timer unit that is created. This option is
+        similar to <option>--property=</option>, but applies to the transient path, socket, or timer unit
+        rather than the transient service unit created. This option takes an assignment in the same format as
         <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
         <command>set-property</command> command. These options may not be combined with
         <option>--scope</option> or <option>--pty</option>.</para>
index f90a1e25d0d9d607d9a39af52ff205fb3bdb27a8..2e843be2e5446df15ae0a6245b935bf5984bd2b6 100644 (file)
@@ -1227,7 +1227,7 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
     affecting the process' ability to operate. Note that many of these sandboxing features are gracefully turned off on
     systems where the underlying security mechanism is not available. For example, <varname>ProtectSystem=</varname>
     has no effect if the kernel is built without file system namespacing or if the service manager runs in a container
-    manager that makes file system namespacing unavailable to its payload. Similar,
+    manager that makes file system namespacing unavailable to its payload. Similarly,
     <varname>RestrictRealtime=</varname> has no effect on systems that lack support for SECCOMP system call filtering,
     or in containers where support for this is turned off.</para>
 
@@ -2536,14 +2536,15 @@ SystemCallErrorNumber=EPERM</programlisting>
       <varlistentry>
         <term><varname>EnvironmentFile=</varname></term>
 
-        <listitem><para>Similar to <varname>Environment=</varname> but reads the environment variables from a text file.
-        The text file should contain newline-separated variable assignments. Empty lines, lines without an
-        <literal>=</literal> separator, or lines starting with <literal>;</literal> or <literal>#</literal> will be
-        ignored, which may be used for commenting. The file must be UTF-8 encoded. Valid characters are <ulink
-        url="https://www.unicode.org/glossary/#unicode_scalar_value">unicode scalar values</ulink> other than <ulink
-        url="https://www.unicode.org/glossary/#noncharacter">noncharacters</ulink>, U+0000 NUL, and U+FEFF <ulink
-        url="https://www.unicode.org/glossary/#byte_order_mark">byte order mark</ulink>. Control codes other than NUL
-        are allowed.</para>
+        <listitem><para>Similar to <varname>Environment=</varname>, but reads the environment variables from
+        a text file. The text file should contain newline-separated variable assignments. Empty lines, lines
+        without an <literal>=</literal> separator, or lines starting with <literal>;</literal> or
+        <literal>#</literal> will be ignored, which may be used for commenting. The file must be UTF-8
+        encoded. Valid characters are <ulink
+        url="https://www.unicode.org/glossary/#unicode_scalar_value">unicode scalar values</ulink> other than
+        <ulink url="https://www.unicode.org/glossary/#noncharacter">noncharacters</ulink>, U+0000 NUL, and
+        U+FEFF <ulink url="https://www.unicode.org/glossary/#byte_order_mark">byte order mark</ulink>.
+        Control codes other than NUL are allowed.</para>
 
         <para>In the file, an unquoted value after the <literal>=</literal> is parsed with the same backslash-escape
         rules as <ulink
@@ -2933,8 +2934,8 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX
         <para>Internally, journal namespaces are implemented through Linux mount namespacing and
         over-mounting the directory that contains the relevant <constant>AF_UNIX</constant> sockets used for
         logging in the unit's mount namespace. Since mount namespaces are used this setting disconnects
-        propagation of mounts from the unit's processes to the host, similar to how
-        <varname>ReadOnlyPaths=</varname> and similar settings (see above) work. Journal namespaces may hence
+        propagation of mounts from the unit's processes to the host, similarly to how
+        <varname>ReadOnlyPaths=</varname> and similar settings describe above work. Journal namespaces may hence
         not be used for services that need to establish mount points on the host.</para>
 
         <para>When this option is used the unit will automatically gain ordering and requirement dependencies
@@ -3381,14 +3382,14 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX
 
           <listitem><para>The PID of the unit's main process if it is
           known. This is only set for control processes as invoked by
-          <varname>ExecReload=</varname> and similar. </para></listitem>
+          <varname>ExecReload=</varname> and similar.</para></listitem>
         </varlistentry>
 
         <varlistentry>
           <term><varname>$MANAGERPID</varname></term>
 
           <listitem><para>The PID of the user <command>systemd</command>
-          instance, set for processes spawned by it. </para></listitem>
+          instance, set for processes spawned by it.</para></listitem>
         </varlistentry>
 
         <varlistentry>
@@ -3426,7 +3427,7 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX
           <listitem><para>The PID of the unit process (e.g. process invoked by
           <varname>ExecStart=</varname>). The child process can use this information to determine
           whether the process is directly invoked by the service manager or indirectly as a child of
-          another process by comparing this value with the current PID (as similar to the scheme used in
+          another process by comparing this value with the current PID (similarly to the scheme used in
           <citerefentry><refentrytitle>sd_listen_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>
           with <varname>$LISTEN_PID</varname> and <varname>$LISTEN_FDS</varname>).</para></listitem>
         </varlistentry>
@@ -3694,6 +3695,21 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX
           system.</para></listitem>
         </varlistentry>
 
+        <varlistentry>
+          <term><varname>$TRIGGER_UNIT</varname></term>
+          <term><varname>$TRIGGER_PATH</varname></term>
+          <term><varname>$TRIGGER_TIMER_REALTIME_USEC</varname></term>
+          <term><varname>$TRIGGER_TIMER_MONOTONIC_USEC</varname></term>
+
+          <listitem><para>If the unit was activated dynamically (e.g.: a corresponding path unit or timer unit), the
+          unit that triggered it and other type-dependent information will be passed via these variables. Note that
+          this information is provided in a best-effort way. For example, multiple triggers happening one after
+          another will be coalesced and only one will be reported, with no guarantee as to which one it will be.
+          Because of this, in most cases this variable will be primarily informational, i.e. useful for debugging
+          purposes, is lossy, and should not be relied upon to propagate a comprehensive reason for activation.
+          </para></listitem>
+        </varlistentry>
+
       </variablelist>
 
       <para>For system services, when <varname>PAMName=</varname> is enabled and <command>pam_systemd</command> is part
index d50e89f0bb9ba0c5754b6be994cdb8215d7cfa08..320b7829923b5711ec3ec4400a4984199df63a2f 100644 (file)
         for details about journal namespaces.</para>
         </listitem>
       </varlistentry>
+      <varlistentry>
+        <term><varname>_SYSTEM_CONTEXT=</varname></term>
+
+        <listitem><para>A string field that specifies the context in which the message was logged. If
+        <literal>initrd</literal>, the log message was processed while systemd-journald
+        was running inside the initrd. If <literal>main</literal>, the log message was generated after
+        journald switched root to the root filesystem.</para></listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 
index 76a924cec73d2dc1facf55c037179d9955f29a5f..818df99e5a1c993d0114160757c987270ecb691d 100644 (file)
@@ -1900,12 +1900,12 @@ Table=1234</programlisting></para>
       <varlistentry>
         <term><varname>UseDomains=</varname></term>
         <listitem>
-          <para>Takes a boolean, or the special value <option>route</option>. When true, the domain
-          name received from the DHCP server will be used as DNS search domain over this link, similar
-          to the effect of the <option>Domains=</option> setting. If set to <option>route</option>, the
-          domain name received from the DHCP server will be used for routing DNS queries only, but not
-          for searching, similar to the effect of the <option>Domains=</option> setting when the
-          argument is prefixed with <literal>~</literal>. Defaults to false.</para>
+          <para>Takes a boolean, or the special value <option>route</option>. When true, the domain name
+          received from the DHCP server will be used as DNS search domain over this link, similarly to the
+          effect of the <option>Domains=</option> setting. If set to <option>route</option>, the domain name
+          received from the DHCP server will be used for routing DNS queries only, but not for searching,
+          similarly to the effect of the <option>Domains=</option> setting when the argument is prefixed with
+          <literal>~</literal>. Defaults to false.</para>
 
           <para>It is recommended to enable this option only on trusted networks, as setting this
           affects resolution of all hostnames, in particular of single-label names. It is generally
@@ -2399,11 +2399,11 @@ Token=prefixstable:2002:da8:1::</programlisting></para>
         <term><varname>UseDomains=</varname></term>
         <listitem>
           <para>Takes a boolean, or the special value <literal>route</literal>. When true, the domain name
-          received via IPv6 Router Advertisement (RA) will be used as DNS search domain over this link, similar to
-          the effect of the <option>Domains=</option> setting. If set to <literal>route</literal>, the domain name
-          received via IPv6 RA will be used for routing DNS queries only, but not for searching, similar to the
-          effect of the <option>Domains=</option> setting when the argument is prefixed with
-          <literal>~</literal>. Defaults to false.</para>
+          received via IPv6 Router Advertisement (RA) will be used as DNS search domain over this link,
+          similarly to the effect of the <option>Domains=</option> setting. If set to
+          <literal>route</literal>, the domain name received via IPv6 RA will be used for routing DNS queries
+          only, but not for searching, similarly to the effect of the <option>Domains=</option> setting when
+          the argument is prefixed with <literal>~</literal>. Defaults to false.</para>
 
           <para>It is recommended to enable this option only on trusted networks, as setting this affects resolution
           of all hostnames, in particular of single-label names. It is generally safer to use the supplied domain
@@ -2924,7 +2924,7 @@ Token=prefixstable:2002:da8:1::</programlisting></para>
       <varlistentry>
         <term><varname>Prefix=</varname></term>
 
-        <listitem><para>The IPv6 prefix that is to be distributed to hosts.  Similarly to configuring static
+        <listitem><para>The IPv6 prefix that is to be distributed to hosts. Similarly to configuring static
         IPv6 addresses, the setting is configured as an IPv6 prefix and its prefix length, separated by a
         <literal>/</literal> character. Use multiple [IPv6Prefix] sections to configure multiple IPv6
         prefixes since prefix lifetimes, address autoconfiguration and onlink status may differ from one
@@ -2979,7 +2979,7 @@ Token=prefixstable:2002:da8:1::</programlisting></para>
       <varlistentry>
         <term><varname>Route=</varname></term>
 
-        <listitem><para>The IPv6 route that is to be distributed to hosts.  Similarly to configuring static
+        <listitem><para>The IPv6 route that is to be distributed to hosts. Similarly to configuring static
         IPv6 routes, the setting is configured as an IPv6 prefix routes and its prefix route length,
         separated by a <literal>/</literal> character. Use multiple [IPv6RoutePrefix] sections to configure
         multiple IPv6 prefix routes.</para></listitem>
index 0392f0dae054c34e525fdd8bf808c38f307eaa83..f143208cb465b05e57c14551f9a4ccaad709f645 100644 (file)
         <varname>PathExists=</varname> may be used to watch the mere
         existence of a file or directory. If the file specified
         exists, the configured unit is activated.
-        <varname>PathExistsGlob=</varname> works similar, but checks
+        <varname>PathExistsGlob=</varname> works similarly, but checks
         for the existence of at least one file matching the globbing
         pattern specified. <varname>PathChanged=</varname> may be used
         to watch a file or directory and activate the configured unit
 
   <refsect1>
       <title>See Also</title>
+      <para>Environment variables with details on the trigger will be set for triggered units. See the
+      <literal>Environment Variables Set on Triggered Units</literal> section in
+      <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+      for more details.</para>
       <para>
         <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
         <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
index 2c36e390f648d104da797a0ef9ba8e3a5be9ea99..98c8bf8c6d3c73f718625fb9f0565ec0cf5e10fc 100644 (file)
         <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
         details.</para>
 
-        <para>This setting also applies to <command>systemd-oomd</command>, similar to the kernel OOM kills
-        this setting determines the state of the service after <command>systemd-oomd</command> kills a cgroup
-        associated with the service.</para></listitem>
+        <para>This setting also applies to <command>systemd-oomd</command>. Similarly to the kernel OOM
+        kills, this setting determines the state of the service after <command>systemd-oomd</command> kills a
+        cgroup associated with the service.</para></listitem>
       </varlistentry>
 
     </variablelist>
index 49bcb18be52b7add99cb8b78c25a1d66d96d5ef8..953faa9b3342af42f1658dc1dcafcc3a1b97c1e5 100644 (file)
 
   <refsect1>
       <title>See Also</title>
+      <para>Environment variables with details on the trigger will be set for triggered units. See the
+      <literal>Environment Variables Set on Triggered Units</literal> section in
+      <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+      for more details.</para>
       <para>
         <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
         <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
index ea95ba886927c7b558f5ae56ab94d9377d01b5df..7e744471c394c92036317082caaca22400bee5e9 100644 (file)
           <literal>uml</literal>,
           <literal>bhyve</literal>,
           <literal>qnx</literal>,
+          <literal>apple</literal>,
           <literal>openvz</literal>,
           <literal>lxc</literal>,
           <literal>lxc-libvirt</literal>,
index 210811e7685773a0627e644e8cd9858db5ecb3df..76a813bf0a245be9ddc3c1250aa588c041e7fbae 100755 (executable)
@@ -47,6 +47,15 @@ if [ "$(locale charmap 2>/dev/null)" != "UTF-8" ] ; then
         fi
 fi
 
+# The bpftool script shipped by Ubuntu tries to find the actual program to run via querying `uname -r` and
+# using the current kernel version. This obviously doesn't work in containers. As a workaround, we override
+# the ubuntu script with a symlink to the first bpftool program we can find.
+for bpftool in /usr/lib/linux-tools/*/bpftool; do
+        [ -x "$bpftool" ] || continue
+        ln -sf "$bpftool" /usr/sbin/bpftool
+        break
+done
+
 if [ ! -f "$BUILDDIR"/build.ninja ] ; then
         sysvinit_path=$(realpath /etc/init.d)
 
@@ -66,7 +75,81 @@ if [ ! -f "$BUILDDIR"/build.ninja ] ; then
                 -D version-tag="${VERSION_TAG}" \
                 -D mode=developer \
                 -D b_sanitize="${SANITIZERS:-none}" \
-                -D install-tests=true
+                -D install-tests=true \
+                -D tests=unsafe \
+                -D slow-tests=true \
+                -D utmp=true \
+                -D hibernate=true \
+                -D ldconfig=true \
+                -D resolve=true \
+                -D efi=true \
+                -D tpm=true \
+                -D environment-d=true \
+                -D binfmt=true \
+                -D repart=true \
+                -D sysupdate=true \
+                -D coredump=true \
+                -D pstore=true \
+                -D oomd=true \
+                -D logind=true \
+                -D hostnamed=true \
+                -D localed=true \
+                -D machined=true \
+                -D portabled=true \
+                -D sysext=true \
+                -D userdb=true \
+                -D homed=true \
+                -D networkd=true \
+                -D timedated=true \
+                -D timesyncd=true \
+                -D remote=true \
+                -D nss-myhostname=true \
+                -D nss-mymachines=true \
+                -D nss-resolve=true \
+                -D nss-systemd=true \
+                -D firstboot=true \
+                -D randomseed=true \
+                -D backlight=true \
+                -D vconsole=true \
+                -D quotacheck=true \
+                -D sysusers=true \
+                -D tmpfiles=true \
+                -D importd=true \
+                -D hwdb=true \
+                -D rfkill=true \
+                -D xdg-autostart=true \
+                -D translations=true \
+                -D polkit=true \
+                -D acl=true \
+                -D audit=true \
+                -D blkid=true \
+                -D fdisk=true \
+                -D kmod=true  \
+                -D pam=true \
+                -D pwquality=true \
+                -D microhttpd=true \
+                -D libcryptsetup=true \
+                -D libcurl=true \
+                -D idn=true \
+                -D libidn2=true \
+                -D qrencode=true \
+                -D gcrypt=true \
+                -D gnutls=true \
+                -D openssl=true \
+                -D cryptolib=openssl \
+                -D p11kit=true \
+                -D libfido2=true \
+                -D tpm2=true \
+                -D elfutils=true \
+                -D zstd=true \
+                -D xkbcommon=true \
+                -D pcre2=true \
+                -D glib=true \
+                -D dbus=true \
+                -D gnu-efi=true \
+                -D kernel-install=true \
+                -D analyze=true \
+                -D bpf-framework=true
 fi
 
 cd "$BUILDDIR"
@@ -172,3 +255,7 @@ TTYVHangup=no
 CapabilityBoundingSet=~CAP_SYS_TTY_CONFIG
 EOF
 fi
+
+# Make sure services aren't enabled by default on Debian/Ubuntu.
+mkdir -p "$DESTDIR/etc/systemd/system-preset"
+echo "disable *" > "$DESTDIR/etc/systemd/system-preset/99-mkosi.preset"
index 8efd1e97fa3265c1599fb2b5936e531671089c75..1c69dc46e0f2befd3387fc72c8deeca548415f99 100644 (file)
@@ -14,6 +14,46 @@ OutputDirectory=mkosi.output
 BuildDirectory=mkosi.builddir
 Cache=mkosi.cache
 SourceFileTransferFinal=copy-git-others
+Packages=
+        acl
+        bash-completion
+        coreutils
+        diffutils
+        dnsmasq
+        findutils
+        gcc # For sanitizer libraries
+        gdb
+        grep
+        kbd
+        kexec-tools
+        kmod
+        less
+        nano
+        nftables
+        openssl
+        python3
+        qrencode
+        sed
+        strace
+        tree
+        util-linux
+        valgrind
+        wireguard-tools
+        zsh
+
+BuildPackages=
+        clang
+        gcc
+        gettext
+        git
+        gnu-efi
+        gperf
+        llvm
+        meson
+        pkgconf
+        rpm
+        rsync
+        zstd
 
 [Host]
 QemuHeadless=yes
index 12f46c71c70650cea49970328baeac6f8aec4e1e..bd54b08c541997ad88f5571bd76de6ae2ec8cd3b 100644 (file)
@@ -9,65 +9,28 @@
 Distribution=arch
 
 [Content]
-BuildPackages=
-        acl
-        bzip2
-        clang
-        cryptsetup
-        curl
-        dbus
-        diffutils
-        docbook-xsl
-        elfutils
-        gcc
-        git
-        gnu-efi-libs
+Packages=
+        compsize
+        dhcp
         gnutls
-        gperf
-        inetutils
-        iptables
-        kmod
+        iproute
         libbpf
-        libcap
-        libgcrypt
-        libidn2
+        libfido2
         libmicrohttpd
-        libseccomp
-        libutil-linux
+        libpwquality
         libxkbcommon
-        libxslt
-        llvm
-        lz4
-        meson
-        pam
-        pkgconfig
-        python
-        python-lxml
-        python-jinja
-        qrencode
-        rsync
-        xz
-        zstd
-
-Packages=
-        gdb
-        libbpf
-        libidn2
-        nano
-        qrencode
-        strace
-        # For testing "systemd-analyze verify".
         man-db
-        # For testing systemd's bash completion scripts.
-        bash-completion
-        # For testing systemd's zsh completion scripts
-        # Run `autoload -Uz compinit; compinit` from a zsh shell in the booted image to enable completions.
-        zsh
-        # xxd is provided by the vim package
+        openbsd-netcat
+        polkit
+        quota-tools
+        tpm2-tss
         vim
-        # Required to run systemd-networkd-tests.py
-        python
-        iproute
-        dnsmasq
-        wireguard-tools
-        dhcp
+
+BuildPackages=
+        bpf
+        docbook-xsl
+        libxslt
+        linux-api-headers
+        perl
+        python-jinja
+        python-lxml
index 5e726d4aef551458f902718288fbac83b38ebb9d..482b5935ce962551229794abb1b10b7e4e5979db 100644 (file)
@@ -11,39 +11,54 @@ Format=gpt_xfs
 HostonlyInitrd=no
 
 [Content]
-BuildPackages=
-        diffutils
-        docbook-style-xsl
-        findutils
-        gcc
-        gettext
-        git
+Packages=
+        audit
+        cryptsetup
+        dhcp-server
+        glib2
         glibc-minimal-langpack
-        gnu-efi
+        gnutls
+        iproute
+        iproute-tc
+        kernel-modules-extra
+        libbpf
+        libfido2
+        libmicrohttpd
+        libxcrypt
+        libxkbcommon
+        netcat
+        p11-kit
+        pam
+        polkit
+        procps-ng
+        quota
+        tpm2-tss
+        vim-common
+
+BuildPackages=
+        bpftool
+        docbook-xsl
         gnu-efi-devel
-        gperf
-        lz4
-        meson
-        ninja-build
+        libgcrypt-devel # CentOS Stream 8 libgcrypt-devel doesn't ship a pkg-config file.
+        libxslt
         pam-devel
-        # CentOS Stream 8 libgcrypt-devel doesn't ship a pkg-config file.
-        libgcrypt-devel
-        pkgconfig
+        perl-interpreter
         pkgconfig(audit)
         pkgconfig(blkid)
         pkgconfig(bzip2)
         pkgconfig(dbus-1)
         pkgconfig(fdisk)
+        pkgconfig(glib-2.0)
         pkgconfig(gnutls)
         pkgconfig(libacl)
+        pkgconfig(libbpf)
         pkgconfig(libcap)
         pkgconfig(libcryptsetup)
         pkgconfig(libcurl)
         pkgconfig(libdw)
+        pkgconfig(libfido2)
         pkgconfig(libidn2)
         pkgconfig(libkmod)
-        pkgconfig(liblz4)
-        pkgconfig(liblzma)
         pkgconfig(libmicrohttpd)
         pkgconfig(libpcre2-8)
         pkgconfig(libqrencode)
@@ -61,30 +76,3 @@ BuildPackages=
         pkgconfig(xkbcommon)
         python3dist(jinja2)
         python3dist(lxml)
-        rpm
-        tree
-        zstd
-        /usr/bin/xsltproc
-
-Packages=
-        gdb
-        nano
-        # procps-ng provides a set of useful utilities (ps, free, etc)
-        procps-ng
-        strace
-        tpm2-tss
-        less
-        netcat
-        e2fsprogs
-        # xxd is provided by the vim-common package
-        vim-common
-        libasan
-        libubsan
-        # Required to run systemd-networkd-tests.py
-        python3
-        iproute
-        iproute-tc
-        dnsmasq
-        wireguard-tools
-        dhcp-server
-        kernel-modules-extra
index 2488eeb557ecbf54b7e216f07441d85e98d2a94b..2b712d677851f1e8e3ff67740c1171950f49717a 100644 (file)
@@ -8,17 +8,31 @@ Distribution=debian
 Release=testing
 
 [Content]
+Packages=
+        cryptsetup-bin
+        iproute2
+        isc-dhcp-server
+        libbpf0
+        libfido2-1
+        libglib2.0-0
+        libgnutls30
+        libidn2-0
+        libmicrohttpd12
+        libp11-kit0
+        libpam0g
+        libpwquality1
+        libqrencode4
+        libtss2-dev # Use the -dev package to avoid churn in updating version numbers
+        netcat-openbsd
+        policykit-1
+        procps
+        quota
+        xxd
+
 BuildPackages=
-        acl
-        clang
-        docbook-xml
+        bpftool
         docbook-xsl
-        gcc
         g++
-        gettext
-        git
-        gnu-efi
-        gperf
         libacl1-dev
         libaudit-dev
         libblkid-dev
@@ -26,59 +40,28 @@ BuildPackages=
         libbz2-dev
         libcap-dev
         libcryptsetup-dev
-        libcurl4-gnutls-dev
+        libcurl4-openssl-dev
         libdbus-1-dev
         libdw-dev
         libfdisk-dev
         libfido2-dev
         libgcrypt20-dev
+        libglib2.0-dev
         libgnutls28-dev
-        libidn2-0-dev
+        libidn2-dev
         libiptc-dev
         libkmod-dev
-        liblz4-dev
-        liblz4-tool
-        liblzma-dev
         libmicrohttpd-dev
         libmount-dev
+        libp11-kit-dev
         libpam0g-dev
+        libpwquality-dev
         libqrencode-dev
         libseccomp-dev
         libsmartcols-dev
         libssl-dev
-        libtss2-dev
         libxkbcommon-dev
         libzstd-dev
-        llvm
-        meson
-        pkg-config
-        python3
-        python3-lxml
         python3-jinja2
-        tree
-        uuid-dev
+        python3-lxml
         xsltproc
-        xz-utils
-        zstd
-
-Packages=
-        gdb
-        libbpf0
-        libfdisk1
-        libfido2-1
-        libidn2-0
-        libqrencode4
-        # We pull in the -dev package here, since the binary ones appear to change names too often, and the -dev package pulls the right deps in automatically
-        libtss2-dev
-        locales
-        nano
-        strace
-        xxd
-        # Provides libasan/libubsan
-        gcc
-        # Required to run systemd-networkd-tests.py
-        python3
-        iproute2
-        dnsmasq-base
-        wireguard-tools
-        isc-dhcp-server
index c1d8a5755757cda4767354aa6ccb0f975ea374be..95611177890fd795e0e4c4f71b474e34e93affa8 100644 (file)
@@ -8,29 +8,42 @@ Distribution=fedora
 Release=36
 
 [Content]
-BuildPackages=
-        diffutils
-        docbook-style-xsl
-        findutils
-        gcc
-        gettext
-        git
+Packages=
+        compsize
+        cryptsetup
+        dhcp-server
+        glib2
         glibc-minimal-langpack
-        gnu-efi
+        gnutls
+        iproute
+        iproute-tc
+        kernel-modules-extra
+        libbpf
+        libfido2
+        libmicrohttpd
+        libxcrypt
+        libxkbcommon
+        netcat
+        pam
+        polkit
+        procps-ng
+        quota
+        tpm2-tss
+        vim-common
+
+BuildPackages=
+        bpftool
+        docbook-xsl
         gnu-efi-devel
-        gperf
-        lz4
-        meson
-        ninja-build
         pam-devel
-        pkgconfig
+        pkgconfig # pkgconf shim to provide /usr/bin/pkg-config
         pkgconfig(audit)
         pkgconfig(blkid)
-        pkgconfig(bzip2)
         pkgconfig(dbus-1)
         pkgconfig(fdisk)
-        pkgconfig(gnutls)
+        pkgconfig(glib-2.0)
         pkgconfig(libacl)
+        pkgconfig(libbpf)
         pkgconfig(libcap)
         pkgconfig(libcryptsetup)
         pkgconfig(libcurl)
@@ -39,8 +52,6 @@ BuildPackages=
         pkgconfig(libgcrypt)
         pkgconfig(libidn2)
         pkgconfig(libkmod)
-        pkgconfig(liblz4)
-        pkgconfig(liblzma)
         pkgconfig(libmicrohttpd)
         pkgconfig(libpcre2-8)
         pkgconfig(libqrencode)
@@ -58,33 +69,3 @@ BuildPackages=
         pkgconfig(xkbcommon)
         python3dist(jinja2)
         python3dist(lxml)
-        rpm
-        tree
-        zstd
-        /usr/bin/xsltproc
-
-Packages=
-        acl
-        gdb
-        nano
-        # procps-ng provides a set of useful utilities (ps, free, etc)
-        procps-ng
-        strace
-        tpm2-tss
-        less
-        netcat
-        e2fsprogs
-        compsize
-        # xxd is provided by the vim-common package
-        vim-common
-        # Sanitizers
-        libasan
-        libubsan
-        # Required to run systemd-networkd-tests.py
-        python
-        iproute
-        iproute-tc
-        dnsmasq
-        wireguard-tools
-        dhcp-server
-        kernel-modules-extra
index 16fdecdedef2eac933cdacf5550815f7eabb109e..8dbb1dc50fcc9da37b6c991cdfda841a2fe5939c 100644 (file)
@@ -8,72 +8,59 @@ Distribution=opensuse
 Release=tumbleweed
 
 [Content]
+Packages=
+        dbus-1
+        glibc-locale-base
+        libbpf0
+        libcrypt1
+        libcryptsetup12
+        libdw1
+        libelf1
+        libfido2
+        libgcrypt20
+        libglib-2_0-0
+        libkmod2
+        liblz4-1
+        libmount1
+        libp11-kit0
+        libqrencode4
+        libseccomp2
+        libxkbcommon0
+        pam
+        tpm2-0-tss
+        vim
+
 BuildPackages=
+        audit-devel
+        bpftool
+        dbus-1-devel
         docbook-xsl-stylesheets
-        fdupes
-        gcc
-        gnu-efi
-        gperf
-        intltool
+        glib2-devel
+        glibc-locale
         libacl-devel
-        libapparmor-devel
         libblkid-devel
-        libbz2-devel
+        libbpf-devel
         libcap-devel
         libcryptsetup-devel
         libcurl-devel
+        libdw-devel
+        libelf-devel
+        libfdisk-devel
+        libfido2-devel
         libgcrypt-devel
         libgnutls-devel
         libkmod-devel
-        liblz4-devel
         libmicrohttpd-devel
         libmount-devel
+        libpwquality-devel
         libseccomp-devel
         libselinux-devel
+        libxkbcommon-devel
         libxslt-tools
-        meson
+        openssl-devel
         pam-devel
-        pciutils-devel
         pcre-devel
-        python3
         python3-Jinja2
         python3-lxml
         qrencode-devel
-        shadow
-        system-user-nobody
-        systemd-sysvinit
-        zlib-devel
-# to satisfy tests
-        acl
-        diffutils
-        glibc-locale
-        system-group-obsolete
-        system-user-bin
-        system-user-daemon
-        system-user-root
-        timezone
-
-Packages=
-        gdb
-        # brought in via meson->python3
-        libp11-kit0
-        # --bootable=no
-        dbus-1
-        libapparmor1
-        libcrypt1
-        libcryptsetup12
-        libgcrypt20
-        libgnutls30
-        libkmod2
-        liblz4-1
-        libmount1
-        libqrencode4
-        libseccomp2
-        pam
-        nano
-        strace
-        util-linux
-        # xxd is provided by the vim package
-        vim
-        # Provides libasan/libubsan
-        gcc
+        tpm2-0-tss-devel
index 2d73746f3f87adb4433b81aced824ade452f3d1e..60e1bcfa6670e2eaf30ef41d36222bbc9123e8fa 100644 (file)
@@ -9,75 +9,60 @@ Release=jammy
 Repositories=main,universe
 
 [Content]
+Packages=
+        cryptsetup-bin
+        iproute2
+        isc-dhcp-server
+        libbpf0
+        libfdisk1
+        libfido2-1
+        libglib2.0-0
+        libidn2-0
+        libmicrohttpd12
+        libp11-kit0
+        libpwquality1
+        libqrencode4
+        libtss2-dev # Use the -dev package to avoid churn in updating version numbers
+        linux-tools-common
+        linux-tools-generic
+        netcat-openbsd
+        policykit-1
+        procps
+        quota
+        xxd
+
 BuildPackages=
-        acl
-        docbook-xml
         docbook-xsl
-        gcc
-        gettext
-        git
-        gnu-efi
-        gperf
+        g++
         libacl1-dev
         libaudit-dev
         libblkid-dev
+        libbpf-dev
         libbz2-dev
         libcap-dev
         libcryptsetup-dev
-        libcurl4-gnutls-dev
+        libcurl4-openssl-dev
         libdbus-1-dev
         libdw-dev
         libfdisk-dev
         libfido2-dev
         libgcrypt20-dev
+        libglib2.0-dev
         libgnutls28-dev
-        libidn2-0-dev
-        libip4tc-dev
-        libip6tc-dev
+        libidn2-dev
+        libiptc-dev
         libkmod-dev
-        liblz4-dev
-        liblz4-tool
-        liblzma-dev
         libmicrohttpd-dev
         libmount-dev
+        libp11-kit-dev
         libpam0g-dev
+        libpwquality-dev
         libqrencode-dev
         libseccomp-dev
         libsmartcols-dev
         libssl-dev
-        libtss2-dev
         libxkbcommon-dev
-        libxtables-dev
         libzstd-dev
-        meson
-        pkg-config
-        python3
-        python3-lxml
         python3-jinja2
-        tree
-        tzdata
-        uuid-dev
+        python3-lxml
         xsltproc
-        xz-utils
-        zstd
-
-Packages=
-        gdb
-        libfido2-1
-        libidn2-0
-        libqrencode4
-        # We pull in the -dev package here, since the binary ones appear to change names too often, and the -dev package pulls the right deps in automatically
-        libtss2-dev
-        libfdisk1
-        locales
-        nano
-        strace
-        xxd
-        # Provides libasan/libubsan
-        gcc
-        # Required to run systemd-networkd-tests.py
-        python3
-        iproute2
-        dnsmasq-base
-        wireguard-tools
-        isc-dhcp-server
index 1c24b4f51a57aa7cc7b7bd2cebd4e2e331d885ff..fb59d3111523c32df0734b77e762421e198bb2de 100755 (executable)
@@ -18,6 +18,9 @@ EOF
         # `systemd-hwdb update` takes > 50s when built with sanitizers so let's not run it by default.
         systemctl mask systemd-hwdb-update.service
     fi
+
+    # Make sure dnsmasq.service doesn't start on boot on Debian/Ubuntu.
+    rm -f /etc/systemd/system/multi-user.target.wants/dnsmasq.service
 fi
 
 # Temporary workaround until https://github.com/openSUSE/suse-module-tools/commit/158643414ddb8d8208016a5f03a4484d58944d7a
index 531144ba57d47664013f3c50c42f4143999245d7..c309c075163686acde63479a91cd91e2e64eb6fc 100644 (file)
@@ -61,9 +61,9 @@ int verify_prepare_filename(const char *filename, char **ret) {
                         return r;
         }
 
-        dir = dirname_malloc(abspath);
-        if (!dir)
-                return -ENOMEM;
+        r = path_extract_directory(abspath, &dir);
+        if (r < 0)
+                return r;
 
         c = path_join(dir, with_instance ?: name);
         if (!c)
@@ -73,24 +73,30 @@ int verify_prepare_filename(const char *filename, char **ret) {
         return 0;
 }
 
-int verify_generate_path(char **var, char **filenames) {
+int verify_generate_path(char **ret, char **filenames) {
         _cleanup_strv_free_ char **ans = NULL;
+        _cleanup_free_ char *joined = NULL;
         const char *old;
         int r;
 
         STRV_FOREACH(filename, filenames) {
+                _cleanup_free_ char *a = NULL;
                 char *t;
 
-                t = dirname_malloc(*filename);
-                if (!t)
-                        return -ENOMEM;
+                r = path_make_absolute_cwd(*filename, &a);
+                if (r < 0)
+                        return r;
+
+                r = path_extract_directory(a, &t);
+                if (r < 0)
+                        return r;
 
                 r = strv_consume(&ans, t);
                 if (r < 0)
                         return r;
         }
 
-        assert_se(strv_uniq(ans));
+        strv_uniq(ans);
 
         /* First, prepend our directories. Second, if some path was specified, use that, and
          * otherwise use the defaults. Any duplicates will be filtered out in path-lookup.c.
@@ -106,10 +112,11 @@ int verify_generate_path(char **var, char **filenames) {
                         return r;
         }
 
-        *var = strv_join(ans, ":");
-        if (!*var)
+        joined = strv_join(ans, ":");
+        if (!joined)
                 return -ENOMEM;
 
+        *ret = TAKE_PTR(joined);
         return 0;
 }
 
index e026b29478e2fae333040429743711d426a98aa5..fd60a6eda2d085c298ed4d11d7cf75426f09f292 100644 (file)
@@ -47,17 +47,28 @@ int safe_glob(const char *path, int flags, glob_t *pglob) {
         return 0;
 }
 
-int glob_exists(const char *path) {
+int glob_first(const char *path, char **ret_first) {
         _cleanup_globfree_ glob_t g = {};
         int k;
 
         assert(path);
 
         k = safe_glob(path, GLOB_NOSORT|GLOB_BRACE, &g);
-        if (k == -ENOENT)
+        if (k == -ENOENT) {
+                if (ret_first)
+                        *ret_first = NULL;
                 return false;
+        }
         if (k < 0)
                 return k;
+
+        if (ret_first) {
+                char *first = strdup(g.gl_pathv[0]);
+                if (!first)
+                        return log_oom_debug();
+                *ret_first = first;
+        }
+
         return true;
 }
 
index fc86e990dd74979014a2b353311f1e8fec9f3554..7ca26cc27f73903e6661e902f704f363347310c1 100644 (file)
@@ -10,7 +10,9 @@
 /* Note: this function modifies pglob to set various functions. */
 int safe_glob(const char *path, int flags, glob_t *pglob);
 
-int glob_exists(const char *path);
+/* Note: which match is returned depends on the implementation/system and not guaranteed to be stable */
+int glob_first(const char *path, char **ret_first);
+#define glob_exists(path) glob_first(path, NULL)
 int glob_extend(char ***strv, const char *path, int flags);
 
 int glob_non_glob_prefix(const char *path, char **ret);
index d2c6b96a38d66e801863c1302d3364b543d844dd..cd966cba9420662f2db007aab7d48326d5d0aa3d 100644 (file)
@@ -191,34 +191,37 @@ int mkdir_p_safe(const char *prefix, const char *path, mode_t mode, uid_t uid, g
 }
 
 int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m) {
-        _cleanup_free_ char *pp = NULL;
+        _cleanup_free_ char *pp = NULL, *bn = NULL;
         _cleanup_close_ int dfd = -1;
-        const char *bn;
         int r;
 
-        pp = dirname_malloc(p);
-        if (!pp)
-                return -ENOMEM;
-
-        /* Not top-level? */
-        if (!(path_equal(pp, "/") || isempty(pp) || path_equal(pp, "."))) {
-
-                /* Recurse up */
+        r = path_extract_directory(p, &pp);
+        if (r == -EDESTADDRREQ) {
+                /* only fname is passed, no prefix to operate on */
+                dfd = open(".", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
+                if (dfd < 0)
+                        return -errno;
+        } else if (r == -EADDRNOTAVAIL)
+                /* only root dir or "." was passed, i.e. there is no parent to extract, in that case there's nothing to do. */
+                return 0;
+        else if (r < 0)
+                return r;
+        else {
+                /* Extracting the parent dir worked, hence we aren't top-level? Recurse up first. */
                 r = mkdir_p_root(root, pp, uid, gid, m);
                 if (r < 0)
                         return r;
+
+                dfd = chase_symlinks_and_open(pp, root, CHASE_PREFIX_ROOT, O_RDONLY|O_CLOEXEC|O_DIRECTORY, NULL);
+                if (dfd < 0)
+                        return dfd;
         }
 
-        bn = basename(p);
-        if (path_equal(bn, "/") || isempty(bn) || path_equal(bn, "."))
+        r = path_extract_filename(p, &bn);
+        if (r == -EADDRNOTAVAIL) /* Already top-level */
                 return 0;
-
-        if (!filename_is_valid(bn))
-                return -EINVAL;
-
-        dfd = chase_symlinks_and_open(pp, root, CHASE_PREFIX_ROOT, O_RDONLY|O_CLOEXEC|O_DIRECTORY, NULL);
-        if (dfd < 0)
-                return dfd;
+        if (r < 0)
+                return r;
 
         if (mkdirat(dfd, bn, m) < 0) {
                 if (errno == EEXIST)
@@ -230,7 +233,7 @@ int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m
         if (uid_is_valid(uid) || gid_is_valid(gid)) {
                 _cleanup_close_ int nfd = -1;
 
-                nfd = openat(dfd, bn, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
+                nfd = openat(dfd, bn, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
                 if (nfd < 0)
                         return -errno;
 
index 88657d5775059f1781d76b5b1063039e046452a5..c5f30b5be4f339a0dca584c3ade5757d7470fb1e 100644 (file)
@@ -7,12 +7,6 @@
 #include <stdlib.h>
 #include <unistd.h>
 
-/* When we include libgen.h because we need dirname() we immediately
- * undefine basename() since libgen.h defines it as a macro to the
- * POSIX version which is really broken. We prefer GNU basename(). */
-#include <libgen.h>
-#undef basename
-
 #include "alloc-util.h"
 #include "chase-symlinks.h"
 #include "extract-word.h"
@@ -774,27 +768,6 @@ int fsck_exists(const char *fstype) {
         return executable_is_good(checker);
 }
 
-char* dirname_malloc(const char *path) {
-        char *d, *dir, *dir2;
-
-        assert(path);
-
-        d = strdup(path);
-        if (!d)
-                return NULL;
-
-        dir = dirname(d);
-        assert(dir);
-
-        if (dir == d)
-                return d;
-
-        dir2 = strdup(dir);
-        free(d);
-
-        return dir2;
-}
-
 static const char *skip_slash_or_dot(const char *p) {
         for (; !isempty(p); p++) {
                 if (*p == '/')
index 757ed722d51c0f34814ad81ac3fcbaa6e55f4f01..41bbc7bb86f0a6c0175579f91f55ea81e52cf04a 100644 (file)
@@ -151,7 +151,6 @@ int fsck_exists(const char *fstype);
                 _ret;                                                   \
         })
 
-char* dirname_malloc(const char *path);
 int path_find_first_component(const char **p, bool accept_dot_dot, const char **ret);
 int path_find_last_component(const char *path, bool accept_dot_dot, const char **next, const char **ret);
 const char *last_path_component(const char *path);
index e5277b4a4bfc7e537d7770dbec60f0f75c039d6f..fd8954b3becd53812eb8cd94e7109cad63d8f02f 100644 (file)
@@ -156,21 +156,22 @@ static Virtualization detect_vm_dmi_vendor(void) {
                 const char *vendor;
                 Virtualization id;
         } dmi_vendor_table[] = {
-                { "KVM",                 VIRTUALIZATION_KVM       },
-                { "OpenStack",           VIRTUALIZATION_KVM       }, /* Detect OpenStack instance as KVM in non x86 architecture */
-                { "KubeVirt",            VIRTUALIZATION_KVM       }, /* Detect KubeVirt instance as KVM in non x86 architecture */
-                { "Amazon EC2",          VIRTUALIZATION_AMAZON    },
-                { "QEMU",                VIRTUALIZATION_QEMU      },
-                { "VMware",              VIRTUALIZATION_VMWARE    }, /* https://kb.vmware.com/s/article/1009458 */
-                { "VMW",                 VIRTUALIZATION_VMWARE    },
-                { "innotek GmbH",        VIRTUALIZATION_ORACLE    },
-                { "VirtualBox",          VIRTUALIZATION_ORACLE    },
-                { "Xen",                 VIRTUALIZATION_XEN       },
-                { "Bochs",               VIRTUALIZATION_BOCHS     },
-                { "Parallels",           VIRTUALIZATION_PARALLELS },
+                { "KVM",                  VIRTUALIZATION_KVM       },
+                { "OpenStack",            VIRTUALIZATION_KVM       }, /* Detect OpenStack instance as KVM in non x86 architecture */
+                { "KubeVirt",             VIRTUALIZATION_KVM       }, /* Detect KubeVirt instance as KVM in non x86 architecture */
+                { "Amazon EC2",           VIRTUALIZATION_AMAZON    },
+                { "QEMU",                 VIRTUALIZATION_QEMU      },
+                { "VMware",               VIRTUALIZATION_VMWARE    }, /* https://kb.vmware.com/s/article/1009458 */
+                { "VMW",                  VIRTUALIZATION_VMWARE    },
+                { "innotek GmbH",         VIRTUALIZATION_ORACLE    },
+                { "VirtualBox",           VIRTUALIZATION_ORACLE    },
+                { "Xen",                  VIRTUALIZATION_XEN       },
+                { "Bochs",                VIRTUALIZATION_BOCHS     },
+                { "Parallels",            VIRTUALIZATION_PARALLELS },
                 /* https://wiki.freebsd.org/bhyve */
-                { "BHYVE",               VIRTUALIZATION_BHYVE     },
-                { "Hyper-V",             VIRTUALIZATION_MICROSOFT },
+                { "BHYVE",                VIRTUALIZATION_BHYVE     },
+                { "Hyper-V",              VIRTUALIZATION_MICROSOFT },
+                { "Apple Virtualization", VIRTUALIZATION_APPLE },
         };
         int r;
 
@@ -1018,6 +1019,7 @@ static const char *const virtualization_table[_VIRTUALIZATION_MAX] = {
         [VIRTUALIZATION_QNX]             = "qnx",
         [VIRTUALIZATION_ACRN]            = "acrn",
         [VIRTUALIZATION_POWERVM]         = "powervm",
+        [VIRTUALIZATION_APPLE]           = "apple",
         [VIRTUALIZATION_VM_OTHER]        = "vm-other",
 
         [VIRTUALIZATION_SYSTEMD_NSPAWN]  = "systemd-nspawn",
index 6da08b4af141fe9f3aabec9b2314499d9f48d757..e19a238939869e1e5bf76e26840d0e4ba071f3d6 100644 (file)
@@ -25,6 +25,7 @@ typedef enum Virtualization {
         VIRTUALIZATION_QNX,
         VIRTUALIZATION_ACRN,
         VIRTUALIZATION_POWERVM,
+        VIRTUALIZATION_APPLE,
         VIRTUALIZATION_VM_OTHER,
         VIRTUALIZATION_VM_LAST = VIRTUALIZATION_VM_OTHER,
 
index 315a1a37edb529a1ef88b6500b7e28e24963b63e..554a716d8a8ccbdfe1edb353f94696391547b4f1 100644 (file)
@@ -399,7 +399,7 @@ static int verb_status(int argc, char *argv[], void *userdata) {
 }
 
 static int verb_set(int argc, char *argv[], void *userdata) {
-        _cleanup_free_ char *path = NULL, *prefix = NULL, *suffix = NULL, *good = NULL, *bad = NULL, *parent = NULL;
+        _cleanup_free_ char *path = NULL, *prefix = NULL, *suffix = NULL, *good = NULL, *bad = NULL;
         const char *target, *source1, *source2;
         uint64_t done;
         int r;
@@ -448,12 +448,12 @@ static int verb_set(int argc, char *argv[], void *userdata) {
                 r = rename_noreplace(fd, skip_slash(source1), fd, skip_slash(target));
                 if (r == -EEXIST)
                         goto exists;
-                else if (r == -ENOENT) {
+                if (r == -ENOENT) {
 
                         r = rename_noreplace(fd, skip_slash(source2), fd, skip_slash(target));
                         if (r == -EEXIST)
                                 goto exists;
-                        else if (r == -ENOENT) {
+                        if (r == -ENOENT) {
 
                                 if (faccessat(fd, skip_slash(target), F_OK, 0) >= 0) /* Hmm, if we can't find either source file, maybe the destination already exists? */
                                         goto exists;
@@ -463,22 +463,18 @@ static int verb_set(int argc, char *argv[], void *userdata) {
 
                                 /* We found none of the snippets here, try the next directory */
                                 continue;
-                        } else if (r < 0)
+                        }
+                        if (r < 0)
                                 return log_error_errno(r, "Failed to rename '%s' to '%s': %m", source2, target);
-                        else
-                                log_debug("Successfully renamed '%s' to '%s'.", source2, target);
 
+                        log_debug("Successfully renamed '%s' to '%s'.", source2, target);
                 } else if (r < 0)
                         return log_error_errno(r, "Failed to rename '%s' to '%s': %m", source1, target);
                 else
                         log_debug("Successfully renamed '%s' to '%s'.", source1, target);
 
                 /* First, fsync() the directory these files are located in */
-                parent = dirname_malloc(target);
-                if (!parent)
-                        return log_oom();
-
-                r = fsync_path_at(fd, skip_slash(parent));
+                r = fsync_parent_at(fd, skip_slash(target));
                 if (r < 0)
                         log_debug_errno(errno, "Failed to synchronize image directory, ignoring: %m");
 
index 95785dfd5d83d41895079a7f38b24b1a7877533f..efe056c225a507b1d5cf8a3011c87e030dd9fe9f 100644 (file)
@@ -60,7 +60,7 @@ efi_ld = get_option('efi-ld')
 if efi_ld == 'auto'
         efi_ld = cc.get_linker_id().split('.')[1]
         if efi_ld not in ['bfd', 'gold']
-                warning('Not using @0@ as efi-ld, falling back to bfd'.format(efi_ld))
+                message('Not using @0@ as efi-ld, falling back to bfd'.format(efi_ld))
                 efi_ld = 'bfd'
         endif
 endif
index a63119fd0b9a7172825ff70c1313f50f44fc9751..33117fe939684f7556a07a41a9696615b5852aa5 100644 (file)
@@ -267,15 +267,13 @@ static int measure_pcr(PcrState *pcr_states, size_t n) {
         assert(n > 0);
         assert(pcr_states);
 
-        buffer = malloc(BUFFER_SIZE);
-        if (!buffer)
-                return log_oom();
-
         if (arg_current) {
                 /* Shortcut things, if we should just use the current PCR value */
 
                 for (size_t i = 0; i < n; i++) {
                         _cleanup_free_ char *p = NULL, *s = NULL;
+                        _cleanup_free_ void *v = NULL;
+                        size_t sz;
 
                         if (asprintf(&p, "/sys/class/tpm/tpm0/pcr-%s/%" PRIu32, pcr_states[i].bank, TPM_PCR_INDEX_KERNEL_IMAGE) < 0)
                                 return log_oom();
@@ -284,14 +282,21 @@ static int measure_pcr(PcrState *pcr_states, size_t n) {
                         if (r < 0)
                                 return log_error_errno(r, "Failed to read '%s': %m", p);
 
-                        r = unhexmem(strstrip(s), SIZE_MAX, &pcr_states[i].value, &pcr_states[i].value_size);
+                        r = unhexmem(strstrip(s), SIZE_MAX, &v, &sz);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to decode PCR value '%s': %m", s);
+
+                        assert(pcr_states[i].value_size == sz);
+                        memcpy(pcr_states[i].value, v, sz);
                 }
 
                 return 0;
         }
 
+        buffer = malloc(BUFFER_SIZE);
+        if (!buffer)
+                return log_oom();
+
         for (UnifiedSection c = 0; c < _UNIFIED_SECTION_MAX; c++) {
                 _cleanup_(evp_md_ctx_free_all) EVP_MD_CTX **mdctx = NULL;
                 _cleanup_close_ int fd = -1;
index 5adec9e966cc0fbbeb676d6f375c83faa09850a1..39c716fb8122c8eef8f7fc39290354370d42af19 100644 (file)
@@ -134,12 +134,13 @@ static int automount_add_trigger_dependencies(Automount *a) {
 
 static int automount_add_mount_dependencies(Automount *a) {
         _cleanup_free_ char *parent = NULL;
+        int r;
 
         assert(a);
 
-        parent = dirname_malloc(a->where);
-        if (!parent)
-                return -ENOMEM;
+        r = path_extract_directory(a->where, &parent);
+        if (r < 0)
+                return r;
 
         return unit_require_mounts_for(UNIT(a), parent, UNIT_DEPENDENCY_IMPLICIT);
 }
index de474e6d4e0a8701e1366160ff135236bc8f0352..7b1438266beae7fc949d4cbe360ad98174be788e 100644 (file)
@@ -7,6 +7,7 @@
 #include "bus-util.h"
 #include "dbus-job.h"
 #include "dbus-unit.h"
+#include "dbus-util.h"
 #include "dbus.h"
 #include "job.h"
 #include "log.h"
@@ -136,6 +137,7 @@ const sd_bus_vtable bus_job_vtable[] = {
         SD_BUS_PROPERTY("Unit", "(so)", property_get_unit, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("JobType", "s", property_get_type, offsetof(Job, type), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("State", "s", property_get_state, offsetof(Job, state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("ActivationDetails", "a(ss)", bus_property_get_activation_details, offsetof(Job, activation_details), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_VTABLE_END
 };
 
index ee013e1bc5af37d43d9e68473da4bebf00bd7dde..7a16471758ee0f1baf3d178f2e4cb7aca2e0effd 100644 (file)
@@ -951,6 +951,7 @@ const sd_bus_vtable bus_unit_vtable[] = {
         SD_BUS_PROPERTY("InvocationID", "ay", bus_property_get_id128, offsetof(Unit, invocation_id), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("CollectMode", "s", property_get_collect_mode, offsetof(Unit, collect_mode), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("Refs", "as", property_get_refs, 0, 0),
+        SD_BUS_PROPERTY("ActivationDetails", "a(ss)", bus_property_get_activation_details, offsetof(Unit, activation_details), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
 
         SD_BUS_METHOD_WITH_ARGS("Start",
                                 SD_BUS_ARGS("s", mode),
index 264a4f55b67db379634c59ec8002fb04a2af4cd7..edfa0eb69a4f6ba4e239d05f18f75fa059461cdc 100644 (file)
@@ -228,3 +228,35 @@ int bus_read_mount_options(
 
         return 0;
 }
+
+int bus_property_get_activation_details(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        ActivationDetails **details = ASSERT_PTR(userdata);
+        _cleanup_strv_free_ char **pairs = NULL;
+        int r;
+
+        assert(reply);
+
+        r = activation_details_append_pair(*details, &pairs);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_open_container(reply, 'a', "(ss)");
+        if (r < 0)
+                return r;
+
+        STRV_FOREACH_PAIR(key, value, pairs) {
+                r = sd_bus_message_append(reply, "(ss)", *key, *value);
+                if (r < 0)
+                        return r;
+        }
+
+        return sd_bus_message_close_container(reply);
+}
index 799136737ba225b2a169b9f87ae8bf8413fcac79..e12631a0e21c0dfe39b135eead2252034923dada 100644 (file)
@@ -251,3 +251,5 @@ static inline int bus_set_transient_usec_fix_0(Unit *u, const char *name, usec_t
 int bus_verify_manage_units_async_full(Unit *u, const char *verb, int capability, const char *polkit_message, bool interactive, sd_bus_message *call, sd_bus_error *error);
 
 int bus_read_mount_options(sd_bus_message *message, sd_bus_error *error, MountOptions **ret_options, char **ret_format_str, const char *separator);
+
+int bus_property_get_activation_details(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
index e68d23173931fe9b118b5df15648baa5b22146fa..0ce18159bd22b9a64f0bb0997fc7875393df965f 100644 (file)
@@ -3104,9 +3104,9 @@ static int setup_credentials_internal(
                 /* If we do not have our own mount put used the plain directory fallback, then we need to
                  * open access to the top-level credential directory and the per-service directory now */
 
-                parent = dirname_malloc(final);
-                if (!parent)
-                        return -ENOMEM;
+                r = path_extract_directory(final, &parent);
+                if (r < 0)
+                        return r;
                 if (chmod(parent, 0755) < 0)
                         return -errno;
         }
index 6653dbde84b79acbf12036b0d78ff926eb6e371f..dd8d858bd2d945e9eb99ab1b98a5d55cfac1481f 100644 (file)
@@ -104,6 +104,8 @@ Job* job_free(Job *j) {
         sd_bus_track_unref(j->bus_track);
         strv_free(j->deserialized_clients);
 
+        activation_details_unref(j->activation_details);
+
         return mfree(j);
 }
 
@@ -180,9 +182,13 @@ static void job_merge_into_installed(Job *j, Job *other) {
         assert(j->installed);
         assert(j->unit == other->unit);
 
-        if (j->type != JOB_NOP)
+        if (j->type != JOB_NOP) {
                 assert_se(job_type_merge_and_collapse(&j->type, other->type, j->unit) == 0);
-        else
+
+                /* Keep the oldest ActivationDetails, if any */
+                if (!j->activation_details)
+                        j->activation_details = TAKE_PTR(other->activation_details);
+        } else
                 assert(other->type == JOB_NOP);
 
         j->irreversible = j->irreversible || other->irreversible;
@@ -776,6 +782,7 @@ static void job_emit_done_message(Unit *u, uint32_t job_id, JobType t, JobResult
 }
 
 static int job_perform_on_unit(Job **j) {
+        ActivationDetails *a;
         uint32_t id;
         Manager *m;
         JobType t;
@@ -795,10 +802,11 @@ static int job_perform_on_unit(Job **j) {
         u = (*j)->unit;
         t = (*j)->type;
         id = (*j)->id;
+        a = (*j)->activation_details;
 
         switch (t) {
                 case JOB_START:
-                        r = unit_start(u);
+                        r = unit_start(u, a);
                         break;
 
                 case JOB_RESTART:
@@ -1160,6 +1168,8 @@ int job_serialize(Job *j, FILE *f) {
 
         bus_track_serialize(j->bus_track, f, "subscribed");
 
+        activation_details_serialize(j->activation_details, f);
+
         /* End marker */
         fputc('\n', f);
         return 0;
@@ -1257,6 +1267,11 @@ int job_deserialize(Job *j, FILE *f) {
                 else if (streq(l, "subscribed")) {
                         if (strv_extend(&j->deserialized_clients, v) < 0)
                                 return log_oom();
+
+                } else if (startswith(l, "activation-details")) {
+                        if (activation_details_deserialize(l, v, &j->activation_details) < 0)
+                                log_debug("Failed to parse job ActivationDetails element: %s", v);
+
                 } else
                         log_debug("Unknown job serialization key: %s", l);
         }
@@ -1636,3 +1651,11 @@ int job_compare(Job *a, Job *b, UnitDependencyAtom assume_dep) {
         else
                 return -1;
 }
+
+void job_set_activation_details(Job *j, ActivationDetails *info) {
+        /* Existing (older) ActivationDetails win, newer ones are discarded. */
+        if (!j || j->activation_details || !info)
+                return; /* Nothing to do. */
+
+        j->activation_details = activation_details_ref(info);
+}
index c033c8a4faaa0e2d21615fcdac9e287c0364f672..0305e0ea4451244f4b8d64f626037cacf73d90b0 100644 (file)
@@ -10,6 +10,7 @@
 #include "unit-name.h"
 #include "unit.h"
 
+typedef struct ActivationDetails ActivationDetails;
 typedef struct Job Job;
 typedef struct JobDependency JobDependency;
 typedef enum JobType JobType;
@@ -151,6 +152,9 @@ struct Job {
 
         unsigned run_queue_idx;
 
+        /* If the job had a specific trigger that needs to be advertised (eg: a path unit), store it. */
+        ActivationDetails *activation_details;
+
         bool installed:1;
         bool in_run_queue:1;
         bool matters_to_anchor:1;
@@ -243,3 +247,5 @@ JobResult job_result_from_string(const char *s) _pure_;
 const char* job_type_to_access_method(JobType t);
 
 int job_compare(Job *a, Job *b, UnitDependencyAtom assume_dep);
+
+void job_set_activation_details(Job *j, ActivationDetails *info);
index 9dd9fe1293f6b0adbbb07d7e87fb89385b52cfc6..52acd4345b528ec33843b01283017a053f557a85 100644 (file)
@@ -303,9 +303,9 @@ static int mount_add_mount_dependencies(Mount *m) {
 
                 /* Adds in links to other mount points that might lie further up in the hierarchy */
 
-                parent = dirname_malloc(m->where);
-                if (!parent)
-                        return -ENOMEM;
+                r = path_extract_directory(m->where, &parent);
+                if (r < 0)
+                        return r;
 
                 r = unit_require_mounts_for(UNIT(m), parent, UNIT_DEPENDENCY_IMPLICIT);
                 if (r < 0)
index 69bbddf1585cba8f310020517bace9aa4882abe1..2810e30573d826d9c8b96e606f596a4407e8b908 100644 (file)
@@ -197,9 +197,13 @@ int path_spec_fd_event(PathSpec *s, uint32_t revents) {
         return 0;
 }
 
-static bool path_spec_check_good(PathSpec *s, bool initial, bool from_trigger_notify) {
+static bool path_spec_check_good(PathSpec *s, bool initial, bool from_trigger_notify, char **ret_trigger_path) {
+        _cleanup_free_ char *trigger = NULL;
         bool b, good = false;
 
+        assert(s);
+        assert(ret_trigger_path);
+
         switch (s->type) {
 
         case PATH_EXISTS:
@@ -207,7 +211,7 @@ static bool path_spec_check_good(PathSpec *s, bool initial, bool from_trigger_no
                 break;
 
         case PATH_EXISTS_GLOB:
-                good = glob_exists(s->path) > 0;
+                good = glob_first(s->path, &trigger) > 0;
                 break;
 
         case PATH_DIRECTORY_NOT_EMPTY: {
@@ -229,6 +233,15 @@ static bool path_spec_check_good(PathSpec *s, bool initial, bool from_trigger_no
                 ;
         }
 
+        if (good) {
+                if (!trigger) {
+                        trigger = strdup(s->path);
+                        if (!trigger)
+                                (void) log_oom_debug();
+                }
+                *ret_trigger_path = TAKE_PTR(trigger);
+        }
+
         return good;
 }
 
@@ -494,9 +507,11 @@ static void path_enter_dead(Path *p, PathResult f) {
         path_set_state(p, p->result != PATH_SUCCESS ? PATH_FAILED : PATH_DEAD);
 }
 
-static void path_enter_running(Path *p) {
+static void path_enter_running(Path *p, char *trigger_path) {
+        _cleanup_(activation_details_unrefp) ActivationDetails *details = NULL;
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         Unit *trigger;
+        Job *job;
         int r;
 
         assert(p);
@@ -518,10 +533,22 @@ static void path_enter_running(Path *p) {
                 return;
         }
 
-        r = manager_add_job(UNIT(p)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL);
+        details = activation_details_new(UNIT(p));
+        if (!details) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        r = free_and_strdup(&(ACTIVATION_DETAILS_PATH(details))->trigger_path_filename, trigger_path);
         if (r < 0)
                 goto fail;
 
+        r = manager_add_job(UNIT(p)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, &job);
+        if (r < 0)
+                goto fail;
+
+        job_set_activation_details(job, details);
+
         path_set_state(p, PATH_RUNNING);
         path_unwatch(p);
 
@@ -532,17 +559,19 @@ fail:
         path_enter_dead(p, PATH_FAILURE_RESOURCES);
 }
 
-static bool path_check_good(Path *p, bool initial, bool from_trigger_notify) {
+static bool path_check_good(Path *p, bool initial, bool from_trigger_notify, char **ret_trigger_path) {
         assert(p);
+        assert(ret_trigger_path);
 
         LIST_FOREACH(spec, s, p->specs)
-                if (path_spec_check_good(s, initial, from_trigger_notify))
+                if (path_spec_check_good(s, initial, from_trigger_notify, ret_trigger_path))
                         return true;
 
         return false;
 }
 
 static void path_enter_waiting(Path *p, bool initial, bool from_trigger_notify) {
+        _cleanup_free_ char *trigger_path = NULL;
         Unit *trigger;
         int r;
 
@@ -554,9 +583,9 @@ static void path_enter_waiting(Path *p, bool initial, bool from_trigger_notify)
                 return;
         }
 
-        if (path_check_good(p, initial, from_trigger_notify)) {
+        if (path_check_good(p, initial, from_trigger_notify, &trigger_path)) {
                 log_unit_debug(UNIT(p), "Got triggered.");
-                path_enter_running(p);
+                path_enter_running(p, trigger_path);
                 return;
         }
 
@@ -568,9 +597,9 @@ static void path_enter_waiting(Path *p, bool initial, bool from_trigger_notify)
          * might have appeared/been removed by now, so we must
          * recheck */
 
-        if (path_check_good(p, false, from_trigger_notify)) {
+        if (path_check_good(p, false, from_trigger_notify, &trigger_path)) {
                 log_unit_debug(UNIT(p), "Got triggered.");
-                path_enter_running(p);
+                path_enter_running(p, trigger_path);
                 return;
         }
 
@@ -759,7 +788,7 @@ static int path_dispatch_io(sd_event_source *source, int fd, uint32_t revents, v
                 goto fail;
 
         if (changed)
-                path_enter_running(p);
+                path_enter_running(p, found->path);
         else
                 path_enter_waiting(p, false, false);
 
@@ -832,6 +861,89 @@ static int path_can_start(Unit *u) {
         return 1;
 }
 
+static void activation_details_path_done(ActivationDetails *details) {
+        ActivationDetailsPath *p = ASSERT_PTR(ACTIVATION_DETAILS_PATH(details));
+
+        p->trigger_path_filename = mfree(p->trigger_path_filename);
+}
+
+static void activation_details_path_serialize(ActivationDetails *details, FILE *f) {
+        ActivationDetailsPath *p = ASSERT_PTR(ACTIVATION_DETAILS_PATH(details));
+
+        assert(f);
+
+        if (p->trigger_path_filename)
+                (void) serialize_item(f, "activation-details-path-filename", p->trigger_path_filename);
+}
+
+static int activation_details_path_deserialize(const char *key, const char *value, ActivationDetails **details) {
+        int r;
+
+        assert(key);
+        assert(value);
+
+        if (!details || !*details)
+                return -EINVAL;
+
+        ActivationDetailsPath *p = ACTIVATION_DETAILS_PATH(*details);
+        if (!p)
+                return -EINVAL;
+
+        if (!streq(key, "activation-details-path-filename"))
+                return -EINVAL;
+
+        r = free_and_strdup(&p->trigger_path_filename, value);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+static int activation_details_path_append_env(ActivationDetails *details, char ***strv) {
+        ActivationDetailsPath *p = ACTIVATION_DETAILS_PATH(details);
+        char *s;
+        int r;
+
+        assert(details);
+        assert(strv);
+        assert(p);
+
+        if (isempty(p->trigger_path_filename))
+                return 0;
+
+        s = strjoin("TRIGGER_PATH=", p->trigger_path_filename);
+        if (!s)
+                return -ENOMEM;
+
+        r = strv_consume(strv, TAKE_PTR(s));
+        if (r < 0)
+                return r;
+
+        return 1; /* Return the number of variables added to the env block */
+}
+
+static int activation_details_path_append_pair(ActivationDetails *details, char ***strv) {
+        ActivationDetailsPath *p = ACTIVATION_DETAILS_PATH(details);
+        int r;
+
+        assert(details);
+        assert(strv);
+        assert(p);
+
+        if (isempty(p->trigger_path_filename))
+                return 0;
+
+        r = strv_extend(strv, "trigger_path");
+        if (r < 0)
+                return r;
+
+        r = strv_extend(strv, p->trigger_path_filename);
+        if (r < 0)
+                return r;
+
+        return 1; /* Return the number of pairs added to the env block */
+}
+
 static const char* const path_type_table[_PATH_TYPE_MAX] = {
         [PATH_EXISTS]              = "PathExists",
         [PATH_EXISTS_GLOB]         = "PathExistsGlob",
@@ -890,3 +1002,13 @@ const UnitVTable path_vtable = {
 
         .can_start = path_can_start,
 };
+
+const ActivationDetailsVTable activation_details_path_vtable = {
+        .object_size = sizeof(ActivationDetailsPath),
+
+        .done = activation_details_path_done,
+        .serialize = activation_details_path_serialize,
+        .deserialize = activation_details_path_deserialize,
+        .append_env = activation_details_path_append_env,
+        .append_pair = activation_details_path_append_pair,
+};
index d835c241660b530974864c35340ce4b552e57532..c76103cc12944d1ece2896f000d3e3fd79595e7e 100644 (file)
@@ -3,6 +3,7 @@
 
 typedef struct Path Path;
 typedef struct PathSpec PathSpec;
+typedef struct ActivationDetailsPath ActivationDetailsPath;
 
 #include "unit.h"
 
@@ -66,9 +67,15 @@ struct Path {
         RateLimit trigger_limit;
 };
 
+struct ActivationDetailsPath {
+        ActivationDetails meta;
+        char *trigger_path_filename;
+};
+
 void path_free_specs(Path *p);
 
 extern const UnitVTable path_vtable;
+extern const ActivationDetailsVTable activation_details_path_vtable;
 
 const char* path_type_to_string(PathType i) _const_;
 PathType path_type_from_string(const char *s) _pure_;
@@ -77,3 +84,4 @@ const char* path_result_to_string(PathResult i) _const_;
 PathResult path_result_from_string(const char *s) _pure_;
 
 DEFINE_CAST(PATH, Path);
+DEFINE_ACTIVATION_DETAILS_CAST(ACTIVATION_DETAILS_PATH, ActivationDetailsPath, PATH);
index a715a1d1dc82424be0041750aaaccfb5ee6585fd..fa37207dcca8df17e2f4d4de2b4143a9e9070701 100644 (file)
@@ -1641,6 +1641,16 @@ static int service_spawn_internal(
                 }
         }
 
+        if (UNIT(s)->activation_details) {
+                r = activation_details_append_env(UNIT(s)->activation_details, &our_env);
+                if (r < 0)
+                        return r;
+                /* The number of env vars added here can vary, rather than keeping the allocation block in
+                 * sync manually, these functions simply use the strv methods to append to it, so we need
+                 * to update n_env when we are done in case of future usage. */
+                n_env += r;
+        }
+
         r = unit_set_exec_params(UNIT(s), &exec_params);
         if (r < 0)
                 return r;
index 9de325ba66240af365e0d9ca1b00d1187ed79373..b89d593b7598b1aa60ad140882da5d7041cb3e32 100644 (file)
@@ -576,8 +576,10 @@ fail:
 }
 
 static void timer_enter_running(Timer *t) {
+        _cleanup_(activation_details_unrefp) ActivationDetails *details = NULL;
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         Unit *trigger;
+        Job *job;
         int r;
 
         assert(t);
@@ -593,11 +595,20 @@ static void timer_enter_running(Timer *t) {
                 return;
         }
 
-        r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL);
+        details = activation_details_new(UNIT(t));
+        if (!details) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, &job);
         if (r < 0)
                 goto fail;
 
         dual_timestamp_get(&t->last_trigger);
+        ACTIVATION_DETAILS_TIMER(details)->last_trigger = t->last_trigger;
+
+        job_set_activation_details(job, details);
 
         if (t->stamp_path)
                 touch_file(t->stamp_path, true, t->last_trigger.realtime, UID_INVALID, GID_INVALID, MODE_INVALID);
@@ -892,6 +903,91 @@ static int timer_can_start(Unit *u) {
         return 1;
 }
 
+static void activation_details_timer_serialize(ActivationDetails *details, FILE *f) {
+        ActivationDetailsTimer *t = ACTIVATION_DETAILS_TIMER(details);
+
+        assert(details);
+        assert(f);
+        assert(t);
+
+        (void) serialize_dual_timestamp(f, "activation-details-timer-last-trigger", &t->last_trigger);
+}
+
+static int activation_details_timer_deserialize(const char *key, const char *value, ActivationDetails **details) {
+        int r;
+
+        assert(key);
+        assert(value);
+
+        if (!details || !*details)
+                return -EINVAL;
+
+        ActivationDetailsTimer *t = ACTIVATION_DETAILS_TIMER(*details);
+        if (!t)
+                return -EINVAL;
+
+        if (!streq(key, "activation-details-timer-last-trigger"))
+                return -EINVAL;
+
+        r = deserialize_dual_timestamp(value, &t->last_trigger);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+static int activation_details_timer_append_env(ActivationDetails *details, char ***strv) {
+        ActivationDetailsTimer *t = ACTIVATION_DETAILS_TIMER(details);
+        int r;
+
+        assert(details);
+        assert(strv);
+        assert(t);
+
+        if (!dual_timestamp_is_set(&t->last_trigger))
+                return 0;
+
+        r = strv_extendf(strv, "TRIGGER_TIMER_REALTIME_USEC=%" USEC_FMT, t->last_trigger.realtime);
+        if (r < 0)
+                return r;
+
+        r = strv_extendf(strv, "TRIGGER_TIMER_MONOTONIC_USEC=%" USEC_FMT, t->last_trigger.monotonic);
+        if (r < 0)
+                return r;
+
+        return 2; /* Return the number of variables added to the env block */
+}
+
+static int activation_details_timer_append_pair(ActivationDetails *details, char ***strv) {
+        ActivationDetailsTimer *t = ACTIVATION_DETAILS_TIMER(details);
+        int r;
+
+        assert(details);
+        assert(strv);
+        assert(t);
+
+        if (!dual_timestamp_is_set(&t->last_trigger))
+                return 0;
+
+        r = strv_extend(strv, "trigger_timer_realtime_usec");
+        if (r < 0)
+                return r;
+
+        r = strv_extendf(strv, "%" USEC_FMT, t->last_trigger.realtime);
+        if (r < 0)
+                return r;
+
+        r = strv_extend(strv, "trigger_timer_monotonic_usec");
+        if (r < 0)
+                return r;
+
+        r = strv_extendf(strv, "%" USEC_FMT, t->last_trigger.monotonic);
+        if (r < 0)
+                return r;
+
+        return 2; /* Return the number of pairs added to the env block */
+}
+
 static const char* const timer_base_table[_TIMER_BASE_MAX] = {
         [TIMER_ACTIVE]        = "OnActiveSec",
         [TIMER_BOOT]          = "OnBootSec",
@@ -954,3 +1050,12 @@ const UnitVTable timer_vtable = {
 
         .can_start = timer_can_start,
 };
+
+const ActivationDetailsVTable activation_details_timer_vtable = {
+        .object_size = sizeof(ActivationDetailsTimer),
+
+        .serialize = activation_details_timer_serialize,
+        .deserialize = activation_details_timer_deserialize,
+        .append_env = activation_details_timer_append_env,
+        .append_pair = activation_details_timer_append_pair,
+};
index 551e2833417d4be1b2383aea8a89bd32c5988b19..914e42580e350840d0ed712dbaf72c2ccd524f4a 100644 (file)
@@ -2,6 +2,7 @@
 #pragma once
 
 typedef struct Timer Timer;
+typedef struct ActivationDetailsTimer ActivationDetailsTimer;
 
 #include "calendarspec.h"
 #include "unit.h"
@@ -64,11 +65,17 @@ struct Timer {
         char *stamp_path;
 };
 
+struct ActivationDetailsTimer {
+        ActivationDetails meta;
+        dual_timestamp last_trigger;
+};
+
 #define TIMER_MONOTONIC_CLOCK(t) ((t)->wake_system ? CLOCK_BOOTTIME_ALARM : CLOCK_MONOTONIC)
 
 void timer_free_values(Timer *t);
 
 extern const UnitVTable timer_vtable;
+extern const ActivationDetailsVTable activation_details_timer_vtable;
 
 const char *timer_base_to_string(TimerBase i) _const_;
 TimerBase timer_base_from_string(const char *s) _pure_;
@@ -77,3 +84,4 @@ const char* timer_result_to_string(TimerResult i) _const_;
 TimerResult timer_result_from_string(const char *s) _pure_;
 
 DEFINE_CAST(TIMER, Timer);
+DEFINE_ACTIVATION_DETAILS_CAST(ACTIVATION_DETAILS_TIMER, ActivationDetailsTimer, TIMER);
index 0798c29c9d469f3a1f5038866a38154c64db74af..5f1c6109b0bb89d427c837b47befb241cefd6209 100644 (file)
@@ -41,6 +41,7 @@
 #include "path-util.h"
 #include "process-util.h"
 #include "rm-rf.h"
+#include "serialize.h"
 #include "set.h"
 #include "signal-util.h"
 #include "sparse-endian.h"
@@ -594,12 +595,10 @@ static void unit_remove_transient(Unit *u) {
         STRV_FOREACH(i, u->dropin_paths) {
                 _cleanup_free_ char *p = NULL, *pp = NULL;
 
-                p = dirname_malloc(*i); /* Get the drop-in directory from the drop-in file */
-                if (!p)
+                if (path_extract_directory(*i, &p) < 0) /* Get the drop-in directory from the drop-in file */
                         continue;
 
-                pp = dirname_malloc(p); /* Get the config directory from the drop-in directory */
-                if (!pp)
+                if (path_extract_directory(p, &pp) < 0) /* Get the config directory from the drop-in directory */
                         continue;
 
                 /* Only drop transient drop-ins */
@@ -809,6 +808,8 @@ Unit* unit_free(Unit *u) {
         set_free_free(u->aliases);
         free(u->id);
 
+        activation_details_unref(u->activation_details);
+
         return mfree(u);
 }
 
@@ -1190,6 +1191,9 @@ int unit_merge(Unit *u, Unit *other) {
         other->load_state = UNIT_MERGED;
         other->merged_into = u;
 
+        if (!u->activation_details)
+                u->activation_details = activation_details_ref(other->activation_details);
+
         /* If there is still some data attached to the other node, we
          * don't need it anymore, and can free it. */
         if (other->load_state != UNIT_STUB)
@@ -1863,7 +1867,7 @@ static bool unit_verify_deps(Unit *u) {
  *         -ESTALE:     This unit has been started before and can't be started a second time
  *         -ENOENT:     This is a triggering unit and unit to trigger is not loaded
  */
-int unit_start(Unit *u) {
+int unit_start(Unit *u, ActivationDetails *details) {
         UnitActiveState state;
         Unit *following;
         int r;
@@ -1920,7 +1924,7 @@ int unit_start(Unit *u) {
         following = unit_following(u);
         if (following) {
                 log_unit_debug(u, "Redirecting start request from %s to %s.", u->id, following->id);
-                return unit_start(following);
+                return unit_start(following, details);
         }
 
         /* Check our ability to start early so that failure conditions don't cause us to enter a busy loop. */
@@ -1941,6 +1945,9 @@ int unit_start(Unit *u) {
         unit_add_to_dbus_queue(u);
         unit_cgroup_freezer_action(u, FREEZER_THAW);
 
+        if (!u->activation_details) /* Older details object wins */
+                u->activation_details = activation_details_ref(details);
+
         return UNIT_VTABLE(u)->start(u);
 }
 
@@ -5921,3 +5928,154 @@ int unit_get_dependency_array(const Unit *u, UnitDependencyAtom atom, Unit ***re
         assert(n <= INT_MAX);
         return (int) n;
 }
+
+const ActivationDetailsVTable * const activation_details_vtable[_UNIT_TYPE_MAX] = {
+        [UNIT_PATH] = &activation_details_path_vtable,
+        [UNIT_TIMER] = &activation_details_timer_vtable,
+};
+
+ActivationDetails *activation_details_new(Unit *trigger_unit) {
+        _cleanup_free_ ActivationDetails *details = NULL;
+
+        assert(trigger_unit);
+        assert(trigger_unit->type != _UNIT_TYPE_INVALID);
+        assert(trigger_unit->id);
+
+        details = malloc0(activation_details_vtable[trigger_unit->type]->object_size);
+        if (!details)
+                return NULL;
+
+        *details = (ActivationDetails) {
+                .n_ref = 1,
+                .trigger_unit_type = trigger_unit->type,
+        };
+
+        details->trigger_unit_name = strdup(trigger_unit->id);
+        if (!details->trigger_unit_name)
+                return NULL;
+
+        if (ACTIVATION_DETAILS_VTABLE(details)->init)
+                ACTIVATION_DETAILS_VTABLE(details)->init(details, trigger_unit);
+
+        return TAKE_PTR(details);
+}
+
+static ActivationDetails *activation_details_free(ActivationDetails *details) {
+        if (!details)
+                return NULL;
+
+        if (ACTIVATION_DETAILS_VTABLE(details)->done)
+                ACTIVATION_DETAILS_VTABLE(details)->done(details);
+
+        free(details->trigger_unit_name);
+
+        return mfree(details);
+}
+
+void activation_details_serialize(ActivationDetails *details, FILE *f) {
+        if (!details || details->trigger_unit_type == _UNIT_TYPE_INVALID)
+                return;
+
+        (void) serialize_item(f, "activation-details-unit-type", unit_type_to_string(details->trigger_unit_type));
+        if (details->trigger_unit_name)
+                (void) serialize_item(f, "activation-details-unit-name", details->trigger_unit_name);
+        if (ACTIVATION_DETAILS_VTABLE(details)->serialize)
+                ACTIVATION_DETAILS_VTABLE(details)->serialize(details, f);
+}
+
+int activation_details_deserialize(const char *key, const char *value, ActivationDetails **details) {
+        assert(key);
+        assert(value);
+        assert(details);
+
+        if (!*details) {
+                UnitType t;
+
+                if (!streq(key, "activation-details-unit-type"))
+                        return -EINVAL;
+
+                t = unit_type_from_string(value);
+                if (t == _UNIT_TYPE_INVALID)
+                        return -EINVAL;
+
+                *details = malloc0(activation_details_vtable[t]->object_size);
+                if (!*details)
+                        return -ENOMEM;
+
+                **details = (ActivationDetails) {
+                        .n_ref = 1,
+                        .trigger_unit_type = t,
+                };
+
+                return 0;
+        }
+
+        if (streq(key, "activation-details-unit-name")) {
+                (*details)->trigger_unit_name = strdup(value);
+                if (!(*details)->trigger_unit_name)
+                        return -ENOMEM;
+
+                return 0;
+        }
+
+        if (ACTIVATION_DETAILS_VTABLE(*details)->deserialize)
+                return ACTIVATION_DETAILS_VTABLE(*details)->deserialize(key, value, details);
+
+        return -EINVAL;
+}
+
+int activation_details_append_env(ActivationDetails *details, char ***strv) {
+        int r = 0;
+
+        assert(strv);
+
+        if (!details)
+                return 0;
+
+        if (!isempty(details->trigger_unit_name)) {
+                char *s = strjoin("TRIGGER_UNIT=", details->trigger_unit_name);
+                if (!s)
+                        return -ENOMEM;
+
+                r = strv_consume(strv, TAKE_PTR(s));
+                if (r < 0)
+                        return r;
+        }
+
+        if (ACTIVATION_DETAILS_VTABLE(details)->append_env) {
+                r = ACTIVATION_DETAILS_VTABLE(details)->append_env(details, strv);
+                if (r < 0)
+                        return r;
+        }
+
+        return r + !isempty(details->trigger_unit_name); /* Return the number of variables added to the env block */
+}
+
+int activation_details_append_pair(ActivationDetails *details, char ***strv) {
+        int r = 0;
+
+        assert(strv);
+
+        if (!details)
+                return 0;
+
+        if (!isempty(details->trigger_unit_name)) {
+                r = strv_extend(strv, "trigger_unit");
+                if (r < 0)
+                        return r;
+
+                r = strv_extend(strv, details->trigger_unit_name);
+                if (r < 0)
+                        return r;
+        }
+
+        if (ACTIVATION_DETAILS_VTABLE(details)->append_env) {
+                r = ACTIVATION_DETAILS_VTABLE(details)->append_pair(details, strv);
+                if (r < 0)
+                        return r;
+        }
+
+        return r + !isempty(details->trigger_unit_name); /* Return the number of pairs added to the strv */
+}
+
+DEFINE_TRIVIAL_REF_UNREF_FUNC(ActivationDetails, activation_details, activation_details_free);
index 4dabbb9a3c93fcd94243759b88bc1d60d8acaa8a..fc8edaade53ecea791b1e0249c9c7ac7056af878 100644 (file)
@@ -110,6 +110,75 @@ typedef union UnitDependencyInfo {
         } _packed_;
 } UnitDependencyInfo;
 
+/* Store information about why a unit was activated.
+ * We start with trigger units (.path/.timer), eventually it will be expanded to include more metadata. */
+typedef struct ActivationDetails {
+        unsigned n_ref;
+        UnitType trigger_unit_type;
+        char *trigger_unit_name;
+} ActivationDetails;
+
+/* For casting an activation event into the various unit-specific types */
+#define DEFINE_ACTIVATION_DETAILS_CAST(UPPERCASE, MixedCase, UNIT_TYPE)         \
+        static inline MixedCase* UPPERCASE(ActivationDetails *a) {              \
+                if (_unlikely_(!a || a->trigger_unit_type != UNIT_##UNIT_TYPE)) \
+                        return NULL;                                            \
+                                                                                \
+                return (MixedCase*) a;                                          \
+        }
+
+/* For casting the various unit types into a unit */
+#define ACTIVATION_DETAILS(u)                                         \
+        ({                                                            \
+                typeof(u) _u_ = (u);                                  \
+                ActivationDetails *_w_ = _u_ ? &(_u_)->meta : NULL;   \
+                _w_;                                                  \
+        })
+
+ActivationDetails *activation_details_new(Unit *trigger_unit);
+ActivationDetails *activation_details_ref(ActivationDetails *p);
+ActivationDetails *activation_details_unref(ActivationDetails *p);
+void activation_details_serialize(ActivationDetails *p, FILE *f);
+int activation_details_deserialize(const char *key, const char *value, ActivationDetails **info);
+int activation_details_append_env(ActivationDetails *info, char ***strv);
+int activation_details_append_pair(ActivationDetails *info, char ***strv);
+DEFINE_TRIVIAL_CLEANUP_FUNC(ActivationDetails*, activation_details_unref);
+
+typedef struct ActivationDetailsVTable {
+        /* How much memory does an object of this activation type need */
+        size_t object_size;
+
+        /* This should reset all type-specific variables. This should not allocate memory, and is called
+         * with zero-initialized data. It should hence only initialize variables that need to be set != 0. */
+        void (*init)(ActivationDetails *info, Unit *trigger_unit);
+
+        /* This should free all type-specific variables. It should be idempotent. */
+        void (*done)(ActivationDetails *info);
+
+        /* This should serialize all type-specific variables. */
+        void (*serialize)(ActivationDetails *info, FILE *f);
+
+        /* This should deserialize all type-specific variables, one at a time. */
+        int (*deserialize)(const char *key, const char *value, ActivationDetails **info);
+
+        /* This should format the type-specific variables for the env block of the spawned service,
+         * and return the number of added items. */
+        int (*append_env)(ActivationDetails *info, char ***strv);
+
+        /* This should append type-specific variables as key/value pairs for the D-Bus property of the job,
+         * and return the number of added pairs. */
+        int (*append_pair)(ActivationDetails *info, char ***strv);
+} ActivationDetailsVTable;
+
+extern const ActivationDetailsVTable * const activation_details_vtable[_UNIT_TYPE_MAX];
+
+static inline const ActivationDetailsVTable* ACTIVATION_DETAILS_VTABLE(const ActivationDetails *a) {
+        assert(a);
+        assert(a->trigger_unit_type < _UNIT_TYPE_MAX);
+
+        return activation_details_vtable[a->trigger_unit_type];
+}
+
 /* Newer LLVM versions don't like implicit casts from large pointer types to smaller enums, hence let's add
  * explicit type-safe helpers for that. */
 static inline UnitDependency UNIT_DEPENDENCY_FROM_PTR(const void *p) {
@@ -363,6 +432,9 @@ typedef struct Unit {
         JobMode on_success_job_mode;
         JobMode on_failure_job_mode;
 
+        /* If the job had a specific trigger that needs to be advertised (eg: a path unit), store it. */
+        ActivationDetails *activation_details;
+
         /* Tweaking the GC logic */
         CollectMode collect_mode;
 
@@ -813,7 +885,7 @@ bool unit_can_start(Unit *u) _pure_;
 bool unit_can_stop(Unit *u) _pure_;
 bool unit_can_isolate(Unit *u) _pure_;
 
-int unit_start(Unit *u);
+int unit_start(Unit *u, ActivationDetails *details);
 int unit_stop(Unit *u);
 int unit_reload(Unit *u);
 
index d9f3fab835be32e1b4dfa696390ed1dad8b368c0..4ae24e7153616630910e3ce4fb32d2a4eb4f25ec 100644 (file)
@@ -791,9 +791,9 @@ static int action_copy(DissectedImage *m, LoopDevice *d) {
 
                 assert(arg_action == ACTION_COPY_TO);
 
-                dn = dirname_malloc(arg_target);
-                if (!dn)
-                        return log_oom();
+                r = path_extract_directory(arg_target, &dn);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to extract directory name from target path '%s': %m", arg_target);
 
                 r = chase_symlinks(dn, mounted_dir, CHASE_PREFIX_ROOT|CHASE_WARN, NULL, &dfd);
                 if (r < 0)
index 1d8ededcaecdf6acf4f06232656319e69915b532..8a389f721638853d677dc31f3d25f740686e767a 100644 (file)
@@ -2176,9 +2176,9 @@ static int home_get_disk_status_luks(
                                 disk_size = st.st_size;
                                 stat_used = st.st_blocks * 512;
 
-                                parent = dirname_malloc(ip);
-                                if (!parent)
-                                        return log_oom();
+                                r = path_extract_directory(ip, &parent);
+                                if (r < 0)
+                                        return log_error_errno(r, "Failed to extract parent directory from image path '%s': %m", ip);
 
                                 if (statfs(parent, &sfs) < 0)
                                         log_debug_errno(errno, "Failed to statfs() %s, ignoring: %m", parent);
index 5f3e79a67aad8aca168f774c5229a48522b0592b..c83292df7d3ae63ebee21d7b6368b7d5c659e5dc 100644 (file)
@@ -1989,10 +1989,11 @@ static int wait_for_devlink(const char *path) {
                                 return log_error_errno(errno, "Failed to allocate inotify fd: %m");
                 }
 
-                dn = dirname_malloc(path);
+                r = path_extract_directory(path, &dn);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to extract directory from device node path '%s': %m", path);
                 for (;;) {
-                        if (!dn)
-                                return log_oom();
+                        _cleanup_free_ char *ndn = NULL;
 
                         log_info("Watching %s", dn);
 
@@ -2002,10 +2003,13 @@ static int wait_for_devlink(const char *path) {
                         } else
                                 break;
 
-                        if (empty_or_root(dn))
+                        r = path_extract_directory(dn, &ndn);
+                        if (r == -EADDRNOTAVAIL) /* Arrived at the top? */
                                 break;
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to extract directory from device node path '%s': %m", dn);
 
-                        dn = dirname_malloc(dn);
+                        free_and_replace(dn, ndn);
                 }
 
                 w = now(CLOCK_MONOTONIC);
index 6617a9c9b673530c02f42869db224f9a6a241527..a3ff6a393410ef40b07ed79dba86df425d19d704 100644 (file)
@@ -2,12 +2,6 @@
 
 #include <sys/sendfile.h>
 
-/* When we include libgen.h because we need dirname() we immediately
- * undefine basename() since libgen.h defines it as a macro to the POSIX
- * version which is really broken. We prefer GNU basename(). */
-#include <libgen.h>
-#undef basename
-
 #include "sd-daemon.h"
 
 #include "alloc-util.h"
index 15b6844d5d4f53cc440b1316fe09ac6be8c67d89..0061abadff5ef0b2498b6f72cf19081157e0cc77 100644 (file)
@@ -1035,6 +1035,11 @@ static void dispatch_message_real(
         if (!isempty(s->namespace_field))
                 iovec[n++] = IOVEC_MAKE_STRING(s->namespace_field);
 
+        if (in_initrd())
+                iovec[n++] = IOVEC_MAKE_STRING("_SYSTEM_CONTEXT=initrd");
+        else
+                iovec[n++] = IOVEC_MAKE_STRING("_SYSTEM_CONTEXT=main");
+
         assert(n <= m);
 
         if (s->split_mode == SPLIT_UID && c && uid_is_valid(c->uid))
index 01244e1ce10fefc6d799b9a9ac45f2f2a6fcfc43..ee8f37419088c2e7e9c99e29ba078ec28b4923d5 100644 (file)
@@ -179,7 +179,7 @@ struct Server {
 #define SERVER_MACHINE_ID(s) ((s)->machine_id_field + STRLEN("_MACHINE_ID="))
 
 /* Extra fields for any log messages */
-#define N_IOVEC_META_FIELDS 23
+#define N_IOVEC_META_FIELDS 24
 
 /* Extra fields for log messages that contain OBJECT_PID= (i.e. log about another process) */
 #define N_IOVEC_OBJECT_FIELDS 18
index cba1ab2953382a81ff6ffc8e9cb7b1862e61de31..b553f153968899cfe5f48d67871b420151c30f15 100644 (file)
@@ -9,12 +9,6 @@
 #include <sys/mman.h>
 #include <sys/prctl.h>
 
-/* When we include libgen.h because we need dirname() we immediately
- * undefine basename() since libgen.h defines it as a macro to the POSIX
- * version which is really broken. We prefer GNU basename(). */
-#include <libgen.h>
-#undef basename
-
 #include "alloc-util.h"
 #include "bus-internal.h"
 #include "bus-kernel.h"
index fdc8772f84180ba179a48ac8712a071852fb222b..6e522ae54becaadb6fc59fcb45db4d6307d99b04 100644 (file)
@@ -53,8 +53,7 @@ static void* thread_server(void *p) {
         assert_se(mkdir_parents(path, 0755) >= 0);
         (void) usleep(100 * USEC_PER_MSEC);
 
-        d = dirname_malloc(path);
-        assert_se(d);
+        assert_se(path_extract_directory(path, &d) >= 0);
         assert_se(asprintf(&suffixed, "%s.%" PRIx64, d, random_u64()) >= 0);
         assert_se(rename(d, suffixed) >= 0);
         (void) usleep(100 * USEC_PER_MSEC);
index 2a46f11d8ad87aeba3806aeefa2490187a33f5d7..77d03ec95ff3c67399c2e7ada025da28afc8dbba 100644 (file)
@@ -1858,9 +1858,9 @@ static int add_current_paths(sd_journal *j) {
                 _cleanup_free_ char *dir = NULL;
                 int r;
 
-                dir = dirname_malloc(f->path);
-                if (!dir)
-                        return -ENOMEM;
+                r = path_extract_directory(f->path, &dir);
+                if (r < 0)
+                        return r;
 
                 r = add_directory(j, dir, NULL);
                 if (r < 0)
index bd203b37dd291c058159be27d04978341615f15c..87d04c3d5805ad77bc0e555d9529c3a62ef80c77 100644 (file)
@@ -4,12 +4,6 @@
 #include <sys/mount.h>
 #include <sys/wait.h>
 
-/* When we include libgen.h because we need dirname() we immediately
- * undefine basename() since libgen.h defines it as a macro to the POSIX
- * version which is really broken. We prefer GNU basename(). */
-#include <libgen.h>
-#undef basename
-
 #include "alloc-util.h"
 #include "bus-common-errors.h"
 #include "bus-get-properties.h"
@@ -902,7 +896,8 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
 }
 
 int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        const char *src, *dest, *host_path, *container_path, *host_basename, *container_basename, *container_dirname;
+        _cleanup_free_ char *host_basename = NULL, *container_basename = NULL;
+        const char *src, *dest, *host_path, *container_path;
         _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
         CopyFlags copy_flags = COPY_REFLINK|COPY_MERGE|COPY_HARDLINKS;
         _cleanup_close_ int hostfd = -1;
@@ -910,7 +905,6 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
         bool copy_from;
         pid_t child;
         uid_t uid_shift;
-        char *t;
         int r;
 
         assert(message);
@@ -984,11 +978,13 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
                 container_path = dest;
         }
 
-        host_basename = basename(host_path);
+        r = path_extract_filename(host_path, &host_basename);
+        if (r < 0)
+                return sd_bus_error_set_errnof(error, r, "Failed to extract file name of '%s' path: %m", host_path);
 
-        container_basename = basename(container_path);
-        t = strdupa_safe(container_path);
-        container_dirname = dirname(t);
+        r = path_extract_filename(container_path, &container_basename);
+        if (r < 0)
+                return sd_bus_error_set_errnof(error, r, "Failed to extract file name of '%s' path: %m", container_path);
 
         hostfd = open_parent(host_path, O_CLOEXEC, 0);
         if (hostfd < 0)
@@ -1019,9 +1015,9 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
                         goto child_fail;
                 }
 
-                containerfd = open(container_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
+                containerfd = open_parent(container_path, O_CLOEXEC, 0);
                 if (containerfd < 0) {
-                        r = log_error_errno(errno, "Failed to open destination directory: %m");
+                        r = log_error_errno(containerfd, "Failed to open destination directory: %m");
                         goto child_fail;
                 }
 
index 14c1ce0b45c163954c4b3361a9db83cabfb626c8..8a20fa7e47676a56b24632c70a816502799c7c15 100644 (file)
@@ -280,9 +280,9 @@ static int verify_fsroot_dir(
                          * directly instead. It's not as good, due to symlinks and such, but we can't do
                          * anything better here. */
 
-                        parent = dirname_malloc(path);
-                        if (!parent)
-                                return log_oom();
+                        r = path_extract_filename(path, &parent);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to extract parent path from '%s': %m", path);
 
                         r = RET_NERRNO(stat(parent, &st2));
                 }
index 5ae39f6a04e304f9792fa36a9a3b9d1fb5f1de2e..1a0a536080afd302083289c11bdaafe8771d4ab6 100644 (file)
@@ -102,12 +102,13 @@ DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type, UnitFileType);
 
 static int in_search_path(const LookupPaths *lp, const char *path) {
         _cleanup_free_ char *parent = NULL;
+        int r;
 
         assert(path);
 
-        parent = dirname_malloc(path);
-        if (!parent)
-                return -ENOMEM;
+        r = path_extract_directory(path, &parent);
+        if (r < 0)
+                return r;
 
         return path_strv_contains(lp->search_path, parent);
 }
@@ -135,13 +136,14 @@ static const char* skip_root(const char *root_dir, const char *path) {
 
 static int path_is_generator(const LookupPaths *lp, const char *path) {
         _cleanup_free_ char *parent = NULL;
+        int r;
 
         assert(lp);
         assert(path);
 
-        parent = dirname_malloc(path);
-        if (!parent)
-                return -ENOMEM;
+        r = path_extract_directory(path, &parent);
+        if (r < 0)
+                return r;
 
         return path_equal_ptr(parent, lp->generator) ||
                path_equal_ptr(parent, lp->generator_early) ||
@@ -150,26 +152,28 @@ static int path_is_generator(const LookupPaths *lp, const char *path) {
 
 static int path_is_transient(const LookupPaths *lp, const char *path) {
         _cleanup_free_ char *parent = NULL;
+        int r;
 
         assert(lp);
         assert(path);
 
-        parent = dirname_malloc(path);
-        if (!parent)
-                return -ENOMEM;
+        r = path_extract_directory(path, &parent);
+        if (r < 0)
+                return r;
 
         return path_equal_ptr(parent, lp->transient);
 }
 
 static int path_is_control(const LookupPaths *lp, const char *path) {
         _cleanup_free_ char *parent = NULL;
+        int r;
 
         assert(lp);
         assert(path);
 
-        parent = dirname_malloc(path);
-        if (!parent)
-                return -ENOMEM;
+        r = path_extract_directory(path, &parent);
+        if (r < 0)
+                return r;
 
         return path_equal_ptr(parent, lp->persistent_control) ||
                path_equal_ptr(parent, lp->runtime_control);
@@ -177,6 +181,7 @@ static int path_is_control(const LookupPaths *lp, const char *path) {
 
 static int path_is_config(const LookupPaths *lp, const char *path, bool check_parent) {
         _cleanup_free_ char *parent = NULL;
+        int r;
 
         assert(lp);
         assert(path);
@@ -185,9 +190,9 @@ static int path_is_config(const LookupPaths *lp, const char *path, bool check_pa
          * them we couldn't discern configuration from transient or generated units */
 
         if (check_parent) {
-                parent = dirname_malloc(path);
-                if (!parent)
-                        return -ENOMEM;
+                r = path_extract_directory(path, &parent);
+                if (r < 0)
+                        return r;
 
                 path = parent;
         }
@@ -199,6 +204,7 @@ static int path_is_config(const LookupPaths *lp, const char *path, bool check_pa
 static int path_is_runtime(const LookupPaths *lp, const char *path, bool check_parent) {
         _cleanup_free_ char *parent = NULL;
         const char *rpath;
+        int r;
 
         assert(lp);
         assert(path);
@@ -211,9 +217,9 @@ static int path_is_runtime(const LookupPaths *lp, const char *path, bool check_p
                 return true;
 
         if (check_parent) {
-                parent = dirname_malloc(path);
-                if (!parent)
-                        return -ENOMEM;
+                r = path_extract_directory(path, &parent);
+                if (r < 0)
+                        return r;
 
                 path = parent;
         }
@@ -1793,9 +1799,9 @@ int unit_file_verify_alias(
 
                 path_alias ++; /* skip over slash */
 
-                dir = dirname_malloc(dst);
-                if (!dir)
-                        return log_oom();
+                r = path_extract_directory(dst, &dir);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to extract parent directory from '%s': %m", dst);
 
                 p = endswith(dir, ".wants");
                 if (!p)
index d9923e9de8fb367d01fe68cc8814b9338c4cc93d..efc066c4f2e9cf859ebee6f67be46a8dab895f63 100644 (file)
@@ -45,6 +45,7 @@
 #define BATTERY_LOW_CAPACITY_LEVEL 5
 #define DISCHARGE_RATE_FILEPATH "/var/lib/systemd/sleep/battery_discharge_percentage_rate_per_hour"
 #define BATTERY_DISCHARGE_RATE_HASH_KEY SD_ID128_MAKE(5f,9a,20,18,38,76,46,07,8d,36,58,0b,bb,c4,e0,63)
+#define SYS_ENTRY_RAW_FILE_TYPE1 "/sys/firmware/dmi/entries/1-0/raw"
 
 static void *CAPACITY_TO_PTR(int capacity) {
         assert(capacity >= 0);
@@ -526,6 +527,68 @@ int get_total_suspend_interval(Hashmap *last_capacity, usec_t *ret) {
         return 0;
 }
 
+/* Return true if all batteries have acpi_btp support */
+int battery_trip_point_alarm_exists(void) {
+        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+        sd_device *dev;
+        int r;
+
+        r = battery_enumerator_new(&e);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to initialize battery enumerator: %m");
+
+        FOREACH_DEVICE(e, dev) {
+                int battery_alarm;
+                const char *s;
+
+                r = sd_device_get_sysattr_value(dev, "alarm", &s);
+                if (r < 0)
+                        return log_device_debug_errno(dev, r, "Failed to read battery alarm: %m");
+
+                r = safe_atoi(s, &battery_alarm);
+                if (r < 0)
+                        return log_device_debug_errno(dev, r, "Failed to parse battery alarm: %m");
+                if (battery_alarm <= 0)
+                        return false;
+        }
+
+        return true;
+}
+
+/* Return true if wakeup type is APM timer */
+int check_wakeup_type(void) {
+        _cleanup_free_ char *s = NULL;
+        uint8_t wakeup_type_byte, tablesize;
+        size_t readsize;
+        int r;
+
+        /* implementation via dmi/entries */
+        r = read_full_virtual_file(SYS_ENTRY_RAW_FILE_TYPE1, &s, &readsize);
+        if (r < 0)
+                return log_debug_errno(r, "Unable to read %s: %m", SYS_ENTRY_RAW_FILE_TYPE1);
+
+        if (readsize < 25)
+                return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Only read %zu bytes from %s (expected 25)", readsize, SYS_ENTRY_RAW_FILE_TYPE1);
+
+        /* index 1 stores the size of table */
+        tablesize = (uint8_t) s[1];
+        if (tablesize < 25)
+                return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Table size lesser than the index[0x18] where waketype byte is available.");
+
+        wakeup_type_byte = (uint8_t) s[24];
+        /* 0 is Reserved and 8 is AC Power Restored. As per table 12 in
+         * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.4.0.pdf */
+        if (wakeup_type_byte >= 128)
+                return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Expected value in range 0-127");
+
+        if (wakeup_type_byte == 3) {
+                log_debug("DMI BIOS System Information indicates wakeup type is APM Timer");
+                return true;
+        }
+
+        return false;
+}
+
 int can_sleep_state(char **types) {
         _cleanup_free_ char *text = NULL;
         int r;
index 54fe65007ede17aa0eaf3baf659411f1e34d7e92..6645c3e5968f1f52cf3a6eb82a02a5e8391c64af 100644 (file)
@@ -65,6 +65,8 @@ int estimate_battery_discharge_rate_per_hour(
                 Hashmap *current_capacity,
                 usec_t before_timestamp,
                 usec_t after_timestamp);
+int check_wakeup_type(void);
+int battery_trip_point_alarm_exists(void);
 
 const char* sleep_operation_to_string(SleepOperation s) _const_;
 SleepOperation sleep_operation_from_string(const char *s) _pure_;
index 14191cfc61c593c0356d4873235a3b4d9321634a..d8e6380d0a622ee02b3cdf4f5ac9fe6f853b0082 100644 (file)
@@ -262,7 +262,7 @@ static int execute(
         return r;
 }
 
-static int execute_s2h(const SleepConfig *sleep_config) {
+static int custom_timer_suspend(const SleepConfig *sleep_config) {
         _cleanup_hashmap_free_ Hashmap *last_capacity = NULL, *current_capacity = NULL;
         int r;
 
@@ -335,7 +335,55 @@ static int execute_s2h(const SleepConfig *sleep_config) {
                 if (!woken_by_timer)
                         /* Return as manual wakeup done. This also will return in case battery was charged during suspension */
                         return 0;
+
+                r = check_wakeup_type();
+                if (r < 0)
+                        log_debug_errno(r, "Failed to check hardware wakeup type, ignoring: %m");
+                if (r > 0) {
+                        log_debug("wakeup type is APM timer");
+                        /* system should hibernate */
+                        break;
+                }
+        }
+
+        return 1;
+}
+
+static int execute_s2h(const SleepConfig *sleep_config) {
+        int r, k;
+
+        assert(sleep_config);
+
+        r = check_wakeup_type();
+        if (r < 0)
+                log_debug_errno(r, "Failed to check hardware wakeup type, ignoring: %m");
+
+        k = battery_trip_point_alarm_exists();
+        if (k < 0)
+                log_debug_errno(k, "Failed to check whether acpi_btp support is enabled or not, ignoring: %m");
+
+        if (r >= 0 && k > 0) {
+                log_debug("Attempting to suspend...");
+                r = execute(sleep_config, SLEEP_SUSPEND, NULL);
+                if (r < 0)
+                        return r;
+
+                r = check_wakeup_type();
+                if (r < 0)
+                        return log_debug_errno(r, "Failed to check hardware wakeup type: %m");
+
+                if (r == 0)
+                        /* For APM Timer wakeup, system should hibernate else wakeup */
+                        return 0;
+        } else {
+                r = custom_timer_suspend(sleep_config);
+                if(r < 0)
+                        return log_debug_errno(r, "Suspend cycle with manual battery discharge rate estimation failed: %m");
+                if(r == 0)
+                        /* manual wakeup */
+                        return 0;
         }
+        /* For above custom timer, if 1 is returned, system will directly hibernate */
 
         log_debug("Attempting to hibernate");
         r = execute(sleep_config, SLEEP_HIBERNATE, NULL);
index 446dfd7dd63e355e9786028951aa705a2cb3980d..a363d7a494a977d211f9e3f97510e45c20f4aa1f 100644 (file)
@@ -579,9 +579,9 @@ end:
                 if (!arg_full) {
                         _cleanup_free_ char *dir = NULL;
 
-                        dir = dirname_malloc(*original);
-                        if (!dir)
-                                return log_oom();
+                        r = path_extract_directory(*original, &dir);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to extract directory from '%s': %m", *original);
 
                         /* No need to check if the dir is empty, rmdir does nothing if it is not the case. */
                         (void) rmdir(dir);
index 36a0748c14ac0e2a0553acd43939ee8e516f99cf..beeffda316c48d713e152d6f5a3c5f5be387325a 100644 (file)
@@ -393,10 +393,10 @@ static void print_status_info(
 
                                 dir = mfree(dir);
 
-                                dir = dirname_malloc(*dropin);
-                                if (!dir) {
-                                        log_oom();
-                                        return;
+                                r = path_extract_directory(*dropin, &dir);
+                                if (r < 0) {
+                                        log_error_errno(r, "Failed to extract directory of '%s': %m", *dropin);
+                                        break;
                                 }
 
                                 printf("%s\n"
index 587591cf04858adbe90c34b16cde332b9ca6814e..e17548373413ae19869897d135601d0a6cc7acaa 100644 (file)
@@ -295,7 +295,7 @@ int main(int argc, char *argv[]) {
         test_policy_empty(false, cgroup, &prog);
         test_policy_empty(true, cgroup, &prog);
 
-        assert_se(parent = dirname_malloc(cgroup));
+        assert_se(path_extract_directory(cgroup, &parent) >= 0);
 
         assert_se(cg_mask_supported(&supported) >= 0);
         r = cg_attach_everywhere(supported, parent, 0, NULL, NULL);
index 3b99c5aaecb9d0e57a9ca5011cb281ae2ed2f1d8..d655058d3da7afd4b2523a405c6d82814c74edbd 100644 (file)
@@ -176,7 +176,7 @@ int main(int argc, char *argv[]) {
 
         assert_se(r >= 0);
 
-        assert_se(unit_start(u) >= 0);
+        assert_se(unit_start(u, NULL) >= 0);
 
         while (!IN_SET(SERVICE(u)->state, SERVICE_DEAD, SERVICE_FAILED))
                 assert_se(sd_event_run(m->event, UINT64_MAX) >= 0);
@@ -201,7 +201,7 @@ int main(int argc, char *argv[]) {
                 SERVICE(u)->type = SERVICE_ONESHOT;
                 u->load_state = UNIT_LOADED;
 
-                assert_se(unit_start(u) >= 0);
+                assert_se(unit_start(u, NULL) >= 0);
 
                 while (!IN_SET(SERVICE(u)->state, SERVICE_DEAD, SERVICE_FAILED))
                         assert_se(sd_event_run(m->event, UINT64_MAX) >= 0);
index 061426f28720f24ac310c2c9267696f8a8053651..0445c39855ff3a317b64c6ed29c5fcdd541cadc3 100644 (file)
@@ -246,7 +246,7 @@ static int test_bpf_cgroup_programs(Manager *m, const char *unit_name, const Tes
         SERVICE(u)->type = SERVICE_ONESHOT;
         u->load_state = UNIT_LOADED;
 
-        r = unit_start(u);
+        r = unit_start(u, NULL);
         if (r < 0)
                 return log_error_errno(r, "Unit start failed %m");
 
index 9709053d0af4d73f964ee586f1c8ef04f5b50c76..e1df62f1a68797802a80c7045592300061c33014 100644 (file)
@@ -39,7 +39,7 @@ static int test_restrict_filesystems(Manager *m, const char *unit_name, const ch
         SERVICE(u)->type = SERVICE_ONESHOT;
         u->load_state = UNIT_LOADED;
 
-        r = unit_start(u);
+        r = unit_start(u, NULL);
         if (r < 0)
                 return log_error_errno(r, "Unit start failed %m");
 
index 82e4cf5e54d413c9dfacf89249bbc852e2cb4dcd..0283caeca618227e0513a3187eeeaf6ec8679581 100644 (file)
@@ -210,7 +210,7 @@ static void _test(const char *file, unsigned line, const char *func,
         assert_se(unit_name);
 
         assert_se(manager_load_startable_unit_or_warn(m, unit_name, NULL, &unit) >= 0);
-        assert_se(unit_start(unit) >= 0);
+        assert_se(unit_start(unit, NULL) >= 0);
         check_main_result(file, line, func, m, unit, status_expected, code_expected);
 }
 #define test(m, unit_name, status_expected, code_expected) \
@@ -223,7 +223,7 @@ static void _test_service(const char *file, unsigned line, const char *func,
         assert_se(unit_name);
 
         assert_se(manager_load_startable_unit_or_warn(m, unit_name, NULL, &unit) >= 0);
-        assert_se(unit_start(unit) >= 0);
+        assert_se(unit_start(unit, NULL) >= 0);
         check_service_result(file, line, func, m, unit, result_expected);
 }
 #define test_service(m, unit_name, result_expected) \
index ec8b74f48f3481ed1a3e92b6573176becb5d7000..566b68b5892dd652db250337155455518e0b7fa7 100644 (file)
 #include "tests.h"
 #include "tmpfile-util.h"
 
+TEST(glob_first) {
+        char *first, name[] = "/tmp/test-glob_first.XXXXXX";
+        int fd = -1;
+        int r;
+
+        fd = mkostemp_safe(name);
+        assert_se(fd >= 0);
+        close(fd);
+
+        r = glob_first("/tmp/test-glob_first*", &first);
+        assert_se(r == 1);
+        assert_se(streq(name, first));
+        first = mfree(first);
+
+        r = unlink(name);
+        assert_se(r == 0);
+        r = glob_first("/tmp/test-glob_first*", &first);
+        assert_se(r == 0);
+        assert_se(first == NULL);
+}
+
 TEST(glob_exists) {
         char name[] = "/tmp/test-glob_exists.XXXXXX";
         int fd = -1;
index 7fb1f7363c77e942cdd7b1bd5b8a4d50b99ec89b..a440ca08b479a64b433a3518046a09b36d4d4b7f 100644 (file)
@@ -136,7 +136,7 @@ static void test_path_exists(Manager *m) {
         path = PATH(unit);
         service = service_for_path(m, path, NULL);
 
-        assert_se(unit_start(unit) >= 0);
+        assert_se(unit_start(unit, NULL) >= 0);
         if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
                 return;
 
@@ -170,7 +170,7 @@ static void test_path_existsglob(Manager *m) {
         path = PATH(unit);
         service = service_for_path(m, path, NULL);
 
-        assert_se(unit_start(unit) >= 0);
+        assert_se(unit_start(unit, NULL) >= 0);
         if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
                 return;
 
@@ -205,7 +205,7 @@ static void test_path_changed(Manager *m) {
         path = PATH(unit);
         service = service_for_path(m, path, NULL);
 
-        assert_se(unit_start(unit) >= 0);
+        assert_se(unit_start(unit, NULL) >= 0);
         if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
                 return;
 
@@ -247,7 +247,7 @@ static void test_path_modified(Manager *m) {
         path = PATH(unit);
         service = service_for_path(m, path, NULL);
 
-        assert_se(unit_start(unit) >= 0);
+        assert_se(unit_start(unit, NULL) >= 0);
         if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
                 return;
 
@@ -288,7 +288,7 @@ static void test_path_unit(Manager *m) {
         path = PATH(unit);
         service = service_for_path(m, path, "path-mycustomunit.service");
 
-        assert_se(unit_start(unit) >= 0);
+        assert_se(unit_start(unit, NULL) >= 0);
         if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
                 return;
 
@@ -319,7 +319,7 @@ static void test_path_directorynotempty(Manager *m) {
 
         assert_se(access(test_path, F_OK) < 0);
 
-        assert_se(unit_start(unit) >= 0);
+        assert_se(unit_start(unit, NULL) >= 0);
         if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
                 return;
 
@@ -356,7 +356,7 @@ static void test_path_makedirectory_directorymode(Manager *m) {
 
         assert_se(access(test_path, F_OK) < 0);
 
-        assert_se(unit_start(unit) >= 0);
+        assert_se(unit_start(unit, NULL) >= 0);
 
         /* Check if the directory has been created */
         assert_se(access(test_path, F_OK) >= 0);
index dadd2c0dff61c0aa29c1e5565ebc387359a3f6e2..d7d911034321d6b4b2eabed7c281def93db10ea4 100644 (file)
@@ -78,7 +78,7 @@ static int test_socket_bind(
         SERVICE(u)->type = SERVICE_ONESHOT;
         u->load_state = UNIT_LOADED;
 
-        r = unit_start(u);
+        r = unit_start(u, NULL);
         if (r < 0)
                 return log_error_errno(r, "Unit start failed %m");
 
diff --git a/test/testsuite-63.units/test63-glob.path b/test/testsuite-63.units/test63-glob.path
new file mode 100644 (file)
index 0000000..5f237a9
--- /dev/null
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Path]
+PathExistsGlob=/tmp/test63-glob*
diff --git a/test/testsuite-63.units/test63-glob.service b/test/testsuite-63.units/test63-glob.service
new file mode 100644 (file)
index 0000000..3f49dd4
--- /dev/null
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Service]
+ExecStartPre=sh -c 'test "$TRIGGER_PATH" = /tmp/test63-glob-foo'
+ExecStartPre=sh -c 'test "$TRIGGER_UNIT" = test63-glob.path'
+ExecStart=systemd-notify --ready
+RemainAfterExit=yes
+Type=notify
index 1a8721d82c70da920f69d9820fe998992e97b260..01a928b8d6dea2e0a5cd71d58d44acc6fdc143a8 100644 (file)
@@ -3,4 +3,6 @@
 ConditionPathExists=/tmp/nonexistent
 
 [Service]
+ExecStartPre=sh -c 'test "$TRIGGER_PATH" = /tmp/test63'
+ExecStartPre=sh -c 'test "$TRIGGER_UNIT" = test63.path'
 ExecStart=true
index 5e9fe64ea9f9fc87b9402b5834a3ad7edab93d21..95ebe3876ffa428f86f2c12268de46ef3106e582 100755 (executable)
@@ -8,6 +8,9 @@ set -o pipefail
 cat >/lib/systemd/system/my.service <<EOF
 [Service]
 Type=oneshot
+ExecStartPre=sh -c 'test "\$TRIGGER_UNIT" = my.timer'
+ExecStartPre=sh -c 'test -n "\$TRIGGER_TIMER_REALTIME_USEC"'
+ExecStartPre=sh -c 'test -n "\$TRIGGER_TIMER_MONOTONIC_USEC"'
 ExecStart=/bin/echo Timer runs me
 EOF
 
index f2d937daba3a5f8e6776e26da177f234115012db..6170c8ab63fd758059fee9b632e5a98504a3ad0f 100755 (executable)
@@ -187,6 +187,7 @@ if [ "${HAVE_OPENSSL}" -eq 1 ]; then
     sfdisk --part-label "${image}.gpt" 3 "Signature Partition"
 fi
 loop="$(losetup --show -P -f "${image}.gpt")"
+udevadm wait --timeout 60 --settle "${loop:?}"
 dd if="${image}.raw" of="${loop}p1"
 dd if="${image}.verity" of="${loop}p2"
 if [ "${HAVE_OPENSSL}" -eq 1 ]; then
index 40422127ff4d536563de211a0bb7df7749bf7c67..483c6a859bc831e5b5ea2fceea942b32b520f133 100644 (file)
@@ -1,30 +1,8 @@
 # SPDX-License-Identifier: LGPL-2.1-or-later
 [Unit]
-Description=TEST-63-ISSUE-17433
+Description=TEST-63-PATH
 
 [Service]
 ExecStartPre=rm -f /failed /testok
+ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh
 Type=oneshot
-
-# Test that a path unit continuously triggering a service that fails condition checks eventually fails with
-# the trigger-limit-hit error.
-ExecStart=rm -f /tmp/nonexistent
-ExecStart=systemctl start test63.path
-ExecStart=touch /tmp/test63
-# Make sure systemd has sufficient time to hit the trigger limit for test63.path.
-ExecStart=sleep 2
-ExecStart=sh -x -c 'test "$(systemctl show test63.service -P ActiveState)" = inactive'
-ExecStart=sh -x -c 'test "$(systemctl show test63.service -P Result)" = success'
-ExecStart=sh -x -c 'test "$(systemctl show test63.path -P ActiveState)" = failed'
-ExecStart=sh -x -c 'test "$(systemctl show test63.path -P Result)" = trigger-limit-hit'
-
-# Test that starting the service manually doesn't affect the path unit.
-ExecStart=rm -f /tmp/test63
-ExecStart=systemctl reset-failed
-ExecStart=systemctl start test63.path
-ExecStart=systemctl start test63.service
-ExecStart=sh -x -c 'test "$(systemctl show test63.service -P ActiveState)" = inactive'
-ExecStart=sh -x -c 'test "$(systemctl show test63.service -P Result)" = success'
-ExecStart=sh -x -c 'test "$(systemctl show test63.path -P ActiveState)" = active'
-ExecStart=sh -x -c 'test "$(systemctl show test63.path -P Result)" = success'
-ExecStart=sh -x -c 'echo OK >/testok'
diff --git a/test/units/testsuite-63.sh b/test/units/testsuite-63.sh
new file mode 100755 (executable)
index 0000000..7ee7fc1
--- /dev/null
@@ -0,0 +1,46 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -ex
+set -o pipefail
+
+systemctl log-level debug
+
+# Test that a path unit continuously triggering a service that fails condition checks eventually fails with
+# the trigger-limit-hit error.
+rm -f /tmp/nonexistent
+systemctl start test63.path
+touch /tmp/test63
+
+# Make sure systemd has sufficient time to hit the trigger limit for test63.path.
+sleep 2
+test "$(systemctl show test63.service -P ActiveState)" = inactive
+test "$(systemctl show test63.service -P Result)" = success
+test "$(systemctl show test63.path -P ActiveState)" = failed
+test "$(systemctl show test63.path -P Result)" = trigger-limit-hit
+
+# Test that starting the service manually doesn't affect the path unit.
+rm -f /tmp/test63
+systemctl reset-failed
+systemctl start test63.path
+systemctl start test63.service
+test "$(systemctl show test63.service -P ActiveState)" = inactive
+test "$(systemctl show test63.service -P Result)" = success
+test "$(systemctl show test63.path -P ActiveState)" = active
+test "$(systemctl show test63.path -P Result)" = success
+
+# Test that glob matching works too, with $TRIGGER_PATH
+systemctl start test63-glob.path
+touch /tmp/test63-glob-foo
+timeout 60 bash -c 'while ! systemctl -q is-active test63-glob.service; do sleep .2; done'
+test "$(systemctl show test63-glob.service -P ActiveState)" = active
+test "$(systemctl show test63-glob.service -P Result)" = success
+
+test "$(busctl --json=short get-property org.freedesktop.systemd1 /org/freedesktop/systemd1/unit/test63_2dglob_2eservice org.freedesktop.systemd1.Unit ActivationDetails)" = '{"type":"a(ss)","data":[["trigger_unit","test63-glob.path"],["trigger_path","/tmp/test63-glob-foo"]]}'
+
+systemctl stop test63-glob.path test63-glob.service
+
+test "$(busctl --json=short get-property org.freedesktop.systemd1 /org/freedesktop/systemd1/unit/test63_2dglob_2eservice org.freedesktop.systemd1.Unit ActivationDetails)" = '{"type":"a(ss)","data":[]}'
+
+systemctl log-level info
+
+echo OK >/testok