]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #25059 from keszybz/fopen-re
authorFrantisek Sumsal <frantisek@sumsal.cz>
Wed, 19 Oct 2022 12:49:31 +0000 (12:49 +0000)
committerGitHub <noreply@github.com>
Wed, 19 Oct 2022 12:49:31 +0000 (12:49 +0000)
Use "re" or "r" as appropriate for various calls

15 files changed:
.github/workflows/scorecards.yml [new file with mode: 0644]
README.md
TODO
man/systemd.link.xml
src/cryptsetup/cryptsetup.c
src/login/logind.c
src/shared/elf-util.c
src/shared/json.c
src/shared/json.h
src/shared/udev-util.c
src/test/test-json.c
src/test/test-math-util.c
src/udev/udevadm-monitor.c
src/udev/udevd.c
test/units/testsuite-15.sh

diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml
new file mode 100644 (file)
index 0000000..ed3c9d9
--- /dev/null
@@ -0,0 +1,63 @@
+name: Scorecards supply-chain security
+on:
+  # Only the default branch is supported.
+  branch_protection_rule:
+  schedule:
+    - cron: '15 21 * * 6'
+  push:
+    branches: [ "main" ]
+  pull_request:
+    branches: [ "main" ]
+
+# Declare default permissions as read only.
+permissions: read-all
+
+jobs:
+  analysis:
+    name: Scorecards analysis
+    if: github.repository == 'systemd/systemd'
+    runs-on: ubuntu-latest
+    permissions:
+      # Needed to upload the results to code-scanning dashboard.
+      security-events: write
+      # Used to receive a badge.
+      id-token: write
+
+    steps:
+      - name: "Checkout code"
+        uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846 # tag=v3.0.0
+        with:
+          persist-credentials: false
+
+      - name: "Run analysis"
+        uses: ossf/scorecard-action@e363bfca00e752f91de7b7d2a77340e2e523cb18 # tag=v2.0.4
+        with:
+          results_file: results.sarif
+          results_format: sarif
+          # (Optional) Read-only PAT token. Uncomment the `repo_token` line below if:
+          # - you want to enable the Branch-Protection check on a *public* repository, or
+          # - you are installing Scorecards on a *private* repository
+          # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
+          # repo_token: ${{ secrets.SCORECARD_READ_TOKEN }}
+
+          # Publish the results for public repositories to enable scorecard badges. For more details, see
+          # https://github.com/ossf/scorecard-action#publishing-results.
+          # For private repositories, `publish_results` will automatically be set to `false`, regardless
+          # of the value entered here.
+          publish_results: ${{ github.event_name != 'pull_request' }}
+
+      # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
+      # format to the repository Actions tab.
+      - name: "Upload artifact"
+        uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # tag=v3.0.0
+        with:
+          name: SARIF file
+          path: results.sarif
+          retention-days: 5
+
+      # Upload the results to GitHub's code scanning dashboard.
+      - name: "Upload to code-scanning"
+        if: ${{ github.event_name != 'pull_request' }}
+        uses: github/codeql-action/upload-sarif@5f532563584d71fdef14ee64d17bafb34f751ce5 # tag=v1.0.26
+        with:
+          sarif_file: results.sarif
index 5d303c242bf46c83da09d887d71755e3bf385704..e507c4cb571d5d339d06116222ea4566c0c9d83f 100644 (file)
--- a/README.md
+++ b/README.md
@@ -13,7 +13,8 @@ System and Service Manager
 [![CentOS CI - Rawhide (SELinux)](https://jenkins-systemd.apps.ocp.ci.centos.org/buildStatus/icon?subject=CentOS%20CI%20-%20Rawhide%20(SELinux)&job=upstream-vagrant-rawhide-selinux)](https://jenkins-systemd.apps.ocp.ci.centos.org/view/Upstream/job/upstream-vagrant-rawhide-selinux/)<br/>
 [![Fossies codespell report](https://fossies.org/linux/test/systemd-main.tar.gz/codespell.svg)](https://fossies.org/linux/test/systemd-main.tar.gz/codespell.html)</br>
 [![Coverage Status](https://coveralls.io/repos/github/systemd/systemd/badge.svg?branch=main)](https://coveralls.io/github/systemd/systemd?branch=main)</br>
-[![Packaging status](https://repology.org/badge/tiny-repos/systemd.svg)](https://repology.org/project/systemd/versions)
+[![Packaging status](https://repology.org/badge/tiny-repos/systemd.svg)](https://repology.org/project/systemd/versions)</br>
+[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/systemd/systemd/badge)](https://api.securityscorecards.dev/projects/github.com/systemd/systemd)
 
 ## Details
 
diff --git a/TODO b/TODO
index de634330ae1d4f41a0e3f7a80ab44e04e945c689..0de5f3d477b6ba9053a14a571322ceb8f9a056bc 100644 (file)
--- a/TODO
+++ b/TODO
@@ -554,9 +554,6 @@ Features:
 
 * add ability to set hostname with suffix derived from machine id at boot
 
-* ask dracut to generate usr= on the kernel cmdline so that we don't need to
-  read /etc/fstab from the root fs from the initrd and do daemon-reload
-
 * add PR_SET_DUMPABLE service setting
 
 * homed/userdb: maybe define a "companion" dir for home directories where apps
index bb4cd227e6b6b727df0f7355cb4326fbb7a3989f..cc55b02b182f3e7801188ec9f9057de93beecc13 100644 (file)
           must either be unset, empty, disabled, or all policies configured there must fail. Also see the
           example below with <literal>Name=dmz0</literal>.</para>
 
-          <para>Note that specifying a name that the kernel might use for another
-          interface (for example <literal>eth0</literal>) is dangerous because the
-          name assignment done by udev will race with the assignment done by the
-          kernel, and only one interface may use the name. Depending on the order of
-          operations, either udev or the kernel will win, making the naming
-          unpredictable. It is best to use some different prefix, for example
-          <literal>internal0</literal>/<literal>external0</literal> or
-          <literal>lan0</literal>/<literal>lan1</literal>/<literal>lan3</literal>.
-          </para>
+          <para>Note that specifying a name that the kernel might use for another interface (for example
+          <literal>eth0</literal>) is dangerous because the name assignment done by udev will race with the
+          assignment done by the kernel, and only one interface may use the name. Depending on the order of
+          operations, either udev or the kernel will win, making the naming unpredictable. It is best to use
+          some different prefix, for example <literal>internal0</literal>/<literal>external0</literal> or
+          <literal>lan0</literal>/<literal>lan1</literal>/<literal>lan3</literal>.</para>
+
+          <para>Interface names must have a minimum length of 1 character and a maximum length of 15
+          characters, and may contain any 7bit ASCII character, with the exception of control characters,
+          <literal>:</literal>, <literal>/</literal> and <literal>%</literal>. While <literal>.</literal> is
+          an allowed character, it's recommended to avoid it when naming interfaces as various tools (such as
+          <citerefentry><refentrytitle>resolvconf</refentrytitle><manvolnum>1</manvolnum></citerefentry>) use
+          it as separator character. Also, fully numeric interface names are not allowed (in order to avoid
+          ambiguity with interface specification by numeric indexes), as are the special strings
+          <literal>.</literal>, <literal>..</literal>, <literal>all</literal> and
+          <literal>default</literal>.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
           If the empty string is assigned to this option, the list is reset, and all prior assignments
           have no effect. If the kernel does not support the alternative names, then this setting will
           be ignored.</para>
+
+          <para>Alternative interface names may be used to identify interfaces in various tools. In contrast
+          to the primary name (as configured with <varname>Name=</varname> above) there may be multiple
+          alternative names referring to the same interface. Alternative names may have a maximum length of
+          127 characters, in contrast to the 15 allowed for the primary interface name, but otherwise are
+          subject to the same naming constraints.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
index 9405dc787b4d3c34b6d40f358364cc0e04462ce9..7aa36b4b032f54b1139719db78d0b8a68e771eb3 100644 (file)
@@ -870,6 +870,8 @@ static int make_security_device_monitor(
         if (r < 0)
                 return log_error_errno(r, "Failed to allocate device monitor: %m");
 
+        (void) sd_device_monitor_set_description(monitor, "security-device");
+
         r = sd_device_monitor_filter_add_match_tag(monitor, "security-device");
         if (r < 0)
                 return log_error_errno(r, "Failed to configure device monitor: %m");
@@ -1369,6 +1371,8 @@ static int make_tpm2_device_monitor(
         if (r < 0)
                 return log_error_errno(r, "Failed to allocate device monitor: %m");
 
+        (void) sd_device_monitor_set_description(monitor, "tpmrm");
+
         r = sd_device_monitor_filter_add_match_subsystem_devtype(monitor, "tpmrm", NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to configure device monitor: %m");
index 95c5526711490178fcd19c21d05800af405ec847..cdca5ca58ce1eb9394e836718c6e48a80e54ba89 100644 (file)
@@ -809,7 +809,7 @@ static int manager_connect_udev(Manager *m) {
         if (r < 0)
                 return r;
 
-        (void) sd_event_source_set_description(sd_device_monitor_get_event_source(m->device_seat_monitor), "logind-seat-monitor");
+        (void) sd_device_monitor_set_description(m->device_seat_monitor, "seat");
 
         r = sd_device_monitor_new(&m->device_monitor);
         if (r < 0)
@@ -835,7 +835,7 @@ static int manager_connect_udev(Manager *m) {
         if (r < 0)
                 return r;
 
-        (void) sd_event_source_set_description(sd_device_monitor_get_event_source(m->device_monitor), "logind-device-monitor");
+        (void) sd_device_monitor_set_description(m->device_monitor, "input,graphics,drm");
 
         /* Don't watch keys if nobody cares */
         if (!manager_all_buttons_ignored(m)) {
@@ -859,7 +859,7 @@ static int manager_connect_udev(Manager *m) {
                 if (r < 0)
                         return r;
 
-                (void) sd_event_source_set_description(sd_device_monitor_get_event_source(m->device_button_monitor), "logind-button-monitor");
+                (void) sd_device_monitor_set_description(m->device_button_monitor, "button");
         }
 
         /* Don't bother watching VCSA devices, if nobody cares */
@@ -881,7 +881,7 @@ static int manager_connect_udev(Manager *m) {
                 if (r < 0)
                         return r;
 
-                (void) sd_event_source_set_description(sd_device_monitor_get_event_source(m->device_vcsa_monitor), "logind-vcsa-monitor");
+                (void) sd_device_monitor_set_description(m->device_vcsa_monitor, "vcsa");
         }
 
         return 0;
index c0f540abc50a737a52c95426161f4db37e57a093..181735409d42d796e1dca9d8424e6f2046baa9c7 100644 (file)
@@ -30,6 +30,9 @@
 #define THREADS_MAX 64
 #define ELF_PACKAGE_METADATA_ID 0xcafe1a7e
 
+/* The amount of data we're willing to write to each of the output pipes. */
+#define COREDUMP_PIPE_MAX (1024*1024U)
+
 static void *dw_dl = NULL;
 static void *elf_dl = NULL;
 
@@ -759,13 +762,13 @@ int parse_elf_object(int fd, const char *executable, bool fork_disable_dump, cha
                 return r;
 
         if (ret) {
-                r = RET_NERRNO(pipe2(return_pipe, O_CLOEXEC));
+                r = RET_NERRNO(pipe2(return_pipe, O_CLOEXEC|O_NONBLOCK));
                 if (r < 0)
                         return r;
         }
 
         if (ret_package_metadata) {
-                r = RET_NERRNO(pipe2(json_pipe, O_CLOEXEC));
+                r = RET_NERRNO(pipe2(json_pipe, O_CLOEXEC|O_NONBLOCK));
                 if (r < 0)
                         return r;
         }
@@ -809,8 +812,24 @@ int parse_elf_object(int fd, const char *executable, bool fork_disable_dump, cha
                         goto child_fail;
 
                 if (buf) {
-                        r = loop_write(return_pipe[1], buf, strlen(buf), false);
-                        if (r < 0)
+                        size_t len = strlen(buf);
+
+                        if (len > COREDUMP_PIPE_MAX) {
+                                /* This is iffy. A backtrace can be a few hundred kilobytes, but too much is
+                                 * too much. Let's log a warning and ignore the rest. */
+                                log_warning("Generated backtrace is %zu bytes (more than the limit of %u bytes), backtrace will be truncated.",
+                                            len, COREDUMP_PIPE_MAX);
+                                len = COREDUMP_PIPE_MAX;
+                        }
+
+                        /* Bump the space for the returned string.
+                         * Failure is ignored, because partial output is still useful. */
+                        (void) fcntl(return_pipe[1], F_SETPIPE_SZ, len);
+
+                        r = loop_write(return_pipe[1], buf, len, false);
+                        if (r == -EAGAIN)
+                                log_warning("Write failed, backtrace will be truncated.");
+                        else if (r < 0)
                                 goto child_fail;
 
                         return_pipe[1] = safe_close(return_pipe[1]);
@@ -819,13 +838,19 @@ int parse_elf_object(int fd, const char *executable, bool fork_disable_dump, cha
                 if (package_metadata) {
                         _cleanup_fclose_ FILE *json_out = NULL;
 
+                        /* Bump the space for the returned string. We don't know how much space we'll need in
+                         * advance, so we'll just try to write as much as possible and maybe fail later. */
+                        (void) fcntl(json_pipe[1], F_SETPIPE_SZ, COREDUMP_PIPE_MAX);
+
                         json_out = take_fdopen(&json_pipe[1], "w");
                         if (!json_out) {
                                 r = -errno;
                                 goto child_fail;
                         }
 
-                        json_variant_dump(package_metadata, JSON_FORMAT_FLUSH, json_out, NULL);
+                        r = json_variant_dump(package_metadata, JSON_FORMAT_FLUSH, json_out, NULL);
+                        if (r < 0)
+                                log_warning_errno(r, "Failed to write JSON package metadata, ignoring: %m");
                 }
 
                 _exit(EXIT_SUCCESS);
@@ -859,8 +884,8 @@ int parse_elf_object(int fd, const char *executable, bool fork_disable_dump, cha
                         return -errno;
 
                 r = json_parse_file(json_in, NULL, 0, &package_metadata, NULL, NULL);
-                if (r < 0 && r != -EINVAL) /* EINVAL: json was empty, so we got nothing, but that's ok */
-                        return r;
+                if (r < 0 && r != -ENODATA) /* ENODATA: json was empty, so we got nothing, but that's ok */
+                        log_warning_errno(r, "Failed to read or parse json metadata, ignoring: %m");
         }
 
         if (ret)
index 950be9485d58193a6dd18147410a107e4c9c969e..eda7bb19563e560b074fe138b54fb7b70bcb83fd 100644 (file)
@@ -1785,9 +1785,9 @@ int json_variant_format(JsonVariant *v, JsonFormatFlags flags, char **ret) {
         return (int) sz - 1;
 }
 
-void json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const char *prefix) {
+int json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const char *prefix) {
         if (!v)
-                return;
+                return 0;
 
         if (!f)
                 f = stdout;
@@ -1813,7 +1813,8 @@ void json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const cha
                 fputc('\n', f); /* In case of SSE add a second newline */
 
         if (flags & JSON_FORMAT_FLUSH)
-                fflush(f);
+                return fflush_and_check(f);
+        return 0;
 }
 
 int json_variant_filter(JsonVariant **v, char **to_remove) {
@@ -3186,7 +3187,6 @@ int json_parse_continue(const char **p, JsonParseFlags flags, JsonVariant **ret,
 int json_parse_file_at(FILE *f, int dir_fd, const char *path, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) {
         _cleanup_(json_source_unrefp) JsonSource *source = NULL;
         _cleanup_free_ char *text = NULL;
-        const char *p;
         int r;
 
         if (f)
@@ -3198,13 +3198,16 @@ int json_parse_file_at(FILE *f, int dir_fd, const char *path, JsonParseFlags fla
         if (r < 0)
                 return r;
 
+        if (isempty(text))
+                return -ENODATA;
+
         if (path) {
                 source = json_source_new(path);
                 if (!source)
                         return -ENOMEM;
         }
 
-        p = text;
+        const char *p = text;
         return json_parse_internal(&p, source, flags, ret, ret_line, ret_column, false);
 }
 
index 1992170ed7c2a522ce2f421189666010ca838545..5993e05299c6e8c03961647c99d01ccce8f56154 100644 (file)
@@ -197,7 +197,7 @@ typedef enum JsonFormatFlags {
 } JsonFormatFlags;
 
 int json_variant_format(JsonVariant *v, JsonFormatFlags flags, char **ret);
-void json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const char *prefix);
+int json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const char *prefix);
 
 int json_variant_filter(JsonVariant **v, char **to_remove);
 
index 96fd39f30c6c74e83d642c5533c68c6aab89dcb0..aac02cd61bcaed4eebb0f92b46058e69e33867e9 100644 (file)
@@ -237,6 +237,15 @@ static int device_wait_for_initialization_internal(
                         return log_error_errno(r, "Failed to add %s subsystem match to monitor: %m", subsystem);
         }
 
+        _cleanup_free_ char *desc = NULL;
+        const char *sysname = NULL;
+        if (device)
+                (void) sd_device_get_sysname(device, &sysname);
+
+        desc = strjoin(sysname ?: subsystem, devlink ? ":" : ":initialization", devlink);
+        if (desc)
+                (void) sd_device_monitor_set_description(monitor, desc);
+
         r = sd_device_monitor_attach_event(monitor, event);
         if (r < 0)
                 return log_error_errno(r, "Failed to attach event to device monitor: %m");
index 3563d004c8fa69a3e4f17437a0d56129a981f39d..946c827ccf008915b288d60a66f80b02d629c59b 100644 (file)
@@ -344,6 +344,24 @@ TEST(build) {
         assert_se(json_variant_equal(a, b));
 }
 
+TEST(json_parse_file_empty) {
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
+
+        assert_se(fopen_unlocked("/dev/null", "re", &f) >= 0);
+        assert_se(json_parse_file(f, "waldo", 0, &v, NULL, NULL) == -ENODATA);
+        assert_se(v == NULL);
+}
+
+TEST(json_parse_file_invalid) {
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
+
+        assert_se(f = fmemopen_unlocked((void*) "kookoo", 6, "r"));
+        assert_se(json_parse_file(f, "waldo", 0, &v, NULL, NULL) == -EINVAL);
+        assert_se(v == NULL);
+}
+
 TEST(source) {
         static const char data[] =
                 "\n"
index 891bbfc84a592a83d096f09c66ee016295dce49a..0162bf7dc0433be4df774e464972cae790561c9d 100644 (file)
@@ -54,7 +54,16 @@ TEST(iszero_safe) {
         assert_se( iszero_safe(DBL_MIN / -INFINITY));
         assert_se( iszero_safe(DBL_MAX / INFINITY / 2));
         assert_se( iszero_safe(DBL_MAX / -INFINITY * DBL_MAX));
+#if defined(__i386__) && !defined(__SSE2_MATH__)
+        /* On 32bit x86, -mfpmath=387 is the default and SSE2 is not used. Then, floating point values are
+         * calculated in 80bit, and truncated to the length of the used type (double in this case). Hence,
+         * DBL_MAX * 2 is temporary calculated as a normal value, and goes to zero when divided with
+         * INFINITY. See issue #25044. */
+        log_debug("i386 architecture without SSE2 is detected. "
+                  "Skipping \"assert_se(!iszero_safe(DBL_MAX * 2 / INFINITY))\".");
+#else
         assert_se(!iszero_safe(DBL_MAX * 2 / INFINITY));
+#endif
 
         /* infinity / infinity is NaN */
         assert_se(!iszero_safe(INFINITY / INFINITY));
index 76aaf7c42e54b22ef8d6f1159df15d45855bee5b..99ad22a759e936a4a6d2cdcd478e1f32bb753808 100644 (file)
@@ -91,8 +91,7 @@ static int setup_monitor(MonitorNetlinkGroup sender, sd_event *event, sd_device_
         if (r < 0)
                 return log_error_errno(r, "Failed to start device monitor: %m");
 
-        (void) sd_event_source_set_description(sd_device_monitor_get_event_source(monitor),
-                                               sender == MONITOR_GROUP_UDEV ? "device-monitor-udev" : "device-monitor-kernel");
+        (void) sd_device_monitor_set_description(monitor, sender == MONITOR_GROUP_UDEV ? "udev" : "kernel");
 
         *ret = TAKE_PTR(monitor);
         return 0;
index 2c9de63da6ec0acf8adc656a6ef9743664f75d37..e3a2742733e22abfa5995b9b5b02c8051446f973 100644 (file)
@@ -714,8 +714,6 @@ static int worker_main(Manager *_manager, sd_device_monitor *monitor, sd_device
         if (r < 0)
                 return log_error_errno(r, "Failed to start device monitor: %m");
 
-        (void) sd_event_source_set_description(sd_device_monitor_get_event_source(monitor), "worker-device-monitor");
-
         /* Process first device */
         (void) worker_device_monitor_handler(monitor, dev, manager);
 
@@ -1957,8 +1955,6 @@ static int main_loop(Manager *manager) {
         if (r < 0)
                 return log_error_errno(r, "Failed to start device monitor: %m");
 
-        (void) sd_event_source_set_description(sd_device_monitor_get_event_source(manager->monitor), "device-monitor");
-
         r = sd_event_add_io(manager->event, NULL, fd_worker, EPOLLIN, on_worker, manager);
         if (r < 0)
                 return log_error_errno(r, "Failed to create worker event source: %m");
index 079c8b290eceb10a0d1762839af4c2193f1394a4..2f80cf256480bad0aa7a95b8925c06fc605467f3 100755 (executable)
@@ -317,6 +317,56 @@ test_transient_service_dropins () {
        /etc/systemd/system/a-b-.service.d/drop3.conf
 }
 
+test_transient_slice_dropins () {
+    echo "Testing dropins for a transient slice..."
+    echo "*** test transient slice drop-ins"
+
+    # FIXME: implement reloading of individual units.
+    #
+    # The settings here are loaded twice. For most settings it doesn't matter,
+    # but Documentation is not deduplicated, so we current get repeated entried
+    # which is a bug.
+
+    mkdir -p /etc/systemd/system/slice.d
+    mkdir -p /etc/systemd/system/a-.slice.d
+    mkdir -p /etc/systemd/system/a-b-.slice.d
+    mkdir -p /etc/systemd/system/a-b-c.slice.d
+
+    echo -e '[Unit]\nDocumentation=man:drop1' >/etc/systemd/system/slice.d/drop1.conf
+    echo -e '[Unit]\nDocumentation=man:drop2' >/etc/systemd/system/a-.slice.d/drop2.conf
+    echo -e '[Unit]\nDocumentation=man:drop3' >/etc/systemd/system/a-b-.slice.d/drop3.conf
+    echo -e '[Unit]\nDocumentation=man:drop4' >/etc/systemd/system/a-b-c.slice.d/drop4.conf
+
+    # Invoke daemon-reload to make sure that the call below doesn't fail
+    systemctl daemon-reload
+
+    # No fragment is required, so this works
+    systemctl cat a-b-c.slice
+
+    busctl call \
+           org.freedesktop.systemd1 \
+           /org/freedesktop/systemd1 \
+           org.freedesktop.systemd1.Manager \
+           StartTransientUnit 'ssa(sv)a(sa(sv))' \
+           'a-b-c.slice' 'replace' \
+           1 \
+           'Documentation' as 1 'man:drop5' \
+           0
+
+    data=$(systemctl show -P Documentation a-b-c.slice)
+    test "$data" = "man:drop1 man:drop2 man:drop3 man:drop4 man:drop5 man:drop1 man:drop2 man:drop3 man:drop4"
+
+    # Do a reload and check again
+    systemctl daemon-reload
+    data=$(systemctl show -P Documentation a-b-c.slice)
+    test "$data" = "man:drop5 man:drop1 man:drop2 man:drop3 man:drop4"
+
+    clear_units a-b-c.slice
+    rm /etc/systemd/system/slice.d/drop1.conf \
+       /etc/systemd/system/a-.slice.d/drop2.conf \
+       /etc/systemd/system/a-b-.slice.d/drop3.conf
+}
+
 test_template_dropins () {
     echo "Testing template dropins..."
 
@@ -657,6 +707,7 @@ test_template_alias
 test_hierarchical_service_dropins
 test_hierarchical_slice_dropins
 test_transient_service_dropins
+test_transient_slice_dropins
 test_template_dropins
 test_alias_dropins
 test_masked_dropins