]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #24242 from msekletar/terminate-idle-sessions
authorLennart Poettering <lennart@poettering.net>
Thu, 25 Aug 2022 09:39:42 +0000 (11:39 +0200)
committerGitHub <noreply@github.com>
Thu, 25 Aug 2022 09:39:42 +0000 (11:39 +0200)
Add option to stop idle sessions after specified timeout

141 files changed:
.github/workflows/build_test.sh
.github/workflows/build_test.yml
.github/workflows/mkosi.yml
.github/workflows/run_mkosi.sh [deleted file]
.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/kernel-command-line.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_creds_get_pid.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-cgtop.xml
man/systemd-debug-generator.xml
man/systemd-detect-virt.xml
man/systemd-nspawn.xml
man/systemd-run.xml
man/systemd-system.conf.xml
man/systemd-sysusers.xml
man/systemd.exec.xml
man/systemd.journal-fields.xml
man/systemd.network.xml
man/systemd.path.xml
man/systemd.resource-control.xml
man/systemd.service.xml
man/systemd.timer.xml
man/systemd.unit.xml
man/systemd.xml
meson_options.txt
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/devnum-util.c
src/basic/devnum-util.h
src/basic/glob-util.c
src/basic/glob-util.h
src/basic/log.h
src/basic/mkdir.c
src/basic/path-util.c
src/basic/path-util.h
src/basic/ratelimit.c
src/basic/ratelimit.h
src/basic/time-util.h
src/basic/user-util.c
src/basic/user-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/load-fragment.c
src/core/mount.c
src/core/path.c
src/core/path.h
src/core/service.c
src/core/system.conf.in
src/core/timer.c
src/core/timer.h
src/core/unit.c
src/core/unit.h
src/dissect/dissect.c
src/firstboot/firstboot.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-device/device-private.h
src/libsystemd/sd-device/sd-device.c
src/libsystemd/sd-device/test-sd-device.c
src/libsystemd/sd-journal/sd-journal.c
src/machine/machine-dbus.c
src/nss-systemd/nss-systemd.c
src/partition/growfs.c
src/shared/clock-util.c
src/shared/find-esp.c
src/shared/install.c
src/shared/selinux-util.c
src/shared/sleep-config.c
src/shared/sleep-config.h
src/shared/udev-util.c
src/shutdown/shutdown.c
src/sleep/sleep.c
src/systemctl/systemctl-edit.c
src/systemctl/systemctl-show.c
src/sysusers/sysusers.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-ratelimit.c
src/test/test-socket-bind.c
src/test/test-time-util.c
src/test/test-user-util.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/TEST-75-RESOLVED/test.sh
test/test-execute/exec-specifier.service
test/test-execute/exec-specifier@.service
test/test-sysusers.sh.in
test/test-sysusers/unhappy-1.expected-err
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-60.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 dddeb5fcb324dd8fb493bdb33222ebf4a4edc704..c2c12f33931a37a7230e57ba424fbec15401ce8c 100644 (file)
@@ -44,14 +44,12 @@ jobs:
             release: rawhide
           - distro: opensuse
             release: tumbleweed
-          - distro: centos_epel
-            release: 8-stream
           - distro: centos_epel
             release: 9-stream
 
     steps:
     - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
-    - uses: systemd/mkosi@f37c19e7217a41c52d9a9a8769e98496255e2e2d
+    - uses: systemd/mkosi@d93967b94225ca63b3f5c18045db815439897b5c
 
     - name: Install
       run: sudo apt-get update && sudo apt-get install --no-install-recommends python3-pexpect python3-jinja2
@@ -70,22 +68,20 @@ jobs:
         KernelCommandLine=${{ env.KERNEL_CMDLINE }}
         EOF
 
-        echo systemd-stable/ >> .gitignore
-
     - name: Build ${{ matrix.distro }}
-      run: ./.github/workflows/run_mkosi.sh build
+      run: sudo python3 -m mkosi build
 
     - name: Show ${{ matrix.distro }} image summary
-      run: ./.github/workflows/run_mkosi.sh summary
+      run: sudo python3 -m mkosi summary
 
     - name: Boot ${{ matrix.distro }} systemd-nspawn
-      run: ./.github/workflows/run_mkosi.sh boot ${{ env.KERNEL_CMDLINE }}
+      run: sudo python3 -m mkosi boot ${{ env.KERNEL_CMDLINE }}
 
     - name: Check ${{ matrix.distro }} systemd-nspawn
-      run: ./.github/workflows/run_mkosi.sh shell bash -c "[[ -e /testok ]] || { cat /failed-services; exit 1; }"
+      run: sudo python3 -m mkosi shell bash -c "[[ -e /testok ]] || { cat /failed-services; exit 1; }"
 
     - name: Boot ${{ matrix.distro }} QEMU
-      run: ./.github/workflows/run_mkosi.sh qemu
+      run: sudo timeout -k 30 10m python3 -m mkosi qemu
 
     - name: Check ${{ matrix.distro }} QEMU
-      run: ./.github/workflows/run_mkosi.sh shell bash -c "[[ -e /testok ]] || { cat /failed-services; exit 1; }"
+      run: sudo python3 -m mkosi shell bash -c "[[ -e /testok ]] || { cat /failed-services; exit 1; }"
diff --git a/.github/workflows/run_mkosi.sh b/.github/workflows/run_mkosi.sh
deleted file mode 100755 (executable)
index acdb3fc..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/usr/bin/env bash
-# SPDX-License-Identifier: LGPL-2.1-or-later
-# shellcheck disable=SC2064
-
-set -eu
-set -o pipefail
-
-EC=0
-TEMPFILE="$(mktemp)"
-TEMP_EXTRA_TREE="$(mktemp --directory)"
-trap "rm -rf '$TEMPFILE' '$TEMP_EXTRA_TREE'" EXIT
-
-# We need isc-dhcp-server to be installed for the networkd unit tests, but we don't want to
-# run it by default. mktemp creates the directory as 700, so change it, otherwise it will
-# affect the image's root folder permissions.
-chmod 755 "$TEMP_EXTRA_TREE"
-mkdir -p "$TEMP_EXTRA_TREE/etc/systemd/system/"
-ln -s /dev/null "$TEMP_EXTRA_TREE/etc/systemd/system/isc-dhcp-server.service"
-ln -s /dev/null "$TEMP_EXTRA_TREE/etc/systemd/system/isc-dhcp-server6.service"
-
-for ((i = 0; i < 5; i++)); do
-    EC=0
-    (sudo timeout -k 30 10m python3 -m mkosi --extra-tree="$TEMP_EXTRA_TREE" "$@") |& tee "$TEMPFILE" || EC=$?
-    if [[ $EC -eq 0 ]]; then
-        # The command passed â€” let's return immediately
-        break
-    fi
-
-    if ! grep -E "Failed to dissect image .+: Connection timed out" "$TEMPFILE"; then
-        # The command failed for other reason than the dissect-related timeout -
-        # let's exit with the same EC
-        exit $EC
-    fi
-
-    # The command failed due to the dissect-related timeout â€” let's try again
-    sleep 1
-done
-
-exit $EC
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 99464eb14a3f4496af34da40af145504529f652e..c648f7779e7bb24fbebb28eed120505c8eab1622 100644 (file)
@@ -71,8 +71,6 @@
         <term><varname>systemd.default_standard_error=</varname></term>
         <term><varname>systemd.setenv=</varname></term>
         <term><varname>systemd.machine_id=</varname></term>
-        <term><varname>systemd.unified_cgroup_hierarchy</varname></term>
-        <term><varname>systemd.legacy_systemd_cgroup_controller</varname></term>
         <term><varname>systemd.set_credential=</varname></term>
         <term><varname>systemd.import_credentials=</varname></term>
         <listitem>
         the hostname, it simply controls the initial hostname set during early boot.</para></listitem>
       </varlistentry>
     </variablelist>
+  </refsect1>
 
+  <refsect1>
+      <title>History</title>
+
+      <variablelist>
+        <varlistentry>
+          <term>systemd 252</term>
+          <listitem><para>Kernel command-line arguments <varname>systemd.unified_cgroup_hierarchy</varname>
+          and <varname>systemd.legacy_systemd_cgroup_controller</varname> were deprecated. Please switch to
+          the unified cgroup hierarchy.</para></listitem>
+        </varlistentry>
+      </variablelist>
   </refsect1>
 
   <refsect1>
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 277ba3ff85db7611480176658925df48f0083d5e..6781e1dcaaec50e59a5e8615d6a9a869a20e8c30 100644 (file)
@@ -879,8 +879,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
@@ -913,8 +914,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>
 
@@ -1006,7 +1007,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>
@@ -1056,8 +1057,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 48007f50bd8eeb48cec276558e39e644d006df7d..56cfa4efa579778a571f45f349cf3292fedd7395 100644 (file)
     that kernel threads do not have a command line, in which case
     -ENXIO is returned.</para>
 
-    <para><function>sd_bus_creds_get_cgroup()</function> will retrieve
-    the control group path. See <ulink
-    url="https://docs.kernel.org/admin-guide/cgroup-v1/index.html">Control Groups version 1</ulink>.
+    <para><function>sd_bus_creds_get_cgroup()</function> will retrieve the control group path. See <ulink
+    url="https://docs.kernel.org/admin-guide/cgroup-v2.html">Control Groups v2</ulink>.
     </para>
 
     <para><function>sd_bus_creds_get_unit()</function> will retrieve
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 a6d9671952b4e7dbec98512e4810158224a67d09..074eeb246bb77e18c0fd056503b224fc8f0d8f11 100644 (file)
     one iteration. The <option>--iterations=</option> argument, if
     given, is honored. This mode is suitable for scripting.</para>
 
-    <para>Resource usage is only accounted for control groups in the
-    relevant hierarchy, i.e. CPU usage is only accounted for control
-    groups in the <literal>cpuacct</literal> hierarchy, memory usage
-    only for those in <literal>memory</literal> and disk I/O usage for
-    those in <literal>blkio</literal>. If resource monitoring for
-    these resources is required, it is recommended to add the
-    <varname>CPUAccounting=1</varname>,
-    <varname>MemoryAccounting=1</varname> and
-    <varname>BlockIOAccounting=1</varname> settings in the unit files
-    in question. See
+    <para>Resource usage is only accounted for control groups with the appropriate controllers turned on:
+    <literal>cpu</literal> controller for CPU usage, <literal>memory</literal> controller for memory usage,
+    and <literal>io</literal> contoller for disk I/O consumption. If resource monitoring for these resources
+    is required, it is recommended to add the <varname>CPUAccounting=1</varname>,
+    <varname>MemoryAccounting=1</varname> and <varname>IOAccounting=1</varname> settings in the unit files in
+    question. See
     <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
     for details.</para>
 
     the CPU load value is going to be between 0% and 800%. The number of
     processors can be found in <literal>/proc/cpuinfo</literal>.</para>
 
-    <para>To emphasize this: unless
-    <literal>CPUAccounting=1</literal>,
-    <literal>MemoryAccounting=1</literal> and
-    <literal>BlockIOAccounting=1</literal> are enabled for the
-    services in question, no resource accounting will be available for
-    system services and the data shown by
-    <command>systemd-cgtop</command> will be incomplete.</para>
+    <para>To emphasize: unless <literal>CPUAccounting=1</literal>, <literal>MemoryAccounting=1</literal>, and
+    <literal>IOAccounting=1</literal> are enabled for the services in question, no resource accounting will
+    be available for system services and the data shown by <command>systemd-cgtop</command> will be
+    incomplete.</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..00f1586a5b5576356adb9e5c359774d3f94d1762 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>
@@ -447,14 +448,13 @@ Sep 08 07:37:21 bupkis env[19948]: BOOT_IMAGE=/vmlinuz-3.11.0-0.rc5.git6.2.fc20.
     <example>
       <title>Limiting resources available to a command</title>
 
-      <programlisting># systemd-run -p BlockIOWeight=10 updatedb</programlisting>
+      <programlisting># systemd-run -p IOWeight=10 updatedb</programlisting>
 
-      <para>This command invokes the
-      <citerefentry project='man-pages'><refentrytitle>updatedb</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      <para>This command invokes the <citerefentry
+      project='man-pages'><refentrytitle>updatedb</refentrytitle><manvolnum>8</manvolnum></citerefentry>
       tool, but lowers the block I/O weight for it to 10. See
       <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-      for more information on the <varname>BlockIOWeight=</varname>
-      property.</para>
+      for more information on the <varname>IOWeight=</varname> property.</para>
     </example>
 
     <example>
index 065bbd5a647091f4f3f80bf64398667c19a435b8..ac21c31d9aa3b3bf0b65d3871c9ac05bfcd498f6 100644 (file)
 
       <varlistentry>
         <term><varname>DefaultCPUAccounting=</varname></term>
-        <term><varname>DefaultBlockIOAccounting=</varname></term>
         <term><varname>DefaultMemoryAccounting=</varname></term>
         <term><varname>DefaultTasksAccounting=</varname></term>
         <term><varname>DefaultIOAccounting=</varname></term>
         <term><varname>DefaultIPAccounting=</varname></term>
 
         <listitem><para>Configure the default resource accounting settings, as configured per-unit by
-        <varname>CPUAccounting=</varname>, <varname>BlockIOAccounting=</varname>, <varname>MemoryAccounting=</varname>,
-        <varname>TasksAccounting=</varname>, <varname>IOAccounting=</varname> and <varname>IPAccounting=</varname>. See
+        <varname>CPUAccounting=</varname>, <varname>MemoryAccounting=</varname>,
+        <varname>TasksAccounting=</varname>, <varname>IOAccounting=</varname> and
+        <varname>IPAccounting=</varname>. See
         <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
         for details on the per-unit settings. <varname>DefaultTasksAccounting=</varname> defaults to yes,
-        <varname>DefaultMemoryAccounting=</varname> to &MEMORY_ACCOUNTING_DEFAULT;. <varname>DefaultCPUAccounting=</varname>
-        defaults to yes if enabling CPU accounting doesn't require the CPU controller to be enabled (Linux 4.15+ using the
-        unified hierarchy for resource control), otherwise it defaults to no. The other three settings default to no.</para></listitem>
+        <varname>DefaultMemoryAccounting=</varname> to
+        &MEMORY_ACCOUNTING_DEFAULT;. <varname>DefaultCPUAccounting=</varname> defaults to yes if enabling CPU
+        accounting doesn't require the CPU controller to be enabled (Linux 4.15+ using the unified hierarchy
+        for resource control), otherwise it defaults to no. The other three settings default to
+        no.</para></listitem>
       </varlistentry>
 
       <varlistentry>
       </table>
   </refsect1>
 
+  <refsect1>
+      <title>History</title>
+
+      <variablelist>
+        <varlistentry>
+          <term>systemd 252</term>
+          <listitem><para>Option <varname>DefaultBlockIOAccounting=</varname> was deprecated. Please switch
+          to the unified cgroup hierarchy.</para></listitem>
+        </varlistentry>
+      </variablelist>
+  </refsect1>
+
   <refsect1>
       <title>See Also</title>
       <para>
index 9011cdb7552f1bc3e78b74b78031d5c6c8112965..b399b3b04c91d9154871501cb61163c0408fa7de 100644 (file)
   <refsect1>
     <title>Description</title>
 
-    <para><command>systemd-sysusers</command> creates system users and
-    groups, based on the file format and location specified in
+    <para><command>systemd-sysusers</command> creates system users and groups, based on files in the format
+    described in
     <citerefentry><refentrytitle>sysusers.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
     </para>
 
-    <para>If invoked with no arguments, it applies all directives from all files
-    found in the directories specified by
-    <citerefentry><refentrytitle>sysusers.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
-    When invoked with positional arguments, if option
-    <option>--replace=<replaceable>PATH</replaceable></option> is specified, arguments
-    specified on the command line are used instead of the configuration file
-    <replaceable>PATH</replaceable>. Otherwise, just the configuration specified by
-    the command line arguments is executed. The string <literal>-</literal> may be
-    specified instead of a filename to instruct <command>systemd-sysusers</command>
-    to read the configuration from standard input. If only the basename of a file is
-    specified, all configuration directories are searched for a matching file and
-    the file found that has the highest priority is executed.</para>
+    <para>If invoked with no arguments, it applies all directives from all files found in the directories
+    specified by
+    <citerefentry><refentrytitle>sysusers.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>. When
+    invoked with positional arguments, if option <option>--replace=<replaceable>PATH</replaceable></option>
+    is specified, arguments specified on the command line are used instead of the configuration file
+    <replaceable>PATH</replaceable>. Otherwise, just the configuration specified by the command line
+    arguments is executed. The string <literal>-</literal> may be specified instead of a filename to instruct
+    <command>systemd-sysusers</command> to read the configuration from standard input. If the argument is a
+    relative path, all configuration directories are searched for a matching file and the file found that has
+    the highest priority is executed. If the argument is an absolute path, that file is used directly without
+    searching of the configuration directories.</para>
   </refsect1>
 
   <refsect1>
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 c16eb3951a18cf806562415397c492d29af21443..940395a44276a6e7068e9751d1c0824837c183a9 100644 (file)
 
   <!-- We don't have any default dependency here. -->
 
-  <refsect1>
-    <title>Unified and Legacy Control Group Hierarchies</title>
-
-    <para>The unified control group hierarchy is the new version of kernel control group interface, see
-    <ulink url="https://docs.kernel.org/admin-guide/cgroup-v2.html">Control Groups v2</ulink>.
-    Depending on the resource type, there are differences in resource control capabilities. Also, because of
-    interface changes, some resource types have separate set of options on the unified hierarchy.</para>
-
-    <para>
-      <variablelist>
-
-        <varlistentry>
-          <term>CPU</term>
-          <listitem>
-            <para><varname>CPUWeight=</varname> and <varname>StartupCPUWeight=</varname> replace
-            <varname>CPUShares=</varname> and <varname>StartupCPUShares=</varname>, respectively.</para>
-
-            <para>The <literal>cpuacct</literal> controller does not exist separately on the unified hierarchy.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term>Memory</term>
-          <listitem>
-            <para><varname>MemoryMax=</varname> replaces <varname>MemoryLimit=</varname>. <varname>MemoryLow=</varname>
-            and <varname>MemoryHigh=</varname> are effective only on unified hierarchy.</para>
-          </listitem>
-        </varlistentry>
-
-        <varlistentry>
-          <term>IO</term>
-          <listitem>
-            <para><literal>IO</literal>-prefixed settings are a superset of and replace
-            <literal>BlockIO</literal>-prefixed ones. On unified hierarchy, IO resource control also applies
-            to buffered writes.</para>
-          </listitem>
-        </varlistentry>
-
-      </variablelist>
-    </para>
-
-    <para>To ease the transition, there is best-effort translation between the two versions of settings. For each
-    controller, if any of the settings for the unified hierarchy are present, all settings for the legacy hierarchy are
-    ignored. If the resulting settings are for the other type of hierarchy, the configurations are translated before
-    application.</para>
-
-    <para>Legacy control group hierarchy (see <ulink
-    url="https://docs.kernel.org/admin-guide/cgroup-v1/">Control Groups version 1</ulink>),
-    also called cgroup-v1, doesn't allow safe delegation of controllers to unprivileged processes. If the
-    system uses the legacy control group hierarchy, resource control is disabled for the systemd user
-    instance, see
-    <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
-  </refsect1>
-
   <refsect1>
     <title>Options</title>
 
           <varname>CPUWeight=</varname> applies to normal runtime of the system, and if the former is not set also to
           the startup and shutdown phases. Using <varname>StartupCPUWeight=</varname> allows prioritizing specific services at
           boot-up and shutdown differently than during normal runtime.</para>
-
-          <para>These settings replace <varname>CPUShares=</varname> and <varname>StartupCPUShares=</varname>.</para>
         </listitem>
       </varlistentry>
 
           For details about this control group attribute, see <ulink
           url="https://docs.kernel.org/admin-guide/cgroup-v2.html#memory-interface-files">Memory Interface Files</ulink>.</para>
 
-          <para>This setting is supported only if the unified control group hierarchy is used and disables
-          <varname>MemoryLimit=</varname>.</para>
-
           <para>Units may have their children use a default <literal>memory.min</literal> or
           <literal>memory.low</literal> value by specifying <varname>DefaultMemoryMin=</varname> or
           <varname>DefaultMemoryLow=</varname>, which has the same semantics as
           special value <literal>infinity</literal>, no memory throttling is applied. This controls the
           <literal>memory.high</literal> control group attribute. For details about this control group attribute, see
           <ulink url="https://docs.kernel.org/admin-guide/cgroup-v2.html#memory-interface-files">Memory Interface Files</ulink>.</para>
-
-          <para>This setting is supported only if the unified control group hierarchy is used and disables
-          <varname>MemoryLimit=</varname>.</para>
         </listitem>
       </varlistentry>
 
           assigned the special value <literal>infinity</literal>, no memory limit is applied. This controls the
           <literal>memory.max</literal> control group attribute. For details about this control group attribute, see
           <ulink url="https://docs.kernel.org/admin-guide/cgroup-v2.html#memory-interface-files">Memory Interface Files</ulink>.</para>
-
-          <para>This setting replaces <varname>MemoryLimit=</varname>.</para>
         </listitem>
       </varlistentry>
 
           special value <literal>infinity</literal>, no swap limit is applied. This controls the
           <literal>memory.swap.max</literal> control group attribute. For details about this control group attribute,
           see <ulink url="https://docs.kernel.org/admin-guide/cgroup-v2.html#memory-interface-files">Memory Interface Files</ulink>.</para>
-
-          <para>This setting is supported only if the unified control group hierarchy is used and disables
-          <varname>MemoryLimit=</varname>.</para>
         </listitem>
       </varlistentry>
 
         <term><varname>TasksMax=<replaceable>N</replaceable></varname></term>
 
         <listitem>
-          <para>Specify the maximum number of tasks that may be created in the unit. This ensures that the number of
-          tasks accounted for the unit (see above) stays below a specific limit. This either takes an absolute number
-          of tasks or a percentage value that is taken relative to the configured maximum number of tasks on the
-          system.  If assigned the special value <literal>infinity</literal>, no tasks limit is applied. This controls
-          the <literal>pids.max</literal> control group attribute. For details about this control group attribute, see
-          <ulink url="https://docs.kernel.org/admin-guide/cgroup-v1/pids.html">Process Number Controller</ulink>.
-          </para>
+          <para>Specify the maximum number of tasks that may be created in the unit. This ensures that the
+          number of tasks accounted for the unit (see above) stays below a specific limit. This either takes
+          an absolute number of tasks or a percentage value that is taken relative to the configured maximum
+          number of tasks on the system. If assigned the special value <literal>infinity</literal>, no tasks
+          limit is applied. This controls the <literal>pids.max</literal> control group attribute. For
+          details about this control group attribute, the
+          <ulink url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html#pid">pids controller
+          </ulink>.</para>
 
           <para>The system default for this setting may be controlled with
           <varname>DefaultTasksMax=</varname> in
           therein. The system default for this setting may be controlled with <varname>DefaultIOAccounting=</varname>
           in
           <citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
-
-          <para>This setting replaces <varname>BlockIOAccounting=</varname> and disables settings prefixed with
-          <varname>BlockIO</varname> or <varname>StartupBlockIO</varname>.</para>
         </listitem>
       </varlistentry>
 
           the system, and if the former is not set also to the startup
           and shutdown phases. This allows prioritizing specific services at boot-up
           and shutdown differently than during runtime.</para>
-
-          <para>These settings replace <varname>BlockIOWeight=</varname> and <varname>StartupBlockIOWeight=</varname>
-          and disable settings prefixed with <varname>BlockIO</varname> or <varname>StartupBlockIO</varname>.</para>
         </listitem>
       </varlistentry>
 
           For details about this control group attribute, see <ulink
           url="https://docs.kernel.org/admin-guide/cgroup-v2.html#io-interface-files">IO Interface Files</ulink>.</para>
 
-          <para>This setting replaces <varname>BlockIODeviceWeight=</varname> and disables settings prefixed with
-          <varname>BlockIO</varname> or <varname>StartupBlockIO</varname>.</para>
-
           <para>The specified device node should reference a block device that has an I/O scheduler
           associated, i.e. should not refer to partition or loopback block devices, but to the originating,
           physical device. When a path to a regular file or directory is specified it is attempted to
           url="https://docs.kernel.org/admin-guide/cgroup-v2.html#io-interface-files">IO Interface Files</ulink>.
           </para>
 
-          <para>These settings replace <varname>BlockIOReadBandwidth=</varname> and
-          <varname>BlockIOWriteBandwidth=</varname> and disable settings prefixed with <varname>BlockIO</varname> or
-          <varname>StartupBlockIO</varname>.</para>
-
           <para>Similar restrictions on block device discovery as for <varname>IODeviceWeight=</varname> apply, see above.</para>
         </listitem>
       </varlistentry>
           url="https://docs.kernel.org/admin-guide/cgroup-v2.html#io-interface-files">IO Interface Files</ulink>.
           </para>
 
-          <para>These settings are supported only if the unified control group hierarchy is used and disable settings
-          prefixed with <varname>BlockIO</varname> or <varname>StartupBlockIO</varname>.</para>
-
           <para>Similar restrictions on block device discovery as for <varname>IODeviceWeight=</varname> apply, see above.</para>
         </listitem>
       </varlistentry>
@@ -935,11 +853,8 @@ RestrictNetworkInterfaces=~eth1</programlisting>
           strings: a device node specifier followed by a combination of <constant>r</constant>,
           <constant>w</constant>, <constant>m</constant> to control <emphasis>r</emphasis>eading,
           <emphasis>w</emphasis>riting, or creation of the specific device node(s) by the unit
-          (<emphasis>m</emphasis>knod), respectively. On cgroup-v1 this controls the
-          <literal>devices.allow</literal> control group attribute. For details about this control group
-          attribute, see <ulink
-          url="https://docs.kernel.org/admin-guide/cgroup-v1/devices.html">Device Whitelist Controller</ulink>.
-          In the unified cgroup hierarchy this functionality is implemented using eBPF filtering.</para>
+          (<emphasis>m</emphasis>knod), respectively. This functionality is implemented using eBPF
+          filtering.</para>
 
           <para>When access to <emphasis>all</emphasis> physical devices should be disallowed,
           <varname>PrivateDevices=</varname> may be used instead. See
@@ -1189,146 +1104,28 @@ DeviceAllow=/dev/loop-control
   </refsect1>
 
   <refsect1>
-    <title>Deprecated Options</title>
-
-    <para>The following options are deprecated. Use the indicated superseding options instead:</para>
-
-    <variablelist class='unit-directives'>
-
-      <varlistentry>
-        <term><varname>CPUShares=<replaceable>weight</replaceable></varname></term>
-        <term><varname>StartupCPUShares=<replaceable>weight</replaceable></varname></term>
-
-        <listitem>
-          <para>Assign the specified CPU time share weight to the processes executed. These options take an integer
-          value and control the <literal>cpu.shares</literal> control group attribute. The allowed range is 2 to
-          262144. Defaults to 1024. For details about this control group attribute, see <ulink
-          url="https://docs.kernel.org/scheduler/sched-design-CFS.html">CFS Scheduler</ulink>.
-          The available CPU time is split up among all units within one slice relative to their CPU time share
-          weight.</para>
-
-          <para>While <varname>StartupCPUShares=</varname> applies to the startup and shutdown phases of the system,
-          <varname>CPUShares=</varname> applies to normal runtime of the system, and if the former is not set also to
-          the startup and shutdown phases. Using <varname>StartupCPUShares=</varname> allows prioritizing specific services at
-          boot-up and shutdown differently than during normal runtime.</para>
-
-          <para>Implies <literal>CPUAccounting=yes</literal>.</para>
-
-          <para>These settings are deprecated. Use <varname>CPUWeight=</varname> and
-          <varname>StartupCPUWeight=</varname> instead.</para>
-        </listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><varname>MemoryLimit=<replaceable>bytes</replaceable></varname></term>
-
-        <listitem>
-          <para>Specify the limit on maximum memory usage of the executed processes. The limit specifies how much
-          process and kernel memory can be used by tasks in this unit. Takes a memory size in bytes. If the value is
-          suffixed with K, M, G or T, the specified memory size is parsed as Kilobytes, Megabytes, Gigabytes, or
-          Terabytes (with the base 1024), respectively. Alternatively, a percentage value may be specified, which is
-          taken relative to the installed physical memory on the system. If assigned the special value
-          <literal>infinity</literal>, no memory limit is applied. This controls the
-          <literal>memory.limit_in_bytes</literal> control group attribute. For details about this control group
-          attribute, see <ulink
-          url="https://docs.kernel.org/admin-guide/cgroup-v1/memory.html">Memory Resource Controller</ulink>.</para>
-
-          <para>Implies <literal>MemoryAccounting=yes</literal>.</para>
-
-          <para>This setting is deprecated. Use <varname>MemoryMax=</varname> instead.</para>
-        </listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><varname>BlockIOAccounting=</varname></term>
-
-        <listitem>
-          <para>Turn on Block I/O accounting for this unit, if the legacy control group hierarchy is used on the
-          system. Takes a boolean argument. Note that turning on block I/O accounting for one unit will also implicitly
-          turn it on for all units contained in the same slice and all for its parent slices and the units contained
-          therein. The system default for this setting may be controlled with
-          <varname>DefaultBlockIOAccounting=</varname> in
-          <citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
-
-          <para>This setting is deprecated. Use <varname>IOAccounting=</varname> instead.</para>
-        </listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><varname>BlockIOWeight=<replaceable>weight</replaceable></varname></term>
-        <term><varname>StartupBlockIOWeight=<replaceable>weight</replaceable></varname></term>
-
-        <listitem><para>Set the default overall block I/O weight for the executed processes, if the legacy control
-        group hierarchy is used on the system. Takes a single weight value (between 10 and 1000) to set the default
-        block I/O weight. This controls the <literal>blkio.weight</literal> control group attribute, which defaults to
-        500. For details about this control group attribute, see <ulink
-        url="https://docs.kernel.org/admin-guide/cgroup-v1/blkio-controller.html">Block IO Controller</ulink>.
-        The available I/O bandwidth is split up among all units within one slice relative to their block I/O
-        weight.</para>
-
-        <para>While <varname>StartupBlockIOWeight=</varname> only
-        applies to the startup and shutdown phases of the system,
-        <varname>BlockIOWeight=</varname> applies to the later runtime
-        of the system, and if the former is not set also to the
-        startup and shutdown phases. This allows prioritizing specific services at
-        boot-up and shutdown differently than during runtime.</para>
-
-        <para>Implies
-        <literal>BlockIOAccounting=yes</literal>.</para>
-
-        <para>These settings are deprecated. Use <varname>IOWeight=</varname> and <varname>StartupIOWeight=</varname>
-        instead.</para>
-
-      </listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><varname>BlockIODeviceWeight=<replaceable>device</replaceable> <replaceable>weight</replaceable></varname></term>
+      <title>History</title>
 
-        <listitem>
-          <para>Set the per-device overall block I/O weight for the executed processes, if the legacy control group
-          hierarchy is used on the system. Takes a space-separated pair of a file path and a weight value to specify
-          the device specific weight value, between 10 and 1000. (Example: "/dev/sda 500"). The file path may be
-          specified as path to a block device node or as any other file, in which case the backing block device of the
-          file system of the file is determined. This controls the <literal>blkio.weight_device</literal> control group
-          attribute, which defaults to 1000. Use this option multiple times to set weights for multiple devices. For
-          details about this control group attribute, see <ulink
-          url="https://docs.kernel.org/admin-guide/cgroup-v1/blkio-controller.html">Block IO Controller</ulink>.</para>
-
-          <para>Implies
-          <literal>BlockIOAccounting=yes</literal>.</para>
-
-          <para>This setting is deprecated. Use <varname>IODeviceWeight=</varname> instead.</para>
-        </listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><varname>BlockIOReadBandwidth=<replaceable>device</replaceable> <replaceable>bytes</replaceable></varname></term>
-        <term><varname>BlockIOWriteBandwidth=<replaceable>device</replaceable> <replaceable>bytes</replaceable></varname></term>
-
-        <listitem>
-          <para>Set the per-device overall block I/O bandwidth limit for the executed processes, if the legacy control
-          group hierarchy is used on the system. Takes a space-separated pair of a file path and a bandwidth value (in
-          bytes per second) to specify the device specific bandwidth. The file path may be a path to a block device
-          node, or as any other file in which case the backing block device of the file system of the file is used. If
-          the bandwidth is suffixed with K, M, G, or T, the specified bandwidth is parsed as Kilobytes, Megabytes,
-          Gigabytes, or Terabytes, respectively, to the base of 1000. (Example:
-          "/dev/disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0 5M"). This controls the
-          <literal>blkio.throttle.read_bps_device</literal> and <literal>blkio.throttle.write_bps_device</literal>
-          control group attributes. Use this option multiple times to set bandwidth limits for multiple devices. For
-          details about these control group attributes, see <ulink
-          url="https://docs.kernel.org/admin-guide/cgroup-v1/blkio-controller.html">Block IO Controller</ulink>.
-          </para>
-
-          <para>Implies
-          <literal>BlockIOAccounting=yes</literal>.</para>
-
-          <para>These settings are deprecated. Use <varname>IOReadBandwidthMax=</varname> and
-          <varname>IOWriteBandwidthMax=</varname> instead.</para>
-        </listitem>
-      </varlistentry>
-
-    </variablelist>
+      <variablelist>
+        <varlistentry>
+          <term>systemd 252</term>
+          <listitem><para> Options for controlling the Legacy Control Group Hierarchy (<ulink
+          url="https://docs.kernel.org/admin-guide/cgroup-v1/index.html">Control Groups version 1</ulink> are
+          now fully deprecated: <varname>CPUShares=<replaceable>weight</replaceable></varname>,
+          <varname>StartupCPUShares=<replaceable>weight</replaceable></varname>,
+          <varname>MemoryLimit=<replaceable>bytes</replaceable></varname>,
+          <varname>BlockIOAccounting=</varname>,
+          <varname>BlockIOWeight=<replaceable>weight</replaceable></varname>,
+          <varname>StartupBlockIOWeight=<replaceable>weight</replaceable></varname>,
+          <varname>BlockIODeviceWeight=<replaceable>device</replaceable>
+          <replaceable>weight</replaceable></varname>,
+          <varname>BlockIOReadBandwidth=<replaceable>device</replaceable>
+          <replaceable>bytes</replaceable></varname>,
+          <varname>BlockIOWriteBandwidth=<replaceable>device</replaceable>
+          <replaceable>bytes</replaceable></varname>.
+          Please switch to the unified cgroup hierarchy.</para></listitem>
+        </varlistentry>
+      </variablelist>
   </refsect1>
 
   <refsect1>
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..95f1b98cbd13a13246ef9724774e27f0acada948 100644 (file)
           <literal>uml</literal>,
           <literal>bhyve</literal>,
           <literal>qnx</literal>,
+          <literal>apple</literal>,
           <literal>openvz</literal>,
           <literal>lxc</literal>,
           <literal>lxc-libvirt</literal>,
           <term><varname>ConditionControlGroupController=</varname></term>
 
           <listitem><para>Check whether given cgroup controllers (e.g. <literal>cpu</literal>) are available
-          for use on the system or whether the legacy v1 cgroup or the modern v2 cgroup hierarchy is used.
-          </para>
+          for use on the system.</para>
 
           <para>Multiple controllers may be passed with a space separating them; in this case the condition
           will only pass if all listed controllers are available for use. Controllers unknown to systemd are
-          ignored. Valid controllers are <literal>cpu</literal>, <literal>cpuacct</literal>,
-          <literal>io</literal>, <literal>blkio</literal>, <literal>memory</literal>,
-          <literal>devices</literal>, and <literal>pids</literal>. Even if available in the kernel, a
-          particular controller may not be available if it was disabled on the kernel command line with
-          <varname>cgroup_disable=controller</varname>.</para>
-
-          <para>Alternatively, two special strings <literal>v1</literal> and <literal>v2</literal> may be
-          specified (without any controller names). <literal>v2</literal> will pass if the unified v2 cgroup
-          hierarchy is used, and <literal>v1</literal> will pass if the legacy v1 hierarchy or the hybrid
-          hierarchy are used (see the discussion of <varname>systemd.unified_cgroup_hierarchy</varname> and
-          <varname>systemd.legacy_systemd_cgroup_controller</varname> in
-          <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-          for more information).</para>
-          </listitem>
+          ignored. Valid controllers are <literal>cpu</literal>, <literal>cpuset</literal>,
+          <literal>io</literal>, <literal>memory</literal>, and <literal>pids</literal>. Even if available in
+          the kernel, a particular controller may not be available if it was disabled on the kernel command
+          line with <varname>cgroup_disable=controller</varname>.</para></listitem>
         </varlistentry>
 
         <varlistentry>
@@ -2118,7 +2108,7 @@ Note that this setting is <emphasis>not</emphasis> influenced by the <varname>Us
           <row>
             <entry><literal>%s</literal></entry>
             <entry>User shell</entry>
-            <entry>This is the shell of the user running the service manager instance. In case of the system manager this resolves to <literal>/bin/sh</literal>.</entry>
+            <entry>This is the shell of the user running the service manager instance.</entry>
           </row>
           <row>
             <entry><literal>%S</literal></entry>
index 30484e09a9b01b81d1c850aba6587840370f340b..99b6f11b908a1af630e7e730aa4ac24ae1b6ff68 100644 (file)
     memory its accounting data is flushed out too. However, this data is generally not lost, as a journal log record
     is generated declaring the consumed resources whenever a unit shuts down.</para>
 
-    <para>Processes systemd spawns are placed in individual Linux
-    control groups named after the unit which they belong to in the
-    private systemd hierarchy. (see <ulink
-    url="https://docs.kernel.org/admin-guide/cgroup-v1/index.html">Control Groups version 1</ulink>
-    for more information about control groups, or short "cgroups").
-    systemd uses this to effectively keep track of processes. Control
-    group information is maintained in the kernel, and is accessible
-    via the file system hierarchy (beneath
-    <filename>/sys/fs/cgroup/systemd/</filename>), or in tools such as
-    <citerefentry project='man-pages'><refentrytitle>systemd-cgls</refentrytitle><manvolnum>1</manvolnum></citerefentry>
-    or
-    <citerefentry project='man-pages'><refentrytitle>ps</refentrytitle><manvolnum>1</manvolnum></citerefentry>
-    (<command>ps xawf -eo pid,user,cgroup,args</command> is
-    particularly useful to list all processes and the systemd units
-    they belong to.).</para>
+    <para>Processes systemd spawns are placed in individual Linux control groups named after the unit which
+    they belong to in the private systemd hierarchy. (see <ulink
+    url="https://docs.kernel.org/admin-guide/cgroup-v2.html">Control Groups v2</ulink> for more information
+    about control groups, or short "cgroups").  systemd uses this to effectively keep track of
+    processes. Control group information is maintained in the kernel, and is accessible via the file system
+    hierarchy (beneath <filename>/sys/fs/cgroup/</filename>), or in tools such as <citerefentry
+    project='man-pages'><refentrytitle>systemd-cgls</refentrytitle><manvolnum>1</manvolnum></citerefentry> or
+    <citerefentry
+    project='man-pages'><refentrytitle>ps</refentrytitle><manvolnum>1</manvolnum></citerefentry> (<command>ps
+    xawf -eo pid,user,cgroup,args</command> is particularly useful to list all processes and the systemd
+    units they belong to.).</para>
 
     <para>systemd is compatible with the SysV init system to a large
     degree: SysV init scripts are supported and simply read as an
         for every boot.</para></listitem>
       </varlistentry>
 
-      <varlistentry>
-        <term><varname>systemd.unified_cgroup_hierarchy</varname></term>
-
-        <listitem><para>When specified without an argument or with a true argument,
-        enables the usage of
-        <ulink url="https://docs.kernel.org/admin-guide/cgroup-v2.html">unified cgroup hierarchy</ulink>
-        (a.k.a. cgroups-v2). When specified with a false argument, fall back to
-        hybrid or full legacy cgroup hierarchy.</para>
-
-        <para>If this option is not specified, the default behaviour is determined
-        during compilation (the <option>-Ddefault-hierarchy=</option> meson
-        option). If the kernel does not support unified cgroup hierarchy, the legacy
-        hierarchy will be used even if this option is specified.</para>
-        </listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><varname>systemd.legacy_systemd_cgroup_controller</varname></term>
-
-        <listitem><para>Takes effect if the full unified cgroup hierarchy is not used
-        (see previous option). When specified without an argument or with a true
-        argument, disables the use of "hybrid" cgroup hierarchy (i.e. a cgroups-v2
-        tree used for systemd, and
-        <ulink url="https://docs.kernel.org/admin-guide/cgroup-v1/index.html">legacy
-        cgroup hierarchy</ulink>, a.k.a. cgroups-v1, for other controllers), and
-        forces a full "legacy" mode. When specified with a false argument, enables
-        the use of "hybrid" hierarchy.</para>
-
-        <para>If this option is not specified, the default behaviour is determined
-        during compilation (the <option>-Ddefault-hierarchy=</option> meson
-        option). If the kernel does not support unified cgroup hierarchy, the legacy
-        hierarchy will be used  even if this option is specified.</para>
-        </listitem>
-      </varlistentry>
-
       <varlistentry>
         <term><varname>systemd.set_credential=</varname></term>
 
     </variablelist>
   </refsect1>
 
+  <refsect1>
+      <title>History</title>
+
+      <variablelist>
+        <varlistentry>
+          <term>systemd 252</term>
+          <listitem><para>Kernel command-line arguments <varname>systemd.unified_cgroup_hierarchy</varname>
+          and <varname>systemd.legacy_systemd_cgroup_controller</varname> were deprecated. Please switch to
+          the unified cgroup hierarchy.</para></listitem>
+        </varlistentry>
+      </variablelist>
+  </refsect1>
+
   <refsect1>
     <title>See Also</title>
     <para>
index d5237f02ae3c878ce934c237f500158efb0aa325..814f34084099a21cd259a565b591a1c0d5d93e0e 100644 (file)
@@ -223,7 +223,7 @@ option('status-unit-format-default', type : 'combo',
 option('time-epoch', type : 'integer', value : 0,
        description : 'time epoch for time clients')
 option('clock-valid-range-usec-max', type : 'integer', value : 473364000000000, # 15 years
-       description : 'maximum value in microseconds for the difference between RTC and epoch, exceeding which is considered an RTC error')
+       description : 'maximum value in microseconds for the difference between RTC and epoch, exceeding which is considered an RTC error ["0" disables]')
 option('default-user-shell', type : 'string', value : '/bin/bash',
        description : 'default interactive shell')
 
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 70c07315c599f6743a11b3d76d171da7b2c36cc2..fbefa2bd69ca40556a5a90fce83473567fc5e440 100644 (file)
@@ -5,6 +5,7 @@
 
 #include "chase-symlinks.h"
 #include "devnum-util.h"
+#include "fs-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "string-util.h"
@@ -57,6 +58,53 @@ int device_path_make_major_minor(mode_t mode, dev_t devnum, char **ret) {
         return 0;
 }
 
+int device_path_make_major_minor_sysfs(mode_t mode, dev_t devnum, char **ret) {
+        _cleanup_free_ char *syspath = NULL, *link = NULL, *fname = NULL;
+        _cleanup_free_ char *devpath = NULL;
+        const char *t;
+        int r;
+
+        /* Generates the /dev/... path given a dev_t. What makes this different
+         * from device_path_make_major_minor is that it works even when udev 
+         * hasn't yet run */
+
+        if (S_ISCHR(mode))
+                t = "char";
+        else if (S_ISBLK(mode))
+                t = "block";
+        else
+                return -ENODEV;
+
+        if (asprintf(&syspath, "/sys/dev/%s/" DEVNUM_FORMAT_STR, t, DEVNUM_FORMAT_VAL(devnum)) < 0)
+                return -ENOMEM;
+
+        r = readlink_malloc(syspath, &link);
+        if (r < 0)
+                return r;
+
+        r = path_extract_filename(link, &fname);
+        if (r < 0)
+                return r;
+
+        devpath = path_join("/dev", fname);
+        if (!devpath)
+                return -ENOMEM;
+
+        struct stat st;
+        if (stat(devpath, &st) < 0)
+                return -errno;
+
+        if (((st.st_mode ^ mode) & S_IFMT) != 0)
+                return S_ISBLK(mode) ? -ENOTBLK : -ENODEV;
+
+        if (st.st_rdev != devnum)
+                return -ENXIO;
+
+        *ret = TAKE_PTR(devpath);
+
+        return 0;
+}
+
 int device_path_make_canonical(mode_t mode, dev_t devnum, char **ret) {
         _cleanup_free_ char *p = NULL;
         int r;
index 3f1894b2fd7875d8e0e54a05fa92446bb0314c1a..7adb6fb249ee36637ccbb28a0ce731ecb8b00366 100644 (file)
@@ -29,6 +29,7 @@ int parse_devnum(const char *s, dev_t *ret);
         })
 
 int device_path_make_major_minor(mode_t mode, dev_t devnum, char **ret);
+int device_path_make_major_minor_sysfs(mode_t mode, dev_t devnum, char **ret);
 int device_path_make_canonical(mode_t mode, dev_t devnum, char **ret);
 int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devnum);
 
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 b7b0a42e49454dc9aa89b007ba094870c94f23b9..c51941c14167a0165ad56e8bbe3a8fb5ebe762d0 100644 (file)
@@ -8,6 +8,7 @@
 #include <syslog.h>
 
 #include "macro.h"
+#include "ratelimit.h"
 
 /* Some structures we reference but don't want to pull in headers for */
 struct iovec;
@@ -367,3 +368,41 @@ int log_syntax_invalid_utf8_internal(
 #define DEBUG_LOGGING _unlikely_(log_get_max_level() >= LOG_DEBUG)
 
 void log_setup(void);
+
+typedef struct LogRateLimit {
+        int error;
+        int level;
+        RateLimit ratelimit;
+} LogRateLimit;
+
+#define log_ratelimit_internal(_level, _error, _format, _file, _line, _func, ...)        \
+({                                                                              \
+        int _log_ratelimit_error = (_error);                                    \
+        int _log_ratelimit_level = (_level);                                    \
+        static LogRateLimit _log_ratelimit = {                                  \
+                .ratelimit = {                                                  \
+                        .interval = 1 * USEC_PER_SEC,                           \
+                        .burst = 1,                                             \
+                },                                                              \
+        };                                                                      \
+        unsigned _num_dropped_errors = ratelimit_num_dropped(&_log_ratelimit.ratelimit); \
+        if (_log_ratelimit_error != _log_ratelimit.error || _log_ratelimit_level != _log_ratelimit.level) { \
+                ratelimit_reset(&_log_ratelimit.ratelimit);                     \
+                _log_ratelimit.error = _log_ratelimit_error;                    \
+                _log_ratelimit.level = _log_ratelimit_level;                    \
+        }                                                                       \
+        if (ratelimit_below(&_log_ratelimit.ratelimit))                         \
+                _log_ratelimit_error = _num_dropped_errors > 0                  \
+                ? log_internal(_log_ratelimit_level, _log_ratelimit_error, _file, _line, _func, _format " (Dropped %u similar message(s))", __VA_ARGS__, _num_dropped_errors) \
+                : log_internal(_log_ratelimit_level, _log_ratelimit_error, _file, _line, _func, _format, __VA_ARGS__); \
+        _log_ratelimit_error;                                                   \
+})
+
+#define log_ratelimit_full_errno(level, error, format, ...)             \
+        ({                                                              \
+                int _level = (level), _e = (error);                     \
+                _e = (log_get_max_level() >= LOG_PRI(_level))           \
+                        ? log_ratelimit_internal(_level, _e, format, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__) \
+                        : -ERRNO_VALUE(_e);                             \
+                _e < 0 ? _e : -ESTRPIPE;                                \
+        })
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 005bf31dc7ceeb14821e3ec8d5c67df69486c406..c16c8f7103ae0bb76eea1f56fe4ba7636303aaf3 100644 (file)
@@ -30,9 +30,16 @@ bool ratelimit_below(RateLimit *r) {
         if (r->num < r->burst)
                 goto good;
 
+        r->num++;
         return false;
 
 good:
         r->num++;
         return true;
 }
+
+unsigned ratelimit_num_dropped(RateLimit *r) {
+        assert(r);
+
+        return r->num > r->burst ? r->num - r->burst : 0;
+}
index ee1d17c0e74e5afcc7b240cd5f6936bfdb2e6ac4..2236189851e6fcbf2167826daa9a41e8a9f525c4 100644 (file)
@@ -4,7 +4,6 @@
 #include <stdbool.h>
 
 #include "time-util.h"
-#include "util.h"
 
 typedef struct RateLimit {
         usec_t interval; /* Keep those two fields first so they can be initialized easily: */
@@ -22,3 +21,5 @@ static inline bool ratelimit_configured(RateLimit *rl) {
 }
 
 bool ratelimit_below(RateLimit *r);
+
+unsigned ratelimit_num_dropped(RateLimit *r);
index bf312442b0eae741dddc77c7b9c731ce22a747dd..c98f95a5301d85ccc6f29ce0c5b479b530c3de58 100644 (file)
@@ -189,10 +189,15 @@ static inline usec_t usec_sub_unsigned(usec_t timestamp, usec_t delta) {
 }
 
 static inline usec_t usec_sub_signed(usec_t timestamp, int64_t delta) {
+        if (delta == INT64_MIN) { /* prevent overflow */
+                assert_cc(-(INT64_MIN + 1) == INT64_MAX);
+                assert_cc(USEC_INFINITY > INT64_MAX);
+                return usec_add(timestamp, (usec_t) INT64_MAX + 1);
+        }
         if (delta < 0)
                 return usec_add(timestamp, (usec_t) (-delta));
-        else
-                return usec_sub_unsigned(timestamp, (usec_t) delta);
+
+        return usec_sub_unsigned(timestamp, (usec_t) delta);
 }
 
 #if SIZEOF_TIME_T == 8
index 16185332f9b5193ed8f661f6bd6e7226c1e425aa..80f9ff144b1a3c7372d26116f563e5cc9beacb41 100644 (file)
@@ -13,6 +13,7 @@
 #include "sd-messages.h"
 
 #include "alloc-util.h"
+#include "chase-symlinks.h"
 #include "errno-util.h"
 #include "fd-util.h"
 #include "fileio.h"
@@ -136,7 +137,6 @@ char *getusername_malloc(void) {
 }
 
 bool is_nologin_shell(const char *shell) {
-
         return PATH_IN_SET(shell,
                            /* 'nologin' is the friendliest way to disable logins for a user account. It prints a nice
                             * message and exits. Different distributions place the binary at different places though,
@@ -154,6 +154,21 @@ bool is_nologin_shell(const char *shell) {
                            "/usr/bin/true");
 }
 
+const char* default_root_shell(const char *root) {
+        /* We want to use the preferred shell, i.e. DEFAULT_USER_SHELL, which usually
+         * will be /bin/bash. Fall back to /bin/sh if DEFAULT_USER_SHELL is not found,
+         * or any access errors. */
+
+        int r = chase_symlinks(DEFAULT_USER_SHELL, root, CHASE_PREFIX_ROOT, NULL, NULL);
+        if (r < 0 && r != -ENOENT)
+                log_debug_errno(r, "Failed to look up shell '%s%s%s': %m",
+                                strempty(root), root ? "/" : "", DEFAULT_USER_SHELL);
+        if (r > 0)
+                return DEFAULT_USER_SHELL;
+
+        return "/bin/sh";
+}
+
 static int synthesize_user_creds(
                 const char **username,
                 uid_t *uid, gid_t *gid,
@@ -176,13 +191,13 @@ static int synthesize_user_creds(
                         *home = "/root";
 
                 if (shell)
-                        *shell = "/bin/sh";
+                        *shell = default_root_shell(NULL);
 
                 return 0;
         }
 
-        if (synthesize_nobody() &&
-            STR_IN_SET(*username, NOBODY_USER_NAME, "65534")) {
+        if (STR_IN_SET(*username, NOBODY_USER_NAME, "65534") &&
+            synthesize_nobody()) {
                 *username = NOBODY_USER_NAME;
 
                 if (uid)
@@ -326,8 +341,8 @@ int get_group_creds(const char **groupname, gid_t *gid, UserCredsFlags flags) {
                 return 0;
         }
 
-        if (synthesize_nobody() &&
-            STR_IN_SET(*groupname, NOBODY_GROUP_NAME, "65534")) {
+        if (STR_IN_SET(*groupname, NOBODY_GROUP_NAME, "65534") &&
+            synthesize_nobody()) {
                 *groupname = NOBODY_GROUP_NAME;
 
                 if (gid)
@@ -373,8 +388,7 @@ char* uid_to_name(uid_t uid) {
         /* Shortcut things to avoid NSS lookups */
         if (uid == 0)
                 return strdup("root");
-        if (synthesize_nobody() &&
-            uid == UID_NOBODY)
+        if (uid == UID_NOBODY && synthesize_nobody())
                 return strdup(NOBODY_USER_NAME);
 
         if (uid_is_valid(uid)) {
@@ -417,8 +431,7 @@ char* gid_to_name(gid_t gid) {
 
         if (gid == 0)
                 return strdup("root");
-        if (synthesize_nobody() &&
-            gid == GID_NOBODY)
+        if (gid == GID_NOBODY && synthesize_nobody())
                 return strdup(NOBODY_GROUP_NAME);
 
         if (gid_is_valid(gid)) {
@@ -556,43 +569,29 @@ int getgroups_alloc(gid_t** gids) {
         return ngroups;
 }
 
-int get_home_dir(char **_h) {
+int get_home_dir(char **ret) {
         struct passwd *p;
         const char *e;
         char *h;
         uid_t u;
 
-        assert(_h);
+        assert(ret);
 
         /* Take the user specified one */
         e = secure_getenv("HOME");
-        if (e && path_is_valid(e) && path_is_absolute(e)) {
-                h = strdup(e);
-                if (!h)
-                        return -ENOMEM;
-
-                *_h = path_simplify(h);
-                return 0;
-        }
+        if (e && path_is_valid(e) && path_is_absolute(e))
+                goto found;
 
         /* Hardcode home directory for root and nobody to avoid NSS */
         u = getuid();
         if (u == 0) {
-                h = strdup("/root");
-                if (!h)
-                        return -ENOMEM;
-
-                *_h = h;
-                return 0;
+                e = "/root";
+                goto found;
         }
-        if (synthesize_nobody() &&
-            u == UID_NOBODY) {
-                h = strdup("/");
-                if (!h)
-                        return -ENOMEM;
 
-                *_h = h;
-                return 0;
+        if (u == UID_NOBODY && synthesize_nobody()) {
+                e = "/";
+                goto found;
         }
 
         /* Check the database... */
@@ -600,56 +599,42 @@ int get_home_dir(char **_h) {
         p = getpwuid(u);
         if (!p)
                 return errno_or_else(ESRCH);
+        e = p->pw_dir;
 
-        if (!path_is_valid(p->pw_dir) ||
-            !path_is_absolute(p->pw_dir))
+        if (!path_is_valid(e) || !path_is_absolute(e))
                 return -EINVAL;
 
-        h = strdup(p->pw_dir);
+ found:
+        h = strdup(e);
         if (!h)
                 return -ENOMEM;
 
-        *_h = path_simplify(h);
+        *ret = path_simplify(h);
         return 0;
 }
 
-int get_shell(char **_s) {
+int get_shell(char **ret) {
         struct passwd *p;
         const char *e;
         char *s;
         uid_t u;
 
-        assert(_s);
+        assert(ret);
 
         /* Take the user specified one */
         e = secure_getenv("SHELL");
-        if (e && path_is_valid(e) && path_is_absolute(e)) {
-                s = strdup(e);
-                if (!s)
-                        return -ENOMEM;
-
-                *_s = path_simplify(s);
-                return 0;
-        }
+        if (e && path_is_valid(e) && path_is_absolute(e))
+                goto found;
 
         /* Hardcode shell for root and nobody to avoid NSS */
         u = getuid();
         if (u == 0) {
-                s = strdup("/bin/sh");
-                if (!s)
-                        return -ENOMEM;
-
-                *_s = s;
-                return 0;
+                e = default_root_shell(NULL);
+                goto found;
         }
-        if (synthesize_nobody() &&
-            u == UID_NOBODY) {
-                s = strdup(NOLOGIN);
-                if (!s)
-                        return -ENOMEM;
-
-                *_s = s;
-                return 0;
+        if (u == UID_NOBODY && synthesize_nobody()) {
+                e = NOLOGIN;
+                goto found;
         }
 
         /* Check the database... */
@@ -657,16 +642,17 @@ int get_shell(char **_s) {
         p = getpwuid(u);
         if (!p)
                 return errno_or_else(ESRCH);
+        e = p->pw_shell;
 
-        if (!path_is_valid(p->pw_shell) ||
-            !path_is_absolute(p->pw_shell))
+        if (!path_is_valid(e) || !path_is_absolute(e))
                 return -EINVAL;
 
-        s = strdup(p->pw_shell);
+ found:
+        s = strdup(e);
         if (!s)
                 return -ENOMEM;
 
-        *_s = path_simplify(s);
+        *ret = path_simplify(s);
         return 0;
 }
 
index e1692c4f66ab426524434a8115dd76112f3b5d11..614dec2fde8a5845e7a184c493c2e1c29fd1e7d3 100644 (file)
@@ -55,7 +55,7 @@ int merge_gid_lists(const gid_t *list1, size_t size1, const gid_t *list2, size_t
 int getgroups_alloc(gid_t** gids);
 
 int get_home_dir(char **ret);
-int get_shell(char **_ret);
+int get_shell(char **ret);
 
 int reset_uid_gid(void);
 
@@ -130,6 +130,7 @@ int putsgent_sane(const struct sgrp *sg, FILE *stream);
 #endif
 
 bool is_nologin_shell(const char *shell);
+const char* default_root_shell(const char *root);
 
 int is_this_me(const char *username);
 
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 801e7d6ccc2611e25bc082e8672c82d1f53f9eb7..30d885e7a1d74819a3df6e1eca2464a71466d3d3 100644 (file)
@@ -148,12 +148,36 @@ DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_ip_tos, ip_tos, int, -1, "Fai
 DEFINE_CONFIG_PARSE_PTR(config_parse_blockio_weight, cg_blkio_weight_parse, uint64_t, "Invalid block IO weight");
 DEFINE_CONFIG_PARSE_PTR(config_parse_cg_weight, cg_weight_parse, uint64_t, "Invalid weight");
 DEFINE_CONFIG_PARSE_PTR(config_parse_cg_cpu_weight, cg_cpu_weight_parse, uint64_t, "Invalid CPU weight");
-DEFINE_CONFIG_PARSE_PTR(config_parse_cpu_shares, cg_cpu_shares_parse, uint64_t, "Invalid CPU shares");
+static DEFINE_CONFIG_PARSE_PTR(config_parse_cpu_shares_internal, cg_cpu_shares_parse, uint64_t, "Invalid CPU shares");
 DEFINE_CONFIG_PARSE_PTR(config_parse_exec_mount_flags, mount_propagation_flags_from_string, unsigned long, "Failed to parse mount flag");
 DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_numa_policy, mpol, int, -1, "Invalid NUMA policy type");
 DEFINE_CONFIG_PARSE_ENUM(config_parse_status_unit_format, status_unit_format, StatusUnitFormat, "Failed to parse status unit format");
 DEFINE_CONFIG_PARSE_ENUM_FULL(config_parse_socket_timestamping, socket_timestamping_from_string_harder, SocketTimestamping, "Failed to parse timestamping precision");
 
+int config_parse_cpu_shares(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+
+
+        log_syntax(unit, LOG_WARNING, filename, line, 0,
+                   "Unit uses %s=; please use CPUWeight= instead. Support for %s= will be removed soon.",
+                   lvalue, lvalue);
+
+        return config_parse_cpu_shares_internal(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
+}
+
 bool contains_instance_specifier_superset(const char *s) {
         const char *p, *q;
         bool percent = false;
@@ -819,9 +843,9 @@ int config_parse_kill_mode(
 
         if (m == KILL_NONE)
                 log_syntax(unit, LOG_WARNING, filename, line, 0,
-                           "Unit configured to use KillMode=none. "
+                           "Unit uses KillMode=none. "
                            "This is unsafe, as it disables systemd's process lifecycle management for the service. "
-                           "Please update your service to use a safer KillMode=, such as 'mixed' or 'control-group'. "
+                           "Please update the service to use a safer KillMode=, such as 'mixed' or 'control-group'. "
                            "Support for KillMode=none is deprecated and will eventually be removed.");
 
         *k = m;
@@ -3883,9 +3907,11 @@ int config_parse_memory_limit(
                 c->memory_max = bytes;
         else if (streq(lvalue, "MemorySwapMax"))
                 c->memory_swap_max = bytes;
-        else if (streq(lvalue, "MemoryLimit"))
+        else if (streq(lvalue, "MemoryLimit")) {
+                log_syntax(unit, LOG_WARNING, filename, line, 0,
+                           "Unit uses MemoryLimit=; please use MemoryMax= instead. Support for MemoryLimit= will be removed soon.");
                 c->memory_limit = bytes;
-        else
+        else
                 return -EINVAL;
 
         return 0;
@@ -4411,6 +4437,10 @@ int config_parse_blockio_device_weight(
         assert(lvalue);
         assert(rvalue);
 
+        log_syntax(unit, LOG_WARNING, filename, line, 0,
+                   "Unit uses %s=; please use IO*= settings instead. Support for %s= will be removed soon.",
+                   lvalue, lvalue);
+
         if (isempty(rvalue)) {
                 while (c->blockio_device_weights)
                         cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
@@ -4486,6 +4516,10 @@ int config_parse_blockio_bandwidth(
         assert(lvalue);
         assert(rvalue);
 
+        log_syntax(unit, LOG_WARNING, filename, line, 0,
+                   "Unit uses %s=; please use IO*= settings instead. Support for %s= will be removed soon.",
+                   lvalue, lvalue);
+
         read = streq("BlockIOReadBandwidth", lvalue);
 
         if (isempty(rvalue)) {
index 9dc04cd07e97228eb7aec877534b787225706cb0..52acd4345b528ec33843b01283017a053f557a85 100644 (file)
@@ -51,6 +51,9 @@ static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = {
 
 static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
 static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
+static void mount_enter_dead(Mount *m, MountResult f);
+static void mount_enter_mounted(Mount *m, MountResult f);
+static void mount_cycle_clear(Mount *m);
 static int mount_process_proc_self_mountinfo(Manager *m);
 
 static bool MOUNT_STATE_WITH_PROCESS(MountState state) {
@@ -300,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)
@@ -762,23 +765,17 @@ static void mount_set_state(Mount *m, MountState state) {
 
 static int mount_coldplug(Unit *u) {
         Mount *m = MOUNT(u);
-        MountState new_state = MOUNT_DEAD;
         int r;
 
         assert(m);
         assert(m->state == MOUNT_DEAD);
 
-        if (m->deserialized_state != m->state)
-                new_state = m->deserialized_state;
-        else if (m->from_proc_self_mountinfo)
-                new_state = MOUNT_MOUNTED;
-
-        if (new_state == m->state)
+        if (m->deserialized_state == m->state)
                 return 0;
 
         if (m->control_pid > 0 &&
             pid_is_unwaited(m->control_pid) &&
-            MOUNT_STATE_WITH_PROCESS(new_state)) {
+            MOUNT_STATE_WITH_PROCESS(m->deserialized_state)) {
 
                 r = unit_watch_pid(UNIT(m), m->control_pid, false);
                 if (r < 0)
@@ -789,15 +786,52 @@ static int mount_coldplug(Unit *u) {
                         return r;
         }
 
-        if (!IN_SET(new_state, MOUNT_DEAD, MOUNT_FAILED)) {
+        if (!IN_SET(m->deserialized_state, MOUNT_DEAD, MOUNT_FAILED)) {
                 (void) unit_setup_dynamic_creds(u);
                 (void) unit_setup_exec_runtime(u);
         }
 
-        mount_set_state(m, new_state);
+        mount_set_state(m, m->deserialized_state);
         return 0;
 }
 
+static void mount_catchup(Unit *u) {
+        Mount *m = MOUNT(ASSERT_PTR(u));
+
+        assert(m);
+
+        /* Adjust the deserialized state. See comments in mount_process_proc_self_mountinfo(). */
+        if (m->from_proc_self_mountinfo)
+                switch (m->state) {
+                case MOUNT_DEAD:
+                case MOUNT_FAILED:
+                        assert(m->control_pid == 0);
+                        unit_acquire_invocation_id(u);
+                        mount_cycle_clear(m);
+                        mount_enter_mounted(m, MOUNT_SUCCESS);
+                        break;
+                case MOUNT_MOUNTING:
+                        assert(m->control_pid > 0);
+                        mount_set_state(m, MOUNT_MOUNTING_DONE);
+                        break;
+                default:
+                        break;
+                }
+        else
+                switch (m->state) {
+                case MOUNT_MOUNTING_DONE:
+                        assert(m->control_pid > 0);
+                        mount_set_state(m, MOUNT_MOUNTING);
+                        break;
+                case MOUNT_MOUNTED:
+                        assert(m->control_pid == 0);
+                        mount_enter_dead(m, MOUNT_SUCCESS);
+                        break;
+                default:
+                        break;
+                }
+}
+
 static void mount_dump(Unit *u, FILE *f, const char *prefix) {
         Mount *m = MOUNT(u);
         MountParameters *p;
@@ -2227,6 +2261,7 @@ const UnitVTable mount_vtable = {
         .done = mount_done,
 
         .coldplug = mount_coldplug,
+        .catchup = mount_catchup,
 
         .dump = mount_dump,
 
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 318c0348264f553bec0387681b2bab15588ceada..a4e79d30330bee0b1d7aa9ce4807afa22a3e27e6 100644 (file)
@@ -54,7 +54,6 @@
 #DefaultCPUAccounting=no
 #DefaultIOAccounting=no
 #DefaultIPAccounting=no
-#DefaultBlockIOAccounting=no
 #DefaultMemoryAccounting={{ 'yes' if MEMORY_ACCOUNTING_DEFAULT else 'no' }}
 #DefaultTasksAccounting=yes
 #DefaultTasksMax=15%
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 9169129a6880776464d3e9dbcce3782c1102d4f5..fd9954b54d4f52452722112f01c1126569da8819 100644 (file)
@@ -755,7 +755,7 @@ static int write_root_passwd(const char *passwd_path, const char *password, cons
                         .pw_gid = 0,
                         .pw_gecos = (char *) "Super User",
                         .pw_dir = (char *) "/root",
-                        .pw_shell = (char *) (shell ?: "/bin/sh"),
+                        .pw_shell = (char *) (shell ?: default_root_shell(arg_root)),
                 };
 
                 if (errno != ENOENT)
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..49cede6892fed9bc11a11f76bb3b1c4591e0be67 100644 (file)
@@ -873,14 +873,14 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, size_t n
         }
 
         if (vacuumed || !shall_try_append_again(f->file, r)) {
-                log_error_errno(r, "Failed to write entry (%zu items, %zu bytes), ignoring: %m", n, IOVEC_TOTAL_SIZE(iovec, n));
+                log_ratelimit_full_errno(LOG_ERR, r, "Failed to write entry (%zu items, %zu bytes), ignoring: %m", n, IOVEC_TOTAL_SIZE(iovec, n));
                 return;
         }
 
         if (r == -E2BIG)
                 log_debug("Journal file %s is full, rotating to a new file", f->file->path);
         else
-                log_info_errno(r, "Failed to write entry to %s (%zu items, %zu bytes), rotating before retrying: %m", f->file->path, n, IOVEC_TOTAL_SIZE(iovec, n));
+                log_ratelimit_full_errno(LOG_INFO, r, "Failed to write entry to %s (%zu items, %zu bytes), rotating before retrying: %m", f->file->path, n, IOVEC_TOTAL_SIZE(iovec, n));
 
         server_rotate(s);
         server_vacuum(s, false);
@@ -892,7 +892,7 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, size_t n
         log_debug("Retrying write.");
         r = journal_file_append_entry(f->file, &ts, NULL, iovec, n, &s->seqnum, NULL, NULL);
         if (r < 0)
-                log_error_errno(r, "Failed to write entry to %s (%zu items, %zu bytes) despite vacuuming, ignoring: %m", f->file->path, n, IOVEC_TOTAL_SIZE(iovec, n));
+                log_ratelimit_full_errno(LOG_ERR, r, "Failed to write entry to %s (%zu items, %zu bytes) despite vacuuming, ignoring: %m", f->file->path, n, IOVEC_TOTAL_SIZE(iovec, n));
         else
                 server_schedule_sync(s, priority);
 }
@@ -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 3d670a3afccf1769730b6f13b84359e857192b79..d993b77b49c8b3341feddb21e636f13b12b26102 100644 (file)
@@ -18,6 +18,7 @@ static inline int device_new_from_watch_handle(sd_device **ret, int wd) {
 }
 
 int device_get_property_bool(sd_device *device, const char *key);
+int device_get_sysattr_unsigned(sd_device *device, const char *sysattr, unsigned *ret_value);
 int device_get_sysattr_bool(sd_device *device, const char *sysattr);
 int device_get_device_id(sd_device *device, const char **ret);
 int device_get_devlink_priority(sd_device *device, int *ret);
index 6bc4e6a019fa131b0d373b07f1aefa40fef496d7..51bee24d511f3bc2c9eac2b10d5a7755d7955d7c 100644 (file)
@@ -2206,6 +2206,25 @@ _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr,
         return 0;
 }
 
+int device_get_sysattr_unsigned(sd_device *device, const char *sysattr, unsigned *ret_value) {
+        const char *value;
+        int r;
+
+        r = sd_device_get_sysattr_value(device, sysattr, &value);
+        if (r < 0)
+                return r;
+
+        unsigned v;
+        r = safe_atou(value, &v);
+        if (r < 0)
+                return log_device_debug_errno(device, r, "Failed to parse '%s' attribute: %m", sysattr);
+
+        if (ret_value)
+                *ret_value = v;
+        /* We return "true" if the value is positive. */
+        return v > 0;
+}
+
 int device_get_sysattr_bool(sd_device *device, const char *sysattr) {
         const char *value;
         int r;
index 8172c64e456d31d60dc40b583b2099048c54d9e4..3deb9beaac7d16b8629826020be013b6ebc27415 100644 (file)
@@ -180,6 +180,13 @@ static void test_sd_device_one(sd_device *d) {
 
         r = sd_device_get_sysattr_value(d, "name_assign_type", &val);
         assert_se(r >= 0 || ERRNO_IS_PRIVILEGE(r) || IN_SET(r, -ENOENT, -EINVAL));
+
+        if (r > 0) {
+                unsigned x;
+
+                assert_se(device_get_sysattr_unsigned(d, "name_assign_type", NULL) >= 0);
+                assert_se(device_get_sysattr_unsigned(d, "name_assign_type", &x) >= 0);
+        }
 }
 
 TEST(sd_device_enumerator_devices) {
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 e24828450fb15c951ef6ba4fb80847c8f0c6762f..75d749e736da1631abaff8156c7c0148aa3ef364 100644 (file)
@@ -26,7 +26,7 @@ static const struct passwd root_passwd = {
         .pw_gid = 0,
         .pw_gecos = (char*) "Super User",
         .pw_dir = (char*) "/root",
-        .pw_shell = (char*) "/bin/sh",
+        .pw_shell = NULL,
 };
 
 static const struct spwd root_spwd = {
@@ -142,24 +142,25 @@ NSS_INITGROUPS_PROTOTYPE(systemd);
 static enum nss_status copy_synthesized_passwd(
                 struct passwd *dest,
                 const struct passwd *src,
+                const char *fallback_shell,
                 char *buffer, size_t buflen,
                 int *errnop) {
 
-        size_t required;
-
         assert(dest);
         assert(src);
         assert(src->pw_name);
         assert(src->pw_passwd);
         assert(src->pw_gecos);
         assert(src->pw_dir);
-        assert(src->pw_shell);
 
-        required = strlen(src->pw_name) + 1;
-        required += strlen(src->pw_passwd) + 1;
-        required += strlen(src->pw_gecos) + 1;
-        required += strlen(src->pw_dir) + 1;
-        required += strlen(src->pw_shell) + 1;
+        const char *shell = ASSERT_PTR(src->pw_shell ?: fallback_shell);
+
+        size_t required =
+                strlen(src->pw_name) + 1 +
+                strlen(src->pw_passwd) + 1 +
+                strlen(src->pw_gecos) + 1 +
+                strlen(src->pw_dir) + 1 +
+                strlen(shell) + 1;
 
         if (buflen < required) {
                 *errnop = ERANGE;
@@ -176,7 +177,7 @@ static enum nss_status copy_synthesized_passwd(
         dest->pw_gecos = stpcpy(dest->pw_passwd, src->pw_passwd) + 1;
         dest->pw_dir = stpcpy(dest->pw_gecos, src->pw_gecos) + 1;
         dest->pw_shell = stpcpy(dest->pw_dir, src->pw_dir) + 1;
-        strcpy(dest->pw_shell, src->pw_shell);
+        strcpy(dest->pw_shell, shell);
 
         return NSS_STATUS_SUCCESS;
 }
@@ -187,15 +188,14 @@ static enum nss_status copy_synthesized_spwd(
                 char *buffer, size_t buflen,
                 int *errnop) {
 
-        size_t required;
-
         assert(dest);
         assert(src);
         assert(src->sp_namp);
         assert(src->sp_pwdp);
 
-        required = strlen(src->sp_namp) + 1;
-        required += strlen(src->sp_pwdp) + 1;
+        size_t required =
+                strlen(src->sp_namp) + 1 +
+                strlen(src->sp_pwdp) + 1;
 
         if (buflen < required) {
                 *errnop = ERANGE;
@@ -220,8 +220,6 @@ static enum nss_status copy_synthesized_group(
                 char *buffer, size_t buflen,
                 int *errnop) {
 
-        size_t required;
-
         assert(dest);
         assert(src);
         assert(src->gr_name);
@@ -229,9 +227,10 @@ static enum nss_status copy_synthesized_group(
         assert(src->gr_mem);
         assert(!*src->gr_mem); /* Our synthesized records' gr_mem is always just NULL... */
 
-        required = strlen(src->gr_name) + 1;
-        required += strlen(src->gr_passwd) + 1;
-        required += sizeof(char*); /* ...but that NULL still needs to be stored into the buffer! */
+        size_t required =
+                strlen(src->gr_name) + 1 +
+                strlen(src->gr_passwd) + 1 +
+                sizeof(char*); /* ...but that NULL still needs to be stored into the buffer! */
 
         if (buflen < ALIGN(required)) {
                 *errnop = ERANGE;
@@ -257,15 +256,14 @@ static enum nss_status copy_synthesized_sgrp(
                 char *buffer, size_t buflen,
                 int *errnop) {
 
-        size_t required;
-
         assert(dest);
         assert(src);
         assert(src->sg_namp);
         assert(src->sg_passwd);
 
-        required = strlen(src->sg_namp) + 1;
-        required += strlen(src->sg_passwd) + 1;
+        size_t required =
+                strlen(src->sg_namp) + 1 +
+                strlen(src->sg_passwd) + 1;
 
         if (buflen < required) {
                 *errnop = ERANGE;
@@ -310,13 +308,17 @@ enum nss_status _nss_systemd_getpwnam_r(
         if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
 
                 if (streq(name, root_passwd.pw_name))
-                        return copy_synthesized_passwd(pwd, &root_passwd, buffer, buflen, errnop);
+                        return copy_synthesized_passwd(pwd, &root_passwd,
+                                                       default_root_shell(NULL),
+                                                       buffer, buflen, errnop);
 
                 if (streq(name, nobody_passwd.pw_name)) {
                         if (!synthesize_nobody())
                                 return NSS_STATUS_NOTFOUND;
 
-                        return copy_synthesized_passwd(pwd, &nobody_passwd, buffer, buflen, errnop);
+                        return copy_synthesized_passwd(pwd, &nobody_passwd,
+                                                       NULL,
+                                                       buffer, buflen, errnop);
                 }
 
         } else if (STR_IN_SET(name, root_passwd.pw_name, nobody_passwd.pw_name))
@@ -354,13 +356,17 @@ enum nss_status _nss_systemd_getpwuid_r(
         if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
 
                 if (uid == root_passwd.pw_uid)
-                        return copy_synthesized_passwd(pwd, &root_passwd, buffer, buflen, errnop);
+                        return copy_synthesized_passwd(pwd, &root_passwd,
+                                                       default_root_shell(NULL),
+                                                       buffer, buflen, errnop);
 
                 if (uid == nobody_passwd.pw_uid) {
                         if (!synthesize_nobody())
                                 return NSS_STATUS_NOTFOUND;
 
-                        return copy_synthesized_passwd(pwd, &nobody_passwd, buffer, buflen, errnop);
+                        return copy_synthesized_passwd(pwd, &nobody_passwd,
+                                                       NULL,
+                                                       buffer, buflen, errnop);
                 }
 
         } else if (uid == root_passwd.pw_uid || uid == nobody_passwd.pw_uid)
index e105c0e151a56ea0f58827c13b407b7f5c913ae2..e940dccd48b96a89f3da15f995e2d54efe6d19a4 100644 (file)
@@ -41,7 +41,7 @@ static int resize_crypt_luks_device(dev_t devno, const char *fstype, dev_t main_
         if (r < 0)
                 return log_error_errno(r, "Cannot resize LUKS device: %m");
 
-        r = device_path_make_major_minor(S_IFBLK, main_devno, &main_devpath);
+        r = device_path_make_major_minor_sysfs(S_IFBLK, main_devno, &main_devpath);
         if (r < 0)
                 return log_error_errno(r, "Failed to format device major/minor path: %m");
 
@@ -54,7 +54,7 @@ static int resize_crypt_luks_device(dev_t devno, const char *fstype, dev_t main_
                                        main_devpath);
 
         log_debug("%s is %"PRIu64" bytes", main_devpath, size);
-        r = device_path_make_major_minor(S_IFBLK, devno, &devpath);
+        r = device_path_make_major_minor_sysfs(S_IFBLK, devno, &devpath);
         if (r < 0)
                 return log_error_errno(r, "Failed to format major/minor path: %m");
 
@@ -115,7 +115,7 @@ static int maybe_resize_underlying_device(
         if (devno == main_devno)
                 return 0;
 
-        r = device_path_make_major_minor(S_IFBLK, devno, &devpath);
+        r = device_path_make_major_minor_sysfs(S_IFBLK, devno, &devpath);
         if (r < 0)
                 return log_error_errno(r, "Failed to format device major/minor path: %m");
 
@@ -237,7 +237,7 @@ static int run(int argc, char *argv[]) {
         if (r < 0)
                 log_warning_errno(r, "Unable to resize underlying device of \"%s\", proceeding anyway: %m", arg_target);
 
-        r = device_path_make_major_minor(S_IFBLK, devno, &devpath);
+        r = device_path_make_major_minor_sysfs(S_IFBLK, devno, &devpath);
         if (r < 0)
                 return log_error_errno(r, "Failed to format device major/minor path: %m");
 
index eb6f12a2556b028d29a1d234e344bc7d8e026503..a4c00d713e3887dd8aca49fbc490b6b5673bfb23 100644 (file)
@@ -153,7 +153,7 @@ int clock_apply_epoch(ClockChangeDirection *ret_attempted_change) {
         now_usec = now(CLOCK_REALTIME);
         if (now_usec < epoch_usec)
                 *ret_attempted_change = CLOCK_CHANGE_FORWARD;
-        else if (now_usec > usec_add(epoch_usec, CLOCK_VALID_RANGE_USEC_MAX))
+        else if (CLOCK_VALID_RANGE_USEC_MAX > 0 && now_usec > usec_add(epoch_usec, CLOCK_VALID_RANGE_USEC_MAX))
                 *ret_attempted_change = CLOCK_CHANGE_BACKWARD;
         else {
                 *ret_attempted_change = CLOCK_CHANGE_NOOP;
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 57f330f8bc32484b9cfbafa7cbf2db3e38f8442d..f7d8353b49c182ab8d28439f75e7b2403dc520a9 100644 (file)
@@ -372,7 +372,6 @@ int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
 #if HAVE_SELINUX
         _cleanup_freecon_ char *mycon = NULL, *fcon = NULL;
         security_class_t sclass;
-        int r;
 
         assert(exe);
         assert(label);
@@ -380,12 +379,10 @@ int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
         if (!mac_selinux_use())
                 return -EOPNOTSUPP;
 
-        r = getcon_raw(&mycon);
-        if (r < 0)
+        if (getcon_raw(&mycon) < 0)
                 return -errno;
 
-        r = getfilecon_raw(exe, &fcon);
-        if (r < 0)
+        if (getfilecon_raw(exe, &fcon) < 0)
                 return -errno;
 
         sclass = string_to_security_class("process");
@@ -411,36 +408,29 @@ int mac_selinux_get_our_label(char **label) {
 #endif
 }
 
-int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *exec_label, char **label) {
+int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *exec_label, char **ret_label) {
 #if HAVE_SELINUX
         _cleanup_freecon_ char *mycon = NULL, *peercon = NULL, *fcon = NULL;
         _cleanup_context_free_ context_t pcon = NULL, bcon = NULL;
+        const char *range = NULL, *bcon_str = NULL;
         security_class_t sclass;
-        const char *range = NULL;
-        int r;
 
         assert(socket_fd >= 0);
         assert(exe);
-        assert(label);
+        assert(ret_label);
 
         if (!mac_selinux_use())
                 return -EOPNOTSUPP;
 
-        r = getcon_raw(&mycon);
-        if (r < 0)
+        if (getcon_raw(&mycon) < 0)
                 return -errno;
 
-        r = getpeercon_raw(socket_fd, &peercon);
-        if (r < 0)
+        if (getpeercon_raw(socket_fd, &peercon) < 0)
                 return -errno;
 
-        if (!exec_label) {
-                /* If there is no context set for next exec let's use context
-                   of target executable */
-                r = getfilecon_raw(exe, &fcon);
-                if (r < 0)
+        if (!exec_label) /* If there is no context set for next exec let's use context of target executable */
+                if (getfilecon_raw(exe, &fcon) < 0)
                         return -errno;
-        }
 
         bcon = context_new(mycon);
         if (!bcon)
@@ -454,20 +444,18 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *
         if (!range)
                 return -errno;
 
-        r = context_range_set(bcon, range);
-        if (r)
+        if (context_range_set(bcon, range) != 0)
                 return -errno;
 
-        freecon(mycon);
-        mycon = strdup(context_str(bcon));
-        if (!mycon)
+        bcon_str = context_str(bcon);
+        if (!bcon_str)
                 return -ENOMEM;
 
         sclass = string_to_security_class("process");
         if (sclass == 0)
                 return -ENOSYS;
 
-        return RET_NERRNO(security_compute_create_raw(mycon, fcon, sclass, label));
+        return RET_NERRNO(security_compute_create_raw(bcon_str, fcon, sclass, ret_label));
 #else
         return -EOPNOTSUPP;
 #endif
@@ -610,6 +598,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
         _cleanup_freecon_ char *fcon = NULL;
         const struct sockaddr_un *un;
         bool context_changed = false;
+        size_t sz;
         char *path;
         int r;
 
@@ -633,8 +622,10 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
         if (un->sun_path[0] == 0)
                 goto skipped;
 
-        path = strndupa_safe(un->sun_path,
-                             addrlen - offsetof(struct sockaddr_un, sun_path));
+        sz = addrlen - offsetof(struct sockaddr_un, sun_path);
+        if (sz > PATH_MAX)
+                goto skipped;
+        path = strndupa_safe(un->sun_path, sz);
 
         /* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */
         mac_selinux_maybe_reload();
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 0c6dea4264d8119f2d2b0c62da06a10054a58e95..2845e62c79cd714cd05fd787a24ce51e2b92d5ee 100644 (file)
@@ -661,7 +661,7 @@ static int device_is_power_sink(sd_device *device) {
 
 int on_ac_power(void) {
         _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
-        bool found_offline = false, found_online = false, found_battery = false;
+        bool found_ac_online = false, found_battery = false;
         sd_device *d;
         int r;
 
@@ -678,22 +678,15 @@ int on_ac_power(void) {
                 return r;
 
         FOREACH_DEVICE(e, d) {
-                const char *val;
-                unsigned v;
-
-                r = sd_device_get_sysattr_value(d, "type", &val);
-                if (r < 0) {
-                        log_device_debug_errno(d, r, "Failed to read 'type' sysfs attribute, ignoring: %m");
-                        continue;
-                }
-
-                /* We assume every power source is AC, except for batteries. See
+                /* See
                  * https://github.com/torvalds/linux/blob/4eef766b7d4d88f0b984781bc1bcb574a6eafdc7/include/linux/power_supply.h#L176
                  * for defined power source types. Also see:
                  * https://docs.kernel.org/admin-guide/abi-testing.html#abi-file-testing-sysfs-class-power */
-                if (streq(val, "Battery")) {
-                        found_battery = true;
-                        log_device_debug(d, "The power supply is battery, ignoring.");
+
+                const char *val;
+                r = sd_device_get_sysattr_value(d, "type", &val);
+                if (r < 0) {
+                        log_device_debug_errno(d, r, "Failed to read 'type' sysfs attribute, ignoring device: %m");
                         continue;
                 }
 
@@ -702,43 +695,48 @@ int on_ac_power(void) {
                         r = device_is_power_sink(d);
                         if (r <= 0) {
                                 if (r < 0)
-                                        log_device_debug_errno(d, r, "Failed to determine the current power role, ignoring: %m");
+                                        log_device_debug_errno(d, r, "Failed to determine the current power role, ignoring device: %m");
                                 else
-                                        log_device_debug(d, "USB power supply is in source mode, ignoring.");
+                                        log_device_debug(d, "USB power supply is in source mode, ignoring device.");
                                 continue;
                         }
                 }
 
-                r = sd_device_get_sysattr_value(d, "online", &val);
-                if (r < 0) {
-                        log_device_debug_errno(d, r, "Failed to read 'online' sysfs attribute, ignoring: %m");
+                bool is_battery = streq(val, "Battery");
+                if (is_battery) {
+                        r = sd_device_get_sysattr_value(d, "scope", &val);
+                        if (r < 0)
+                                log_device_debug_errno(d, r, "Failed to read 'scope' sysfs attribute, ignoring: %m");
+                        else if (streq(val, "Device")) {
+                                log_device_debug(d, "The power supply is a device battery, ignoring.");
+                                continue;
+                        }
+
+                        found_battery = true;
+                        log_device_debug(d, "The power supply is battery.");
                         continue;
                 }
 
-                r = safe_atou(val, &v);
+                r = device_get_sysattr_unsigned(d, "online", NULL);
                 if (r < 0) {
-                        log_device_debug_errno(d, r, "Failed to parse 'online' attribute, ignoring: %m");
+                        log_device_debug_errno(d, r, "Failed to query 'online' sysfs attribute: %m");
                         continue;
-                }
-
-                if (v > 0) /* At least 1 and 2 are defined as different types of 'online' */
-                        found_online = true;
-                else
-                        found_offline = true;
+                } else if (r > 0)  /* At least 1 and 2 are defined as different types of 'online' */
+                        found_ac_online = true;
 
-                log_device_debug(d, "The power supply is currently %s.", v > 0 ? "online" : "offline");
+                log_device_debug(d, "The power supply is currently %s.", r > 0 ? "online" : "offline");
         }
 
-        if (found_online)
-                log_debug("Found at least one online non-battery power supply, system is running on AC power.");
-        else if (!found_offline)
-                log_debug("Found no offline non-battery power supply, assuming system is running on AC power.");
-        else if (!found_battery)
-                log_debug("Found no battery, assuming system is running on AC power.");
-        else
-                log_debug("All non-battery power supplies are offline, assuming system is running with battery.");
-
-        return found_online || !found_offline || !found_battery;
+        if (found_ac_online) {
+                log_debug("Found at least one online non-battery power supply, system is running on AC.");
+                return true;
+        } else if (found_battery) {
+                log_debug("Found battery and no online power sources, assuming system is running from battery.");
+                return false;
+        } else {
+                log_debug("No power supply reported online and no battery, assuming system is running on AC.");
+                return true;
+        }
 }
 
 bool udev_available(void) {
index af9697526d38eeb725b809bebce2309dac233162..dcee0f900616d2fb98bdc99258528c2a198ebab7 100644 (file)
@@ -497,7 +497,7 @@ int main(int argc, char *argv[]) {
                         break;
                 }
 
-                if (!changed && last_try && !can_initrd) {
+                if (!changed && !last_try && !can_initrd) {
                         /* There are things we cannot get rid of. Loop one more time in which we will log
                          * with higher priority to inform the user. Note that we don't need to do this if
                          * there is an initrd to switch to, because that one is likely to get rid of the
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 9c1abf984ecdf3886d063d08ed0b349c9469a1ec..14f5ac3246a3c36754e0efcfbaa1b779bc3de57b 100644 (file)
@@ -4,6 +4,7 @@
 #include <utmp.h>
 
 #include "alloc-util.h"
+#include "chase-symlinks.h"
 #include "conf-files.h"
 #include "copy.h"
 #include "creds-util.h"
@@ -27,6 +28,7 @@
 #include "set.h"
 #include "smack-util.h"
 #include "specifier.h"
+#include "stat-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "sync-util.h"
@@ -390,8 +392,14 @@ static int putsgent_with_members(const struct sgrp *sg, FILE *gshadow) {
 }
 #endif
 
-static const char* default_shell(uid_t uid) {
-        return uid == 0 ? "/bin/sh" : NOLOGIN;
+static const char* pick_shell(const Item *i) {
+        if (i->type != ADD_USER)
+                return NULL;
+        if (i->shell)
+                return i->shell;
+        if (i->uid_set && i->uid == 0)
+                return default_root_shell(arg_root);
+        return NOLOGIN;
 }
 
 static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char **tmpfile_path) {
@@ -473,7 +481,7 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char
 
                         /* Initialize the shell to nologin, with one exception:
                          * for root we patch in something special */
-                        .pw_shell = i->shell ?: (char*) default_shell(i->uid),
+                        .pw_shell = (char*) pick_shell(i),
                 };
 
                 /* Try to pick up the shell for this account via the credentials logic */
@@ -659,14 +667,14 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char **
 
         r = fopen_temporary_label("/etc/group", group_path, &group, &group_tmp);
         if (r < 0)
-                return log_debug_errno(r, "Failed to open temporary copy of %s: %m", group_path);
+                return log_error_errno(r, "Failed to open temporary copy of %s: %m", group_path);
 
         original = fopen(group_path, "re");
         if (original) {
 
                 r = copy_rights_with_fallback(fileno(original), fileno(group), group_tmp);
                 if (r < 0)
-                        return log_debug_errno(r, "Failed to copy permissions from %s to %s: %m",
+                        return log_error_errno(r, "Failed to copy permissions from %s to %s: %m",
                                                group_path, group_tmp);
 
                 while ((r = fgetgrent_sane(original, &gr)) > 0) {
@@ -692,19 +700,19 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char **
 
                         r = putgrent_with_members(gr, group);
                         if (r < 0)
-                                return log_debug_errno(r, "Failed to add existing group \"%s\" to temporary group file: %m",
+                                return log_error_errno(r, "Failed to add existing group \"%s\" to temporary group file: %m",
                                                        gr->gr_name);
                         if (r > 0)
                                 group_changed = true;
                 }
                 if (r < 0)
-                        return log_debug_errno(r, "Failed to read %s: %m", group_path);
+                        return log_error_errno(r, "Failed to read %s: %m", group_path);
 
         } else {
                 if (errno != ENOENT)
-                        return log_debug_errno(errno, "Failed to open %s: %m", group_path);
+                        return log_error_errno(errno, "Failed to open %s: %m", group_path);
                 if (fchmod(fileno(group), 0644) < 0)
-                        return log_debug_errno(errno, "Failed to fchmod %s: %m", group_tmp);
+                        return log_error_errno(errno, "Failed to fchmod %s: %m", group_tmp);
         }
 
         ORDERED_HASHMAP_FOREACH(i, todo_gids) {
@@ -716,7 +724,7 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char **
 
                 r = putgrent_with_members(&n, group);
                 if (r < 0)
-                        return log_debug_errno(r, "Failed to add new group \"%s\" to temporary group file: %m",
+                        return log_error_errno(r, "Failed to add new group \"%s\" to temporary group file: %m",
                                                gr->gr_name);
 
                 group_changed = true;
@@ -726,19 +734,19 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char **
         while (gr) {
                 r = putgrent_sane(gr, group);
                 if (r < 0)
-                        return log_debug_errno(r, "Failed to add existing group \"%s\" to temporary group file: %m",
+                        return log_error_errno(r, "Failed to add existing group \"%s\" to temporary group file: %m",
                                                gr->gr_name);
 
                 r = fgetgrent_sane(original, &gr);
                 if (r < 0)
-                        return log_debug_errno(r, "Failed to read %s: %m", group_path);
+                        return log_error_errno(r, "Failed to read %s: %m", group_path);
                 if (r == 0)
                         break;
         }
 
         r = fflush_sync_and_check(group);
         if (r < 0)
-                return log_debug_errno(r, "Failed to flush %s: %m", group_tmp);
+                return log_error_errno(r, "Failed to flush %s: %m", group_tmp);
 
         if (group_changed) {
                 *tmpfile = TAKE_PTR(group);
@@ -765,7 +773,7 @@ static int write_temporary_gshadow(const char * gshadow_path, FILE **tmpfile, ch
 
         r = fopen_temporary_label("/etc/gshadow", gshadow_path, &gshadow, &gshadow_tmp);
         if (r < 0)
-                return log_debug_errno(r, "Failed to open temporary copy of %s: %m", gshadow_path);
+                return log_error_errno(r, "Failed to open temporary copy of %s: %m", gshadow_path);
 
         original = fopen(gshadow_path, "re");
         if (original) {
@@ -773,7 +781,7 @@ static int write_temporary_gshadow(const char * gshadow_path, FILE **tmpfile, ch
 
                 r = copy_rights_with_fallback(fileno(original), fileno(gshadow), gshadow_tmp);
                 if (r < 0)
-                        return log_debug_errno(r, "Failed to copy permissions from %s to %s: %m",
+                        return log_error_errno(r, "Failed to copy permissions from %s to %s: %m",
                                                gshadow_path, gshadow_tmp);
 
                 while ((r = fgetsgent_sane(original, &sg)) > 0) {
@@ -786,7 +794,7 @@ static int write_temporary_gshadow(const char * gshadow_path, FILE **tmpfile, ch
 
                         r = putsgent_with_members(sg, gshadow);
                         if (r < 0)
-                                return log_debug_errno(r, "Failed to add existing group \"%s\" to temporary gshadow file: %m",
+                                return log_error_errno(r, "Failed to add existing group \"%s\" to temporary gshadow file: %m",
                                                        sg->sg_namp);
                         if (r > 0)
                                 group_changed = true;
@@ -796,9 +804,9 @@ static int write_temporary_gshadow(const char * gshadow_path, FILE **tmpfile, ch
 
         } else {
                 if (errno != ENOENT)
-                        return log_debug_errno(errno, "Failed to open %s: %m", gshadow_path);
+                        return log_error_errno(errno, "Failed to open %s: %m", gshadow_path);
                 if (fchmod(fileno(gshadow), 0000) < 0)
-                        return log_debug_errno(errno, "Failed to fchmod %s: %m", gshadow_tmp);
+                        return log_error_errno(errno, "Failed to fchmod %s: %m", gshadow_tmp);
         }
 
         ORDERED_HASHMAP_FOREACH(i, todo_gids) {
@@ -809,7 +817,7 @@ static int write_temporary_gshadow(const char * gshadow_path, FILE **tmpfile, ch
 
                 r = putsgent_with_members(&n, gshadow);
                 if (r < 0)
-                        return log_debug_errno(r, "Failed to add new group \"%s\" to temporary gshadow file: %m",
+                        return log_error_errno(r, "Failed to add new group \"%s\" to temporary gshadow file: %m",
                                                n.sg_namp);
 
                 group_changed = true;
@@ -817,7 +825,7 @@ static int write_temporary_gshadow(const char * gshadow_path, FILE **tmpfile, ch
 
         r = fflush_sync_and_check(gshadow);
         if (r < 0)
-                return log_debug_errno(r, "Failed to flush %s: %m", gshadow_tmp);
+                return log_error_errno(r, "Failed to flush %s: %m", gshadow_tmp);
 
         if (group_changed) {
                 *tmpfile = TAKE_PTR(gshadow);
@@ -858,30 +866,30 @@ static int write_files(void) {
         if (group) {
                 r = make_backup("/etc/group", group_path);
                 if (r < 0)
-                        return log_debug_errno(r, "Failed to make backup %s: %m", group_path);
+                        return log_error_errno(r, "Failed to make backup %s: %m", group_path);
         }
         if (gshadow) {
                 r = make_backup("/etc/gshadow", gshadow_path);
                 if (r < 0)
-                        return log_debug_errno(r, "Failed to make backup %s: %m", gshadow_path);
+                        return log_error_errno(r, "Failed to make backup %s: %m", gshadow_path);
         }
 
         if (passwd) {
                 r = make_backup("/etc/passwd", passwd_path);
                 if (r < 0)
-                        return log_debug_errno(r, "Failed to make backup %s: %m", passwd_path);
+                        return log_error_errno(r, "Failed to make backup %s: %m", passwd_path);
         }
         if (shadow) {
                 r = make_backup("/etc/shadow", shadow_path);
                 if (r < 0)
-                        return log_debug_errno(r, "Failed to make backup %s: %m", shadow_path);
+                        return log_error_errno(r, "Failed to make backup %s: %m", shadow_path);
         }
 
         /* And make the new files count */
         if (group) {
                 r = rename_and_apply_smack_floor_label(group_tmp, group_path);
                 if (r < 0)
-                        return log_debug_errno(r, "Failed to rename %s to %s: %m",
+                        return log_error_errno(r, "Failed to rename %s to %s: %m",
                                                group_tmp, group_path);
                 group_tmp = mfree(group_tmp);
 
@@ -891,7 +899,7 @@ static int write_files(void) {
         if (gshadow) {
                 r = rename_and_apply_smack_floor_label(gshadow_tmp, gshadow_path);
                 if (r < 0)
-                        return log_debug_errno(r, "Failed to rename %s to %s: %m",
+                        return log_error_errno(r, "Failed to rename %s to %s: %m",
                                                gshadow_tmp, gshadow_path);
 
                 gshadow_tmp = mfree(gshadow_tmp);
@@ -900,7 +908,7 @@ static int write_files(void) {
         if (passwd) {
                 r = rename_and_apply_smack_floor_label(passwd_tmp, passwd_path);
                 if (r < 0)
-                        return log_debug_errno(r, "Failed to rename %s to %s: %m",
+                        return log_error_errno(r, "Failed to rename %s to %s: %m",
                                                passwd_tmp, passwd_path);
 
                 passwd_tmp = mfree(passwd_tmp);
@@ -911,7 +919,7 @@ static int write_files(void) {
         if (shadow) {
                 r = rename_and_apply_smack_floor_label(shadow_tmp, shadow_path);
                 if (r < 0)
-                        return log_debug_errno(r, "Failed to rename %s to %s: %m",
+                        return log_error_errno(r, "Failed to rename %s to %s: %m",
                                                shadow_tmp, shadow_path);
 
                 shadow_tmp = mfree(shadow_tmp);
@@ -981,7 +989,7 @@ static int root_stat(const char *p, struct stat *st) {
         return RET_NERRNO(stat(fix, st));
 }
 
-static int read_id_from_file(Item *i, uid_t *_uid, gid_t *_gid) {
+static int read_id_from_file(Item *i, uid_t *ret_uid, gid_t *ret_gid) {
         struct stat st;
         bool found_uid = false, found_gid = false;
         uid_t uid = 0;
@@ -990,13 +998,13 @@ static int read_id_from_file(Item *i, uid_t *_uid, gid_t *_gid) {
         assert(i);
 
         /* First, try to get the GID directly */
-        if (_gid && i->gid_path && root_stat(i->gid_path, &st) >= 0) {
+        if (ret_gid && i->gid_path && root_stat(i->gid_path, &st) >= 0) {
                 gid = st.st_gid;
                 found_gid = true;
         }
 
         /* Then, try to get the UID directly */
-        if ((_uid || (_gid && !found_gid))
+        if ((ret_uid || (ret_gid && !found_gid))
             && i->uid_path
             && root_stat(i->uid_path, &st) >= 0) {
 
@@ -1004,14 +1012,14 @@ static int read_id_from_file(Item *i, uid_t *_uid, gid_t *_gid) {
                 found_uid = true;
 
                 /* If we need the gid, but had no success yet, also derive it from the UID path */
-                if (_gid && !found_gid) {
+                if (ret_gid && !found_gid) {
                         gid = st.st_gid;
                         found_gid = true;
                 }
         }
 
         /* If that didn't work yet, then let's reuse the GID as UID */
-        if (_uid && !found_uid && i->gid_path) {
+        if (ret_uid && !found_uid && i->gid_path) {
 
                 if (found_gid) {
                         uid = (uid_t) gid;
@@ -1022,18 +1030,18 @@ static int read_id_from_file(Item *i, uid_t *_uid, gid_t *_gid) {
                 }
         }
 
-        if (_uid) {
+        if (ret_uid) {
                 if (!found_uid)
                         return 0;
 
-                *_uid = uid;
+                *ret_uid = uid;
         }
 
-        if (_gid) {
+        if (ret_gid) {
                 if (!found_gid)
                         return 0;
 
-                *_gid = gid;
+                *ret_gid = gid;
         }
 
         return 1;
@@ -1444,7 +1452,9 @@ static int add_implicit(void) {
         return 0;
 }
 
-static bool item_equal(Item *a, Item *b) {
+static int item_equivalent(Item *a, Item *b) {
+        int r;
+
         assert(a);
         assert(b);
 
@@ -1454,6 +1464,7 @@ static bool item_equal(Item *a, Item *b) {
         if (!streq_ptr(a->name, b->name))
                 return false;
 
+        /* Paths were simplified previously, so we can use streq. */
         if (!streq_ptr(a->uid_path, b->uid_path))
                 return false;
 
@@ -1478,8 +1489,38 @@ static bool item_equal(Item *a, Item *b) {
         if (!streq_ptr(a->home, b->home))
                 return false;
 
-        if (!streq_ptr(a->shell, b->shell))
-                return false;
+        /* Check if the two paths refer to the same file.
+         * If the paths are equal (after normalization), it's obviously the same file.
+         * If both paths specify a nologin shell, treat them as the same (e.g. /bin/true and /bin/false).
+         * Otherwise, try to resolve the paths, and see if we get the same result, (e.g. /sbin/nologin and
+         * /usr/sbin/nologin).
+         * If we can't resolve something, treat different paths as different. */
+
+        const char *a_shell = pick_shell(a),
+                   *b_shell = pick_shell(b);
+        if (!path_equal_ptr(a_shell, b_shell) &&
+            !(is_nologin_shell(a_shell) && is_nologin_shell(b_shell))) {
+                _cleanup_free_ char *pa = NULL, *pb = NULL;
+
+                r = chase_symlinks(a_shell, arg_root, CHASE_PREFIX_ROOT | CHASE_NONEXISTENT, &pa, NULL);
+                if (r < 0) {
+                        log_full_errno(ERRNO_IS_RESOURCE(r) ? LOG_ERR : LOG_DEBUG,
+                                       r, "Failed to look up path '%s%s%s': %m",
+                                       strempty(arg_root), arg_root ? "/" : "", a_shell);
+                        return ERRNO_IS_RESOURCE(r) ? r : false;
+                }
+
+                r = chase_symlinks(b_shell, arg_root, CHASE_PREFIX_ROOT | CHASE_NONEXISTENT, &pb, NULL);
+                if (r < 0) {
+                        log_full_errno(ERRNO_IS_RESOURCE(r) ? LOG_ERR : LOG_DEBUG,
+                                       r, "Failed to look up path '%s%s%s': %m",
+                                       strempty(arg_root), arg_root ? "/" : "", b_shell);
+                        return ERRNO_IS_RESOURCE(r) ? r : false;
+                }
+
+                if (!path_equal(pa, pb))
+                        return false;
+        }
 
         return true;
 }
@@ -1506,22 +1547,22 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         r = extract_many_words(&p, NULL, EXTRACT_UNQUOTE,
                                &action, &name, &id, &description, &home, &shell, NULL);
         if (r < 0)
-                return log_error_errno(r, "[%s:%u] Syntax error.", fname, line);
+                return log_syntax(NULL, LOG_ERR, fname, line, r, "Syntax error.");
         if (r < 2)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "[%s:%u] Missing action and name columns.", fname, line);
+                return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
+                                  "Missing action and name columns.");
         if (!isempty(p))
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "[%s:%u] Trailing garbage.", fname, line);
+                return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
+                                  "Trailing garbage.");
 
         /* Verify action */
         if (strlen(action) != 1)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "[%s:%u] Unknown modifier '%s'", fname, line, action);
+                return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
+                                  "Unknown modifier '%s'.", action);
 
         if (!IN_SET(action[0], ADD_USER, ADD_GROUP, ADD_MEMBER, ADD_RANGE))
-                return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
-                                       "[%s:%u] Unknown command type '%c'.", fname, line, action[0]);
+                return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
+                                  "Unknown command type '%c'.", action[0]);
 
         /* Verify name */
         if (empty_or_dash(name))
@@ -1530,12 +1571,11 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         if (name) {
                 r = specifier_printf(name, NAME_MAX, system_and_tmp_specifier_table, arg_root, NULL, &resolved_name);
                 if (r < 0)
-                        return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m", fname, line, name);
+                        return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to replace specifiers in '%s': %m", name);
 
                 if (!valid_user_group_name(resolved_name, 0))
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                               "[%s:%u] '%s' is not a valid user or group name.",
-                                               fname, line, resolved_name);
+                        return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
+                                          "'%s' is not a valid user or group name.", resolved_name);
         }
 
         /* Verify id */
@@ -1545,8 +1585,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         if (id) {
                 r = specifier_printf(id, PATH_MAX-1, system_and_tmp_specifier_table, arg_root, NULL, &resolved_id);
                 if (r < 0)
-                        return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m",
-                                               fname, line, name);
+                        return log_syntax(NULL, LOG_ERR, fname, line, r,
+                                          "Failed to replace specifiers in '%s': %m", name);
         }
 
         /* Verify description */
@@ -1556,13 +1596,12 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         if (description) {
                 r = specifier_printf(description, LONG_LINE_MAX, system_and_tmp_specifier_table, arg_root, NULL, &resolved_description);
                 if (r < 0)
-                        return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m",
-                                               fname, line, description);
+                        return log_syntax(NULL, LOG_ERR, fname, line, r,
+                                          "Failed to replace specifiers in '%s': %m", description);
 
                 if (!valid_gecos(resolved_description))
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                               "[%s:%u] '%s' is not a valid GECOS field.",
-                                               fname, line, resolved_description);
+                        return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
+                                          "'%s' is not a valid GECOS field.", resolved_description);
         }
 
         /* Verify home */
@@ -1572,13 +1611,14 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         if (home) {
                 r = specifier_printf(home, PATH_MAX-1, system_and_tmp_specifier_table, arg_root, NULL, &resolved_home);
                 if (r < 0)
-                        return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m",
-                                               fname, line, home);
+                        return log_syntax(NULL, LOG_ERR, fname, line, r,
+                                          "Failed to replace specifiers in '%s': %m", home);
+
+                path_simplify(resolved_home);
 
                 if (!valid_home(resolved_home))
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                               "[%s:%u] '%s' is not a valid home directory field.",
-                                               fname, line, resolved_home);
+                        return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
+                                          "'%s' is not a valid home directory field.", resolved_home);
         }
 
         /* Verify shell */
@@ -1588,63 +1628,59 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         if (shell) {
                 r = specifier_printf(shell, PATH_MAX-1, system_and_tmp_specifier_table, arg_root, NULL, &resolved_shell);
                 if (r < 0)
-                        return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m",
-                                               fname, line, shell);
+                        return log_syntax(NULL, LOG_ERR, fname, line, r,
+                                          "Failed to replace specifiers in '%s': %m", shell);
+
+                path_simplify(resolved_shell);
 
                 if (!valid_shell(resolved_shell))
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                               "[%s:%u] '%s' is not a valid login shell field.",
-                                               fname, line, resolved_shell);
+                        return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
+                                          "'%s' is not a valid login shell field.", resolved_shell);
         }
 
         switch (action[0]) {
 
         case ADD_RANGE:
                 if (resolved_name)
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                               "[%s:%u] Lines of type 'r' don't take a name field.",
-                                               fname, line);
+                        return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
+                                          "Lines of type 'r' don't take a name field.");
 
                 if (!resolved_id)
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                               "[%s:%u] Lines of type 'r' require an ID range in the third field.",
-                                               fname, line);
+                        return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
+                                          "Lines of type 'r' require an ID range in the third field.");
 
                 if (description || home || shell)
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                               "[%s:%u] Lines of type '%c' don't take a %s field.",
-                                               fname, line, action[0],
-                                               description ? "GECOS" : home ? "home directory" : "login shell");
+                        return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
+                                          "Lines of type '%c' don't take a %s field.",
+                                          action[0],
+                                          description ? "GECOS" : home ? "home directory" : "login shell");
 
                 r = uid_range_add_str(&uid_range, &n_uid_range, resolved_id);
                 if (r < 0)
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                               "[%s:%u] Invalid UID range %s.", fname, line, resolved_id);
+                        return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
+                                          "Invalid UID range %s.", resolved_id);
 
                 return 0;
 
         case ADD_MEMBER: {
                 /* Try to extend an existing member or group item */
                 if (!name)
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                               "[%s:%u] Lines of type 'm' require a user name in the second field.",
-                                               fname, line);
+                        return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
+                                          "Lines of type 'm' require a user name in the second field.");
 
                 if (!resolved_id)
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                               "[%s:%u] Lines of type 'm' require a group name in the third field.",
-                                               fname, line);
+                        return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
+                                          "Lines of type 'm' require a group name in the third field.");
 
                 if (!valid_user_group_name(resolved_id, 0))
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                               "[%s:%u] '%s' is not a valid user or group name.",
-                                               fname, line, resolved_id);
+                        return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
+                                               "'%s' is not a valid user or group name.", resolved_id);
 
                 if (description || home || shell)
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                               "[%s:%u] Lines of type '%c' don't take a %s field.",
-                                               fname, line, action[0],
-                                               description ? "GECOS" : home ? "home directory" : "login shell");
+                        return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
+                                          "Lines of type '%c' don't take a %s field.",
+                                          action[0],
+                                          description ? "GECOS" : home ? "home directory" : "login shell");
 
                 r = string_strv_ordered_hashmap_put(&members, resolved_id, resolved_name);
                 if (r < 0)
@@ -1655,9 +1691,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
 
         case ADD_USER:
                 if (!name)
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                               "[%s:%u] Lines of type 'u' require a user name in the second field.",
-                                               fname, line);
+                        return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
+                                          "Lines of type 'u' require a user name in the second field.");
 
                 r = ordered_hashmap_ensure_allocated(&users, &item_hash_ops);
                 if (r < 0)
@@ -1679,7 +1714,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
                                                 if (valid_user_group_name(gid, 0))
                                                         i->group_name = TAKE_PTR(gid);
                                                 else
-                                                        return log_error_errno(r, "Failed to parse GID: '%s': %m", id);
+                                                        return log_syntax(NULL, LOG_ERR, fname, line, r,
+                                                                          "Failed to parse GID: '%s': %m", id);
                                         } else {
                                                 i->gid_set = true;
                                                 i->id_set_strict = true;
@@ -1689,7 +1725,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
                                 if (!streq(resolved_id, "-")) {
                                         r = parse_uid(resolved_id, &i->uid);
                                         if (r < 0)
-                                                return log_error_errno(r, "Failed to parse UID: '%s': %m", id);
+                                                return log_syntax(NULL, LOG_ERR, fname, line, r,
+                                                                  "Failed to parse UID: '%s': %m", id);
                                         i->uid_set = true;
                                 }
                         }
@@ -1704,15 +1741,14 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
 
         case ADD_GROUP:
                 if (!name)
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                               "[%s:%u] Lines of type 'g' require a user name in the second field.",
-                                               fname, line);
+                        return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
+                                          "Lines of type 'g' require a user name in the second field.");
 
                 if (description || home || shell)
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                               "[%s:%u] Lines of type '%c' don't take a %s field.",
-                                               fname, line, action[0],
-                                               description ? "GECOS" : home ? "home directory" : "login shell");
+                        return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
+                                          "Lines of type '%c' don't take a %s field.",
+                                          action[0],
+                                          description ? "GECOS" : home ? "home directory" : "login shell");
 
                 r = ordered_hashmap_ensure_allocated(&groups, &item_hash_ops);
                 if (r < 0)
@@ -1729,7 +1765,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
                         } else {
                                 r = parse_gid(resolved_id, &i->gid);
                                 if (r < 0)
-                                        return log_error_errno(r, "Failed to parse GID: '%s': %m", id);
+                                        return log_syntax(NULL, LOG_ERR, fname, line, r,
+                                                          "Failed to parse GID: '%s': %m", id);
 
                                 i->gid_set = true;
                         }
@@ -1747,11 +1784,14 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
 
         existing = ordered_hashmap_get(h, i->name);
         if (existing) {
-                /* Two identical items are fine */
-                if (!item_equal(existing, i))
-                        log_warning("%s:%u: conflict with earlier configuration for %s '%s', ignoring line.",
-                                    fname, line,
-                                    item_type_to_string(i->type), i->name);
+                /* Two functionally-equivalent items are fine */
+                r = item_equivalent(existing, i);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        log_syntax(NULL, LOG_WARNING, fname, line, SYNTHETIC_ERRNO(EUCLEAN),
+                                   "Conflict with earlier configuration for %s '%s', ignoring line.",
+                                   item_type_to_string(i->type), i->name);
 
                 return 0;
         }
@@ -2146,11 +2186,7 @@ static int run(int argc, char *argv[]) {
         ORDERED_HASHMAP_FOREACH(i, users)
                 (void) process_item(i);
 
-        r = write_files();
-        if (r < 0)
-                return log_error_errno(r, "Failed to write files: %m");
-
-        return 0;
+        return write_files();
 }
 
 DEFINE_MAIN_FUNCTION(run);
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 479781210797d2c8faee8d8e7e48cf6c648b70dc..d82bda53472f059a59c03dbd39ce81413db30055 100644 (file)
@@ -23,4 +23,21 @@ TEST(ratelimit_below) {
                 assert_se(ratelimit_below(&ratelimit));
 }
 
+TEST(ratelimit_num_dropped) {
+        int i;
+        RateLimit ratelimit = { 1 * USEC_PER_SEC, 10 };
+
+        for (i = 0; i < 10; i++) {
+                assert_se(ratelimit_below(&ratelimit));
+                assert_se(ratelimit_num_dropped(&ratelimit) == 0);
+        }
+        assert_se(!ratelimit_below(&ratelimit));
+        assert_se(ratelimit_num_dropped(&ratelimit) == 1);
+        assert_se(!ratelimit_below(&ratelimit));
+        assert_se(ratelimit_num_dropped(&ratelimit) == 2);
+        sleep(1);
+        assert_se(ratelimit_below(&ratelimit));
+        assert_se(ratelimit_num_dropped(&ratelimit) == 0);
+}
+
 DEFINE_TEST_MAIN(LOG_INFO);
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");
 
index 58c5fa9be40cc6574f075bd611b0ac800b699d74..6b546fb9f572daf185262cfbe5df80fd5bdc40c9 100644 (file)
@@ -311,10 +311,26 @@ TEST(usec_sub_signed) {
         assert_se(usec_sub_signed(4, 1) == 3);
         assert_se(usec_sub_signed(4, 4) == 0);
         assert_se(usec_sub_signed(4, 5) == 0);
+
         assert_se(usec_sub_signed(USEC_INFINITY-3, -3) == USEC_INFINITY);
         assert_se(usec_sub_signed(USEC_INFINITY-3, -4) == USEC_INFINITY);
         assert_se(usec_sub_signed(USEC_INFINITY-3, -5) == USEC_INFINITY);
         assert_se(usec_sub_signed(USEC_INFINITY, 5) == USEC_INFINITY);
+
+        assert_se(usec_sub_signed(0, INT64_MAX) == 0);
+        assert_se(usec_sub_signed(0, -INT64_MAX) == INT64_MAX);
+        assert_se(usec_sub_signed(0, INT64_MIN) == (usec_t) INT64_MAX + 1);
+        assert_se(usec_sub_signed(0, -(INT64_MIN+1)) == 0);
+
+        assert_se(usec_sub_signed(USEC_INFINITY, INT64_MAX) == USEC_INFINITY);
+        assert_se(usec_sub_signed(USEC_INFINITY, -INT64_MAX) == USEC_INFINITY);
+        assert_se(usec_sub_signed(USEC_INFINITY, INT64_MIN) == USEC_INFINITY);
+        assert_se(usec_sub_signed(USEC_INFINITY, -(INT64_MIN+1)) == USEC_INFINITY);
+
+        assert_se(usec_sub_signed(USEC_INFINITY-1, INT64_MAX) == USEC_INFINITY-1-INT64_MAX);
+        assert_se(usec_sub_signed(USEC_INFINITY-1, -INT64_MAX) == USEC_INFINITY);
+        assert_se(usec_sub_signed(USEC_INFINITY-1, INT64_MIN) == USEC_INFINITY);
+        assert_se(usec_sub_signed(USEC_INFINITY-1, -(INT64_MIN+1)) == USEC_INFINITY-1-((usec_t) (-(INT64_MIN+1))));
 }
 
 TEST(format_timestamp) {
index 907de54eaa5422f4ba8908d93844f86c24e3fc9d..48d9b1e0fb987a505a1283c5a274007dde03074e 100644 (file)
@@ -347,8 +347,8 @@ static void test_get_user_creds_one(const char *id, const char *name, uid_t uid,
 }
 
 TEST(get_user_creds) {
-        test_get_user_creds_one("root", "root", 0, 0, "/root", "/bin/sh");
-        test_get_user_creds_one("0", "root", 0, 0, "/root", "/bin/sh");
+        test_get_user_creds_one("root", "root", 0, 0, "/root", DEFAULT_USER_SHELL);
+        test_get_user_creds_one("0", "root", 0, 0, "/root", DEFAULT_USER_SHELL);
         test_get_user_creds_one(NOBODY_USER_NAME, NOBODY_USER_NAME, UID_NOBODY, GID_NOBODY, "/", NOLOGIN);
         test_get_user_creds_one("65534", NOBODY_USER_NAME, UID_NOBODY, GID_NOBODY, "/", NOLOGIN);
 }
index b0021712e309c386134552904c2d855628405989..cbf35ee29260fbea227c942a7e406732a0493203 100755 (executable)
@@ -27,6 +27,7 @@ test_append_files() {
     image_install /lib/tmpfiles.d/knot.conf
     image_install "${ROOTLIBDIR:?}/system/knot.service"
     image_install -o /etc/dbus-1/system.d/cz.nic.knotd.conf
+    image_install -o /etc/default/knot
 
     # Copy over our configuration
     mkdir -p "${workspace:?}/var/lib/knot/zones/" "${workspace:?}/etc/knot/"
index ae8b2428bc813e5e6c1b1b4add97fd3e4dd27b9e..321d0e338a82e11ca6c8be053947bda08d0da40b 100644 (file)
@@ -26,7 +26,7 @@ ExecStart=sh -c 'test %U = $$(id -u)'
 ExecStart=sh -c 'test %g = $$(id -gn)'
 ExecStart=sh -c 'test %G = $$(id -g)'
 ExecStart=test %h = /root
-ExecStart=sh -c 'test %s = /bin/sh'
+ExecStart=sh -c 'test -x %s'
 ExecStart=sh -c 'test %m = $$(cat /etc/machine-id)'
 ExecStart=sh -c 'test %b = $$(cat /proc/sys/kernel/random/boot_id | sed -e 's/-//g')'
 ExecStart=sh -c 'test %H = $$(uname -n)'
index 5e30efce4c54e6ad9d55a093cda4a72903a8929f..46c8503f1d8ad38d5a722046bc764b0fe6f4f905 100644 (file)
@@ -23,7 +23,7 @@ ExecStart=sh -c 'test %U = $$(id -u)'
 ExecStart=sh -c 'test %g = $$(id -gn)'
 ExecStart=sh -c 'test %G = $$(id -g)'
 ExecStart=test %h = /root
-ExecStart=sh -c 'test %s = /bin/sh'
+ExecStart=sh -c 'test -x %s'
 ExecStart=sh -c 'test %m = $$(cat /etc/machine-id)'
 ExecStart=sh -c 'test %b = $$(cat /proc/sys/kernel/random/boot_id | sed -e 's/-//g')'
 ExecStart=sh -c 'test %H = $$(uname -n)'
index c9d9bd993b971ba55b50df595084b22d53e1acc0..950dc297d8b08f8e7e3509e3f1d2a13ed7cab62a 100755 (executable)
@@ -152,7 +152,7 @@ for f in $(ls -1 $SOURCE/unhappy-*.input | sort -V); do
     echo "*** Running test $f"
     prepare_testdir ${f%.input}
     cp $f $TESTDIR/usr/lib/sysusers.d/test.conf
-    $SYSUSERS --root=$TESTDIR 2>&1 | tail -n1 $TESTDIR/err
+    $SYSUSERS --root=$TESTDIR 2>&1 | tail -n1 | sed -r 's/^[^:]+:[^:]+://' >$TESTDIR/err
     if ! diff -u $TESTDIR/err  ${f%.*}.expected-err; then
         echo "**** Unexpected error output for $f"
         cat $TESTDIR/err
index d3342402e98daf00ad03f085026bd56c6b998fa5..f6b1b3c5e6f0e9896d77c8a38d8c4ea6702f62b5 100644 (file)
@@ -1 +1 @@
-Failed to parse UID: '9999999999': Numerical result out of range
+ Failed to parse UID: '9999999999': Numerical result out of range
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 13fe139a38fffb11c07621f3a431c2ab23154b14..a29364568db9c8964f30cb0da368a103b242dfd8 100755 (executable)
@@ -202,6 +202,45 @@ EOF
     }
 }
 
+test_issue_23796() {
+    local mount_path mount_mytmpfs
+
+    mount_path="$(command -v mount 2>/dev/null)"
+    mount_mytmpfs="${mount_path/\/bin/\/sbin}.mytmpfs"
+    cat >"$mount_mytmpfs" <<EOF
+#!/bin/bash
+sleep ".\$RANDOM"
+exec -- $mount_path -t tmpfs tmpfs "\$2"
+EOF
+    chmod +x "$mount_mytmpfs"
+
+    mkdir -p /run/systemd/system
+    cat >/run/systemd/system/tmp-hoge.mount <<EOF
+[Mount]
+What=mytmpfs
+Where=/tmp/hoge
+Type=mytmpfs
+EOF
+
+    # shellcheck disable=SC2064
+    trap "rm -f /run/systemd/system/tmp-hoge.mount '$mount_mytmpfs'" RETURN
+
+    for ((i = 0; i < 10; i++)); do
+        systemctl --no-block start tmp-hoge.mount
+        sleep ".$RANDOM"
+        systemctl daemon-reexec
+
+        sleep 1
+
+        if [[ "$(systemctl is-failed tmp-hoge.mount)" == "failed" ]] || \
+           journalctl -u tmp-hoge.mount -q --grep "but there is no mount"; then
+                exit 1
+        fi
+
+        systemctl stop tmp-hoge.mount
+    done
+}
+
 : >/failed
 
 systemd-analyze log-level debug
@@ -263,6 +302,9 @@ test_dependencies
 # test that handling of mount start jobs is delayed when /proc/self/mouninfo monitor is rate limited
 test_issue_20329
 
+# test for reexecuting with background mount job
+test_issue_23796
+
 systemd-analyze log-level info
 
 touch /testok
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