[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1057861: bookworm-pu: package systemd/252.20-1~deb12u1



Control: retitle -1 bookworm-pu: package systemd/252.21-1~deb12u1

On Sat, 09 Dec 2023 19:51:46 +0000 Luca Boccassi <bluca@debian.org>
wrote:
> Package: release.debian.org
> Severity: normal
> Tags: bookworm
> User: release.debian.org@packages.debian.org
> Usertags: pu
> X-Debbugs-Cc: pkg-systemd-maintainers@lists.alioth.debian.org
> 
> Dear Release Team,
> 
> We would like to upload the latest stable point release of systemd
252
> to bookworm-p-u. Stable release branches are maintained upstream with
> the intention of providing bug fixes only and no compatibility
> breakages, and with automated non-trivial CI jobs that also cover
> Debian and Ubuntu. I have already uploaded to p-u.
> 
> No packaging changes besides refreshing patches. Attached debdiff
> excludes hwdb.d/ changes, which are just a large number of hardware
> vendor/devices IDs and constitutes the bulk of the changes. The list
of
> commits included can be seen at:
> 
> https://github.com/systemd/systemd-stable/compare/v252.19...v252.20

Dear Release Team,

I have uploaded 252.21-1~deb12u1, which among other fixes also includes
the patch for CVE-2023-7008. Debdiff from 252.20-1~deb12u1 attached
with hwdb changes pruned.

https://github.com/systemd/systemd-stable/compare/v252.10...v252.21

-- 
Kind regards,
Luca Boccassi
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/debian/changelog systemd-252.21/debian/changelog
--- systemd-252.20/debian/changelog	2023-12-07 00:13:24.000000000 +0100
+++ systemd-252.21/debian/changelog	2023-12-24 15:29:22.000000000 +0100
@@ -1,3 +1,11 @@
+systemd (252.21-1~deb12u1) bookworm; urgency=medium
+
+  * New upstream version 252.21
+    CVE-2023-7008 (Closes: #1059278)
+  * Refresh patches
+
+ -- Luca Boccassi <bluca@debian.org>  Sun, 24 Dec 2023 15:29:22 +0100
+
 systemd (252.20-1~deb12u1) bookworm; urgency=medium
 
   * New upstream version 252.20
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/debian/patches/debian/Downgrade-a-couple-of-warnings-to-debug.patch systemd-252.21/debian/patches/debian/Downgrade-a-couple-of-warnings-to-debug.patch
--- systemd-252.20/debian/patches/debian/Downgrade-a-couple-of-warnings-to-debug.patch	2023-12-07 00:13:24.000000000 +0100
+++ systemd-252.21/debian/patches/debian/Downgrade-a-couple-of-warnings-to-debug.patch	2023-12-24 15:29:22.000000000 +0100
@@ -16,7 +16,7 @@
  3 files changed, 7 insertions(+), 3 deletions(-)
 
 diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
-index a730159..815d9f8 100644
+index 1001faa..555492e 100644
 --- a/src/core/load-fragment.c
 +++ b/src/core/load-fragment.c
 @@ -543,6 +543,7 @@ static int patch_var_run(
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/debian/patches/debian/Revert-core-set-RLIMIT_CORE-to-unlimited-by-default.patch systemd-252.21/debian/patches/debian/Revert-core-set-RLIMIT_CORE-to-unlimited-by-default.patch
--- systemd-252.20/debian/patches/debian/Revert-core-set-RLIMIT_CORE-to-unlimited-by-default.patch	2023-12-07 00:13:24.000000000 +0100
+++ systemd-252.21/debian/patches/debian/Revert-core-set-RLIMIT_CORE-to-unlimited-by-default.patch	2023-12-24 15:29:22.000000000 +0100
@@ -19,7 +19,7 @@
  2 files changed, 1 insertion(+), 21 deletions(-)
 
 diff --git a/src/core/main.c b/src/core/main.c
-index c3b1a35..59ea0c6 100644
+index 1c4b464..e84e7dd 100644
 --- a/src/core/main.c
 +++ b/src/core/main.c
 @@ -1650,24 +1650,6 @@ static void cmdline_take_random_seed(void) {
@@ -47,7 +47,7 @@
  static void initialize_core_pattern(bool skip_setup) {
          int r;
  
-@@ -2816,8 +2798,6 @@ int main(int argc, char *argv[]) {
+@@ -2814,8 +2796,6 @@ int main(int argc, char *argv[]) {
                          kernel_timestamp = DUAL_TIMESTAMP_NULL;
                  }
  
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/debian/patches/p11kit-switch-to-dlopen.patch systemd-252.21/debian/patches/p11kit-switch-to-dlopen.patch
--- systemd-252.20/debian/patches/p11kit-switch-to-dlopen.patch	2023-12-07 00:13:24.000000000 +0100
+++ systemd-252.21/debian/patches/p11kit-switch-to-dlopen.patch	2023-12-24 15:29:22.000000000 +0100
@@ -718,10 +718,10 @@
  }
  
 diff --git a/test/test-functions b/test/test-functions
-index 345dc66..5d0a421 100644
+index 29f346f..c169635 100644
 --- a/test/test-functions
 +++ b/test/test-functions
-@@ -1361,7 +1361,7 @@ install_missing_libraries() {
+@@ -1369,7 +1369,7 @@ install_missing_libraries() {
      local lib path
      # A number of dependencies is now optional via dlopen, so the install
      # script will not pick them up, since it looks at linkage.
@@ -730,7 +730,7 @@
          ddebug "Searching for $lib via pkg-config"
          if pkg-config --exists "$lib"; then
                  path="$(pkg-config --variable=libdir "$lib")"
-@@ -1373,6 +1373,10 @@ install_missing_libraries() {
+@@ -1381,6 +1381,10 @@ install_missing_libraries() {
                  if ! [[ ${lib} =~ ^lib ]]; then
                          lib="lib${lib}"
                  fi
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/docs/CREDENTIALS.md systemd-252.21/docs/CREDENTIALS.md
--- systemd-252.20/docs/CREDENTIALS.md	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/docs/CREDENTIALS.md	2023-12-24 10:01:00.000000000 +0100
@@ -396,7 +396,7 @@
         -drive if=none,id=hd,file=test.raw,format=raw \
         -device virtio-scsi-pci,id=scsi \
         -device scsi-hd,drive=hd,bootindex=1 \
-        -smbios type=11,value=io.systemd.credential.binary:tmpfiles.extra=$(echo "f~ /root/.ssh/authorized_keys 700 root root - $(ssh-add -L | base64 -w 0)" | base64 -w 0)
+        -smbios type=11,value=io.systemd.credential.binary:tmpfiles.extra=$(echo "f~ /root/.ssh/authorized_keys 600 root root - $(ssh-add -L | base64 -w 0)" | base64 -w 0)
 ```
 ## Relevant Paths
 
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/man/org.freedesktop.systemd1.xml systemd-252.21/man/org.freedesktop.systemd1.xml
--- systemd-252.20/man/org.freedesktop.systemd1.xml	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/man/org.freedesktop.systemd1.xml	2023-12-24 10:01:00.000000000 +0100
@@ -1287,7 +1287,7 @@
       <para><function>ResetFailed()</function> resets the "failed" state of all units.</para>
 
       <para><function>ListUnits()</function> returns an array of all currently loaded units. Note that
-      units may be known by multiple names at the same name, and hence there might be more unit names loaded
+      units may be known by multiple names at the same time, and hence there might be more unit names loaded
       than actual units behind them. The array consists of structures with the following elements:
       <itemizedlist>
         <listitem><para>The primary unit name as string</para></listitem>
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/analyze/analyze-condition.c systemd-252.21/src/analyze/analyze-condition.c
--- systemd-252.20/src/analyze/analyze-condition.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/analyze/analyze-condition.c	2023-12-24 10:01:00.000000000 +0100
@@ -78,18 +78,9 @@
         int r, q = 1;
 
         if (unit) {
-                _cleanup_strv_free_ char **filenames = NULL;
-                _cleanup_free_ char *var = NULL;
-
-                filenames = strv_new(unit);
-                if (!filenames)
-                        return log_oom();
-
-                r = verify_generate_path(&var, filenames);
+                r = verify_set_unit_path(STRV_MAKE(unit));
                 if (r < 0)
-                        return log_error_errno(r, "Failed to generate unit load path: %m");
-
-                assert_se(set_unit_path(var) >= 0);
+                        return log_error_errno(r, "Failed to set unit load path: %m");
         }
 
         r = manager_new(scope, MANAGER_TEST_RUN_MINIMAL, &m);
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/analyze/analyze-security.c systemd-252.21/src/analyze/analyze-security.c
--- systemd-252.20/src/analyze/analyze-security.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/analyze/analyze-security.c	2023-12-24 10:01:00.000000000 +0100
@@ -2697,19 +2697,15 @@
 
         _cleanup_(manager_freep) Manager *m = NULL;
         Unit *units[strv_length(filenames)];
-        _cleanup_free_ char *var = NULL;
         int r, k;
         size_t count = 0;
 
         if (strv_isempty(filenames))
                 return 0;
 
-        /* set the path */
-        r = verify_generate_path(&var, filenames);
+        r = verify_set_unit_path(filenames);
         if (r < 0)
-                return log_error_errno(r, "Failed to generate unit load path: %m");
-
-        assert_se(set_unit_path(var) >= 0);
+                return log_error_errno(r, "Failed to set unit load path: %m");
 
         r = manager_new(scope, flags, &m);
         if (r < 0)
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/analyze/analyze-verify-util.c systemd-252.21/src/analyze/analyze-verify-util.c
--- systemd-252.20/src/analyze/analyze-verify-util.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/analyze/analyze-verify-util.c	2023-12-24 10:01:00.000000000 +0100
@@ -72,50 +72,90 @@
         return 0;
 }
 
-int verify_generate_path(char **ret, char **filenames) {
+static int find_unit_directory(const char *p, char **ret) {
+        _cleanup_free_ char *a = NULL, *u = NULL, *t = NULL, *d = NULL;
+        int r;
+
+        assert(p);
+        assert(ret);
+
+        r = path_make_absolute_cwd(p, &a);
+        if (r < 0)
+                return r;
+
+        if (access(a, F_OK) >= 0) {
+                r = path_extract_directory(a, &d);
+                if (r < 0)
+                        return r;
+
+                *ret = TAKE_PTR(d);
+                return 0;
+        }
+
+        r = path_extract_filename(a, &u);
+        if (r < 0)
+                return r;
+
+        if (!unit_name_is_valid(u, UNIT_NAME_INSTANCE))
+                return -ENOENT;
+
+        /* If the specified unit is an instance of a template unit, then let's try to find the template unit. */
+        r = unit_name_template(u, &t);
+        if (r < 0)
+                return r;
+
+        r = path_extract_directory(a, &d);
+        if (r < 0)
+                return r;
+
+        free(a);
+        a = path_join(d, t);
+        if (!a)
+                return -ENOMEM;
+
+        if (access(a, F_OK) < 0)
+                return -errno;
+
+        *ret = TAKE_PTR(d);
+        return 0;
+}
+
+int verify_set_unit_path(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;
+                _cleanup_free_ char *t = NULL;
 
-                r = path_make_absolute_cwd(*filename, &a);
-                if (r < 0)
+                r = find_unit_directory(*filename, &t);
+                if (r == -ENOMEM)
                         return r;
-
-                r = path_extract_directory(a, &t);
                 if (r < 0)
-                        return r;
+                        continue;
 
-                r = strv_consume(&ans, t);
+                r = strv_consume(&ans, TAKE_PTR(t));
                 if (r < 0)
                         return r;
         }
 
-        strv_uniq(ans);
+        if (strv_isempty(ans))
+                return 0;
+
+        joined = strv_join(strv_uniq(ans), ":");
+        if (!joined)
+                return -ENOMEM;
 
         /* 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.
-         * Treat explicit empty path to mean that nothing should be appended.
-         */
+         * Treat explicit empty path to mean that nothing should be appended. */
         old = getenv("SYSTEMD_UNIT_PATH");
-        if (!streq_ptr(old, "")) {
-                if (!old)
-                        old = "";
-
-                r = strv_extend(&ans, old);
-                if (r < 0)
-                        return r;
-        }
-
-        joined = strv_join(ans, ":");
-        if (!joined)
+        if (!streq_ptr(old, "") &&
+            !strextend_with_separator(&joined, ":", old ?: ""))
                 return -ENOMEM;
 
-        *ret = TAKE_PTR(joined);
+        assert_se(set_unit_path(joined) >= 0);
         return 0;
 }
 
@@ -259,7 +299,6 @@
         _cleanup_(set_destroy_ignore_pointer_max) Set *s = NULL;
         _unused_ _cleanup_(clear_log_syntax_callback) dummy_t dummy;
         Unit *units[strv_length(filenames)];
-        _cleanup_free_ char *var = NULL;
         int r, k, i, count = 0;
 
         if (strv_isempty(filenames))
@@ -271,11 +310,9 @@
         set_log_syntax_callback(log_syntax_callback, &s);
 
         /* set the path */
-        r = verify_generate_path(&var, filenames);
+        r = verify_set_unit_path(filenames);
         if (r < 0)
-                return log_error_errno(r, "Failed to generate unit load path: %m");
-
-        assert_se(set_unit_path(var) >= 0);
+                return log_error_errno(r, "Failed to set unit load path: %m");
 
         r = manager_new(scope, flags, &m);
         if (r < 0)
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/analyze/analyze-verify-util.h systemd-252.21/src/analyze/analyze-verify-util.h
--- systemd-252.20/src/analyze/analyze-verify-util.h	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/analyze/analyze-verify-util.h	2023-12-24 10:01:00.000000000 +0100
@@ -14,7 +14,7 @@
         _RECURSIVE_ERRORS_INVALID = -EINVAL,
 } RecursiveErrors;
 
-int verify_generate_path(char **var, char **filenames);
+int verify_set_unit_path(char **filenames);
 int verify_prepare_filename(const char *filename, char **ret);
 int verify_executable(Unit *u, const ExecCommand *exec, const char *root);
 int verify_units(char **filenames, LookupScope scope, bool check_man, bool run_generators, RecursiveErrors recursive_errors, const char *root);
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/basic/log.c systemd-252.21/src/basic/log.c
--- systemd-252.20/src/basic/log.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/basic/log.c	2023-12-24 10:01:00.000000000 +0100
@@ -48,6 +48,7 @@
 static int log_facility = LOG_DAEMON;
 
 static int console_fd = STDERR_FILENO;
+static int console_fd_is_tty = -1; /* tri-state: -1 means don't know */
 static int syslog_fd = -1;
 static int kmsg_fd = -1;
 static int journal_fd = -1;
@@ -85,12 +86,14 @@
 static void log_close_console(void) {
         /* See comment in log_close_journal() */
         (void) safe_close_above_stdio(TAKE_FD(console_fd));
+        console_fd_is_tty = -1;
 }
 
 static int log_open_console(void) {
 
         if (!always_reopen_console) {
                 console_fd = STDERR_FILENO;
+                console_fd_is_tty = -1;
                 return 0;
         }
 
@@ -102,6 +105,7 @@
                         return fd;
 
                 console_fd = fd_move_above_stdio(fd);
+                console_fd_is_tty = true;
         }
 
         return 0;
@@ -353,6 +357,7 @@
         /* Do not call from library code. */
 
         console_fd = kmsg_fd = syslog_fd = journal_fd = -1;
+        console_fd_is_tty = -1;
 }
 
 void log_set_max_level(int level) {
@@ -365,6 +370,16 @@
         log_facility = facility;
 }
 
+static bool check_console_fd_is_tty(void) {
+        if (console_fd < 0)
+                return false;
+
+        if (console_fd_is_tty < 0)
+                console_fd_is_tty = isatty(console_fd) > 0;
+
+        return console_fd_is_tty;
+}
+
 static int write_to_console(
                 int level,
                 int error,
@@ -419,7 +434,12 @@
         iovec[n++] = IOVEC_MAKE_STRING(buffer);
         if (off)
                 iovec[n++] = IOVEC_MAKE_STRING(off);
-        iovec[n++] = IOVEC_MAKE_STRING("\n");
+
+        /* When writing to a TTY we output an extra '\r' (i.e. CR) first, to generate CRNL rather than just
+         * NL. This is a robustness thing in case the TTY is currently in raw mode (specifically: has the
+         * ONLCR flag off). We want that subsequent output definitely starts at the beginning of the line
+         * again, after all. If the TTY is not in raw mode the extra CR should not hurt. */
+        iovec[n++] = IOVEC_MAKE_STRING((check_console_fd_is_tty() ? "\r\n" : "\n"));
 
         if (writev(console_fd, iovec, n) < 0) {
 
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/basic/parse-util.c systemd-252.21/src/basic/parse-util.c
--- systemd-252.20/src/basic/parse-util.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/basic/parse-util.c	2023-12-24 10:01:00.000000000 +0100
@@ -105,8 +105,7 @@
 }
 
 int parse_mtu(int family, const char *s, uint32_t *ret) {
-        uint64_t u;
-        size_t m;
+        uint64_t u, m;
         int r;
 
         r = parse_size(s, 1024, &u);
@@ -116,10 +115,16 @@
         if (u > UINT32_MAX)
                 return -ERANGE;
 
-        if (family == AF_INET6)
+        switch (family) {
+        case AF_INET:
+                m = IPV4_MIN_MTU; /* This is 68 */
+                break;
+        case AF_INET6:
                 m = IPV6_MIN_MTU; /* This is 1280 */
-        else
-                m = IPV4_MIN_MTU; /* For all other protocols, including 'unspecified' we assume the IPv4 minimal MTU */
+                break;
+        default:
+                m = 0;
+        }
 
         if (u < m)
                 return -ERANGE;
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/core/device.c systemd-252.21/src/core/device.c
--- systemd-252.20/src/core/device.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/core/device.c	2023-12-24 10:01:00.000000000 +0100
@@ -1266,6 +1266,7 @@
         .status_message_formats = {
                 .starting_stopping = {
                         [0] = "Expecting device %s...",
+                        [1] = "Waiting for device %s to disappear...",
                 },
                 .finished_start_job = {
                         [JOB_DONE]       = "Found device %s.",
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/core/execute.c systemd-252.21/src/core/execute.c
--- systemd-252.20/src/core/execute.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/core/execute.c	2023-12-24 10:01:00.000000000 +0100
@@ -151,7 +151,7 @@
         return 0;
 }
 
-static int flags_fds(const int fds[], size_t n_socket_fds, size_t n_storage_fds, bool nonblock) {
+static int flag_fds(const int fds[], size_t n_socket_fds, size_t n_storage_fds, bool nonblock) {
         size_t n_fds;
         int r;
 
@@ -160,6 +160,7 @@
                 return 0;
 
         assert(fds);
+        assert(fds || n_fds == 0);
 
         /* Drops/Sets O_NONBLOCK and FD_CLOEXEC from the file flags.
          * O_NONBLOCK only applies to socket activation though. */
@@ -4855,7 +4856,7 @@
         if (r >= 0)
                 r = shift_fds(fds, n_fds);
         if (r >= 0)
-                r = flags_fds(fds, n_socket_fds, n_storage_fds, context->non_blocking);
+                r = flag_fds(fds, n_socket_fds, n_storage_fds, context->non_blocking);
         if (r < 0) {
                 *exit_status = EXIT_FDS;
                 return log_unit_error_errno(unit, r, "Failed to adjust passed file descriptors: %m");
@@ -6315,7 +6316,7 @@
         if (!path)
                 return;
 
-        fd = open(path, O_PATH|O_CLOEXEC);
+        fd = open(path, O_PATH|O_CLOEXEC); /* Pin the inode */
         if (fd < 0)
                 return (void) log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno,
                                              "Failed to open TTY inode of '%s' to adjust ownership/access mode, ignoring: %m",
@@ -6334,7 +6335,7 @@
 
         r = fchmod_and_chown(fd, TTY_MODE, 0, TTY_GID);
         if (r < 0)
-                log_warning_errno(r, "Failed to reset TTY ownership/access mode of %s, ignoring: %m", path);
+                log_warning_errno(r, "Failed to reset TTY ownership/access mode of %s to " UID_FMT ":" GID_FMT ", ignoring: %m", path, (uid_t) 0, (gid_t) TTY_GID);
 }
 
 int exec_context_get_clean_directories(
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/core/job.c systemd-252.21/src/core/job.c
--- systemd-252.20/src/core/job.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/core/job.c	2023-12-24 10:01:00.000000000 +0100
@@ -805,13 +805,12 @@
         Manager *m;
         JobType t;
         Unit *u;
+        bool wait_only;
         int r;
 
-        /* While we execute this operation the job might go away (for
-         * example: because it finishes immediately or is replaced by
-         * a new, conflicting job.) To make sure we don't access a
-         * freed job later on we store the id here, so that we can
-         * verify the job is still valid. */
+        /* While we execute this operation the job might go away (for example: because it finishes immediately
+         * or is replaced by a new, conflicting job). To make sure we don't access a freed job later on we
+         * store the id here, so that we can verify the job is still valid. */
 
         assert(j);
         assert(*j);
@@ -825,6 +824,7 @@
         switch (t) {
                 case JOB_START:
                         r = unit_start(u, a);
+                        wait_only = r == -EBADR; /* If the unit type does not support starting, then simply wait. */
                         break;
 
                 case JOB_RESTART:
@@ -832,24 +832,28 @@
                         _fallthrough_;
                 case JOB_STOP:
                         r = unit_stop(u);
+                        wait_only = r == -EBADR; /* If the unit type does not support stopping, then simply wait. */
                         break;
 
                 case JOB_RELOAD:
                         r = unit_reload(u);
+                        wait_only = false; /* A clear error is generated if reload is not supported. */
                         break;
 
                 default:
                         assert_not_reached();
         }
 
-        /* Log if the job still exists and the start/stop/reload function actually did something. Note that this means
-         * for units for which there's no 'activating' phase (i.e. because we transition directly from 'inactive' to
-         * 'active') we'll possibly skip the "Starting..." message. */
+        /* Log if the job still exists and the start/stop/reload function actually did something or we're
+         * only waiting for unit status change (common for device units). The latter ensures that job start
+         * messages for device units are correctly shown. Note that if the job disappears too quickly, e.g.
+         * for units for which there's no 'activating' phase (i.e. because we transition directly from
+         * 'inactive' to 'active'), we'll possibly skip the "Starting..." message. */
         *j = manager_get_job(m, id);
-        if (*j && r > 0)
+        if (*j && (r > 0 || wait_only))
                 job_emit_start_message(u, id, t);
 
-        return r;
+        return wait_only ? 0 : r;
 }
 
 int job_run_and_invalidate(Job *j) {
@@ -891,13 +895,6 @@
                 case JOB_START:
                 case JOB_STOP:
                 case JOB_RESTART:
-                        r = job_perform_on_unit(&j);
-
-                        /* If the unit type does not support starting/stopping, then simply wait. */
-                        if (r == -EBADR)
-                                r = 0;
-                        break;
-
                 case JOB_RELOAD:
                         r = job_perform_on_unit(&j);
                         break;
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/core/load-fragment.c systemd-252.21/src/core/load-fragment.c
--- systemd-252.20/src/core/load-fragment.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/core/load-fragment.c	2023-12-24 10:01:00.000000000 +0100
@@ -3787,8 +3787,23 @@
                 void *userdata) {
 
         CPUSet *c = data;
+        const Unit *u = userdata;
+        _cleanup_free_ char *k = NULL;
+        int r;
 
-        (void) parse_cpu_set_extend(rvalue, c, true, unit, filename, line, lvalue);
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+
+        r = unit_full_printf(u, rvalue, &k);
+        if (r < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, r,
+                           "Failed to resolve unit specifiers in '%s', ignoring: %m",
+                           rvalue);
+                return 0;
+        }
+
+        (void) parse_cpu_set_extend(k, c, true, unit, filename, line, lvalue);
         return 0;
 }
 
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/core/main.c systemd-252.21/src/core/main.c
--- systemd-252.20/src/core/main.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/core/main.c	2023-12-24 10:01:00.000000000 +0100
@@ -2635,8 +2635,6 @@
                 return log_emergency_errno(r, "Failed to allocate fd set: %m");
         }
 
-        (void) fdset_cloexec(*ret_fds, true);
-
         /* The serialization fd should have O_CLOEXEC turned on already, let's verify that we didn't pick it up here */
         assert_se(!arg_serialization || !fdset_contains(*ret_fds, fileno(arg_serialization)));
 
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/core/show-status.c systemd-252.21/src/core/show-status.c
--- systemd-252.20/src/core/show-status.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/core/show-status.c	2023-12-24 10:01:00.000000000 +0100
@@ -95,7 +95,7 @@
         }
 
         iovec[n++] = IOVEC_MAKE_STRING(s);
-        iovec[n++] = IOVEC_MAKE_STRING("\n");
+        iovec[n++] = IOVEC_MAKE_STRING("\r\n"); /* use CRNL instead of just NL, to be robust towards TTYs in raw mode */
 
         if (prev_ephemeral && !FLAGS_SET(flags, SHOW_STATUS_EPHEMERAL))
                 iovec[n++] = IOVEC_MAKE_STRING(ANSI_ERASE_TO_END_OF_LINE);
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/creds/creds.c systemd-252.21/src/creds/creds.c
--- systemd-252.20/src/creds/creds.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/creds/creds.c	2023-12-24 10:01:00.000000000 +0100
@@ -353,14 +353,15 @@
         }
 
         if (fwrite(data, 1, size, f) != size)
-                return log_error_errno(errno, "Failed to write credential data: %m");
+                return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to write credential data.");
 
         r = print_newline(f, data, size);
         if (r < 0)
                 return r;
 
-        if (fflush(f) != 0)
-                return log_error_errno(errno, "Failed to flush output: %m");
+        r = fflush_and_check(f);
+        if (r < 0)
+                return log_error_errno(r, "Failed to flush output: %m");
 
         return 0;
 }
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/dissect/dissect.c systemd-252.21/src/dissect/dissect.c
--- systemd-252.20/src/dissect/dissect.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/dissect/dissect.c	2023-12-24 10:01:00.000000000 +0100
@@ -574,7 +574,7 @@
                 return log_oom();
 
         table_set_ersatz_string(t, TABLE_ERSATZ_DASH);
-        (void) table_set_align_percent(t, table_get_cell(t, 0, 7), 100);
+        (void) table_set_align_percent(t, table_get_cell(t, 0, 9), 100);
 
         for (PartitionDesignator i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
                 DissectedPartition *p = m->partitions + i;
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/hostname/hostnamectl.c systemd-252.21/src/hostname/hostnamectl.c
--- systemd-252.20/src/hostname/hostnamectl.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/hostname/hostnamectl.c	2023-12-24 10:01:00.000000000 +0100
@@ -52,6 +52,8 @@
         const char *hardware_vendor;
         const char *hardware_model;
         const char *firmware_version;
+        sd_id128_t machine_id;
+        sd_id128_t boot_id;
 } StatusInfo;
 
 static const char* chassis_string_to_glyph(const char *chassis) {
@@ -76,7 +78,6 @@
 
 static int print_status_info(StatusInfo *i) {
         _cleanup_(table_unrefp) Table *table = NULL;
-        sd_id128_t mid = {}, bid = {};
         TableCell *cell;
         int r;
 
@@ -156,20 +157,18 @@
                         return table_log_add_error(r);
         }
 
-        r = sd_id128_get_machine(&mid);
-        if (r >= 0) {
+        if (!sd_id128_is_null(i->machine_id)) {
                 r = table_add_many(table,
                                    TABLE_STRING, "Machine ID:",
-                                   TABLE_ID128, mid);
+                                   TABLE_ID128, i->machine_id);
                 if (r < 0)
                         return table_log_add_error(r);
         }
 
-        r = sd_id128_get_boot(&bid);
-        if (r >= 0) {
+        if (!sd_id128_is_null(i->boot_id)) {
                 r = table_add_many(table,
                                    TABLE_STRING, "Boot ID:",
-                                   TABLE_ID128, bid);
+                                   TABLE_ID128, i->boot_id);
                 if (r < 0)
                         return table_log_add_error(r);
         }
@@ -342,6 +341,13 @@
         if (r < 0)
                 return log_error_errno(r, "Failed to query system properties: %s", bus_error_message(&error, r));
 
+        if (!arg_host) {
+                if (sd_id128_is_null(info.machine_id))
+                        (void) sd_id128_get_machine(&info.machine_id);
+                if (sd_id128_is_null(info.boot_id))
+                        (void) sd_id128_get_boot(&info.boot_id);
+        }
+
         return print_status_info(&info);
 }
 
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/libsystemd/sd-journal/journal-verify.c systemd-252.21/src/libsystemd/sd-journal/journal-verify.c
--- systemd-252.20/src/libsystemd/sd-journal/journal-verify.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/libsystemd/sd-journal/journal-verify.c	2023-12-24 10:01:00.000000000 +0100
@@ -385,7 +385,7 @@
 
 static int write_uint64(FILE *fp, uint64_t p) {
         if (fwrite(&p, sizeof(p), 1, fp) != 1)
-                return -errno;
+                return -EIO;
 
         return 0;
 }
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/network/generator/network-generator.c systemd-252.21/src/network/generator/network-generator.c
--- systemd-252.20/src/network/generator/network-generator.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/network/generator/network-generator.c	2023-12-24 10:01:00.000000000 +0100
@@ -87,6 +87,8 @@
         Address *address;
 
         assert(network);
+        assert(IN_SET(family, AF_INET, AF_INET6));
+        assert(addr);
 
         address = new(Address, 1);
         if (!address)
@@ -96,7 +98,7 @@
                 .family = family,
                 .prefixlen = prefixlen,
                 .address = *addr,
-                .peer = *peer,
+                .peer = peer ? *peer : IN_ADDR_NULL,
         };
 
         LIST_PREPEND(addresses, network->addresses, address);
@@ -123,6 +125,8 @@
         Route *route;
 
         assert(network);
+        assert(IN_SET(family, AF_INET, AF_INET6));
+        assert(dest || gateway);
 
         route = new(Route, 1);
         if (!route)
@@ -132,7 +136,7 @@
                 .family = family,
                 .prefixlen = prefixlen,
                 .dest = dest ? *dest : IN_ADDR_NULL,
-                .gateway = *gateway,
+                .gateway = gateway ? *gateway : IN_ADDR_NULL,
         };
 
         LIST_PREPEND(routes, network->routes, route);
@@ -225,6 +229,7 @@
         int r;
 
         assert(context);
+        assert(_kind);
 
         if (!ifname_valid(_ifname))
                 return -EINVAL;
@@ -339,6 +344,10 @@
         DHCPType t;
         int r;
 
+        assert(context);
+        assert(ifname);
+        assert(dhcp_type);
+
         t = dracut_dhcp_type_from_string(dhcp_type);
         if (t < 0)
                 return t;
@@ -357,6 +366,9 @@
 static int network_set_hostname(Context *context, const char *ifname, const char *hostname) {
         Network *network;
 
+        assert(context);
+        assert(ifname);
+
         network = network_get(context, ifname);
         if (!network)
                 return -ENODEV;
@@ -364,19 +376,29 @@
         return free_and_strdup(&network->hostname, hostname);
 }
 
-static int network_set_mtu(Context *context, const char *ifname, int family, const char *mtu) {
+static int network_set_mtu(Context *context, const char *ifname, const char *mtu) {
         Network *network;
 
+        assert(context);
+        assert(ifname);
+
+        if (isempty(mtu))
+                return 0;
+
         network = network_get(context, ifname);
         if (!network)
                 return -ENODEV;
 
-        return parse_mtu(family, mtu, &network->mtu);
+        return parse_mtu(AF_UNSPEC, mtu, &network->mtu);
 }
 
 static int network_set_mac_address(Context *context, const char *ifname, const char *mac) {
         Network *network;
 
+        assert(context);
+        assert(ifname);
+        assert(mac);
+
         network = network_get(context, ifname);
         if (!network)
                 return -ENODEV;
@@ -388,6 +410,11 @@
                                union in_addr_union *addr, union in_addr_union *peer) {
         Network *network;
 
+        assert(context);
+        assert(ifname);
+        assert(IN_SET(family, AF_INET, AF_INET6));
+        assert(addr);
+
         if (!in_addr_is_set(family, addr))
                 return 0;
 
@@ -403,7 +430,12 @@
         Network *network;
         int r;
 
-        if (!in_addr_is_set(family, gateway))
+        assert(context);
+        assert(ifname);
+        assert(IN_SET(family, AF_INET, AF_INET6));
+
+        if (!(dest && in_addr_is_set(family, dest)) &&
+            !(gateway && in_addr_is_set(family, gateway)))
                 return 0;
 
         network = network_get(context, ifname);
@@ -416,12 +448,20 @@
         return route_new(network, family, prefixlen, dest, gateway, NULL);
 }
 
-static int network_set_dns(Context *context, const char *ifname, const char *dns) {
+static int network_set_dns(Context *context, const char *ifname, int family, const char *dns) {
         union in_addr_union a;
         Network *network;
-        int family, r;
+        int r;
 
-        r = in_addr_from_string_auto(dns, &family, &a);
+        assert(context);
+        assert(ifname);
+        assert(IN_SET(family, AF_UNSPEC, AF_INET, AF_INET6));
+        assert(dns);
+
+        if (family == AF_UNSPEC)
+                r = in_addr_from_string_auto(dns, &family, &a);
+        else
+                r = in_addr_from_string(family, dns, &a);
         if (r < 0)
                 return r;
 
@@ -439,6 +479,9 @@
         Network *network;
         int r;
 
+        assert(context);
+        assert(ifname);
+
         network = network_get(context, ifname);
         if (!network) {
                 r = network_new(context, ifname, &network);
@@ -455,6 +498,9 @@
         Network *network;
         int r;
 
+        assert(context);
+        assert(ifname);
+
         network = network_get(context, ifname);
         if (!network) {
                 r = network_new(context, ifname, &network);
@@ -469,6 +515,9 @@
         Network *network;
         int r;
 
+        assert(context);
+        assert(ifname);
+
         network = network_get(context, ifname);
         if (!network) {
                 r = network_new(context, ifname, &network);
@@ -483,6 +532,9 @@
         Network *network;
         int r;
 
+        assert(context);
+        assert(ifname);
+
         network = network_get(context, ifname);
         if (!network) {
                 r = network_new(context, ifname, &network);
@@ -493,10 +545,14 @@
         return free_and_strdup(&network->bond, value);
 }
 
-static int parse_cmdline_ip_mtu_mac(Context *context, const char *ifname, int family, const char *value) {
+static int parse_cmdline_ip_mtu_mac(Context *context, const char *ifname, const char *value) {
         const char *mtu, *p;
         int r;
 
+        assert(context);
+        assert(ifname);
+        assert(value);
+
         /* [<mtu>][:<macaddr>] */
 
         p = strchr(value, ':');
@@ -505,11 +561,11 @@
         else
                 mtu = strndupa_safe(value, p - value);
 
-        r = network_set_mtu(context, ifname, family, mtu);
+        r = network_set_mtu(context, ifname, mtu);
         if (r < 0)
                 return r;
 
-        if (!p)
+        if (!p || isempty(p + 1))
                 return 0;
 
         r = network_set_mac_address(context, ifname, p + 1);
@@ -520,9 +576,15 @@
 }
 
 static int parse_ip_address_one(int family, const char **value, union in_addr_union *ret) {
-        const char *p = *value, *q, *buf;
+        const char *p, *q, *buf;
         int r;
 
+        assert(IN_SET(family, AF_INET, AF_INET6));
+        assert(value);
+        assert(ret);
+
+        p = ASSERT_PTR(*value);
+
         if (p[0] == ':') {
                 *value = p + 1;
                 return 0;
@@ -563,6 +625,11 @@
         const char *p, *q;
         int r;
 
+        assert(IN_SET(family, AF_INET, AF_INET6));
+        assert(value);
+        assert(*value);
+        assert(ret);
+
         r = parse_ip_address_one(family, value, &netmask);
         if (r > 0) {
                 if (family == AF_INET6)
@@ -588,12 +655,58 @@
         return 0;
 }
 
+static int parse_ip_dns_address_one(Context *context, const char *ifname, const char **value) {
+        const char *p, *q, *buf;
+        int r, family;
+
+        assert(context);
+        assert(ifname);
+        assert(value);
+
+        p = ASSERT_PTR(*value);
+
+        if (isempty(p))
+                return 0;
+
+        if (p[0] == '[') {
+                q = strchr(p + 1, ']');
+                if (!q)
+                        return -EINVAL;
+                if (!IN_SET(q[1], ':', '\0'))
+                        return -EINVAL;
+
+                buf = strndupa_safe(p + 1, q - p - 1);
+                p = q + 1;
+                family = AF_INET6;
+        } else {
+                q = strchr(p, ':');
+                if (!q)
+                        buf = *value;
+                else
+                        buf = strndupa_safe(*value, q - *value);
+
+                p += strlen(buf);
+                family = AF_INET;
+        }
+
+        r = network_set_dns(context, ifname, family, buf);
+        if (r < 0)
+                return r;
+
+        *value = p;
+        return 0;
+}
+
 static int parse_cmdline_ip_address(Context *context, int family, const char *value) {
         union in_addr_union addr = {}, peer = {}, gateway = {};
-        const char *hostname = NULL, *ifname, *dhcp_type, *dns, *p;
+        const char *hostname = NULL, *ifname, *dhcp_type, *p;
         unsigned char prefixlen;
         int r;
 
+        assert(context);
+        assert(IN_SET(family, AF_INET, AF_INET6));
+        assert(value);
+
         /* ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|ibft|link6}[:[<mtu>][:<macaddr>]]
          * ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|ibft|link6}[:[<dns1>][:<dns2>]] */
 
@@ -660,26 +773,24 @@
                 return 0;
 
         /* First, try [<mtu>][:<macaddr>] */
-        r = parse_cmdline_ip_mtu_mac(context, ifname, AF_UNSPEC, p + 1);
+        r = parse_cmdline_ip_mtu_mac(context, ifname, p + 1);
         if (r >= 0)
                 return 0;
 
         /* Next, try [<dns1>][:<dns2>] */
         value = p + 1;
-        p = strchr(value, ':');
-        if (!p) {
-                r = network_set_dns(context, ifname, value);
-                if (r < 0)
-                        return r;
-        } else {
-                dns = strndupa_safe(value, p - value);
-                r = network_set_dns(context, ifname, dns);
-                if (r < 0)
-                        return r;
-                r = network_set_dns(context, ifname, p + 1);
-                if (r < 0)
-                        return r;
-        }
+        r = parse_ip_dns_address_one(context, ifname, &value);
+        if (r < 0)
+                return r;
+
+        value += *value == ':';
+        r = parse_ip_dns_address_one(context, ifname, &value);
+        if (r < 0)
+                return r;
+
+        /* refuse unexpected trailing strings */
+        if (!isempty(value))
+                return -EINVAL;
 
         return 0;
 }
@@ -688,6 +799,9 @@
         const char *ifname, *dhcp_type, *p;
         int r;
 
+        assert(context);
+        assert(value);
+
         /* ip=<interface>:{dhcp|on|any|dhcp6|auto6|link6}[:[<mtu>][:<macaddr>]] */
 
         p = strchr(value, ':');
@@ -710,13 +824,16 @@
         if (!p)
                 return 0;
 
-        return parse_cmdline_ip_mtu_mac(context, ifname, AF_UNSPEC, p + 1);
+        return parse_cmdline_ip_mtu_mac(context, ifname, p + 1);
 }
 
 static int parse_cmdline_ip(Context *context, const char *key, const char *value) {
         const char *p;
         int r;
 
+        assert(context);
+        assert(key);
+
         if (proc_cmdline_value_missing(key, value))
                 return -EINVAL;
 
@@ -741,6 +858,9 @@
         const char *buf, *p;
         int family, r;
 
+        assert(context);
+        assert(key);
+
         /* rd.route=<net>/<netmask>:<gateway>[:<interface>] */
 
         if (proc_cmdline_value_missing(key, value))
@@ -783,15 +903,21 @@
 }
 
 static int parse_cmdline_nameserver(Context *context, const char *key, const char *value) {
+        assert(context);
+        assert(key);
+
         if (proc_cmdline_value_missing(key, value))
                 return -EINVAL;
 
-        return network_set_dns(context, "", value);
+        return network_set_dns(context, "", AF_UNSPEC, value);
 }
 
 static int parse_cmdline_rd_peerdns(Context *context, const char *key, const char *value) {
         int r;
 
+        assert(context);
+        assert(key);
+
         if (proc_cmdline_value_missing(key, value))
                 return network_set_dhcp_use_dns(context, "", true);
 
@@ -807,6 +933,9 @@
         NetDev *netdev;
         int r;
 
+        assert(context);
+        assert(key);
+
         if (proc_cmdline_value_missing(key, value))
                 return -EINVAL;
 
@@ -831,6 +960,9 @@
         NetDev *netdev;
         int r;
 
+        assert(context);
+        assert(key);
+
         if (proc_cmdline_value_missing(key, value))
                 return -EINVAL;
 
@@ -869,6 +1001,9 @@
         NetDev *netdev;
         int r;
 
+        assert(context);
+        assert(key);
+
         if (proc_cmdline_value_missing(key, value))
                 return -EINVAL;
 
@@ -926,6 +1061,9 @@
         const char *name, *p;
         int r;
 
+        assert(context);
+        assert(key);
+
         /* ifname=<interface>:<MAC> */
 
         if (proc_cmdline_value_missing(key, value))
@@ -950,6 +1088,9 @@
         Link *link;
         int r;
 
+        assert(context);
+        assert(key);
+
         /* net.ifname-policy=policy1[,policy2,...][,<MAC>] */
 
         if (proc_cmdline_value_missing(key, value))
@@ -1080,6 +1221,9 @@
 }
 
 static int address_dump(Address *address, FILE *f) {
+        assert(address);
+        assert(f);
+
         fprintf(f,
                 "\n[Address]\n"
                 "Address=%s\n",
@@ -1091,12 +1235,16 @@
 }
 
 static int route_dump(Route *route, FILE *f) {
+        assert(route);
+        assert(f);
+
         fputs("\n[Route]\n", f);
         if (in_addr_is_set(route->family, &route->dest))
                 fprintf(f, "Destination=%s\n",
                         IN_ADDR_PREFIX_TO_STRING(route->family, &route->dest, route->prefixlen));
-        fprintf(f, "Gateway=%s\n",
-                IN_ADDR_TO_STRING(route->family, &route->gateway));
+        if (in_addr_is_set(route->family, &route->gateway))
+                fprintf(f, "Gateway=%s\n",
+                        IN_ADDR_TO_STRING(route->family, &route->gateway));
 
         return 0;
 }
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/network/networkd-link.c systemd-252.21/src/network/networkd-link.c
--- systemd-252.20/src/network/networkd-link.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/network/networkd-link.c	2023-12-24 10:01:00.000000000 +0100
@@ -1013,6 +1013,10 @@
         if (r < 0)
                 return r;
 
+        r = link_configure_mtu(link);
+        if (r < 0)
+                return r;
+
         if (link->iftype == ARPHRD_CAN) {
                 /* let's shortcut things for CAN which doesn't need most of what's done below. */
                 r = link_request_to_set_can(link);
@@ -1046,10 +1050,6 @@
         if (r < 0)
                 return r;
 
-        r = link_configure_mtu(link);
-        if (r < 0)
-                return r;
-
         r = link_request_to_set_addrgen_mode(link);
         if (r < 0)
                 return r;
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/network/networkd-manager.c systemd-252.21/src/network/networkd-manager.c
--- systemd-252.20/src/network/networkd-manager.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/network/networkd-manager.c	2023-12-24 10:01:00.000000000 +0100
@@ -643,7 +643,6 @@
          * by the upstream link. And the links may be referenced by netlink slots. Hence, two
          * set_free() must be called after the above sd_netlink_unref(). */
         m->routes = set_free(m->routes);
-        m->routes_foreign = set_free(m->routes_foreign);
 
         m->nexthops = set_free(m->nexthops);
         m->nexthops_by_id = hashmap_free(m->nexthops_by_id);
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/network/networkd-manager.h systemd-252.21/src/network/networkd-manager.h
--- systemd-252.20/src/network/networkd-manager.h	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/network/networkd-manager.h	2023-12-24 10:01:00.000000000 +0100
@@ -76,7 +76,6 @@
         /* Manager stores routes without RTA_OIF attribute. */
         unsigned route_remove_messages;
         Set *routes;
-        Set *routes_foreign;
 
         /* Route table name */
         Hashmap *route_table_numbers_by_name;
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/network/networkd-neighbor.c systemd-252.21/src/network/networkd-neighbor.c
--- systemd-252.20/src/network/networkd-neighbor.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/network/networkd-neighbor.c	2023-12-24 10:01:00.000000000 +0100
@@ -502,6 +502,8 @@
         }
 
         tmp = new0(Neighbor, 1);
+        if (!tmp)
+                return log_oom();
 
         r = sd_rtnl_message_neigh_get_family(message, &tmp->family);
         if (r < 0) {
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/network/networkd-route-util.c systemd-252.21/src/network/networkd-route-util.c
--- systemd-252.20/src/network/networkd-route-util.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/network/networkd-route-util.c	2023-12-24 10:01:00.000000000 +0100
@@ -152,9 +152,9 @@
                         continue;
                 if (FLAGS_SET(a->flags, IFA_F_NOPREFIXROUTE))
                         continue;
-                if (in_addr_is_set(a->family, &a->in_addr_peer))
-                        continue;
-                if (in_addr_prefix_covers(family, &a->in_addr, a->prefixlen, gw) > 0)
+                if (in_addr_prefix_covers(a->family,
+                                          in_addr_is_set(a->family, &a->in_addr_peer) ? &a->in_addr_peer : &a->in_addr,
+                                          a->prefixlen, gw) > 0)
                         return true;
         }
 
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/network/networkd-setlink.c systemd-252.21/src/network/networkd-setlink.c
--- systemd-252.20/src/network/networkd-setlink.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/network/networkd-setlink.c	2023-12-24 10:01:00.000000000 +0100
@@ -555,12 +555,20 @@
                 break;
         }
         case REQUEST_TYPE_SET_LINK_MTU: {
-                Request req_ipoib = {
-                        .link = link,
-                        .type = REQUEST_TYPE_SET_LINK_IPOIB,
-                };
-
-                return !ordered_set_contains(link->manager->request_queue, &req_ipoib);
+                if (ordered_set_contains(link->manager->request_queue,
+                                         &(const Request) {
+                                                 .link = link,
+                                                 .type = REQUEST_TYPE_SET_LINK_IPOIB,
+                                         }))
+                        return false;
+
+                /* Changing FD mode may affect MTU. */
+                if (ordered_set_contains(link->manager->request_queue,
+                                         &(const Request) {
+                                                 .link = link,
+                                                 .type = REQUEST_TYPE_SET_LINK_CAN,
+                                         }))
+                        return false;
         }
         default:
                 break;
@@ -832,7 +840,7 @@
 
 int link_request_to_set_mtu(Link *link, uint32_t mtu) {
         const char *origin;
-        uint32_t min_mtu;
+        uint32_t min_mtu, max_mtu;
         Request *req;
         int r;
 
@@ -860,10 +868,19 @@
                 mtu = min_mtu;
         }
 
-        if (mtu > link->max_mtu) {
+        max_mtu = link->max_mtu;
+        if (link->iftype == ARPHRD_CAN)
+                /* The maximum MTU may be changed when FD mode is changed.
+                 * See https://docs.kernel.org/networking/can.html#can-fd-flexible-data-rate-driver-support
+                 *   MTU = 16 (CAN_MTU)   => Classical CAN device
+                 *   MTU = 72 (CANFD_MTU) => CAN FD capable device
+                 * So, even if the current maximum is 16, we should not reduce the requested value now. */
+                max_mtu = MAX(max_mtu, 72u);
+
+        if (mtu > max_mtu) {
                 log_link_warning(link, "Reducing the requested MTU %"PRIu32" to the interface's maximum MTU %"PRIu32".",
-                                 mtu, link->max_mtu);
-                mtu = link->max_mtu;
+                                 mtu, max_mtu);
+                mtu = max_mtu;
         }
 
         if (link->mtu == mtu)
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/nspawn/nspawn.c systemd-252.21/src/nspawn/nspawn.c
--- systemd-252.20/src/nspawn/nspawn.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/nspawn/nspawn.c	2023-12-24 10:01:00.000000000 +0100
@@ -1721,13 +1721,6 @@
 
         arg_caps_retain |= plus;
         arg_caps_retain |= arg_private_network ? UINT64_C(1) << CAP_NET_ADMIN : 0;
-
-        /* If we're not unsharing the network namespace and are unsharing the user namespace, we won't have
-         * permissions to bind ports in the container, so let's drop the CAP_NET_BIND_SERVICE capability to
-         * indicate that. */
-        if (!arg_private_network && arg_userns_mode != USER_NAMESPACE_NO && arg_uid_shift > 0)
-                arg_caps_retain &= ~(UINT64_C(1) << CAP_NET_BIND_SERVICE);
-
         arg_caps_retain &= ~minus;
 
         /* Make sure to parse environment before we reset the settings mask below */
@@ -5487,6 +5480,12 @@
         if (r < 0)
                 goto finish;
 
+        /* If we're not unsharing the network namespace and are unsharing the user namespace, we won't have
+         * permissions to bind ports in the container, so let's drop the CAP_NET_BIND_SERVICE capability to
+         * indicate that. */
+        if (!arg_private_network && arg_userns_mode != USER_NAMESPACE_NO && arg_uid_shift > 0)
+                arg_caps_retain &= ~(UINT64_C(1) << CAP_NET_BIND_SERVICE);
+
         r = cg_unified();
         if (r < 0) {
                 log_error_errno(r, "Failed to determine whether the unified cgroups hierarchy is used: %m");
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/nspawn/nspawn-cgroup.c systemd-252.21/src/nspawn/nspawn-cgroup.c
--- systemd-252.20/src/nspawn/nspawn-cgroup.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/nspawn/nspawn-cgroup.c	2023-12-24 10:01:00.000000000 +0100
@@ -36,6 +36,8 @@
                        "cgroup.stat",
                        "cgroup.subtree_control",
                        "cgroup.threads",
+                       "memory.oom.group",
+                       "memory.reclaim",
                        "notify_on_release",
                        "tasks")
                 if (fchownat(fd, fn, uid_shift, uid_shift, 0) < 0)
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/oom/test-oomd-util.c systemd-252.21/src/oom/test-oomd-util.c
--- systemd-252.20/src/oom/test-oomd-util.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/oom/test-oomd-util.c	2023-12-24 10:01:00.000000000 +0100
@@ -291,19 +291,19 @@
 
 static void test_oomd_mem_and_swap_free_below(void) {
         OomdSystemContext ctx = (OomdSystemContext) {
-                .mem_total = 20971512 * 1024U,
-                .mem_used = 3310136 * 1024U,
-                .swap_total = 20971512 * 1024U,
-                .swap_used = 20971440 * 1024U,
+                .mem_total = UINT64_C(20971512) * 1024U,
+                .mem_used = UINT64_C(3310136) * 1024U,
+                .swap_total = UINT64_C(20971512) * 1024U,
+                .swap_used = UINT64_C(20971440) * 1024U,
         };
         assert_se(oomd_mem_available_below(&ctx, 2000) == false);
         assert_se(oomd_swap_free_below(&ctx, 2000) == true);
 
         ctx = (OomdSystemContext) {
-                .mem_total = 20971512 * 1024U,
-                .mem_used = 20971440 * 1024U,
-                .swap_total = 20971512 * 1024U,
-                .swap_used = 3310136 * 1024U,
+                .mem_total = UINT64_C(20971512) * 1024U,
+                .mem_used = UINT64_C(20971440) * 1024U,
+                .swap_total = UINT64_C(20971512) * 1024U,
+                .swap_used = UINT64_C(3310136) * 1024U,
         };
         assert_se(oomd_mem_available_below(&ctx, 2000) == true);
         assert_se(oomd_swap_free_below(&ctx, 2000) == false);
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/resolve/resolved-dns-scope.c systemd-252.21/src/resolve/resolved-dns-scope.c
--- systemd-252.20/src/resolve/resolved-dns-scope.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/resolve/resolved-dns-scope.c	2023-12-24 10:01:00.000000000 +0100
@@ -1410,6 +1410,14 @@
         if (scope->protocol != DNS_PROTOCOL_MDNS)
                 return 0;
 
+        r = sd_event_get_state(scope->manager->event);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to get event loop state: %m");
+
+        /* If this is called on exit, through manager_free() -> link_free(), then we cannot announce. */
+        if (r == SD_EVENT_FINISHED)
+                return 0;
+
         /* Check if we're done with probing. */
         LIST_FOREACH(transactions_by_scope, t, scope->transactions)
                 if (DNS_TRANSACTION_IS_LIVE(t->state))
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/resolve/resolved-dns-stub.c systemd-252.21/src/resolve/resolved-dns-stub.c
--- systemd-252.20/src/resolve/resolved-dns-stub.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/resolve/resolved-dns-stub.c	2023-12-24 10:01:00.000000000 +0100
@@ -775,7 +775,7 @@
 
                         cname_result = dns_query_process_cname_one(q);
                         if (cname_result == -ELOOP) { /* CNAME loop, let's send what we already have */
-                                log_debug_errno(r, "Detected CNAME loop, returning what we already have.");
+                                log_debug("Detected CNAME loop, returning what we already have.");
                                 (void) dns_stub_send_reply(q, q->answer_rcode);
                                 break;
                         }
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/resolve/resolved-dns-transaction.c systemd-252.21/src/resolve/resolved-dns-transaction.c
--- systemd-252.20/src/resolve/resolved-dns-transaction.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/resolve/resolved-dns-transaction.c	2023-12-24 10:01:00.000000000 +0100
@@ -2817,7 +2817,7 @@
                         if (r == 0)
                                 continue;
 
-                        return FLAGS_SET(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED);
+                        return FLAGS_SET(dt->answer_query_flags, SD_RESOLVED_AUTHENTICATED);
                 }
 
                 return true;
@@ -2844,7 +2844,7 @@
                         /* We found the transaction that was supposed to find the SOA RR for us. It was
                          * successful, but found no RR for us. This means we are not at a zone cut. In this
                          * case, we require authentication if the SOA lookup was authenticated too. */
-                        return FLAGS_SET(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED);
+                        return FLAGS_SET(dt->answer_query_flags, SD_RESOLVED_AUTHENTICATED);
                 }
 
                 return true;
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/shared/bootspec.c systemd-252.21/src/shared/bootspec.c
--- systemd-252.20/src/shared/bootspec.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/shared/bootspec.c	2023-12-24 10:01:00.000000000 +0100
@@ -1270,8 +1270,8 @@
         assert(id);
 
         for (size_t j = 0; j < config->n_entries; j++)
-                if (streq_ptr(config->entries[j].id, id) ||
-                    streq_ptr(config->entries[j].id_old, id))
+                if (strcaseeq_ptr(config->entries[j].id, id) ||
+                    strcaseeq_ptr(config->entries[j].id_old, id))
                         return config->entries + j;
 
         return NULL;
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/shared/cgroup-setup.c systemd-252.21/src/shared/cgroup-setup.c
--- systemd-252.20/src/shared/cgroup-setup.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/shared/cgroup-setup.c	2023-12-24 10:01:00.000000000 +0100
@@ -421,6 +421,8 @@
                 { "cgroup.procs",           true  },
                 { "cgroup.subtree_control", true  },
                 { "cgroup.threads",         false },
+                { "memory.oom.group",       false },
+                { "memory.reclaim",         false },
                 {},
         };
 
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/shared/dissect-image.c systemd-252.21/src/shared/dissect-image.c
--- systemd-252.20/src/shared/dissect-image.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/shared/dissect-image.c	2023-12-24 10:01:00.000000000 +0100
@@ -1644,7 +1644,7 @@
                                 if (r > 0)
                                         ok = true;
                         }
-                        if (!ok && FLAGS_SET(flags, DISSECT_IMAGE_VALIDATE_OS_EXT)) {
+                        if (!ok && FLAGS_SET(flags, DISSECT_IMAGE_VALIDATE_OS_EXT) && m->image_name) {
                                 r = path_is_extension_tree(where, m->image_name, FLAGS_SET(flags, DISSECT_IMAGE_RELAX_SYSEXT_CHECK));
                                 if (r < 0)
                                         return r;
@@ -2887,6 +2887,9 @@
                         switch (k) {
 
                         case META_EXTENSION_RELEASE:
+                                if (!m->image_name)
+                                        goto next;
+
                                 /* As per the os-release spec, if the image is an extension it will have a file
                                  * named after the image name in extension-release.d/ - we use the image name
                                  * and try to resolve it with the extension-release helpers, as sometimes
@@ -2923,7 +2926,7 @@
                                 if (r < 0)
                                         goto inner_fail;
 
-                                continue;
+                                goto next;
                         }
 
                         default:
@@ -2936,14 +2939,14 @@
 
                         if (fd < 0) {
                                 log_debug_errno(fd, "Failed to read %s file of image, ignoring: %m", paths[k]);
-                                fds[2*k+1] = safe_close(fds[2*k+1]);
-                                continue;
+                                goto next;
                         }
 
                         r = copy_bytes(fd, fds[2*k+1], UINT64_MAX, 0);
                         if (r < 0)
                                 goto inner_fail;
 
+                next:
                         fds[2*k+1] = safe_close(fds[2*k+1]);
                 }
 
@@ -3039,18 +3042,25 @@
         r = wait_for_terminate_and_check("(sd-dissect)", child, 0);
         child = 0;
         if (r < 0)
-                return r;
+                goto finish;
 
         n = read(error_pipe[0], &v, sizeof(v));
-        if (n < 0)
-                return -errno;
-        if (n == sizeof(v))
-                return v; /* propagate error sent to us from child */
-        if (n != 0)
-                return -EIO;
-
-        if (r != EXIT_SUCCESS)
-                return -EPROTO;
+        if (n < 0) {
+                r = -errno;
+                goto finish;
+        }
+        if (n == sizeof(v)) {
+                r = v; /* propagate error sent to us from child */
+                goto finish;
+        }
+        if (n != 0) {
+                r = -EIO;
+                goto finish;
+        }
+        if (r != EXIT_SUCCESS) {
+                r = -EPROTO;
+                goto finish;
+        }
 
         free_and_replace(m->hostname, hostname);
         m->machine_id = machine_id;
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/shared/dissect-image.h systemd-252.21/src/shared/dissect-image.h
--- systemd-252.20/src/shared/dissect-image.h	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/shared/dissect-image.h	2023-12-24 10:01:00.000000000 +0100
@@ -230,9 +230,9 @@
         LoopDevice *loop;
         DissectedPartition partitions[_PARTITION_DESIGNATOR_MAX];
         DecryptedImage *decrypted_image;
+        char *image_name;
 
         /* Meta information extracted from /etc/os-release and similar */
-        char *image_name;
         char *hostname;
         sd_id128_t machine_id;
         char **machine_info;
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/shared/fdset.c systemd-252.21/src/shared/fdset.c
--- systemd-252.20/src/shared/fdset.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/shared/fdset.c	2023-12-24 10:01:00.000000000 +0100
@@ -141,8 +141,8 @@
 
         assert(_s);
 
-        /* Creates an fdset and fills in all currently open file
-         * descriptors. */
+        /* Creates an fdset and fills in all currently open file descriptors. Also set all collected fds
+         * to CLOEXEC. */
 
         d = opendir("/proc/self/fd");
         if (!d)
@@ -173,6 +173,7 @@
                         /* If user asked for that filter by O_CLOEXEC. This is useful so that fds that have
                          * been passed in can be collected and fds which have been created locally can be
                          * ignored, under the assumption that only the latter have O_CLOEXEC set. */
+
                         fl = fcntl(fd, F_GETFD);
                         if (fl < 0)
                                 return -errno;
@@ -181,6 +182,13 @@
                                 continue;
                 }
 
+                /* We need to set CLOEXEC manually only if we're collecting non-CLOEXEC fds. */
+                if (filter_cloexec <= 0) {
+                        r = fd_cloexec(fd, true);
+                        if (r < 0)
+                                return r;
+                }
+
                 r = fdset_put(s, fd);
                 if (r < 0)
                         goto finish;
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/shared/killall.c systemd-252.21/src/shared/killall.c
--- systemd-252.20/src/shared/killall.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/shared/killall.c	2023-12-24 10:01:00.000000000 +0100
@@ -63,7 +63,7 @@
                 return false;
 
         if (warn_rootfs &&
-            pid_from_same_root_fs(pid) == 0) {
+            pid_from_same_root_fs(pid) > 0) {
 
                 _cleanup_free_ char *comm = NULL;
 
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/shared/varlink.c systemd-252.21/src/shared/varlink.c
--- systemd-252.20/src/shared/varlink.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/shared/varlink.c	2023-12-24 10:01:00.000000000 +0100
@@ -678,12 +678,25 @@
 }
 
 static int varlink_sanitize_parameters(JsonVariant **v) {
+        int r;
+
         assert(v);
 
         /* Varlink always wants a parameters list, hence make one if the caller doesn't want any */
         if (!*v)
                 return json_variant_new_object(v, NULL, 0);
-        else if (!json_variant_is_object(*v))
+        if (json_variant_is_null(*v)) {
+                JsonVariant *empty;
+
+                r = json_variant_new_object(&empty, NULL, 0);
+                if (r < 0)
+                        return r;
+
+                json_variant_unref(*v);
+                *v = empty;
+                return 0;
+        }
+        if (!json_variant_is_object(*v))
                 return -EINVAL;
 
         return 0;
@@ -723,7 +736,7 @@
                 } else if (streq(k, "parameters")) {
                         if (parameters)
                                 goto invalid;
-                        if (!json_variant_is_object(e))
+                        if (!json_variant_is_object(e) && !json_variant_is_null(e))
                                 goto invalid;
 
                         parameters = json_variant_ref(e);
@@ -822,7 +835,7 @@
                 } else if (streq(k, "parameters")) {
                         if (parameters)
                                 goto invalid;
-                        if (!json_variant_is_object(e))
+                        if (!json_variant_is_object(e) && !json_variant_is_null(e))
                                 goto invalid;
 
                         parameters = json_variant_ref(e);
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/systemctl/systemctl-list-units.c systemd-252.21/src/systemctl/systemctl-list-units.c
--- systemd-252.20/src/systemctl/systemctl-list-units.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/systemctl/systemctl-list-units.c	2023-12-24 10:01:00.000000000 +0100
@@ -208,12 +208,14 @@
 
                 if (arg_all || strv_contains(arg_states, "inactive"))
                         printf("%s%zu loaded units listed.%s\n"
-                               "To show all installed unit files use 'systemctl list-unit-files'.\n",
-                               on, records, off);
+                               "%sTo show all installed unit files use 'systemctl list-unit-files'.%s\n",
+                               on, records, off,
+                               ansi_grey(), ansi_normal());
                 else if (!arg_states)
-                        printf("%s%zu loaded units listed.%s Pass --all to see loaded but inactive units, too.\n"
-                               "To show all installed unit files use 'systemctl list-unit-files'.\n",
-                               on, records, off);
+                        printf("%s%zu loaded units listed.%s %sPass --all to see loaded but inactive units, too.%s\n"
+                               "%sTo show all installed unit files use 'systemctl list-unit-files'.%s\n",
+                               on, records, off,
+                               ansi_grey(), ansi_normal(), ansi_grey(), ansi_normal());
                 else
                         printf("%zu loaded units listed.\n", records);
         }
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/test/test-bootspec.c systemd-252.21/src/test/test-bootspec.c
--- systemd-252.20/src/test/test-bootspec.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/test/test-bootspec.c	2023-12-24 10:01:00.000000000 +0100
@@ -149,4 +149,63 @@
         return 0;
 }
 
+TEST_RET(bootspec_boot_config_find_entry) {
+
+        static const struct {
+                const char *fname;
+                const char *contents;
+        } entries[] = {
+                {
+                        .fname = "a-10.conf",
+                        .contents =
+                        "title A\n"
+                        "version 10\n"
+                        "machine-id dd235d00696545768f6f693bfd23b15f\n",
+                },
+                {
+                        .fname = "a-05.conf",
+                        .contents =
+                        "title A\n"
+                        "version 10\n"
+                        "machine-id dd235d00696545768f6f693bfd23b15f\n",
+                },
+        };
+
+        _cleanup_(rm_rf_physical_and_freep) char *d = NULL;
+        _cleanup_(boot_config_free) BootConfig config = BOOT_CONFIG_NULL;
+
+        assert_se(mkdtemp_malloc("/tmp/bootspec-testXXXXXX", &d) >= 0);
+
+        for (size_t i = 0; i < ELEMENTSOF(entries); i++) {
+                _cleanup_free_ char *j = NULL;
+
+                j = path_join(d, "/loader/entries/", entries[i].fname);
+                assert_se(j);
+
+                assert_se(write_string_file(j, entries[i].contents, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755) >= 0);
+        }
+
+        assert_se(boot_config_load(&config, d, NULL) >= 0);
+        assert_se(config.n_entries == 2);
+
+        // Test finding the first entry
+        BootEntry *entry = boot_config_find_entry(&config, "a-10.conf");
+        assert_se(entry && streq(entry->id, "a-10.conf"));
+
+        // Test finding the second entry
+        entry = boot_config_find_entry(&config, "a-05.conf");
+        assert_se(entry && streq(entry->id, "a-05.conf"));
+
+        // Test finding a non-existent entry
+        entry = boot_config_find_entry(&config, "nonexistent.conf");
+        assert_se(entry == NULL);
+
+        // Test case-insensitivity
+        entry = boot_config_find_entry(&config, "A-10.CONF");
+        assert_se(entry && streq(entry->id, "a-10.conf"));
+
+
+        return 0;
+}
+
 DEFINE_TEST_MAIN(LOG_INFO);
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/test/test-fdset.c systemd-252.21/src/test/test-fdset.c
--- systemd-252.20/src/test/test-fdset.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/test/test-fdset.c	2023-12-24 10:01:00.000000000 +0100
@@ -11,8 +11,8 @@
 #include "util.h"
 
 TEST(fdset_new_fill) {
-        int fd = -1;
         _cleanup_fdset_free_ FDSet *fdset = NULL;
+        int fd = -1, flags;
 
         log_close();
         log_set_open_when_needed(true);
@@ -50,6 +50,9 @@
 
         assert_se(fdset_new_fill(/* filter_cloexec= */ 0, &fdset) >= 0);
         assert_se(fdset_contains(fdset, fd));
+        flags = fcntl(fd, F_GETFD);
+        assert_se(flags >= 0);
+        assert_se(FLAGS_SET(flags, FD_CLOEXEC));
         fdset = fdset_free(fdset);
         assert_se(fcntl(fd, F_GETFD) < 0);
         assert_se(errno == EBADF);
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/test/test-parse-util.c systemd-252.21/src/test/test-parse-util.c
--- systemd-252.20/src/test/test-parse-util.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/test/test-parse-util.c	2023-12-24 10:01:00.000000000 +0100
@@ -875,15 +875,30 @@
         assert_se(parse_mtu(AF_UNSPEC, "4294967295", &mtu) >= 0 && mtu == 4294967295);
         assert_se(parse_mtu(AF_UNSPEC, "500", &mtu) >= 0 && mtu == 500);
         assert_se(parse_mtu(AF_UNSPEC, "1280", &mtu) >= 0 && mtu == 1280);
+        assert_se(parse_mtu(AF_UNSPEC, "4294967296", &mtu) == -ERANGE);
+        assert_se(parse_mtu(AF_UNSPEC, "68", &mtu) >= 0 && mtu == 68);
+        assert_se(parse_mtu(AF_UNSPEC, "67", &mtu) >= 0 && mtu == 67);
+        assert_se(parse_mtu(AF_UNSPEC, "0", &mtu) >= 0 && mtu == 0);
+        assert_se(parse_mtu(AF_UNSPEC, "", &mtu) == -EINVAL);
+
+        assert_se(parse_mtu(AF_INET, "1500", &mtu) >= 0 && mtu == 1500);
+        assert_se(parse_mtu(AF_INET, "1400", &mtu) >= 0 && mtu == 1400);
+        assert_se(parse_mtu(AF_INET, "65535", &mtu) >= 0 && mtu == 65535);
+        assert_se(parse_mtu(AF_INET, "65536", &mtu) >= 0 && mtu == 65536);
+        assert_se(parse_mtu(AF_INET, "4294967295", &mtu) >= 0 && mtu == 4294967295);
+        assert_se(parse_mtu(AF_INET, "500", &mtu) >= 0 && mtu == 500);
+        assert_se(parse_mtu(AF_INET, "1280", &mtu) >= 0 && mtu == 1280);
+        assert_se(parse_mtu(AF_INET, "4294967296", &mtu) == -ERANGE);
+        assert_se(parse_mtu(AF_INET, "68", &mtu) >= 0 && mtu == 68);
+        assert_se(parse_mtu(AF_INET, "67", &mtu) == -ERANGE);
+        assert_se(parse_mtu(AF_INET, "0", &mtu) == -ERANGE);
+        assert_se(parse_mtu(AF_INET, "", &mtu) == -EINVAL);
+
         assert_se(parse_mtu(AF_INET6, "1280", &mtu) >= 0 && mtu == 1280);
         assert_se(parse_mtu(AF_INET6, "1279", &mtu) == -ERANGE);
-        assert_se(parse_mtu(AF_UNSPEC, "4294967296", &mtu) == -ERANGE);
         assert_se(parse_mtu(AF_INET6, "4294967296", &mtu) == -ERANGE);
         assert_se(parse_mtu(AF_INET6, "68", &mtu) == -ERANGE);
-        assert_se(parse_mtu(AF_UNSPEC, "68", &mtu) >= 0 && mtu == 68);
-        assert_se(parse_mtu(AF_UNSPEC, "67", &mtu) == -ERANGE);
-        assert_se(parse_mtu(AF_UNSPEC, "0", &mtu) == -ERANGE);
-        assert_se(parse_mtu(AF_UNSPEC, "", &mtu) == -EINVAL);
+        assert_se(parse_mtu(AF_INET6, "", &mtu) == -EINVAL);
 }
 
 TEST(parse_loadavg_fixed_point) {
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/src/userdb/userdbd-manager.c systemd-252.21/src/userdb/userdbd-manager.c
--- systemd-252.20/src/userdb/userdbd-manager.c	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/src/userdb/userdbd-manager.c	2023-12-24 10:01:00.000000000 +0100
@@ -132,6 +132,8 @@
         sd_event_source_disable_unref(m->sigusr2_event_source);
         sd_event_source_disable_unref(m->sigchld_event_source);
 
+        safe_close(m->listen_fd);
+
         sd_event_unref(m->event);
 
         return mfree(m);
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/test/test-functions systemd-252.21/test/test-functions
--- systemd-252.20/test/test-functions	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/test/test-functions	2023-12-24 10:01:00.000000000 +0100
@@ -1077,26 +1077,34 @@
 }
 
 install_lvm() {
+    local lvm_rules rule_prefix
+
     image_install lvm
     image_install "${ROOTLIBDIR:?}"/system/lvm2-lvmpolld.{service,socket}
     image_install "${ROOTLIBDIR:?}"/system/{blk-availability,lvm2-monitor}.service
     image_install -o "/lib/tmpfiles.d/lvm2.conf"
+
     if get_bool "$LOOKS_LIKE_DEBIAN"; then
-        inst_rules 56-lvm.rules 69-lvm-metad.rules
+        lvm_rules="56-lvm.rules"
+        rule_prefix=""
+    else
+        lvm_rules="11-dm-lvm.rules"
+        rule_prefix="dm-"
+    fi
+
+    # Support the new udev autoactivation introduced in lvm 2.03.14
+    # https://sourceware.org/git/?p=lvm2.git;a=commit;h=67722b312390cdab29c076c912e14bd739c5c0f6
+    # Static autoactivation (via lvm2-activation-generator) was dropped
+    # in lvm 2.03.15
+    # https://sourceware.org/git/?p=lvm2.git;a=commit;h=ee8fb0310c53ed003a43b324c99cdfd891dd1a7c
+    if [[ -f "/lib/udev/rules.d/69-${rule_prefix}lvm.rules" ]]; then
+        inst_rules "$lvm_rules" "69-${rule_prefix}lvm.rules"
     else
-        # Support the new udev autoactivation introduced in lvm 2.03.14
-        # https://sourceware.org/git/?p=lvm2.git;a=commit;h=67722b312390cdab29c076c912e14bd739c5c0f6
-        # Static autoactivation (via lvm2-activation-generator) was dropped
-        # in lvm 2.03.15
-        # https://sourceware.org/git/?p=lvm2.git;a=commit;h=ee8fb0310c53ed003a43b324c99cdfd891dd1a7c
-        if [[ -f /lib/udev/rules.d/69-dm-lvm.rules ]]; then
-            inst_rules 11-dm-lvm.rules 69-dm-lvm.rules
-        else
-            image_install "${ROOTLIBDIR:?}"/system-generators/lvm2-activation-generator
-            image_install "${ROOTLIBDIR:?}"/system/lvm2-pvscan@.service
-            inst_rules 11-dm-lvm.rules 69-dm-lvm-metad.rules
-        fi
+        image_install "${ROOTLIBDIR:?}"/system-generators/lvm2-activation-generator
+        image_install "${ROOTLIBDIR:?}"/system/lvm2-pvscan@.service
+        inst_rules "$lvm_rules" "69-${rule_prefix}lvm-metad.rules"
     fi
+
     mkdir -p "${initdir:?}/etc/lvm"
 }
 
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/test/test-network/conf/25-route-static.network systemd-252.21/test/test-network/conf/25-route-static.network
--- systemd-252.20/test/test-network/conf/25-route-static.network	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/test/test-network/conf/25-route-static.network	2023-12-24 10:01:00.000000000 +0100
@@ -98,3 +98,10 @@
 Destination=192.168.10.2/32
 MultiPathRoute=2001:1234:5:8fff:ff:ff:ff:ff@dummy98 10
 MultiPathRoute=2001:1234:5:9fff:ff:ff:ff:ff@dummy98 5
+
+[Address]
+Address=1.1.8.105/31
+Peer=1.1.8.104/31
+
+[Route]
+Gateway=1.1.8.104
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/test/test-network/conf/25-vcan98.netdev systemd-252.21/test/test-network/conf/25-vcan98.netdev
--- systemd-252.20/test/test-network/conf/25-vcan98.netdev	1970-01-01 01:00:00.000000000 +0100
+++ systemd-252.21/test/test-network/conf/25-vcan98.netdev	2023-12-24 10:01:00.000000000 +0100
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[NetDev]
+Name=vcan98
+Kind=vcan
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/test/test-network/conf/25-vcan98.network systemd-252.21/test/test-network/conf/25-vcan98.network
--- systemd-252.20/test/test-network/conf/25-vcan98.network	1970-01-01 01:00:00.000000000 +0100
+++ systemd-252.21/test/test-network/conf/25-vcan98.network	2023-12-24 10:01:00.000000000 +0100
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=vcan98
+
+[Link]
+MTUBytes=16
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/test/test-network/conf/25-vcan.netdev systemd-252.21/test/test-network/conf/25-vcan.netdev
--- systemd-252.20/test/test-network/conf/25-vcan.netdev	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/test/test-network/conf/25-vcan.netdev	2023-12-24 10:01:00.000000000 +0100
@@ -2,3 +2,4 @@
 [NetDev]
 Name=vcan99
 Kind=vcan
+MTUBytes=16
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/test/test-network/systemd-networkd-tests.py systemd-252.21/test/test-network/systemd-networkd-tests.py
--- systemd-252.20/test/test-network/systemd-networkd-tests.py	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/test/test-network/systemd-networkd-tests.py	2023-12-24 10:01:00.000000000 +0100
@@ -1520,10 +1520,20 @@
 
     @expectedFailureIfModuleIsNotAvailable('vcan')
     def test_vcan(self):
-        copy_network_unit('25-vcan.netdev', '26-netdev-link-local-addressing-yes.network')
+        copy_network_unit('25-vcan.netdev', '26-netdev-link-local-addressing-yes.network',
+                          '25-vcan98.netdev', '25-vcan98.network')
         start_networkd()
 
-        self.wait_online(['vcan99:carrier'])
+        self.wait_online(['vcan99:carrier', 'vcan98:carrier'])
+
+        # https://github.com/systemd/systemd/issues/30140
+        output = check_output('ip -d link show vcan99')
+        print(output)
+        self.assertIn('mtu 16 ', output)
+
+        output = check_output('ip -d link show vcan98')
+        print(output)
+        self.assertIn('mtu 16 ', output)
 
     @expectedFailureIfModuleIsNotAvailable('vxcan')
     def test_vxcan(self):
@@ -2674,6 +2684,7 @@
         self.assertIn('default via 149.10.125.65 proto static onlink', output)
         self.assertIn('default via 149.10.124.64 proto static', output)
         self.assertIn('default proto static', output)
+        self.assertIn('default via 1.1.8.104 proto static', output)
 
         print('### ip -4 route show table local dev dummy98')
         output = check_output('ip -4 route show table local dev dummy98')
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/test/test-network-generator-conversion.sh systemd-252.21/test/test-network-generator-conversion.sh
--- systemd-252.20/test/test-network-generator-conversion.sh	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/test/test-network-generator-conversion.sh	2023-12-24 10:01:00.000000000 +0100
@@ -1,33 +1,300 @@
 #!/usr/bin/env bash
 # SPDX-License-Identifier: LGPL-2.1-or-later
-set -ex
+# shellcheck disable=SC2235
+set -eux
+set -o pipefail
 
-if [[ -n "$1" ]]; then
-    generator=$1
+# TODO/FIXME:
+#   - we should probably have something like "udevadm verify" but for .network files
+#     (networkctl verify?) so we can check that all directives are in correct sections
+#   - according to dracut.cmdline(7) <peer> address can also be followed by /CIDR,
+#     but this doesn't seem to work with sd-network-generator
+
+if [[ -n "${1:-}" ]]; then
+    GENERATOR_BIN=$1
 elif [[ -x /usr/lib/systemd/systemd-network-generator ]]; then
-    generator=/usr/lib/systemd/systemd-network-generator
+    GENERATOR_BIN=/usr/lib/systemd/systemd-network-generator
 elif [[ -x /lib/systemd/systemd-network-generator ]]; then
-    generator=/lib/systemd/systemd-network-generator
+    GENERATOR_BIN=/lib/systemd/systemd-network-generator
 else
     exit 1
 fi
 
-src="$(dirname "$0")/testdata/test-network-generator-conversion"
+# See: https://github.com/systemd/systemd/pull/29888#issuecomment-1796187440
+unset NOTIFY_SOCKET
+
+WORK_DIR="$(mktemp --directory --tmpdir "test-network-generator-conversion.XXXXXX")"
+# shellcheck disable=SC2064
+trap "rm -rf '$WORK_DIR'" EXIT
+
+# Convert octal netmask to CIDR notation (e.g. 255.255.255.0 => 24)
+netmask_to_cidr() (
+    set +x
+
+    local netmask="${1:?}"
+    local x bits=0
+
+    # shellcheck disable=SC2086
+    x="0$(printf "%o" ${netmask//./ })"
+    while [[ "$x" -gt 0 ]]; do
+        ((bits += x % 2))
+        ((x >>= 1))
+    done
+
+    echo "$bits"
+)
+
+run_network_generator() {
+    local stderr
+
+    rm -rf "${WORK_DIR:?}"/*
+    stderr="$WORK_DIR/stderr"
+    if ! "$GENERATOR_BIN" --root "$WORK_DIR" 2>"$stderr"; then
+        echo >&2 "Generator failed when parsing $SYSTEMD_PROC_CMDLINE"
+        cat "$stderr"
+        return 1
+    fi
+
+    if [[ -s "$stderr" ]]; then
+        echo >&2 "Generator generated unexpected messages on stderr"
+        cat "$stderr"
+        return 1
+    fi
+
+    ls -l "$WORK_DIR/run/systemd/network/"
+
+    rm -f "$stderr"
+    return 0
+}
+
+check_dhcp() {
+    local dhcp="${1:?}"
+    local network_file="${2:?}"
+
+    case "$dhcp" in
+        dhcp)
+            grep -q "^DHCP=ipv4$" "$network_file"
+            ;;
+        dhcp6)
+            grep -q "^DHCP=ipv6$" "$network_file"
+            ;;
+        on|any)
+            grep -q "^DHCP=yes$" "$network_file"
+            ;;
+        none|off)
+            grep -q "^DHCP=no$" "$network_file"
+            ;;
+        auto6|ibft)
+            grep -q "^DHCP=no$" "$network_file"
+            ;;
+        either6)
+            grep -q "^DHCP=ipv6$" "$network_file"
+            ;;
+        link6)
+            grep -q "^DHCP=no$" "$network_file"
+            ;;
+        *)
+            echo >&2 "Invalid assignment $cmdline"
+            return 1
+    esac
+
+    return 0
+}
+
+# Check the shortest ip= variant, i.e.:
+#   ip={dhcp|on|any|dhcp6|auto6|either6|link6}
+#
+# Note:
+#   - dracut also supports single-dhcp
+check_one_dhcp() {
+    local cmdline="${1:?}"
+    local dhcp="${cmdline#ip=}"
+    local network_file
+
+    SYSTEMD_LOG_LEVEL=debug SYSTEMD_PROC_CMDLINE="$cmdline" run_network_generator
+    network_file="${WORK_DIR:?}/run/systemd/network/91-default.network"
+    cat "$network_file"
+
+    check_dhcp "$dhcp" "$network_file"
+
+    return 0
+}
+
+# Similar to the previous one, but with slightly more fields:
+#   ip=<interface>:{dhcp|on|any|dhcp6|auto6|link6}[:[<mtu>][:<macaddr>]]
+#
+# Same notes apply as well.
+check_one_interface_dhcp() {
+    local cmdline="${1:?}"
+    local ifname dhcp mtu mac network_file
+
+    IFS=":" read -r ifname dhcp mtu mac <<< "${cmdline#ip=}"
+
+    SYSTEMD_LOG_LEVEL=debug SYSTEMD_PROC_CMDLINE="$cmdline" run_network_generator
+    network_file="${WORK_DIR:?}/run/systemd/network/90-$ifname.network"
+    cat "$network_file"
+
+    grep -q "^Name=$ifname$" "$network_file"
+    check_dhcp "$dhcp" "$network_file"
+    [[ -n "$mtu" ]] && grep -q "^MTUBytes=$mtu$" "$network_file"
+    [[ -n "$mac" ]] && grep -q "^MACAddress=$mac$" "$network_file"
 
-for f in "$src"/test-*.input; do
-    echo "*** Running $f"
+    return 0
+}
 
-    (
-        out=$(mktemp --tmpdir --directory "test-network-generator-conversion.XXXXXXXXXX")
-        # shellcheck disable=SC2064
-        trap "rm -rf '$out'" EXIT INT QUIT PIPE
-
-        # shellcheck disable=SC2046
-        $generator --root "$out" -- $(cat "$f")
-
-        if ! diff -u "$out/run/systemd/network" "${f%.input}.expected"; then
-            echo "**** Unexpected output for $f"
-            exit 1
+# Check the "long" ip= formats, i.e:
+#   ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|ibft}[:[<mtu>][:<macaddr>]
+#   ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|ibft}[:[<dns1>][:<dns2>]]
+check_one_long() {
+    local cmdline="${1:?}"
+    local ip peer gateway netmask hostname ifname dhcp arg1 arg2 network_file cidr stderr tmp
+
+    # To make parsing a bit easier when IPv6 is involved, replace all colons between [] with #, ...
+    tmp="$(echo "${cmdline#ip=}" | sed -re ':l; s/(\[[^]:]*):/\1#/; tl')"
+    # ... drop the now unnecessary [] and split the string into colon separated fields as usual, ...
+    IFS=":" read -r ip peer gateway netmask hostname ifname dhcp arg1 arg2 <<<"${tmp//[\[\]]}"
+    # ... and then replace # back to colons for fields that might contain an IPv6 address.
+    ip="${ip//#/:}"
+    peer="${peer//#/:}"
+    gateway="${gateway//#/:}"
+    arg1="${arg1//#/:}"
+    arg2="${arg2//#/:}"
+
+    SYSTEMD_LOG_LEVEL=debug SYSTEMD_PROC_CMDLINE="$cmdline" run_network_generator
+
+    if [[ -n "$ifname" ]]; then
+        network_file="${WORK_DIR:?}/run/systemd/network/90-$ifname.network"
+        grep -q "^Name=$ifname$" "$network_file"
+    else
+        network_file="${WORK_DIR:?}/run/systemd/network/91-default.network"
+        grep -q "^Kind=!\*$" "$network_file"
+    fi
+
+    cat "$network_file"
+
+    if [[ -n "$ip" && -n "$netmask" ]]; then
+        # The "ip" and "netmask" fields are merged together into an IP/CIDR value
+        if [[ "$netmask" =~ ^[0-9]+$ ]]; then
+            cidr="$netmask"
+        else
+            cidr="$(netmask_to_cidr "$netmask")"
         fi
-    ) || exit 1
+
+        grep -q "^Address=$ip/$cidr$" "$network_file"
+    else
+        (! grep -q "^Address=" "$network_file")
+    fi
+    # If the "dhcp" field is empty, it defaults to "off"
+    [[ -z "$dhcp" ]] && dhcp="off"
+    [[ -n "$peer" ]] && grep -q "^Peer=$peer$" "$network_file"
+    [[ -n "$gateway" ]] && grep -q "^Gateway=$gateway$" "$network_file"
+    [[ -n "$hostname" ]] && grep -q "^Hostname=$hostname$" "$network_file"
+    check_dhcp "$dhcp" "$network_file"
+
+    # If the first optional argument is empty, assume the first variant
+    # See: https://github.com/dracutdevs/dracut/blob/4d594210d6ef4f04a9dbadacea73e9461ded352d/modules.d/40network/net-lib.sh#L533
+    if [[ -z "$arg1" || "$arg1" =~ ^[0-9]+$ ]]; then
+        # => [:[<mtu>][:<macaddr>]
+        [[ -n "$arg1" ]] && grep -q "^MTUBytes=$arg1$" "$network_file"
+        [[ -n "$arg2" ]] && grep -q "^MACAddress=$arg2$" "$network_file"
+    else
+        # => [:[<dns1>][:<dns2>]]
+        grep -q "^DNS=$arg1$" "$network_file"
+        [[ -n "$arg2" ]] && grep -q "^DNS=$arg2$" "$network_file"
+    fi
+
+    return 0
+}
+
+# Check if the generated .network files match the expected stored ones
+TEST_DATA="$(dirname "$0")/testdata/test-network-generator-conversion"
+for f in "$TEST_DATA"/test-*.input; do
+    fname="${f##*/}"
+    out="$(mktemp --directory "${WORK_DIR:?}/${fname%%.input}.XXX")"
+
+    # shellcheck disable=SC2046
+    "$GENERATOR_BIN" --root "$out" -- $(cat "$f")
+
+    if ! diff -u "$out/run/systemd/network" "${f%.input}.expected"; then
+        echo "**** Unexpected output for $f"
+        exit 1
+    fi
+
+    rm -rf "${out:?}"
+done
+
+# Now generate bunch of .network units on the fly and check if they contain expected
+# directives & values
+
+# ip={dhcp|on|any|dhcp6|auto6|either6|link6}
+for dhcp in dhcp on any dhcp6 auto6 either6 link6 off none ibft; do
+    check_one_dhcp "ip=$dhcp"
+done
+
+# ip=<interface>:{dhcp|on|any|dhcp6|auto6|link6}[:[<mtu>][:<macaddr>]]
+COMMAND_LINES=(
+    "ip=foo:dhcp"
+    "ip=bar:dhcp6"
+    "ip=baz1:any:666"
+    "ip=baz1:any:128:52:54:00:a7:8f:ac"
+)
+for cmdline in "${COMMAND_LINES[@]}"; do
+    check_one_interface_dhcp "$cmdline"
+done
+
+# ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|ibft}[:[<mtu>][:<macaddr>]
+# ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|ibft}[:[<dns1>][:<dns2>]]
+COMMAND_LINES=(
+    "ip=1.2.3.4:2.3.4.5:1.2.3.1:255.255.255.0:hello-world.local:dummy99:off"
+    "ip=1.2.3.4:2.3.4.5:1.2.3.1:24:hello-world.local:dummy99:off"
+    "ip=1.2.3.4:2.3.4.5:1.2.3.1:255.255.255.0:hello-world.local:dummy99:off:123"
+    "ip=1.2.3.4:2.3.4.5:1.2.3.1:255.255.255.0:hello-world.local:dummy99:off:123:52:54:00:a7:8f:ac"
+    "ip=1.2.3.4:2.3.4.5:1.2.3.1:255.255.255.0:hello-world.local:dummy99:off::52:54:00:a7:8f:ac"
+    "ip=1.2.3.4:2.3.4.5:1.2.3.1:255.255.255.0:hello-world.local:dummy99:off::"
+    "ip=1.2.3.4:2.3.4.5:1.2.3.1:255.255.255.0:hello-world.local:dummy99:off:1.2.3.2"
+    "ip=1.2.3.4:2.3.4.5:1.2.3.1:255.255.255.0:hello-world.local:dummy99:off:1.2.3.2:1.2.3.3"
+    "ip=192.168.0.2::192.168.0.1:255.255.128.0::foo1:off"
+    "ip=192.168.0.2::192.168.0.1:17::foo1:off"
+    "ip=10.0.0.1:::255.255.255.0::foo99:off"
+    "ip=[fdef:c400:bd01:1096::2]::[fdef:c400:bd01:1096::1]:64::ipv6:off"
+    "ip=[fdef:c400:bd01:1096::2]:[fdef:c400:bd01:1096::99]::64::ipv6:off"
+    "ip=[fdef:c400:bd01:1096::2]::[fdef:c400:bd01:1096::1]:64::ipv6:off:666"
+    "ip=[fdef:c400:bd01:1096::2]::[fdef:c400:bd01:1096::1]:64::ipv6:off:666:52:54:00:a7:8f:ac"
+    "ip=[fdef:c400:bd01:1096::2]::[fdef:c400:bd01:1096::1]:64::ipv6:off::52:54:00:a7:8f:ac"
+    "ip=[fdef:c400:bd01:1096::2]::[fdef:c400:bd01:1096::1]:64::ipv6:off::"
+    "ip=[fdef:c400:bd01:1096::2]::[fdef:c400:bd01:1096::1]:64::ipv6:off:[fdef:c400:bd01:1096::aaaa]"
+    "ip=[fdef:c400:bd01:1096::2]::[fdef:c400:bd01:1096::1]:64::ipv6:off:[fdef:c400:bd01:1096::aaaa]:[fdef:c400:bd01:1096::bbbb]"
+    "ip=:::::dhcp99:any"
+    "ip=:::::dhcp99:dhcp6:666"
+    "ip=:::::dhcp99:dhcp6:666:52:54:00:a7:8f:ac"
+    "ip=:::::dhcp99:dhcp6:10.0.0.128"
+    "ip=:::::dhcp99:dhcp6:10.0.0.128:10.0.0.129"
+    "ip=:::::dhcp99:dhcp6:10.0.0.128:[fdef:c400:bd01:1096::bbbb]"
+    "ip=::::::any"
+    "ip=::::::ibft"
+)
+for cmdline in "${COMMAND_LINES[@]}"; do
+    check_one_long "$cmdline"
+done
+
+INVALID_COMMAND_LINES=(
+    "ip=foo"
+    "ip=:::::::"
+    "ip=:::::::foo"
+    "ip=10.0.0:::255.255.255.0::foo99:off"
+    "ip=10.0.0.1:::255.255.255::foo99:off"
+    "ip=10.0.0.1:::255.255.255.0:invalid_hostname:foo99:off"
+    "ip=10.0.0.1:::255.255.255.0::verylonginterfacename:off"
+    "ip=:::::dhcp99:dhcp6:4294967296"
+    "ip=:::::dhcp99:dhcp6:-1"
+    "ip=:::::dhcp99:dhcp6:666:52:54:00"
+    "ip=fdef:c400:bd01:1096::2::[fdef:c400:bd01:1096::1]:64::ipv6:off:[fdef:c400:bd01:1096::aaaa]"
+    "ip=[fdef:c400:bd01:1096::2]::[fdef:c400:bd01:1096::1]:64::ipv6:off:foo"
+    "ip=[fdef:c400:bd01:1096::2]::[fdef:c400:bd01:1096::1]:64::ipv6:off:[fdef:c400:bd01:1096::aaaa]:foo"
+    "ip=[fdef:c400:bd01:1096::2]::[fdef:c400:bd01:1096::1]:64::ipv6:off:[fdef:c400:bd01:1096::aaaa]:[fdef:c400:bd01:1096::bbbb]:"
+    "ip=:::::dhcp99:dhcp6:10.0.0.128:10.0.0.129:"
+    "ip=:::::dhcp99:dhcp6:10.0.0.128:[fdef:c400:bd01:1096::bbbb]:"
+)
+for cmdline in "${INVALID_COMMAND_LINES[@]}"; do
+    (! SYSTEMD_LOG_LEVEL=debug SYSTEMD_PROC_CMDLINE="$cmdline" "$GENERATOR_BIN" --root "$WORK_DIR")
 done
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/test/units/testsuite-17.03.sh systemd-252.21/test/units/testsuite-17.03.sh
--- systemd-252.20/test/units/testsuite-17.03.sh	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/test/units/testsuite-17.03.sh	2023-12-24 10:01:00.000000000 +0100
@@ -2,17 +2,18 @@
 # SPDX-License-Identifier: LGPL-2.1-or-later
 set -ex
 
-test_rule="/run/udev/rules.d/49-test.rules"
+TEST_RULE="/run/udev/rules.d/49-test.rules"
 KILL_PID=
 
 setup() {
-    mkdir -p "${test_rule%/*}"
-    cp -f /etc/udev/udev.conf /etc/udev/udev.conf.bckp
-    cat >"${test_rule}" <<EOF
+    mkdir -p "${TEST_RULE%/*}"
+    [[ -e /etc/udev/udev.conf ]] && cp -f /etc/udev/udev.conf /etc/udev/udev.conf.bak
+
+    cat >"${TEST_RULE}" <<EOF
 ACTION=="add", SUBSYSTEM=="mem", KERNEL=="null", OPTIONS="log_level=debug"
 ACTION=="add", SUBSYSTEM=="mem", KERNEL=="null", PROGRAM=="/bin/sleep 60"
 EOF
-    cat >>/etc/udev/udev.conf <<EOF
+    cat >/etc/udev/udev.conf <<EOF
 event_timeout=10
 timeout_signal=SIGABRT
 EOF
@@ -28,9 +29,8 @@
     fi
 
     rm -rf "$TMPDIR"
-
-    mv -f /etc/udev/udev.conf.bckp /etc/udev/udev.conf
-    rm -f "$test_rule"
+    rm -f "$TEST_RULE"
+    [[ -e /etc/udev/udev.conf.bak ]] && mv -f /etc/udev/udev.conf.bak /etc/udev/udev.conf
     systemctl restart systemd-udevd.service
 }
 
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/test/units/testsuite-17.06.sh systemd-252.21/test/units/testsuite-17.06.sh
--- systemd-252.20/test/units/testsuite-17.06.sh	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/test/units/testsuite-17.06.sh	2023-12-24 10:01:00.000000000 +0100
@@ -64,5 +64,6 @@
 rm /run/udev/rules.d/50-testsuite.rules
 
 udevadm control --reload
+systemctl reset-failed systemd-udevd.service
 
 exit 0
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/test/units/testsuite-64.sh systemd-252.21/test/units/testsuite-64.sh
--- systemd-252.20/test/units/testsuite-64.sh	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/test/units/testsuite-64.sh	2023-12-24 10:01:00.000000000 +0100
@@ -988,6 +988,10 @@
 
 : >/failed
 
+# Disable the mdmonitor service, since it fails if there's no valid email address
+# configured in /etc/mdadm.conf, which just unnecessarily pollutes the logs
+systemctl list-unit-files mdmonitor.service >/dev/null && systemctl mask --runtime mdmonitor.service
+
 udevadm settle
 udevadm control --log-level debug
 lsblk -a
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/test/units/testsuite-65.sh systemd-252.21/test/units/testsuite-65.sh
--- systemd-252.20/test/units/testsuite-65.sh	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/test/units/testsuite-65.sh	2023-12-24 10:01:00.000000000 +0100
@@ -285,6 +285,44 @@
 # Verifies that the --offline= option works with --root=
 systemd-analyze security --threshold=90 --offline=true --root=/tmp/img/ testfile.service
 
+cat <<EOF >/tmp/foo@.service
+[Service]
+ExecStart=ls
+EOF
+
+cat <<EOF >/tmp/hoge@test.service
+[Service]
+ExecStart=ls
+EOF
+
+# issue #30357
+pushd /tmp
+systemd-analyze verify foo@bar.service
+systemd-analyze verify foo@.service
+systemd-analyze verify hoge@test.service
+(! systemd-analyze verify hoge@nonexist.service)
+(! systemd-analyze verify hoge@.service)
+popd
+pushd /
+systemd-analyze verify tmp/foo@bar.service
+systemd-analyze verify tmp/foo@.service
+systemd-analyze verify tmp/hoge@test.service
+(! systemd-analyze verify tmp/hoge@nonexist.service)
+(! systemd-analyze verify tmp/hoge@.service)
+popd
+pushd /usr
+systemd-analyze verify ../tmp/foo@bar.service
+systemd-analyze verify ../tmp/foo@.service
+systemd-analyze verify ../tmp/hoge@test.service
+(! systemd-analyze verify ../tmp/hoge@nonexist.service)
+(! systemd-analyze verify ../tmp/hoge@.service)
+popd
+systemd-analyze verify /tmp/foo@bar.service
+systemd-analyze verify /tmp/foo@.service
+systemd-analyze verify /tmp/hoge@test.service
+(! systemd-analyze verify /tmp/hoge@nonexist.service)
+(! systemd-analyze verify /tmp/hoge@.service)
+
 # Added an additional "INVALID_ID" id to the .json to verify that nothing breaks when input is malformed
 # The PrivateNetwork id description and weight was changed to verify that 'security' is actually reading in
 # values from the .json file when required. The default weight for "PrivateNetwork" is 2500, and the new weight
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/tmpfiles.d/systemd-nologin.conf systemd-252.21/tmpfiles.d/systemd-nologin.conf
--- systemd-252.20/tmpfiles.d/systemd-nologin.conf	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/tmpfiles.d/systemd-nologin.conf	2023-12-24 10:01:00.000000000 +0100
@@ -7,4 +7,4 @@
 
 # See tmpfiles.d(5), systemd-user-sessions.service(8) and pam_nologin(8).
 
-F! /run/nologin 0644 - - - "System is booting up. Unprivileged users are not permitted to log in yet. Please come back later. For technical details, see pam_nologin(8)."
+f+! /run/nologin 0644 - - - "System is booting up. Unprivileged users are not permitted to log in yet. Please come back later. For technical details, see pam_nologin(8)."
diff -Nru --exclude pnp_id_registry.html --exclude acpi_id_registry.html --exclude parse_hwdb.py --exclude acpi_id_registry.csv --exclude pnp_id_registry.csv --exclude usb.ids --exclude pci.ids --exclude ma-large.txt --exclude ma-medium.txt --exclude ma-small.txt --exclude '*hwdb.patch' --exclude '*hwdb' systemd-252.20/units/systemd-binfmt.service.in systemd-252.21/units/systemd-binfmt.service.in
--- systemd-252.20/units/systemd-binfmt.service.in	2023-12-06 21:35:33.000000000 +0100
+++ systemd-252.21/units/systemd-binfmt.service.in	2023-12-24 10:01:00.000000000 +0100
@@ -18,7 +18,7 @@
 After=proc-sys-fs-binfmt_misc.mount
 After=local-fs.target
 Before=sysinit.target shutdown.target
-ConditionPathIsReadWrite=/proc/sys/
+ConditionPathIsMountPoint=/proc/sys/fs/binfmt_misc
 ConditionDirectoryNotEmpty=|/lib/binfmt.d
 ConditionDirectoryNotEmpty=|/usr/lib/binfmt.d
 ConditionDirectoryNotEmpty=|/usr/local/lib/binfmt.d

Attachment: signature.asc
Description: This is a digitally signed message part


Reply to: