diff --git a/SOURCES/0435-cgroup-freezer-action-must-be-NOP-when-cgroup-v2-fre.patch b/SOURCES/0435-cgroup-freezer-action-must-be-NOP-when-cgroup-v2-fre.patch
new file mode 100644
index 0000000..04c1355
--- /dev/null
+++ b/SOURCES/0435-cgroup-freezer-action-must-be-NOP-when-cgroup-v2-fre.patch
@@ -0,0 +1,48 @@
+From 45d093a37b6f8c2ceae9bfd090c5265f35413b46 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20Sekleta=CC=81r?= <msekleta@redhat.com>
+Date: Tue, 8 Sep 2020 14:51:39 +0200
+Subject: [PATCH] cgroup: freezer action must be NOP when cgroup v2 freezer is
+ not available
+
+Low-level cgroup freezer state manipulation is invoked directly from the
+job engine when we are about to execute the job in order to make sure
+the unit is not frozen and job execution is not blocked because of
+that.
+
+Currently with cgroup v1 we would needlessly do a bunch of work in the
+function and even falsely update the freezer state. Don't do any of this
+and skip the function silently when v2 freezer is not available.
+
+Following bug is fixed by this commit,
+
+$ systemd-run --unit foo.service /bin/sleep infinity
+$ systemctl restart foo.service
+$ systemctl show -p FreezerState foo.service
+
+Before (cgroup v1, i.e. full "legacy" mode):
+FreezerState=thawing
+
+After:
+FreezerState=running
+
+(cherry picked from commit 9a1e90aee556b7a30d87553a891a4175ae77ed68)
+
+Resolves: #1868831
+---
+ src/core/cgroup.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/core/cgroup.c b/src/core/cgroup.c
+index e0eb184fd2..f1ce070f9a 100644
+--- a/src/core/cgroup.c
++++ b/src/core/cgroup.c
+@@ -2936,6 +2936,9 @@ int unit_cgroup_freezer_action(Unit *u, FreezerAction action) {
+         assert(u);
+         assert(IN_SET(action, FREEZER_FREEZE, FREEZER_THAW));
+ 
++        if (!cg_freezer_supported())
++                return 0;
++
+         if (!u->cgroup_realized)
+                 return -EBUSY;
+ 
diff --git a/SOURCES/0436-logind-don-t-print-warning-when-user-.service-templa.patch b/SOURCES/0436-logind-don-t-print-warning-when-user-.service-templa.patch
new file mode 100644
index 0000000..961f814
--- /dev/null
+++ b/SOURCES/0436-logind-don-t-print-warning-when-user-.service-templa.patch
@@ -0,0 +1,32 @@
+From 65e96327360ab41d44d5383dcecc82a19fad198c Mon Sep 17 00:00:00 2001
+From: Michal Sekletar <msekleta@redhat.com>
+Date: Fri, 22 Feb 2019 15:50:55 +0100
+Subject: [PATCH] logind: don't print warning when user@.service template is
+ masked
+
+User instance of systemd is optional feature and if user@.service
+template is masked then administrator most likely doesn't want --user
+instances of systemd for logged in users. We don't need to be verbose
+about it.
+
+(cherry picked from commit 03b6fa0c5b51b0d39334ff6ba183a3391443bcf6)
+
+Resolves: #1880270
+---
+ src/login/logind-user.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/src/login/logind-user.c b/src/login/logind-user.c
+index 8c4cd54a29..56b8066f12 100644
+--- a/src/login/logind-user.c
++++ b/src/login/logind-user.c
+@@ -326,7 +326,8 @@ static int user_start_service(User *u) {
+                         &job);
+         if (r < 0)
+                 /* we don't fail due to this, let's try to continue */
+-                log_error_errno(r, "Failed to start user service, ignoring: %s", bus_error_message(&error, r));
++                log_full_errno(sd_bus_error_has_name(&error, BUS_ERROR_UNIT_MASKED) ? LOG_DEBUG : LOG_WARNING, r,
++                               "Failed to start user service '%s', ignoring: %s", u->service, bus_error_message(&error, r));
+         else
+                 u->service_job = job;
+ 
diff --git a/SOURCES/0437-build-use-simple-project-version-in-pkgconfig-files.patch b/SOURCES/0437-build-use-simple-project-version-in-pkgconfig-files.patch
new file mode 100644
index 0000000..6ea481d
--- /dev/null
+++ b/SOURCES/0437-build-use-simple-project-version-in-pkgconfig-files.patch
@@ -0,0 +1,80 @@
+From a6d76bf2d21e01a2e031e204966d946925ecc3f6 Mon Sep 17 00:00:00 2001
+From: Jan Synacek <jsynacek@redhat.com>
+Date: Mon, 17 Aug 2020 14:29:04 +0200
+Subject: [PATCH] build: use simple project version in pkgconfig files
+
+Loosely based on commit a67c318df8800ba98d7361308937ed276dc73982.
+
+Resolves: #1862714
+---
+ meson.build                     | 2 ++
+ src/core/systemd.pc.in          | 2 +-
+ src/libsystemd/libsystemd.pc.in | 2 +-
+ src/libudev/libudev.pc.in       | 2 +-
+ src/udev/udev.pc.in             | 2 +-
+ 5 files changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/meson.build b/meson.build
+index 0ba3f924ea..65c1d0785e 100644
+--- a/meson.build
++++ b/meson.build
+@@ -27,12 +27,14 @@ endif
+ # names, sometimes. Not all variables are included in every
+ # set. Ugh, ugh, ugh!
+ conf = configuration_data()
++conf.set_quoted('PROJECT_VERSION', meson.project_version())
+ conf.set_quoted('PACKAGE_STRING',  meson.project_name() + ' ' + dist_version)
+ conf.set_quoted('PACKAGE_VERSION', dist_version)
+ 
+ substs = configuration_data()
+ substs.set('PACKAGE_URL',          'https://www.freedesktop.org/wiki/Software/systemd')
+ substs.set('PACKAGE_VERSION',      dist_version)
++substs.set('PROJECT_VERSION',      meson.project_version())
+ 
+ #####################################################################
+ 
+diff --git a/src/core/systemd.pc.in b/src/core/systemd.pc.in
+index 655773ea8a..a350737cf2 100644
+--- a/src/core/systemd.pc.in
++++ b/src/core/systemd.pc.in
+@@ -37,4 +37,4 @@ containeruidbasemax=@containeruidbasemax@
+ Name: systemd
+ Description: systemd System and Service Manager
+ URL: @PACKAGE_URL@
+-Version: @PACKAGE_VERSION@
++Version: @PROJECT_VERSION@
+diff --git a/src/libsystemd/libsystemd.pc.in b/src/libsystemd/libsystemd.pc.in
+index c861905b67..85d6ebf293 100644
+--- a/src/libsystemd/libsystemd.pc.in
++++ b/src/libsystemd/libsystemd.pc.in
+@@ -15,6 +15,6 @@ includedir=@includedir@
+ Name: systemd
+ Description: systemd Library
+ URL: @PACKAGE_URL@
+-Version: @PACKAGE_VERSION@
++Version: @PROJECT_VERSION@
+ Libs: -L${libdir} -lsystemd
+ Cflags: -I${includedir}
+diff --git a/src/libudev/libudev.pc.in b/src/libudev/libudev.pc.in
+index 69f5c6463e..40b340362e 100644
+--- a/src/libudev/libudev.pc.in
++++ b/src/libudev/libudev.pc.in
+@@ -14,6 +14,6 @@ includedir=@includedir@
+ 
+ Name: libudev
+ Description: Library to access udev device information
+-Version: @PACKAGE_VERSION@
++Version: @PROJECT_VERSION@
+ Libs: -L${libdir} -ludev
+ Cflags: -I${includedir}
+diff --git a/src/udev/udev.pc.in b/src/udev/udev.pc.in
+index e384a6f7c9..5acbb2d01a 100644
+--- a/src/udev/udev.pc.in
++++ b/src/udev/udev.pc.in
+@@ -1,5 +1,5 @@
+ Name: udev
+ Description: udev
+-Version: @PACKAGE_VERSION@
++Version: @PROJECT_VERSION@
+ 
+ udevdir=@udevlibexecdir@
diff --git a/SOURCES/0438-basic-virt-try-the-proc-1-sched-hack-also-for-PID1.patch b/SOURCES/0438-basic-virt-try-the-proc-1-sched-hack-also-for-PID1.patch
new file mode 100644
index 0000000..4237fa1
--- /dev/null
+++ b/SOURCES/0438-basic-virt-try-the-proc-1-sched-hack-also-for-PID1.patch
@@ -0,0 +1,57 @@
+From 2f584bd93d64a75ab11b5a5aa31d0b7145da5a86 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Fri, 26 Apr 2019 13:37:31 +0200
+Subject: [PATCH] basic/virt: try the /proc/1/sched hack also for PID1
+
+If a container manager does not set $container, we could end up
+in a strange situation when detect-virt returns container-other when
+run as non-pid-1 and none when run as pid-1.
+
+(cherry picked from commit 342bed02084c4396dd2f1054bd559bfb2699cfcb)
+Resolves: #1868877
+---
+ src/basic/virt.c | 16 +++++++++++-----
+ 1 file changed, 11 insertions(+), 5 deletions(-)
+
+diff --git a/src/basic/virt.c b/src/basic/virt.c
+index e05b3e6d99..dfa1525219 100644
+--- a/src/basic/virt.c
++++ b/src/basic/virt.c
+@@ -427,7 +427,6 @@ finish:
+ }
+ 
+ int detect_container(void) {
+-
+         static const struct {
+                 const char *value;
+                 int id;
+@@ -456,9 +455,15 @@ int detect_container(void) {
+         }
+ 
+         if (getpid_cached() == 1) {
+-                /* If we are PID 1 we can just check our own environment variable, and that's authoritative. */
+-
++                /* If we are PID 1 we can just check our own environment variable, and that's authoritative.
++                 * We distinguish three cases:
++                 * - the variable is not defined → we jump to other checks
++                 * - the variable is defined to an empty value → we are not in a container
++                 * - anything else → some container, either one of the known ones or "container-other"
++                 */
+                 e = getenv("container");
++                if (!e)
++                        goto check_sched;
+                 if (isempty(e)) {
+                         r = VIRTUALIZATION_NONE;
+                         goto finish;
+@@ -486,8 +491,9 @@ int detect_container(void) {
+         if (r < 0) /* This only works if we have CAP_SYS_PTRACE, hence let's better ignore failures here */
+                 log_debug_errno(r, "Failed to read $container of PID 1, ignoring: %m");
+ 
+-        /* Interestingly /proc/1/sched actually shows the host's PID for what we see as PID 1. Hence, if the PID shown
+-         * there is not 1, we know we are in a PID namespace. and hence a container. */
++        /* Interestingly /proc/1/sched actually shows the host's PID for what we see as PID 1. If the PID
++         * shown there is not 1, we know we are in a PID namespace and hence a container. */
++ check_sched:
+         r = read_one_line_file("/proc/1/sched", &m);
+         if (r >= 0) {
+                 const char *t;
diff --git a/SOURCES/0439-seccomp-rework-how-the-S-UG-ID-filter-is-installed.patch b/SOURCES/0439-seccomp-rework-how-the-S-UG-ID-filter-is-installed.patch
new file mode 100644
index 0000000..f824c4d
--- /dev/null
+++ b/SOURCES/0439-seccomp-rework-how-the-S-UG-ID-filter-is-installed.patch
@@ -0,0 +1,287 @@
+From 8cc497e735104080f6830a8f468b2724ae372990 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Wed, 3 Apr 2019 13:11:00 +0200
+Subject: [PATCH] seccomp: rework how the S[UG]ID filter is installed
+
+If we know that a syscall is undefined on the given architecture, don't
+even try to add it.
+
+Try to install the filter even if some syscalls fail. Also use a helper
+function to make the whole a bit less magic.
+
+This allows the S[UG]ID test to pass on arm64.
+
+(cherry picked from commit da4dc9a6748797e804b6bc92ad513d509abf581c)
+
+Resolves: #1860374
+---
+ src/shared/seccomp-util.c | 244 +++++++++++++++++++++-----------------
+ 1 file changed, 138 insertions(+), 106 deletions(-)
+
+diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c
+index fd46b9f88d..d91fb4e269 100644
+--- a/src/shared/seccomp-util.c
++++ b/src/shared/seccomp-util.c
+@@ -1750,9 +1750,139 @@ int seccomp_lock_personality(unsigned long personality) {
+         return 0;
+ }
+ 
++static int seccomp_restrict_sxid(scmp_filter_ctx seccomp, mode_t m) {
++        /* Checks the mode_t parameter of the following system calls:
++         *
++         *       → chmod() + fchmod() + fchmodat()
++         *       → open() + creat() + openat()
++         *       → mkdir() + mkdirat()
++         *       → mknod() + mknodat()
++         *
++         * Returns error if *everything* failed, and 0 otherwise.
++         */
++        int r = 0;
++        bool any = false;
++
++        r = seccomp_rule_add_exact(
++                        seccomp,
++                        SCMP_ACT_ERRNO(EPERM),
++                        SCMP_SYS(chmod),
++                        1,
++                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
++        if (r < 0)
++                log_debug_errno(r, "Failed to add filter for chmod: %m");
++        else
++                any = true;
++
++        r = seccomp_rule_add_exact(
++                        seccomp,
++                        SCMP_ACT_ERRNO(EPERM),
++                        SCMP_SYS(fchmod),
++                        1,
++                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
++        if (r < 0)
++                log_debug_errno(r, "Failed to add filter for fchmod: %m");
++        else
++                any = true;
++
++        r = seccomp_rule_add_exact(
++                        seccomp,
++                        SCMP_ACT_ERRNO(EPERM),
++                        SCMP_SYS(fchmodat),
++                        1,
++                        SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
++        if (r < 0)
++                log_debug_errno(r, "Failed to add filter for fchmodat: %m");
++        else
++                any = true;
++
++        r = seccomp_rule_add_exact(
++                        seccomp,
++                        SCMP_ACT_ERRNO(EPERM),
++                        SCMP_SYS(mkdir),
++                        1,
++                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
++        if (r < 0)
++                log_debug_errno(r, "Failed to add filter for mkdir: %m");
++        else
++                any = true;
++
++        r = seccomp_rule_add_exact(
++                        seccomp,
++                        SCMP_ACT_ERRNO(EPERM),
++                        SCMP_SYS(mkdirat),
++                        1,
++                        SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
++        if (r < 0)
++                log_debug_errno(r, "Failed to add filter for mkdirat: %m");
++        else
++                any = true;
++
++        r = seccomp_rule_add_exact(
++                        seccomp,
++                        SCMP_ACT_ERRNO(EPERM),
++                        SCMP_SYS(mknod),
++                        1,
++                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
++        if (r < 0)
++                log_debug_errno(r, "Failed to add filter for mknod: %m");
++        else
++                any = true;
++
++        r = seccomp_rule_add_exact(
++                        seccomp,
++                        SCMP_ACT_ERRNO(EPERM),
++                        SCMP_SYS(mknodat),
++                        1,
++                        SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
++        if (r < 0)
++                log_debug_errno(r, "Failed to add filter for mknodat: %m");
++        else
++                any = true;
++
++#if SCMP_SYS(open) > 0
++        r = seccomp_rule_add_exact(
++                        seccomp,
++                        SCMP_ACT_ERRNO(EPERM),
++                        SCMP_SYS(open),
++                        2,
++                        SCMP_A1(SCMP_CMP_MASKED_EQ, O_CREAT, O_CREAT),
++                        SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
++        if (r < 0)
++                log_debug_errno(r, "Failed to add filter for open: %m");
++        else
++                any = true;
++#endif
++
++        r = seccomp_rule_add_exact(
++                        seccomp,
++                        SCMP_ACT_ERRNO(EPERM),
++                        SCMP_SYS(openat),
++                        2,
++                        SCMP_A2(SCMP_CMP_MASKED_EQ, O_CREAT, O_CREAT),
++                        SCMP_A3(SCMP_CMP_MASKED_EQ, m, m));
++        if (r < 0)
++                log_debug_errno(r, "Failed to add filter for openat: %m");
++        else
++                any = true;
++
++        r = seccomp_rule_add_exact(
++                        seccomp,
++                        SCMP_ACT_ERRNO(EPERM),
++                        SCMP_SYS(creat),
++                        1,
++                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
++        if (r < 0)
++                log_debug_errno(r, "Failed to add filter for creat: %m");
++        else
++                any = true;
++
++        return any ? 0 : r;
++}
++
+ int seccomp_restrict_suid_sgid(void) {
+         uint32_t arch;
+-        int r;
++        int r, k;
+ 
+         SECCOMP_FOREACH_LOCAL_ARCH(arch) {
+                 _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
+@@ -1761,114 +1891,16 @@ int seccomp_restrict_suid_sgid(void) {
+                 if (r < 0)
+                         return r;
+ 
+-                /* Checks the mode_t parameter of the following system calls:
+-                 *
+-                 *       → chmod() + fchmod() + fchmodat()
+-                 *       → open() + creat() + openat()
+-                 *       → mkdir() + mkdirat()
+-                 *       → mknod() + mknodat()
+-                 */
+-
+-                for (unsigned bit = 0; bit < 2; bit ++) {
+-                        /* Block S_ISUID in the first iteration, S_ISGID in the second */
+-                        mode_t m = bit == 0 ? S_ISUID : S_ISGID;
+-
+-                        r = seccomp_rule_add_exact(
+-                                        seccomp,
+-                                        SCMP_ACT_ERRNO(EPERM),
+-                                        SCMP_SYS(chmod),
+-                                        1,
+-                                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
+-                        if (r < 0)
+-                                break;
+-
+-                        r = seccomp_rule_add_exact(
+-                                        seccomp,
+-                                        SCMP_ACT_ERRNO(EPERM),
+-                                        SCMP_SYS(fchmod),
+-                                        1,
+-                                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
+-                        if (r < 0)
+-                                break;
+-
+-                        r = seccomp_rule_add_exact(
+-                                        seccomp,
+-                                        SCMP_ACT_ERRNO(EPERM),
+-                                        SCMP_SYS(fchmodat),
+-                                        1,
+-                                        SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
+-                        if (r < 0)
+-                                break;
+-
+-                        r = seccomp_rule_add_exact(
+-                                        seccomp,
+-                                        SCMP_ACT_ERRNO(EPERM),
+-                                        SCMP_SYS(mkdir),
+-                                        1,
+-                                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
+-                        if (r < 0)
+-                                break;
+-
+-                        r = seccomp_rule_add_exact(
+-                                        seccomp,
+-                                        SCMP_ACT_ERRNO(EPERM),
+-                                        SCMP_SYS(mkdirat),
+-                                        1,
+-                                        SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
+-                        if (r < 0)
+-                                break;
+-
+-                        r = seccomp_rule_add_exact(
+-                                        seccomp,
+-                                        SCMP_ACT_ERRNO(EPERM),
+-                                        SCMP_SYS(mknod),
+-                                        1,
+-                                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
+-                        if (r < 0)
+-                                break;
+-
+-                        r = seccomp_rule_add_exact(
+-                                        seccomp,
+-                                        SCMP_ACT_ERRNO(EPERM),
+-                                        SCMP_SYS(mknodat),
+-                                        1,
+-                                        SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
+-                        if (r < 0)
+-                                break;
+-
+-                        r = seccomp_rule_add_exact(
+-                                        seccomp,
+-                                        SCMP_ACT_ERRNO(EPERM),
+-                                        SCMP_SYS(open),
+-                                        2,
+-                                        SCMP_A1(SCMP_CMP_MASKED_EQ, O_CREAT, O_CREAT),
+-                                        SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
+-                        if (r < 0)
+-                                break;
++                r = seccomp_restrict_sxid(seccomp, S_ISUID);
++                if (r < 0)
++                        log_debug_errno(r, "Failed to add suid rule for architecture %s, ignoring: %m", seccomp_arch_to_string(arch));
+ 
+-                        r = seccomp_rule_add_exact(
+-                                        seccomp,
+-                                        SCMP_ACT_ERRNO(EPERM),
+-                                        SCMP_SYS(openat),
+-                                        2,
+-                                        SCMP_A2(SCMP_CMP_MASKED_EQ, O_CREAT, O_CREAT),
+-                                        SCMP_A3(SCMP_CMP_MASKED_EQ, m, m));
+-                        if (r < 0)
+-                                break;
++                k = seccomp_restrict_sxid(seccomp, S_ISGID);
++                if (k < 0)
++                        log_debug_errno(r, "Failed to add sgid rule for architecture %s, ignoring: %m", seccomp_arch_to_string(arch));
+ 
+-                        r = seccomp_rule_add_exact(
+-                                        seccomp,
+-                                        SCMP_ACT_ERRNO(EPERM),
+-                                        SCMP_SYS(creat),
+-                                        1,
+-                                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
+-                        if (r < 0)
+-                                break;
+-                }
+-                if (r < 0) {
+-                        log_debug_errno(r, "Failed to add suid/sgid rule for architecture %s, skipping: %m", seccomp_arch_to_string(arch));
++                if (r < 0 && k < 0)
+                         continue;
+-                }
+ 
+                 r = seccomp_load(seccomp);
+                 if (IN_SET(r, -EPERM, -EACCES))
diff --git a/SOURCES/0440-vconsole-setup-downgrade-log-message-when-setting-fo.patch b/SOURCES/0440-vconsole-setup-downgrade-log-message-when-setting-fo.patch
new file mode 100644
index 0000000..09874a7
--- /dev/null
+++ b/SOURCES/0440-vconsole-setup-downgrade-log-message-when-setting-fo.patch
@@ -0,0 +1,91 @@
+From 860749038f508617c8fc31b8292b4019b1e621ba Mon Sep 17 00:00:00 2001
+From: Franck Bui <fbui@suse.com>
+Date: Thu, 16 Jul 2020 21:22:37 +0200
+Subject: [PATCH] vconsole-setup: downgrade log message when setting font fails
+ on dummy console
+
+Since commit 883eb9be985fd86d9cabe967eeeab91cdd396a81, vconsole-setup might be
+called again to operate on dummy console where font operations are not
+supported but where it's still important to have the correct keymap set [0][1].
+
+vconsole-setup is mainly called by udev but can also be run via a dependency of
+an early service. Both cases might end up calling vconsole-setup on the dummy
+console.
+
+The first case can happen during early boot even on systems that use (instead
+of the dummy console) a "simple" video console driver supporting font
+operations (such as vgacon) until a more specific driver (such as i915) takes
+the console over. While this is happening vgacon is deactivated and temporarly
+replaced by the dummy console [2].
+
+There are also other cases where systemd-vconsole-setup might be called on
+dummy console especially during (very) early boot. Indeed
+systemd-vconsole-setup.service might be pulled in by early interactive services
+such as 'dracut-cmdline-ask.service` which is run before udev.
+
+If that happens on platforms with no grapical HWs (such as embedded ARM) or
+with dummy console initially installed until a driver takes over (like Xen and
+xen-fbfront) then setting font will fail.
+
+Therefore this patch downgrades the log message emitted when setting font fails
+to LOG_DEBUG and when font operations is not implemented like it's the case for
+the dummy console.
+
+Fixes: #16406.
+
+[0] https://github.com/systemd/systemd/issues/10826
+[1] https://bugzilla.redhat.com/show_bug.cgi?id=1652473
+[2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/gpu/vga/vgaarb.c?h=v5.7#n204
+
+(cherry picked from commit 0ef1adf51274960358e852d3bc36ae6c288a70d9)
+
+Resolves: #1889996
+---
+ src/vconsole/vconsole-setup.c | 18 ++++++++++++++----
+ 1 file changed, 14 insertions(+), 4 deletions(-)
+
+diff --git a/src/vconsole/vconsole-setup.c b/src/vconsole/vconsole-setup.c
+index f162d29220..1b406c0bc5 100644
+--- a/src/vconsole/vconsole-setup.c
++++ b/src/vconsole/vconsole-setup.c
+@@ -222,6 +222,7 @@ static void setup_remaining_vcs(int src_fd, unsigned src_idx, bool utf8) {
+         _cleanup_free_ struct unipair* unipairs = NULL;
+         _cleanup_free_ void *fontbuf = NULL;
+         unsigned i;
++        int log_level;
+         int r;
+ 
+         unipairs = new(struct unipair, USHRT_MAX);
+@@ -230,11 +231,20 @@ static void setup_remaining_vcs(int src_fd, unsigned src_idx, bool utf8) {
+                 return;
+         }
+ 
++        log_level = LOG_WARNING;
++
+         /* get metadata of the current font (width, height, count) */
+         r = ioctl(src_fd, KDFONTOP, &cfo);
+-        if (r < 0)
+-                log_warning_errno(errno, "KD_FONT_OP_GET failed while trying to get the font metadata: %m");
+-        else {
++        if (r < 0) {
++                /* We might be called to operate on the dummy console (to setup keymap
++                 * mainly) when fbcon deferred takeover is used for example. In such case,
++                 * setting font is not supported and is expected to fail. */
++                if (errno == ENOSYS)
++                        log_level = LOG_DEBUG;
++
++                log_full_errno(log_level, errno,
++                               "KD_FONT_OP_GET failed while trying to get the font metadata: %m");
++        } else {
+                 /* verify parameter sanity first */
+                 if (cfo.width > 32 || cfo.height > 32 || cfo.charcount > 512)
+                         log_warning("Invalid font metadata - width: %u (max 32), height: %u (max 32), count: %u (max 512)",
+@@ -269,7 +279,7 @@ static void setup_remaining_vcs(int src_fd, unsigned src_idx, bool utf8) {
+         }
+ 
+         if (cfo.op != KD_FONT_OP_SET)
+-                log_warning("Fonts will not be copied to remaining consoles");
++                log_full(log_level, "Fonts will not be copied to remaining consoles");
+ 
+         for (i = 1; i <= 63; i++) {
+                 char ttyname[sizeof("/dev/tty63")];
diff --git a/SOURCES/0441-units-fix-systemd.special-man-page-reference-in-syst.patch b/SOURCES/0441-units-fix-systemd.special-man-page-reference-in-syst.patch
new file mode 100644
index 0000000..4d6bd2e
--- /dev/null
+++ b/SOURCES/0441-units-fix-systemd.special-man-page-reference-in-syst.patch
@@ -0,0 +1,26 @@
+From 46fa8ff1a62e3334582a971cc6bbd9b8a16680d5 Mon Sep 17 00:00:00 2001
+From: Michael Biebl <biebl@debian.org>
+Date: Thu, 7 Mar 2019 12:02:53 +0100
+Subject: [PATCH] units: fix systemd.special man page reference in
+ system-update-cleanup.service
+
+(cherry picked from commit faab72d16b310c17be4b908cfe15eca122d16ae4)
+
+Resolves: #1871827
+---
+ units/system-update-cleanup.service | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/units/system-update-cleanup.service b/units/system-update-cleanup.service
+index 58baab3023..d5eca2546b 100644
+--- a/units/system-update-cleanup.service
++++ b/units/system-update-cleanup.service
+@@ -9,7 +9,7 @@
+ 
+ [Unit]
+ Description=Remove the Offline System Updates symlink
+-Documentation=man:systemd.special(5) man:systemd.offline-updates(7)
++Documentation=man:systemd.special(7) man:systemd.offline-updates(7)
+ After=system-update.target
+ DefaultDependencies=no
+ Conflicts=shutdown.target
diff --git a/SOURCES/0442-units-drop-reference-to-sushell-man-page.patch b/SOURCES/0442-units-drop-reference-to-sushell-man-page.patch
new file mode 100644
index 0000000..d998724
--- /dev/null
+++ b/SOURCES/0442-units-drop-reference-to-sushell-man-page.patch
@@ -0,0 +1,27 @@
+From 5aa59d172189adcbd7f9dedb3b909c6bf9b609f2 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Mon, 29 Apr 2019 16:10:51 +0200
+Subject: [PATCH] units: drop reference to sushell man page
+
+sushell was a Fedoraism, and has been removed since. Hence our upstream
+unit files shouldn't reference it either.
+
+(cherry picked from commit 6dc14d73664390682d47d7e5bcbdbb362d04f623)
+
+Resolves: #1871827
+---
+ units/debug-shell.service.in | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/units/debug-shell.service.in b/units/debug-shell.service.in
+index 1127e68b63..9f3868e106 100644
+--- a/units/debug-shell.service.in
++++ b/units/debug-shell.service.in
+@@ -9,7 +9,6 @@
+ 
+ [Unit]
+ Description=Early root shell on @DEBUGTTY@ FOR DEBUGGING ONLY
+-Documentation=man:sushell(8)
+ Documentation=man:systemd-debug-generator(8)
+ DefaultDependencies=no
+ IgnoreOnIsolate=yes
diff --git a/SOURCES/0443-sd-bus-break-the-loop-in-bus_ensure_running-if-the-b.patch b/SOURCES/0443-sd-bus-break-the-loop-in-bus_ensure_running-if-the-b.patch
new file mode 100644
index 0000000..a53c450
--- /dev/null
+++ b/SOURCES/0443-sd-bus-break-the-loop-in-bus_ensure_running-if-the-b.patch
@@ -0,0 +1,44 @@
+From 6a50c735a3bbf98d06fbfa7815f7bdc14ea96f9f Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Wed, 14 Oct 2020 14:03:13 +0200
+Subject: [PATCH] sd-bus: break the loop in bus_ensure_running() if the bus is
+ not connecting
+
+This might fix #17025:
+> the call trace is
+> bus_ensure_running -> sd_bus_process -> bus_process_internal -> process_closeing --> sd_bus_close
+>                                                                                  |
+>                                                                                  \-> process_match
+
+We ended doing callouts to the Disconnected matches from bus_ensure_running()
+and shouldn't. bus_ensure_running() should never do callouts. This change
+should fix this however: once we notice that the connection is going down we
+will now fail instantly with ENOTOCONN instead of calling any callbacks.
+
+(cherry picked from commit 93a59b1ae5d3bcb0ec1488ebc13d0d1ff4d1729a)
+
+Resolves: #1885553
+---
+ src/libsystemd/sd-bus/sd-bus.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
+index a3509f7e89..c65e24b2d1 100644
+--- a/src/libsystemd/sd-bus/sd-bus.c
++++ b/src/libsystemd/sd-bus/sd-bus.c
+@@ -2059,12 +2059,13 @@ int bus_ensure_running(sd_bus *bus) {
+ 
+         assert(bus);
+ 
+-        if (IN_SET(bus->state, BUS_UNSET, BUS_CLOSED, BUS_CLOSING))
+-                return -ENOTCONN;
+         if (bus->state == BUS_RUNNING)
+                 return 1;
+ 
+         for (;;) {
++                if (IN_SET(bus->state, BUS_UNSET, BUS_CLOSED, BUS_CLOSING))
++                        return -ENOTCONN;
++
+                 r = sd_bus_process(bus, NULL);
+                 if (r < 0)
+                         return r;
diff --git a/SOURCES/0444-core-add-new-API-for-enqueing-a-job-with-returning-t.patch b/SOURCES/0444-core-add-new-API-for-enqueing-a-job-with-returning-t.patch
new file mode 100644
index 0000000..ccd3ae1
--- /dev/null
+++ b/SOURCES/0444-core-add-new-API-for-enqueing-a-job-with-returning-t.patch
@@ -0,0 +1,831 @@
+From 7155c010ef8c620295d230c284849636c07b40c0 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Fri, 22 Mar 2019 20:57:30 +0100
+Subject: [PATCH] core: add new API for enqueing a job with returning the
+ transaction data
+
+(cherry picked from commit 50cbaba4fe5a32850998682699322d012e597e4a)
+
+Related: #846319
+---
+ src/analyze/analyze-verify.c |   2 +-
+ src/core/automount.c         |   4 +-
+ src/core/dbus-manager.c      |  23 +++++-
+ src/core/dbus-unit.c         | 153 +++++++++++++++++++++++++++++++----
+ src/core/dbus-unit.h         |   8 +-
+ src/core/dbus.c              |   2 +-
+ src/core/device.c            |   2 +-
+ src/core/emergency-action.c  |   5 +-
+ src/core/main.c              |   4 +-
+ src/core/manager.c           |  38 +++++----
+ src/core/manager.h           |   6 +-
+ src/core/path.c              |   2 +-
+ src/core/service.c           |   2 +-
+ src/core/socket.c            |   4 +-
+ src/core/timer.c             |   2 +-
+ src/core/transaction.c       |  22 ++++-
+ src/core/transaction.h       |   2 +-
+ src/core/unit.c              |  16 ++--
+ src/test/test-engine.c       |  20 ++---
+ 19 files changed, 244 insertions(+), 73 deletions(-)
+
+diff --git a/src/analyze/analyze-verify.c b/src/analyze/analyze-verify.c
+index ed369532d4..1e143511b2 100644
+--- a/src/analyze/analyze-verify.c
++++ b/src/analyze/analyze-verify.c
+@@ -205,7 +205,7 @@ static int verify_unit(Unit *u, bool check_man) {
+                 unit_dump(u, stdout, "\t");
+ 
+         log_unit_debug(u, "Creating %s/start job", u->id);
+-        r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, &err, NULL);
++        r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, NULL, &err, NULL);
+         if (r < 0)
+                 log_unit_error_errno(u, r, "Failed to create %s/start: %s", u->id, bus_error_message(&err, r));
+ 
+diff --git a/src/core/automount.c b/src/core/automount.c
+index b1a155d8d4..76e70f4dac 100644
+--- a/src/core/automount.c
++++ b/src/core/automount.c
+@@ -776,7 +776,7 @@ static void automount_enter_running(Automount *a) {
+                 goto fail;
+         }
+ 
+-        r = manager_add_job(UNIT(a)->manager, JOB_START, trigger, JOB_REPLACE, &error, NULL);
++        r = manager_add_job(UNIT(a)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL);
+         if (r < 0) {
+                 log_unit_warning(UNIT(a), "Failed to queue mount startup job: %s", bus_error_message(&error, r));
+                 goto fail;
+@@ -1032,7 +1032,7 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo
+                         goto fail;
+                 }
+ 
+-                r = manager_add_job(UNIT(a)->manager, JOB_STOP, trigger, JOB_REPLACE, &error, NULL);
++                r = manager_add_job(UNIT(a)->manager, JOB_STOP, trigger, JOB_REPLACE, NULL, &error, NULL);
+                 if (r < 0) {
+                         log_unit_warning(UNIT(a), "Failed to queue umount startup job: %s", bus_error_message(&error, r));
+                         goto fail;
+diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
+index a0777f63d5..0a1d3df42f 100644
+--- a/src/core/dbus-manager.c
++++ b/src/core/dbus-manager.c
+@@ -549,6 +549,26 @@ static int method_reload_or_try_restart_unit(sd_bus_message *message, void *user
+         return method_start_unit_generic(message, userdata, JOB_TRY_RESTART, true, error);
+ }
+ 
++static int method_enqueue_unit_job(sd_bus_message *message, void *userdata, sd_bus_error *error) {
++        Manager *m = userdata;
++        const char *name;
++        Unit *u;
++        int r;
++
++        assert(message);
++        assert(m);
++
++        r = sd_bus_message_read(message, "s", &name);
++        if (r < 0)
++                return r;
++
++        r = manager_load_unit(m, name, NULL, error, &u);
++        if (r < 0)
++                return r;
++
++        return bus_unit_method_enqueue_job(message, u, error);
++}
++
+ static int method_start_unit_replace(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+         Manager *m = userdata;
+         const char *old_name;
+@@ -978,7 +998,7 @@ static int method_start_transient_unit(sd_bus_message *message, void *userdata,
+                 return r;
+ 
+         /* Finally, start it */
+-        return bus_unit_queue_job(message, u, JOB_START, mode, false, error);
++        return bus_unit_queue_job(message, u, JOB_START, mode, 0, error);
+ }
+ 
+ static int method_get_job(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+@@ -2547,6 +2567,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
+         SD_BUS_METHOD("TryRestartUnit", "ss", "o", method_try_restart_unit, SD_BUS_VTABLE_UNPRIVILEGED),
+         SD_BUS_METHOD("ReloadOrRestartUnit", "ss", "o", method_reload_or_restart_unit, SD_BUS_VTABLE_UNPRIVILEGED),
+         SD_BUS_METHOD("ReloadOrTryRestartUnit", "ss", "o", method_reload_or_try_restart_unit, SD_BUS_VTABLE_UNPRIVILEGED),
++        SD_BUS_METHOD("EnqueueUnitJob", "sss", "uososa(uosos)", method_enqueue_unit_job, SD_BUS_VTABLE_UNPRIVILEGED),
+         SD_BUS_METHOD("KillUnit", "ssi", NULL, method_kill_unit, SD_BUS_VTABLE_UNPRIVILEGED),
+         SD_BUS_METHOD("FreezeUnit", "s", NULL, method_freeze_unit, SD_BUS_VTABLE_UNPRIVILEGED),
+         SD_BUS_METHOD("ThawUnit", "s", NULL, method_thaw_unit, SD_BUS_VTABLE_UNPRIVILEGED),
+diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
+index ce81103e92..549a166abc 100644
+--- a/src/core/dbus-unit.c
++++ b/src/core/dbus-unit.c
+@@ -314,6 +314,14 @@ static int bus_verify_manage_units_async_full(
+                         error);
+ }
+ 
++static const char *const polkit_message_for_job[_JOB_TYPE_MAX] = {
++        [JOB_START]       = N_("Authentication is required to start '$(unit)'."),
++        [JOB_STOP]        = N_("Authentication is required to stop '$(unit)'."),
++        [JOB_RELOAD]      = N_("Authentication is required to reload '$(unit)'."),
++        [JOB_RESTART]     = N_("Authentication is required to restart '$(unit)'."),
++        [JOB_TRY_RESTART] = N_("Authentication is required to restart '$(unit)'."),
++};
++
+ int bus_unit_method_start_generic(
+                 sd_bus_message *message,
+                 Unit *u,
+@@ -324,13 +332,6 @@ int bus_unit_method_start_generic(
+         const char *smode;
+         JobMode mode;
+         _cleanup_free_ char *verb = NULL;
+-        static const char *const polkit_message_for_job[_JOB_TYPE_MAX] = {
+-                [JOB_START]       = N_("Authentication is required to start '$(unit)'."),
+-                [JOB_STOP]        = N_("Authentication is required to stop '$(unit)'."),
+-                [JOB_RELOAD]      = N_("Authentication is required to reload '$(unit)'."),
+-                [JOB_RESTART]     = N_("Authentication is required to restart '$(unit)'."),
+-                [JOB_TRY_RESTART] = N_("Authentication is required to restart '$(unit)'."),
+-        };
+         int r;
+ 
+         assert(message);
+@@ -372,7 +373,8 @@ int bus_unit_method_start_generic(
+         if (r == 0)
+                 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+ 
+-        return bus_unit_queue_job(message, u, job_type, mode, reload_if_possible, error);
++        return bus_unit_queue_job(message, u, job_type, mode,
++                                  reload_if_possible ? BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE : 0, error);
+ }
+ 
+ static int method_start(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+@@ -403,6 +405,62 @@ static int method_reload_or_try_restart(sd_bus_message *message, void *userdata,
+         return bus_unit_method_start_generic(message, userdata, JOB_TRY_RESTART, true, error);
+ }
+ 
++int bus_unit_method_enqueue_job(sd_bus_message *message, void *userdata, sd_bus_error *error) {
++        BusUnitQueueFlags flags = BUS_UNIT_QUEUE_VERBOSE_REPLY;
++        const char *jtype, *smode;
++        Unit *u = userdata;
++        JobType type;
++        JobMode mode;
++        int r;
++
++        assert(message);
++        assert(u);
++
++        r = sd_bus_message_read(message, "ss", &jtype, &smode);
++        if (r < 0)
++                return r;
++
++        /* Parse the two magic reload types "reload-or-…" manually */
++        if (streq(jtype, "reload-or-restart")) {
++                type = JOB_RESTART;
++                flags |= BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE;
++        } else if (streq(jtype, "reload-or-try-restart")) {
++                type = JOB_TRY_RESTART;
++                flags |= BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE;
++        } else {
++                /* And the rest generically */
++                type = job_type_from_string(jtype);
++                if (type < 0)
++                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job type %s invalid", jtype);
++        }
++
++        mode = job_mode_from_string(smode);
++        if (mode < 0)
++                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode);
++
++        r = mac_selinux_unit_access_check(
++                        u, message,
++                        job_type_to_access_method(type),
++                        error);
++        if (r < 0)
++                return r;
++
++        r = bus_verify_manage_units_async_full(
++                        u,
++                        jtype,
++                        CAP_SYS_ADMIN,
++                        polkit_message_for_job[type],
++                        true,
++                        message,
++                        error);
++        if (r < 0)
++                return r;
++        if (r == 0)
++                return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
++
++        return bus_unit_queue_job(message, u, type, mode, flags, error);
++}
++
+ int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+         Unit *u = userdata;
+         const char *swho;
+@@ -722,6 +780,7 @@ const sd_bus_vtable bus_unit_vtable[] = {
+         SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
+         SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, SD_BUS_VTABLE_UNPRIVILEGED),
+         SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
++        SD_BUS_METHOD("EnqueueJob", "ss", "uososa(uosos)", bus_unit_method_enqueue_job, SD_BUS_VTABLE_UNPRIVILEGED),
+         SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
+         SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED),
+         SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, SD_BUS_VTABLE_UNPRIVILEGED),
+@@ -1354,11 +1413,14 @@ int bus_unit_queue_job(
+                 Unit *u,
+                 JobType type,
+                 JobMode mode,
+-                bool reload_if_possible,
++                BusUnitQueueFlags flags,
+                 sd_bus_error *error) {
+ 
+-        _cleanup_free_ char *path = NULL;
+-        Job *j;
++        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
++        _cleanup_free_ char *job_path = NULL, *unit_path = NULL;
++        _cleanup_(set_freep) Set *affected = NULL;
++        Iterator i;
++        Job *j, *a;
+         int r;
+ 
+         assert(message);
+@@ -1373,7 +1435,7 @@ int bus_unit_queue_job(
+         if (r < 0)
+                 return r;
+ 
+-        if (reload_if_possible && unit_can_reload(u)) {
++        if (FLAGS_SET(flags, BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE) && unit_can_reload(u)) {
+                 if (type == JOB_RESTART)
+                         type = JOB_RELOAD_OR_START;
+                 else if (type == JOB_TRY_RESTART)
+@@ -1391,7 +1453,13 @@ int bus_unit_queue_job(
+             (type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start))
+                 return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).", u->id);
+ 
+-        r = manager_add_job(u->manager, type, u, mode, error, &j);
++        if (FLAGS_SET(flags, BUS_UNIT_QUEUE_VERBOSE_REPLY)) {
++                affected = set_new(NULL);
++                if (!affected)
++                        return -ENOMEM;
++        }
++
++        r = manager_add_job(u->manager, type, u, mode, affected, error, &j);
+         if (r < 0)
+                 return r;
+ 
+@@ -1399,11 +1467,64 @@ int bus_unit_queue_job(
+         if (r < 0)
+                 return r;
+ 
+-        path = job_dbus_path(j);
+-        if (!path)
++        job_path = job_dbus_path(j);
++        if (!job_path)
+                 return -ENOMEM;
+ 
+-        return sd_bus_reply_method_return(message, "o", path);
++        /* The classic response is just a job object path */
++        if (!FLAGS_SET(flags, BUS_UNIT_QUEUE_VERBOSE_REPLY))
++                return sd_bus_reply_method_return(message, "o", job_path);
++
++        /* In verbose mode respond with the anchor job plus everything that has been affected */
++        r = sd_bus_message_new_method_return(message, &reply);
++        if (r < 0)
++                return r;
++
++        unit_path = unit_dbus_path(j->unit);
++        if (!unit_path)
++                return -ENOMEM;
++
++        r = sd_bus_message_append(reply, "uosos",
++                                  j->id, job_path,
++                                  j->unit->id, unit_path,
++                                  job_type_to_string(j->type));
++        if (r < 0)
++                return r;
++
++        r = sd_bus_message_open_container(reply, 'a', "(uosos)");
++        if (r < 0)
++                return r;
++
++        SET_FOREACH(a, affected, i) {
++
++                if (a->id == j->id)
++                        continue;
++
++                /* Free paths from previous iteration */
++                job_path = mfree(job_path);
++                unit_path = mfree(unit_path);
++
++                job_path = job_dbus_path(a);
++                if (!job_path)
++                        return -ENOMEM;
++
++                unit_path = unit_dbus_path(a->unit);
++                if (!unit_path)
++                        return -ENOMEM;
++
++                r = sd_bus_message_append(reply, "(uosos)",
++                                          a->id, job_path,
++                                          a->unit->id, unit_path,
++                                          job_type_to_string(a->type));
++                if (r < 0)
++                        return r;
++        }
++
++        r = sd_bus_message_close_container(reply);
++        if (r < 0)
++                return r;
++
++        return sd_bus_send(NULL, reply, NULL);
+ }
+ 
+ static int bus_unit_set_live_property(
+diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h
+index 39aa1bb53c..d298fcc99e 100644
+--- a/src/core/dbus-unit.h
++++ b/src/core/dbus-unit.h
+@@ -15,6 +15,7 @@ int bus_unit_send_pending_freezer_message(Unit *u);
+ void bus_unit_send_removed_signal(Unit *u);
+ 
+ int bus_unit_method_start_generic(sd_bus_message *message, Unit *u, JobType job_type, bool reload_if_possible, sd_bus_error *error);
++int bus_unit_method_enqueue_job(sd_bus_message *message, void *userdata, sd_bus_error *error);
+ int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error);
+ int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus_error *error);
+ 
+@@ -27,7 +28,12 @@ int bus_unit_method_unref(sd_bus_message *message, void *userdata, sd_bus_error
+ int bus_unit_method_freeze(sd_bus_message *message, void *userdata, sd_bus_error *error);
+ int bus_unit_method_thaw(sd_bus_message *message, void *userdata, sd_bus_error *error);
+ 
+-int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible, sd_bus_error *error);
++typedef enum BusUnitQueueFlags {
++        BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE = 1 << 0,
++        BUS_UNIT_QUEUE_VERBOSE_REPLY      = 1 << 1,
++} BusUnitQueueFlags;
++
++int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, BusUnitQueueFlags flags, sd_bus_error *error);
+ int bus_unit_validate_load_state(Unit *u, sd_bus_error *error);
+ 
+ int bus_unit_track_add_name(Unit *u, const char *name);
+diff --git a/src/core/dbus.c b/src/core/dbus.c
+index b69c11c519..584a8a1b01 100644
+--- a/src/core/dbus.c
++++ b/src/core/dbus.c
+@@ -176,7 +176,7 @@ static int signal_activation_request(sd_bus_message *message, void *userdata, sd
+                 goto failed;
+         }
+ 
+-        r = manager_add_job(m, JOB_START, u, JOB_REPLACE, &error, NULL);
++        r = manager_add_job(m, JOB_START, u, JOB_REPLACE, NULL, &error, NULL);
+         if (r < 0)
+                 goto failed;
+ 
+diff --git a/src/core/device.c b/src/core/device.c
+index 021c28dfbd..cb8b66dfc5 100644
+--- a/src/core/device.c
++++ b/src/core/device.c
+@@ -419,7 +419,7 @@ static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
+                         if (strv_contains(d->wants_property, *i)) /* Was this unit already listed before? */
+                                 continue;
+ 
+-                        r = manager_add_job_by_name(u->manager, JOB_START, *i, JOB_FAIL, &error, NULL);
++                        r = manager_add_job_by_name(u->manager, JOB_START, *i, JOB_FAIL, NULL, &error, NULL);
+                         if (r < 0)
+                                 log_unit_warning_errno(u, r, "Failed to enqueue SYSTEMD_WANTS= job, ignoring: %s", bus_error_message(&error, r));
+                 }
+diff --git a/src/core/emergency-action.c b/src/core/emergency-action.c
+index 76e1124cff..766a3b4d2b 100644
+--- a/src/core/emergency-action.c
++++ b/src/core/emergency-action.c
+@@ -54,8 +54,7 @@ int emergency_action(
+                 log_and_status(m, "Rebooting", reason);
+ 
+                 (void) update_reboot_parameter_and_warn(reboot_arg);
+-                (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL);
+-
++                (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL, NULL);
+                 break;
+ 
+         case EMERGENCY_ACTION_REBOOT_FORCE:
+@@ -83,7 +82,7 @@ int emergency_action(
+ 
+         case EMERGENCY_ACTION_POWEROFF:
+                 log_and_status(m, "Powering off", reason);
+-                (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL);
++                (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL, NULL);
+                 break;
+ 
+         case EMERGENCY_ACTION_POWEROFF_FORCE:
+diff --git a/src/core/main.c b/src/core/main.c
+index 25536054b3..d897155644 100644
+--- a/src/core/main.c
++++ b/src/core/main.c
+@@ -1952,13 +1952,13 @@ static int do_queue_default_job(
+ 
+         assert(target->load_state == UNIT_LOADED);
+ 
+-        r = manager_add_job(m, JOB_START, target, JOB_ISOLATE, &error, &default_unit_job);
++        r = manager_add_job(m, JOB_START, target, JOB_ISOLATE, NULL, &error, &default_unit_job);
+         if (r == -EPERM) {
+                 log_debug_errno(r, "Default target could not be isolated, starting instead: %s", bus_error_message(&error, r));
+ 
+                 sd_bus_error_free(&error);
+ 
+-                r = manager_add_job(m, JOB_START, target, JOB_REPLACE, &error, &default_unit_job);
++                r = manager_add_job(m, JOB_START, target, JOB_REPLACE, NULL, &error, &default_unit_job);
+                 if (r < 0) {
+                         *ret_error_message = "Failed to start default target";
+                         return log_emergency_errno(r, "Failed to start default target: %s", bus_error_message(&error, r));
+diff --git a/src/core/manager.c b/src/core/manager.c
+index 4c04896aaa..012615e537 100644
+--- a/src/core/manager.c
++++ b/src/core/manager.c
+@@ -1242,7 +1242,7 @@ static unsigned manager_dispatch_stop_when_unneeded_queue(Manager *m) {
+                 }
+ 
+                 /* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */
+-                r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, &error, NULL);
++                r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, NULL, &error, NULL);
+                 if (r < 0)
+                         log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %s", bus_error_message(&error, r));
+         }
+@@ -1685,9 +1685,17 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
+         return 0;
+ }
+ 
+-int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_error *e, Job **_ret) {
+-        int r;
++int manager_add_job(
++                Manager *m,
++                JobType type,
++                Unit *unit,
++                JobMode mode,
++                Set *affected_jobs,
++                sd_bus_error *error,
++                Job **ret) {
++
+         Transaction *tr;
++        int r;
+ 
+         assert(m);
+         assert(type < _JOB_TYPE_MAX);
+@@ -1695,10 +1703,10 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_e
+         assert(mode < _JOB_MODE_MAX);
+ 
+         if (mode == JOB_ISOLATE && type != JOB_START)
+-                return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Isolate is only valid for start.");
++                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Isolate is only valid for start.");
+ 
+         if (mode == JOB_ISOLATE && !unit->allow_isolate)
+-                return sd_bus_error_setf(e, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
++                return sd_bus_error_setf(error, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
+ 
+         log_unit_debug(unit, "Trying to enqueue job %s/%s/%s", unit->id, job_type_to_string(type), job_mode_to_string(mode));
+ 
+@@ -1710,7 +1718,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_e
+ 
+         r = transaction_add_job_and_dependencies(tr, type, unit, NULL, true, false,
+                                                  IN_SET(mode, JOB_IGNORE_DEPENDENCIES, JOB_IGNORE_REQUIREMENTS),
+-                                                 mode == JOB_IGNORE_DEPENDENCIES, e);
++                                                 mode == JOB_IGNORE_DEPENDENCIES, error);
+         if (r < 0)
+                 goto tr_abort;
+ 
+@@ -1720,7 +1728,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_e
+                         goto tr_abort;
+         }
+ 
+-        r = transaction_activate(tr, m, mode, e);
++        r = transaction_activate(tr, m, mode, affected_jobs, error);
+         if (r < 0)
+                 goto tr_abort;
+ 
+@@ -1728,8 +1736,8 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_e
+                        "Enqueued job %s/%s as %u", unit->id,
+                        job_type_to_string(type), (unsigned) tr->anchor_job->id);
+ 
+-        if (_ret)
+-                *_ret = tr->anchor_job;
++        if (ret)
++                *ret = tr->anchor_job;
+ 
+         transaction_free(tr);
+         return 0;
+@@ -1740,7 +1748,7 @@ tr_abort:
+         return r;
+ }
+ 
+-int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, sd_bus_error *e, Job **ret) {
++int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, Set *affected_jobs, sd_bus_error *e, Job **ret) {
+         Unit *unit = NULL;  /* just to appease gcc, initialization is not really necessary */
+         int r;
+ 
+@@ -1754,10 +1762,10 @@ int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode
+                 return r;
+         assert(unit);
+ 
+-        return manager_add_job(m, type, unit, mode, e, ret);
++        return manager_add_job(m, type, unit, mode, affected_jobs, e, ret);
+ }
+ 
+-int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Job **ret) {
++int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Set *affected_jobs, Job **ret) {
+         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+         int r;
+ 
+@@ -1766,7 +1774,7 @@ int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name,
+         assert(name);
+         assert(mode < _JOB_MODE_MAX);
+ 
+-        r = manager_add_job_by_name(m, type, name, mode, &error, ret);
++        r = manager_add_job_by_name(m, type, name, mode, affected_jobs, &error, ret);
+         if (r < 0)
+                 return log_warning_errno(r, "Failed to enqueue %s job for %s: %s", job_mode_to_string(mode), name, bus_error_message(&error, r));
+ 
+@@ -1794,7 +1802,7 @@ int manager_propagate_reload(Manager *m, Unit *unit, JobMode mode, sd_bus_error
+         /* Failure in adding individual dependencies is ignored, so this always succeeds. */
+         transaction_add_propagate_reload_jobs(tr, unit, tr->anchor_job, mode == JOB_IGNORE_DEPENDENCIES, e);
+ 
+-        r = transaction_activate(tr, m, mode, e);
++        r = transaction_activate(tr, m, mode, NULL, e);
+         if (r < 0)
+                 goto tr_abort;
+ 
+@@ -2512,7 +2520,7 @@ static void manager_start_target(Manager *m, const char *name, JobMode mode) {
+ 
+         log_debug("Activating special unit %s", name);
+ 
+-        r = manager_add_job_by_name(m, JOB_START, name, mode, &error, NULL);
++        r = manager_add_job_by_name(m, JOB_START, name, mode, NULL, &error, NULL);
+         if (r < 0)
+                 log_error("Failed to enqueue %s job: %s", name, bus_error_message(&error, r));
+ }
+diff --git a/src/core/manager.h b/src/core/manager.h
+index 40568d3c8b..c4b8e80093 100644
+--- a/src/core/manager.h
++++ b/src/core/manager.h
+@@ -397,9 +397,9 @@ int manager_load_unit(Manager *m, const char *name, const char *path, sd_bus_err
+ int manager_load_startable_unit_or_warn(Manager *m, const char *name, const char *path, Unit **ret);
+ int manager_load_unit_from_dbus_path(Manager *m, const char *s, sd_bus_error *e, Unit **_u);
+ 
+-int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_error *e, Job **_ret);
+-int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, sd_bus_error *e, Job **_ret);
+-int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Job **ret);
++int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, Set *affected_jobs, sd_bus_error *e, Job **_ret);
++int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, Set *affected_jobs, sd_bus_error *e, Job **_ret);
++int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Set *affected_jobs,  Job **ret);
+ int manager_propagate_reload(Manager *m, Unit *unit, JobMode mode, sd_bus_error *e);
+ 
+ void manager_dump_units(Manager *s, FILE *f, const char *prefix);
+diff --git a/src/core/path.c b/src/core/path.c
+index dda4a3036b..ed40bc6c19 100644
+--- a/src/core/path.c
++++ b/src/core/path.c
+@@ -474,7 +474,7 @@ static void path_enter_running(Path *p) {
+                 return;
+         }
+ 
+-        r = manager_add_job(UNIT(p)->manager, JOB_START, trigger, JOB_REPLACE, &error, NULL);
++        r = manager_add_job(UNIT(p)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL);
+         if (r < 0)
+                 goto fail;
+ 
+diff --git a/src/core/service.c b/src/core/service.c
+index 7cff419e4e..5e3e75b5ae 100644
+--- a/src/core/service.c
++++ b/src/core/service.c
+@@ -2176,7 +2176,7 @@ static void service_enter_restart(Service *s) {
+          * restarted. We use JOB_RESTART (instead of the more obvious
+          * JOB_START) here so that those dependency jobs will be added
+          * as well. */
+-        r = manager_add_job(UNIT(s)->manager, JOB_RESTART, UNIT(s), JOB_REPLACE, &error, NULL);
++        r = manager_add_job(UNIT(s)->manager, JOB_RESTART, UNIT(s), JOB_REPLACE, NULL, &error, NULL);
+         if (r < 0)
+                 goto fail;
+ 
+diff --git a/src/core/socket.c b/src/core/socket.c
+index 7c6d3dfad1..fe061eb73b 100644
+--- a/src/core/socket.c
++++ b/src/core/socket.c
+@@ -2274,7 +2274,7 @@ static void socket_enter_running(Socket *s, int cfd) {
+                                 goto fail;
+                         }
+ 
+-                        r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT_DEREF(s->service), JOB_REPLACE, &error, NULL);
++                        r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT_DEREF(s->service), JOB_REPLACE, NULL, &error, NULL);
+                         if (r < 0)
+                                 goto fail;
+                 }
+@@ -2349,7 +2349,7 @@ static void socket_enter_running(Socket *s, int cfd) {
+ 
+                 service->peer = TAKE_PTR(p); /* Pass ownership of the peer reference */
+ 
+-                r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, &error, NULL);
++                r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, NULL, &error, NULL);
+                 if (r < 0) {
+                         /* We failed to activate the new service, but it still exists. Let's make sure the service
+                          * closes and forgets the connection fd again, immediately. */
+diff --git a/src/core/timer.c b/src/core/timer.c
+index 2876d54a59..281ac7f97f 100644
+--- a/src/core/timer.c
++++ b/src/core/timer.c
+@@ -566,7 +566,7 @@ static void timer_enter_running(Timer *t) {
+                 return;
+         }
+ 
+-        r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, &error, NULL);
++        r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL);
+         if (r < 0)
+                 goto fail;
+ 
+diff --git a/src/core/transaction.c b/src/core/transaction.c
+index 045930838b..cdaaff4f55 100644
+--- a/src/core/transaction.c
++++ b/src/core/transaction.c
+@@ -585,7 +585,12 @@ rescan:
+         }
+ }
+ 
+-static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) {
++static int transaction_apply(
++                Transaction *tr,
++                Manager *m,
++                JobMode mode,
++                Set *affected_jobs) {
++
+         Iterator i;
+         Job *j;
+         int r;
+@@ -642,6 +647,11 @@ static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) {
+                 job_add_to_dbus_queue(j);
+                 job_start_timer(j, false);
+                 job_shutdown_magic(j);
++
++                /* When 'affected' is specified, let's track all in it all jobs that were touched because of
++                 * this transaction. */
++                if (affected_jobs)
++                        (void) set_put(affected_jobs, j);
+         }
+ 
+         return 0;
+@@ -654,7 +664,13 @@ rollback:
+         return r;
+ }
+ 
+-int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error *e) {
++int transaction_activate(
++                Transaction *tr,
++                Manager *m,
++                JobMode mode,
++                Set *affected_jobs,
++                sd_bus_error *e) {
++
+         Iterator i;
+         Job *j;
+         int r;
+@@ -731,7 +747,7 @@ int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error
+                 return log_notice_errno(r, "Requested transaction contradicts existing jobs: %s", bus_error_message(e, r));
+ 
+         /* Tenth step: apply changes */
+-        r = transaction_apply(tr, m, mode);
++        r = transaction_apply(tr, m, mode, affected_jobs);
+         if (r < 0)
+                 return log_warning_errno(r, "Failed to apply transaction: %m");
+ 
+diff --git a/src/core/transaction.h b/src/core/transaction.h
+index 70d74a4ccb..4b5620f5c8 100644
+--- a/src/core/transaction.h
++++ b/src/core/transaction.h
+@@ -29,6 +29,6 @@ int transaction_add_job_and_dependencies(
+                 bool ignore_requirements,
+                 bool ignore_order,
+                 sd_bus_error *e);
+-int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error *e);
++int transaction_activate(Transaction *tr, Manager *m, JobMode mode, Set *affected, sd_bus_error *e);
+ int transaction_add_isolate_jobs(Transaction *tr, Manager *m);
+ void transaction_abort(Transaction *tr);
+diff --git a/src/core/unit.c b/src/core/unit.c
+index 29ce6c1fb7..ffbf3cfd48 100644
+--- a/src/core/unit.c
++++ b/src/core/unit.c
+@@ -2033,7 +2033,7 @@ static void unit_check_binds_to(Unit *u) {
+         log_unit_info(u, "Unit is bound to inactive unit %s. Stopping, too.", other->id);
+ 
+         /* A unit we need to run is gone. Sniff. Let's stop this. */
+-        r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, &error, NULL);
++        r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, NULL, &error, NULL);
+         if (r < 0)
+                 log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %s", bus_error_message(&error, r));
+ }
+@@ -2049,25 +2049,25 @@ static void retroactively_start_dependencies(Unit *u) {
+         HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REQUIRES], i)
+                 if (!hashmap_get(u->dependencies[UNIT_AFTER], other) &&
+                     !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
+-                        manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL);
++                        manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL, NULL);
+ 
+         HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BINDS_TO], i)
+                 if (!hashmap_get(u->dependencies[UNIT_AFTER], other) &&
+                     !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
+-                        manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL);
++                        manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL, NULL);
+ 
+         HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_WANTS], i)
+                 if (!hashmap_get(u->dependencies[UNIT_AFTER], other) &&
+                     !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
+-                        manager_add_job(u->manager, JOB_START, other, JOB_FAIL, NULL, NULL);
++                        manager_add_job(u->manager, JOB_START, other, JOB_FAIL, NULL, NULL, NULL);
+ 
+         HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_CONFLICTS], i)
+                 if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+-                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL);
++                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL, NULL);
+ 
+         HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_CONFLICTED_BY], i)
+                 if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+-                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL);
++                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL, NULL);
+ }
+ 
+ static void retroactively_stop_dependencies(Unit *u) {
+@@ -2081,7 +2081,7 @@ static void retroactively_stop_dependencies(Unit *u) {
+         /* Pull down units which are bound to us recursively if enabled */
+         HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BOUND_BY], i)
+                 if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+-                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL);
++                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL, NULL);
+ }
+ 
+ void unit_start_on_failure(Unit *u) {
+@@ -2100,7 +2100,7 @@ void unit_start_on_failure(Unit *u) {
+         HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_ON_FAILURE], i) {
+                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ 
+-                r = manager_add_job(u->manager, JOB_START, other, u->on_failure_job_mode, &error, NULL);
++                r = manager_add_job(u->manager, JOB_START, other, u->on_failure_job_mode, NULL, &error, NULL);
+                 if (r < 0)
+                         log_unit_warning_errno(u, r, "Failed to enqueue OnFailure= job, ignoring: %s", bus_error_message(&error, r));
+         }
+diff --git a/src/test/test-engine.c b/src/test/test-engine.c
+index 0f3e244dc1..f2e327b3f5 100644
+--- a/src/test/test-engine.c
++++ b/src/test/test-engine.c
+@@ -46,7 +46,7 @@ int main(int argc, char *argv[]) {
+         manager_dump_units(m, stdout, "\t");
+ 
+         printf("Test1: (Trivial)\n");
+-        r = manager_add_job(m, JOB_START, c, JOB_REPLACE, &err, &j);
++        r = manager_add_job(m, JOB_START, c, JOB_REPLACE, NULL, &err, &j);
+         if (sd_bus_error_is_set(&err))
+                 log_error("error: %s: %s", err.name, err.message);
+         assert_se(r == 0);
+@@ -59,15 +59,15 @@ int main(int argc, char *argv[]) {
+         manager_dump_units(m, stdout, "\t");
+ 
+         printf("Test2: (Cyclic Order, Unfixable)\n");
+-        assert_se(manager_add_job(m, JOB_START, d, JOB_REPLACE, NULL, &j) == -EDEADLK);
++        assert_se(manager_add_job(m, JOB_START, d, JOB_REPLACE, NULL, NULL, &j) == -EDEADLK);
+         manager_dump_jobs(m, stdout, "\t");
+ 
+         printf("Test3: (Cyclic Order, Fixable, Garbage Collector)\n");
+-        assert_se(manager_add_job(m, JOB_START, e, JOB_REPLACE, NULL, &j) == 0);
++        assert_se(manager_add_job(m, JOB_START, e, JOB_REPLACE, NULL, NULL, &j) == 0);
+         manager_dump_jobs(m, stdout, "\t");
+ 
+         printf("Test4: (Identical transaction)\n");
+-        assert_se(manager_add_job(m, JOB_START, e, JOB_FAIL, NULL, &j) == 0);
++        assert_se(manager_add_job(m, JOB_START, e, JOB_FAIL, NULL, NULL, &j) == 0);
+         manager_dump_jobs(m, stdout, "\t");
+ 
+         printf("Load3:\n");
+@@ -75,21 +75,21 @@ int main(int argc, char *argv[]) {
+         manager_dump_units(m, stdout, "\t");
+ 
+         printf("Test5: (Colliding transaction, fail)\n");
+-        assert_se(manager_add_job(m, JOB_START, g, JOB_FAIL, NULL, &j) == -EDEADLK);
++        assert_se(manager_add_job(m, JOB_START, g, JOB_FAIL, NULL, NULL, &j) == -EDEADLK);
+ 
+         printf("Test6: (Colliding transaction, replace)\n");
+-        assert_se(manager_add_job(m, JOB_START, g, JOB_REPLACE, NULL, &j) == 0);
++        assert_se(manager_add_job(m, JOB_START, g, JOB_REPLACE, NULL, NULL, &j) == 0);
+         manager_dump_jobs(m, stdout, "\t");
+ 
+         printf("Test7: (Unmergeable job type, fail)\n");
+-        assert_se(manager_add_job(m, JOB_STOP, g, JOB_FAIL, NULL, &j) == -EDEADLK);
++        assert_se(manager_add_job(m, JOB_STOP, g, JOB_FAIL, NULL, NULL, &j) == -EDEADLK);
+ 
+         printf("Test8: (Mergeable job type, fail)\n");
+-        assert_se(manager_add_job(m, JOB_RESTART, g, JOB_FAIL, NULL, &j) == 0);
++        assert_se(manager_add_job(m, JOB_RESTART, g, JOB_FAIL, NULL, NULL, &j) == 0);
+         manager_dump_jobs(m, stdout, "\t");
+ 
+         printf("Test9: (Unmergeable job type, replace)\n");
+-        assert_se(manager_add_job(m, JOB_STOP, g, JOB_REPLACE, NULL, &j) == 0);
++        assert_se(manager_add_job(m, JOB_STOP, g, JOB_REPLACE, NULL, NULL, &j) == 0);
+         manager_dump_jobs(m, stdout, "\t");
+ 
+         printf("Load4:\n");
+@@ -97,7 +97,7 @@ int main(int argc, char *argv[]) {
+         manager_dump_units(m, stdout, "\t");
+ 
+         printf("Test10: (Unmergeable job type of auxiliary job, fail)\n");
+-        assert_se(manager_add_job(m, JOB_START, h, JOB_FAIL, NULL, &j) == 0);
++        assert_se(manager_add_job(m, JOB_START, h, JOB_FAIL, NULL, NULL, &j) == 0);
+         manager_dump_jobs(m, stdout, "\t");
+ 
+         assert_se(!hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], b));
diff --git a/SOURCES/0445-systemctl-replace-switch-statement-by-table-of-struc.patch b/SOURCES/0445-systemctl-replace-switch-statement-by-table-of-struc.patch
new file mode 100644
index 0000000..b95326c
--- /dev/null
+++ b/SOURCES/0445-systemctl-replace-switch-statement-by-table-of-struc.patch
@@ -0,0 +1,115 @@
+From 8b34041ee97069bee8bf03ae5ba651b34b1b8460 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Tue, 26 Mar 2019 15:20:26 +0100
+Subject: [PATCH] systemctl: replace switch statement by table of structures
+
+(cherry picked from commit c45e5fb877033c9e3f9b79121644ed71032af379)
+
+Related: #846319
+---
+ src/systemctl/systemctl.c | 68 ++++++++++++---------------------------
+ 1 file changed, 21 insertions(+), 47 deletions(-)
+
+diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
+index e963f19b0a..04e24691d8 100644
+--- a/src/systemctl/systemctl.c
++++ b/src/systemctl/systemctl.c
+@@ -3179,64 +3179,38 @@ static int logind_set_wall_message(void) {
+ }
+ #endif
+ 
+-/* Ask systemd-logind, which might grant access to unprivileged users
+- * through PolicyKit */
++/* Ask systemd-logind, which might grant access to unprivileged users through polkit */
+ static int logind_reboot(enum action a) {
+ #if ENABLE_LOGIND
++        static const struct {
++                const char *method;
++                const char *description;
++        } actions[_ACTION_MAX] = {
++                [ACTION_POWEROFF]               = { "PowerOff",             "power off system"                },
++                [ACTION_REBOOT]                 = { "Reboot",               "reboot system"                   },
++                [ACTION_HALT]                   = { "Halt",                 "halt system"                     },
++                [ACTION_SUSPEND]                = { "Suspend",              "suspend system"                  },
++                [ACTION_HIBERNATE]              = { "Hibernate",            "hibernate system"                },
++                [ACTION_HYBRID_SLEEP]           = { "HybridSleep",          "put system into hybrid sleep"    },
++                [ACTION_SUSPEND_THEN_HIBERNATE] = { "SuspendThenHibernate", "suspend system, hibernate later" },
++        };
++
+         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+-        const char *method, *description;
+         sd_bus *bus;
+         int r;
+ 
++        if (a < 0 || a >= _ACTION_MAX || !actions[a].method)
++                return -EINVAL;
++
+         r = acquire_bus(BUS_FULL, &bus);
+         if (r < 0)
+                 return r;
+ 
+-        switch (a) {
+-
+-        case ACTION_POWEROFF:
+-                method = "PowerOff";
+-                description = "power off system";
+-                break;
+-
+-        case ACTION_REBOOT:
+-                method = "Reboot";
+-                description = "reboot system";
+-                break;
+-
+-        case ACTION_HALT:
+-                method = "Halt";
+-                description = "halt system";
+-                break;
+-
+-        case ACTION_SUSPEND:
+-                method = "Suspend";
+-                description = "suspend system";
+-                break;
+-
+-        case ACTION_HIBERNATE:
+-                method = "Hibernate";
+-                description = "hibernate system";
+-                break;
+-
+-        case ACTION_HYBRID_SLEEP:
+-                method = "HybridSleep";
+-                description = "put system into hybrid sleep";
+-                break;
+-
+-        case ACTION_SUSPEND_THEN_HIBERNATE:
+-                method = "SuspendThenHibernate";
+-                description = "put system into suspend followed by hibernate";
+-                break;
+-
+-        default:
+-                return -EINVAL;
+-        }
+-
+         polkit_agent_open_maybe();
+         (void) logind_set_wall_message();
+ 
+-        log_debug("%s org.freedesktop.login1.Manager %s dbus call.", arg_dry_run ? "Would execute" : "Executing", method);
++        log_debug("%s org.freedesktop.login1.Manager %s dbus call.", arg_dry_run ? "Would execute" : "Executing", actions[a].method);
++
+         if (arg_dry_run)
+                 return 0;
+ 
+@@ -3245,12 +3219,12 @@ static int logind_reboot(enum action a) {
+                         "org.freedesktop.login1",
+                         "/org/freedesktop/login1",
+                         "org.freedesktop.login1.Manager",
+-                        method,
++                        actions[a].method,
+                         &error,
+                         NULL,
+                         "b", arg_ask_password);
+         if (r < 0)
+-                return log_error_errno(r, "Failed to %s via logind: %s", description, bus_error_message(&error, r));
++                return log_error_errno(r, "Failed to %s via logind: %s", actions[a].description, bus_error_message(&error, r));
+ 
+         return 0;
+ #else
diff --git a/SOURCES/0446-systemctl-reindent-table.patch b/SOURCES/0446-systemctl-reindent-table.patch
new file mode 100644
index 0000000..22ad788
--- /dev/null
+++ b/SOURCES/0446-systemctl-reindent-table.patch
@@ -0,0 +1,53 @@
+From 26d2d89c6216672cedf6abfe1b73081adebbdcf8 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Tue, 26 Mar 2019 15:49:52 +0100
+Subject: [PATCH] systemctl: reindent table
+
+(cherry picked from commit 5fd77930ad9980af5257f9f871556d6973db736c)
+
+Related: #846319
+---
+ src/systemctl/systemctl.c | 30 +++++++++++++++---------------
+ 1 file changed, 15 insertions(+), 15 deletions(-)
+
+diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
+index 04e24691d8..f057dc829c 100644
+--- a/src/systemctl/systemctl.c
++++ b/src/systemctl/systemctl.c
+@@ -2974,21 +2974,21 @@ static const struct {
+         const char *verb;
+         const char *mode;
+ } action_table[_ACTION_MAX] = {
+-        [ACTION_HALT]                 = { SPECIAL_HALT_TARGET,                     "halt",                   "replace-irreversibly" },
+-        [ACTION_POWEROFF]             = { SPECIAL_POWEROFF_TARGET,                 "poweroff",               "replace-irreversibly" },
+-        [ACTION_REBOOT]               = { SPECIAL_REBOOT_TARGET,                   "reboot",                 "replace-irreversibly" },
+-        [ACTION_KEXEC]                = { SPECIAL_KEXEC_TARGET,                    "kexec",                  "replace-irreversibly" },
+-        [ACTION_RUNLEVEL2]            = { SPECIAL_MULTI_USER_TARGET,               NULL,                     "isolate" },
+-        [ACTION_RUNLEVEL3]            = { SPECIAL_MULTI_USER_TARGET,               NULL,                     "isolate" },
+-        [ACTION_RUNLEVEL4]            = { SPECIAL_MULTI_USER_TARGET,               NULL,                     "isolate" },
+-        [ACTION_RUNLEVEL5]            = { SPECIAL_GRAPHICAL_TARGET,                NULL,                     "isolate" },
+-        [ACTION_RESCUE]               = { SPECIAL_RESCUE_TARGET,                   "rescue",                 "isolate" },
+-        [ACTION_EMERGENCY]            = { SPECIAL_EMERGENCY_TARGET,                "emergency",              "isolate" },
+-        [ACTION_DEFAULT]              = { SPECIAL_DEFAULT_TARGET,                  "default",                "isolate" },
+-        [ACTION_EXIT]                 = { SPECIAL_EXIT_TARGET,                     "exit",                   "replace-irreversibly" },
+-        [ACTION_SUSPEND]              = { SPECIAL_SUSPEND_TARGET,                  "suspend",                "replace-irreversibly" },
+-        [ACTION_HIBERNATE]            = { SPECIAL_HIBERNATE_TARGET,                "hibernate",              "replace-irreversibly" },
+-        [ACTION_HYBRID_SLEEP]         = { SPECIAL_HYBRID_SLEEP_TARGET,             "hybrid-sleep",           "replace-irreversibly" },
++        [ACTION_HALT]                   = { SPECIAL_HALT_TARGET,                   "halt",                   "replace-irreversibly" },
++        [ACTION_POWEROFF]               = { SPECIAL_POWEROFF_TARGET,               "poweroff",               "replace-irreversibly" },
++        [ACTION_REBOOT]                 = { SPECIAL_REBOOT_TARGET,                 "reboot",                 "replace-irreversibly" },
++        [ACTION_KEXEC]                  = { SPECIAL_KEXEC_TARGET,                  "kexec",                  "replace-irreversibly" },
++        [ACTION_RUNLEVEL2]              = { SPECIAL_MULTI_USER_TARGET,             NULL,                     "isolate"              },
++        [ACTION_RUNLEVEL3]              = { SPECIAL_MULTI_USER_TARGET,             NULL,                     "isolate"              },
++        [ACTION_RUNLEVEL4]              = { SPECIAL_MULTI_USER_TARGET,             NULL,                     "isolate"              },
++        [ACTION_RUNLEVEL5]              = { SPECIAL_GRAPHICAL_TARGET,              NULL,                     "isolate"              },
++        [ACTION_RESCUE]                 = { SPECIAL_RESCUE_TARGET,                 "rescue",                 "isolate"              },
++        [ACTION_EMERGENCY]              = { SPECIAL_EMERGENCY_TARGET,              "emergency",              "isolate"              },
++        [ACTION_DEFAULT]                = { SPECIAL_DEFAULT_TARGET,                "default",                "isolate"              },
++        [ACTION_EXIT]                   = { SPECIAL_EXIT_TARGET,                   "exit",                   "replace-irreversibly" },
++        [ACTION_SUSPEND]                = { SPECIAL_SUSPEND_TARGET,                "suspend",                "replace-irreversibly" },
++        [ACTION_HIBERNATE]              = { SPECIAL_HIBERNATE_TARGET,              "hibernate",              "replace-irreversibly" },
++        [ACTION_HYBRID_SLEEP]           = { SPECIAL_HYBRID_SLEEP_TARGET,           "hybrid-sleep",           "replace-irreversibly" },
+         [ACTION_SUSPEND_THEN_HIBERNATE] = { SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET, "suspend-then-hibernate", "replace-irreversibly" },
+ };
+ 
diff --git a/SOURCES/0447-systemctl-Only-wait-when-there-s-something-to-wait-f.patch b/SOURCES/0447-systemctl-Only-wait-when-there-s-something-to-wait-f.patch
new file mode 100644
index 0000000..2cd38d4
--- /dev/null
+++ b/SOURCES/0447-systemctl-Only-wait-when-there-s-something-to-wait-f.patch
@@ -0,0 +1,29 @@
+From 91c83bde0904581fbc33eb7821119e665b9505ce Mon Sep 17 00:00:00 2001
+From: Filipe Brandenburger <filbranden@google.com>
+Date: Fri, 20 Jul 2018 11:32:55 -0700
+Subject: [PATCH] systemctl: Only wait when there's something to wait for.
+
+Tested:
+- `systemctl --wait start i-do-not-exist.service` does not wait.
+- `systemctl --wait start i-do-not-exist.service valid-unit.service` does.
+
+(cherry picked from commit 46f2579c2ac9f6780d5afec1000764defc6b581e)
+
+Related: #846319
+---
+ src/systemctl/systemctl.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
+index f057dc829c..1929692480 100644
+--- a/src/systemctl/systemctl.c
++++ b/src/systemctl/systemctl.c
+@@ -3130,7 +3130,7 @@ static int start_unit(int argc, char *argv[], void *userdata) {
+                                 check_triggering_units(bus, *name);
+         }
+ 
+-        if (r >= 0 && arg_wait) {
++        if (r >= 0 && arg_wait && !set_isempty(wait_context.unit_paths)) {
+                 int q;
+                 q = sd_event_loop(wait_context.event);
+                 if (q < 0)
diff --git a/SOURCES/0448-systemctl-clean-up-start_unit_one-error-handling.patch b/SOURCES/0448-systemctl-clean-up-start_unit_one-error-handling.patch
new file mode 100644
index 0000000..ffd9a76
--- /dev/null
+++ b/SOURCES/0448-systemctl-clean-up-start_unit_one-error-handling.patch
@@ -0,0 +1,99 @@
+From 7569756d005d4f780fffd2504eb6f461982833f2 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Sat, 13 Oct 2018 14:38:46 +0200
+Subject: [PATCH] systemctl: clean up start_unit_one() error handling
+
+Let's split exit code handling in two: "r" is only used for errno-style
+errors, and "ret" is used for exit() codes. Then, let's use EXIT_SUCCESS
+for checking whether the latter is already used.
+
+This way it should always be clear what kind of error we are processing,
+and when we propaate one into the other.
+
+Moreover this allows us to drop "q" form all inner loops, avoiding
+confusion when to use "q" and when "r" to store received errors.
+
+Fixes: #9704
+(cherry picked from commit 0e8d9c0c4d7e71487c486f626c59853cfb031d16)
+
+Related: #846319
+---
+ src/systemctl/systemctl.c | 32 +++++++++++++++-----------------
+ 1 file changed, 15 insertions(+), 17 deletions(-)
+
+diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
+index 1929692480..4af9deb98d 100644
+--- a/src/systemctl/systemctl.c
++++ b/src/systemctl/systemctl.c
+@@ -3004,12 +3004,12 @@ static enum action verb_to_action(const char *verb) {
+ 
+ static int start_unit(int argc, char *argv[], void *userdata) {
+         _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
++        _cleanup_(wait_context_free) WaitContext wait_context = {};
+         const char *method, *mode, *one_name, *suffix = NULL;
+         _cleanup_strv_free_ char **names = NULL;
++        int r, ret = EXIT_SUCCESS;
+         sd_bus *bus;
+-        _cleanup_(wait_context_free) WaitContext wait_context = {};
+         char **name;
+-        int r = 0;
+ 
+         if (arg_wait && !STR_IN_SET(argv[0], "start", "restart")) {
+                 log_error("--wait may only be used with the 'start' or 'restart' commands.");
+@@ -3096,16 +3096,15 @@ static int start_unit(int argc, char *argv[], void *userdata) {
+ 
+         STRV_FOREACH(name, names) {
+                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+-                int q;
+ 
+-                q = start_unit_one(bus, method, *name, mode, &error, w, arg_wait ? &wait_context : NULL);
+-                if (r >= 0 && q < 0)
+-                        r = translate_bus_error_to_exit_status(q, &error);
++                r = start_unit_one(bus, method, *name, mode, &error, w, arg_wait ? &wait_context : NULL);
++                if (ret == EXIT_SUCCESS && r < 0)
++                        ret = translate_bus_error_to_exit_status(r, &error);
+         }
+ 
+         if (!arg_no_block) {
+-                int q, arg_count = 0;
+                 const char* extra_args[4] = {};
++                int arg_count = 0;
+ 
+                 if (arg_scope != UNIT_FILE_SYSTEM)
+                         extra_args[arg_count++] = "--user";
+@@ -3119,9 +3118,9 @@ static int start_unit(int argc, char *argv[], void *userdata) {
+                         extra_args[arg_count++] = arg_host;
+                 }
+ 
+-                q = bus_wait_for_jobs(w, arg_quiet, extra_args);
+-                if (q < 0)
+-                        return q;
++                r = bus_wait_for_jobs(w, arg_quiet, extra_args);
++                if (r < 0)
++                        return r;
+ 
+                 /* When stopping units, warn if they can still be triggered by
+                  * another active unit (socket, path, timer) */
+@@ -3130,16 +3129,15 @@ static int start_unit(int argc, char *argv[], void *userdata) {
+                                 check_triggering_units(bus, *name);
+         }
+ 
+-        if (r >= 0 && arg_wait && !set_isempty(wait_context.unit_paths)) {
+-                int q;
+-                q = sd_event_loop(wait_context.event);
+-                if (q < 0)
+-                        return log_error_errno(q, "Failed to run event loop: %m");
++        if (ret == EXIT_SUCCESS && arg_wait && !set_isempty(wait_context.unit_paths)) {
++                r = sd_event_loop(wait_context.event);
++                if (r < 0)
++                        return log_error_errno(r, "Failed to run event loop: %m");
+                 if (wait_context.any_failed)
+-                        r = EXIT_FAILURE;
++                        ret = EXIT_FAILURE;
+         }
+ 
+-        return r;
++        return ret;
+ }
+ 
+ #if ENABLE_LOGIND
diff --git a/SOURCES/0449-systemctl-split-out-extra-args-generation-into-helpe.patch b/SOURCES/0449-systemctl-split-out-extra-args-generation-into-helpe.patch
new file mode 100644
index 0000000..a580c7a
--- /dev/null
+++ b/SOURCES/0449-systemctl-split-out-extra-args-generation-into-helpe.patch
@@ -0,0 +1,68 @@
+From cfb124260a0a9e68102a373c0d136f792e2d4ea7 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Tue, 26 Mar 2019 16:19:35 +0100
+Subject: [PATCH] systemctl: split out extra args generation into helper
+ function of its own
+
+(cherry picked from commit 94369fc0663255bbd327f97dba288ececf51a514)
+
+Related: #846319
+---
+ src/systemctl/systemctl.c | 36 +++++++++++++++++++++---------------
+ 1 file changed, 21 insertions(+), 15 deletions(-)
+
+diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
+index 4af9deb98d..e7a8fd559f 100644
+--- a/src/systemctl/systemctl.c
++++ b/src/systemctl/systemctl.c
+@@ -3002,6 +3002,25 @@ static enum action verb_to_action(const char *verb) {
+         return _ACTION_INVALID;
+ }
+ 
++static const char** make_extra_args(const char *extra_args[static 4]) {
++        size_t n = 0;
++
++        if (arg_scope != UNIT_FILE_SYSTEM)
++                extra_args[n++] = "--user";
++
++        if (arg_transport == BUS_TRANSPORT_REMOTE) {
++                extra_args[n++] = "-H";
++                extra_args[n++] = arg_host;
++        } else if (arg_transport == BUS_TRANSPORT_MACHINE) {
++                extra_args[n++] = "-M";
++                extra_args[n++] = arg_host;
++        } else
++                assert(arg_transport == BUS_TRANSPORT_LOCAL);
++
++        extra_args[n] = NULL;
++        return extra_args;
++}
++
+ static int start_unit(int argc, char *argv[], void *userdata) {
+         _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
+         _cleanup_(wait_context_free) WaitContext wait_context = {};
+@@ -3103,22 +3122,9 @@ static int start_unit(int argc, char *argv[], void *userdata) {
+         }
+ 
+         if (!arg_no_block) {
+-                const char* extra_args[4] = {};
+-                int arg_count = 0;
+-
+-                if (arg_scope != UNIT_FILE_SYSTEM)
+-                        extra_args[arg_count++] = "--user";
+-
+-                assert(IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_REMOTE, BUS_TRANSPORT_MACHINE));
+-                if (arg_transport == BUS_TRANSPORT_REMOTE) {
+-                        extra_args[arg_count++] = "-H";
+-                        extra_args[arg_count++] = arg_host;
+-                } else if (arg_transport == BUS_TRANSPORT_MACHINE) {
+-                        extra_args[arg_count++] = "-M";
+-                        extra_args[arg_count++] = arg_host;
+-                }
++                const char* extra_args[4];
+ 
+-                r = bus_wait_for_jobs(w, arg_quiet, extra_args);
++                r = bus_wait_for_jobs(w, arg_quiet, make_extra_args(extra_args));
+                 if (r < 0)
+                         return r;
+ 
diff --git a/SOURCES/0450-systemctl-add-new-show-transaction-switch.patch b/SOURCES/0450-systemctl-add-new-show-transaction-switch.patch
new file mode 100644
index 0000000..1e804b0
--- /dev/null
+++ b/SOURCES/0450-systemctl-add-new-show-transaction-switch.patch
@@ -0,0 +1,362 @@
+From cacf7a619cdccd9a6da6c2fe7361eac121b9ea0b Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Fri, 22 Mar 2019 20:58:13 +0100
+Subject: [PATCH] systemctl: add new --show-transaction switch
+
+This new switch uses the new method call EnqueueUnitJob() for enqueuing
+a job and showing the jobs it enqueued.
+
+Fixes: #2297
+(cherry picked from commit 85d9b5981ba6b7ee3955f95fa6cf3bb8cdf3444d)
+
+Resolves: #846319
+---
+ src/systemctl/systemctl.c | 183 ++++++++++++++++++++++++++------------
+ 1 file changed, 128 insertions(+), 55 deletions(-)
+
+diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
+index e7a8fd559f..8bec798373 100644
+--- a/src/systemctl/systemctl.c
++++ b/src/systemctl/systemctl.c
+@@ -126,6 +126,7 @@ static bool arg_dry_run = false;
+ static bool arg_quiet = false;
+ static bool arg_full = false;
+ static bool arg_recursive = false;
++static bool arg_show_transaction = false;
+ static int arg_force = 0;
+ static bool arg_ask_password = false;
+ static bool arg_runtime = false;
+@@ -734,7 +735,6 @@ static int get_unit_list_recursive(
+                 *_machines = NULL;
+ 
+         *_unit_infos = TAKE_PTR(unit_infos);
+-
+         *_replies = TAKE_PTR(replies);
+ 
+         return c;
+@@ -2688,25 +2688,26 @@ static int check_triggering_units(sd_bus *bus, const char *name) {
+ }
+ 
+ static const struct {
+-        const char *verb;
+-        const char *method;
++        const char *verb;      /* systemctl verb */
++        const char *method;    /* Name of the specific D-Bus method */
++        const char *job_type;  /* Job type when passing to the generic EnqueueUnitJob() method */
+ } unit_actions[] = {
+-        { "start",                 "StartUnit" },
+-        { "stop",                  "StopUnit" },
+-        { "condstop",              "StopUnit" },
+-        { "reload",                "ReloadUnit" },
+-        { "restart",               "RestartUnit" },
+-        { "try-restart",           "TryRestartUnit" },
+-        { "condrestart",           "TryRestartUnit" },
+-        { "reload-or-restart",     "ReloadOrRestartUnit" },
+-        { "try-reload-or-restart", "ReloadOrTryRestartUnit" },
+-        { "reload-or-try-restart", "ReloadOrTryRestartUnit" },
+-        { "condreload",            "ReloadOrTryRestartUnit" },
+-        { "force-reload",          "ReloadOrTryRestartUnit" }
++        { "start",                 "StartUnit",              "start"                 },
++        { "stop",                  "StopUnit",               "stop"                  },
++        { "condstop",              "StopUnit",               "stop"                  }, /* legacy alias */
++        { "reload",                "ReloadUnit",             "reload"                },
++        { "restart",               "RestartUnit",            "restart"               },
++        { "try-restart",           "TryRestartUnit",         "try-restart"           },
++        { "condrestart",           "TryRestartUnit",         "try-restart"           }, /* legacy alias */
++        { "reload-or-restart",     "ReloadOrRestartUnit",    "reload-or-restart"     },
++        { "try-reload-or-restart", "ReloadOrTryRestartUnit", "reload-or-try-restart" },
++        { "reload-or-try-restart", "ReloadOrTryRestartUnit", "reload-or-try-restart" }, /* legacy alias */
++        { "condreload",            "ReloadOrTryRestartUnit", "reload-or-try-restart" }, /* legacy alias */
++        { "force-reload",          "ReloadOrTryRestartUnit", "reload-or-try-restart" }, /* legacy alias */
+ };
+ 
+ static const char *verb_to_method(const char *verb) {
+-       uint i;
++       size_t i;
+ 
+        for (i = 0; i < ELEMENTSOF(unit_actions); i++)
+                 if (streq_ptr(unit_actions[i].verb, verb))
+@@ -2715,14 +2716,14 @@ static const char *verb_to_method(const char *verb) {
+        return "StartUnit";
+ }
+ 
+-static const char *method_to_verb(const char *method) {
+-       uint i;
++static const char *verb_to_job_type(const char *verb) {
++       size_t i;
+ 
+        for (i = 0; i < ELEMENTSOF(unit_actions); i++)
+-                if (streq_ptr(unit_actions[i].method, method))
+-                        return unit_actions[i].verb;
++                if (streq_ptr(unit_actions[i].verb, verb))
++                        return unit_actions[i].job_type;
+ 
+-       return "n/a";
++       return "start";
+ }
+ 
+ typedef struct {
+@@ -2805,7 +2806,8 @@ static int on_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error
+ 
+ static int start_unit_one(
+                 sd_bus *bus,
+-                const char *method,
++                const char *method,    /* When using classic per-job bus methods */
++                const char *job_type,  /* When using new-style EnqueueUnitJob() */
+                 const char *name,
+                 const char *mode,
+                 sd_bus_error *error,
+@@ -2814,6 +2816,7 @@ static int start_unit_one(
+ 
+         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+         const char *path;
++        bool done = false;
+         int r;
+ 
+         assert(method);
+@@ -2859,44 +2862,81 @@ static int start_unit_one(
+         log_debug("%s dbus call org.freedesktop.systemd1.Manager %s(%s, %s)",
+                   arg_dry_run ? "Would execute" : "Executing",
+                   method, name, mode);
++
+         if (arg_dry_run)
+                 return 0;
+ 
+-        r = sd_bus_call_method(
+-                        bus,
+-                        "org.freedesktop.systemd1",
+-                        "/org/freedesktop/systemd1",
+-                        "org.freedesktop.systemd1.Manager",
+-                        method,
+-                        error,
+-                        &reply,
+-                        "ss", name, mode);
+-        if (r < 0) {
+-                const char *verb;
++        if (arg_show_transaction) {
++                _cleanup_(sd_bus_error_free) sd_bus_error enqueue_error = SD_BUS_ERROR_NULL;
+ 
+-                /* There's always a fallback possible for legacy actions. */
+-                if (arg_action != ACTION_SYSTEMCTL)
+-                        return r;
++                /* Use the new, fancy EnqueueUnitJob() API if the user wants us to print the transaction */
++                r = sd_bus_call_method(
++                                bus,
++                                "org.freedesktop.systemd1",
++                                "/org/freedesktop/systemd1",
++                                "org.freedesktop.systemd1.Manager",
++                                "EnqueueUnitJob",
++                                &enqueue_error,
++                                &reply,
++                                "sss",
++                                name, job_type, mode);
++                if (r < 0) {
++                        if (!sd_bus_error_has_name(&enqueue_error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
++                                (void) sd_bus_error_copy(error, &enqueue_error);
++                                sd_bus_error_free(&enqueue_error);
++                                goto fail;
++                        }
++
++                        /* Hmm, the API is not yet available. Let's use the classic API instead (see below). */
++                        log_notice("--show-transaction not supported by this service manager, proceeding without.");
++                } else {
++                        const char *u, *jt;
++                        uint32_t id;
+ 
+-                verb = method_to_verb(method);
++                        r = sd_bus_message_read(reply, "uosos", &id, &path, &u, NULL, &jt);
++                        if (r < 0)
++                                return bus_log_parse_error(r);
+ 
+-                log_error("Failed to %s %s: %s", verb, name, bus_error_message(error, r));
++                        log_info("Enqueued anchor job %" PRIu32 " %s/%s.", id, u, jt);
+ 
+-                if (!sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) &&
+-                    !sd_bus_error_has_name(error, BUS_ERROR_UNIT_MASKED) &&
+-                    !sd_bus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE))
+-                        log_error("See %s logs and 'systemctl%s status%s %s' for details.",
+-                                   arg_scope == UNIT_FILE_SYSTEM ? "system" : "user",
+-                                   arg_scope == UNIT_FILE_SYSTEM ? "" : " --user",
+-                                   name[0] == '-' ? " --" : "",
+-                                   name);
++                        r = sd_bus_message_enter_container(reply, 'a', "(uosos)");
++                        if (r < 0)
++                                return bus_log_parse_error(r);
++                        for (;;) {
++                                r = sd_bus_message_read(reply, "(uosos)", &id, NULL, &u, NULL, &jt);
++                                if (r < 0)
++                                        return bus_log_parse_error(r);
++                                if (r == 0)
++                                        break;
+ 
+-                return r;
++                                log_info("Enqueued auxiliary job %" PRIu32 " %s/%s.", id, u, jt);
++                        }
++
++                        r = sd_bus_message_exit_container(reply);
++                        if (r < 0)
++                                return bus_log_parse_error(r);
++
++                        done = true;
++                }
+         }
+ 
+-        r = sd_bus_message_read(reply, "o", &path);
+-        if (r < 0)
+-                return bus_log_parse_error(r);
++        if (!done) {
++                r = sd_bus_call_method(
++                                bus,
++                                "org.freedesktop.systemd1",
++                                "/org/freedesktop/systemd1",
++                                "org.freedesktop.systemd1.Manager",
++                                method,
++                                error,
++                                &reply,
++                                "ss", name, mode);
++                if (r < 0)
++                        goto fail;
++
++                r = sd_bus_message_read(reply, "o", &path);
++                if (r < 0)
++                        return bus_log_parse_error(r);
++        }
+ 
+         if (need_daemon_reload(bus, name) > 0)
+                 warn_unit_file_changed(name);
+@@ -2909,6 +2949,24 @@ static int start_unit_one(
+         }
+ 
+         return 0;
++
++fail:
++        /* There's always a fallback possible for legacy actions. */
++        if (arg_action != ACTION_SYSTEMCTL)
++                return r;
++
++        log_error_errno(r, "Failed to %s %s: %s", job_type, name, bus_error_message(error, r));
++
++        if (!sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) &&
++            !sd_bus_error_has_name(error, BUS_ERROR_UNIT_MASKED) &&
++            !sd_bus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE))
++                log_error("See %s logs and 'systemctl%s status%s %s' for details.",
++                          arg_scope == UNIT_FILE_SYSTEM ? "system" : "user",
++                          arg_scope == UNIT_FILE_SYSTEM ? "" : " --user",
++                          name[0] == '-' ? " --" : "",
++                          name);
++
++        return r;
+ }
+ 
+ static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***ret) {
+@@ -2965,7 +3023,6 @@ static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***r
+         }
+ 
+         *ret = TAKE_PTR(mangled);
+-
+         return 0;
+ }
+ 
+@@ -3024,7 +3081,7 @@ static const char** make_extra_args(const char *extra_args[static 4]) {
+ static int start_unit(int argc, char *argv[], void *userdata) {
+         _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
+         _cleanup_(wait_context_free) WaitContext wait_context = {};
+-        const char *method, *mode, *one_name, *suffix = NULL;
++        const char *method, *job_type, *mode, *one_name, *suffix = NULL;
+         _cleanup_strv_free_ char **names = NULL;
+         int r, ret = EXIT_SUCCESS;
+         sd_bus *bus;
+@@ -3050,27 +3107,34 @@ static int start_unit(int argc, char *argv[], void *userdata) {
+                 action = verb_to_action(argv[0]);
+ 
+                 if (action != _ACTION_INVALID) {
++                        /* A command in style "systemctl reboot", "systemctl poweroff", … */
+                         method = "StartUnit";
++                        job_type = "start";
+                         mode = action_table[action].mode;
+                         one_name = action_table[action].target;
+                 } else {
+                         if (streq(argv[0], "isolate")) {
++                                /* A "systemctl isolate <unit1> <unit2> …" command */
+                                 method = "StartUnit";
++                                job_type = "start";
+                                 mode = "isolate";
+-
+                                 suffix = ".target";
+                         } else {
++                                /* A command in style of "systemctl start <unit1> <unit2> …", "sysemctl stop <unit1> <unit2> …" and so on */
+                                 method = verb_to_method(argv[0]);
++                                job_type = verb_to_job_type(argv[0]);
+                                 mode = arg_job_mode;
+                         }
+                         one_name = NULL;
+                 }
+         } else {
++                /* A SysV legacy command such as "halt", "reboot", "poweroff", … */
+                 assert(arg_action >= 0 && arg_action < _ACTION_MAX);
+                 assert(action_table[arg_action].target);
+                 assert(action_table[arg_action].mode);
+ 
+                 method = "StartUnit";
++                job_type = "start";
+                 mode = action_table[arg_action].mode;
+                 one_name = action_table[arg_action].target;
+         }
+@@ -3105,9 +3169,11 @@ static int start_unit(int argc, char *argv[], void *userdata) {
+                                 NULL);
+                 if (r < 0)
+                         return log_error_errno(r, "Failed to enable subscription: %m");
++
+                 r = sd_event_default(&wait_context.event);
+                 if (r < 0)
+                         return log_error_errno(r, "Failed to allocate event loop: %m");
++
+                 r = sd_bus_attach_event(bus, wait_context.event, 0);
+                 if (r < 0)
+                         return log_error_errno(r, "Failed to attach bus to event loop: %m");
+@@ -3116,7 +3182,7 @@ static int start_unit(int argc, char *argv[], void *userdata) {
+         STRV_FOREACH(name, names) {
+                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ 
+-                r = start_unit_one(bus, method, *name, mode, &error, w, arg_wait ? &wait_context : NULL);
++                r = start_unit_one(bus, method, job_type, *name, mode, &error, w, arg_wait ? &wait_context : NULL);
+                 if (ret == EXIT_SUCCESS && r < 0)
+                         ret = translate_bus_error_to_exit_status(r, &error);
+         }
+@@ -7167,6 +7233,8 @@ static void systemctl_help(void) {
+                "     --reverse        Show reverse dependencies with 'list-dependencies'\n"
+                "     --job-mode=MODE  Specify how to deal with already queued jobs, when\n"
+                "                      queueing a new job\n"
++               "  -T --show-transaction\n"
++               "                      When enqueuing a unit job, show full transaction\n"
+                "     --show-types     When showing sockets, explicitly show their type\n"
+                "     --value          When showing properties, only print the value\n"
+                "  -i --ignore-inhibitors\n"
+@@ -7482,6 +7550,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
+                 { "firmware-setup",      no_argument,       NULL, ARG_FIRMWARE_SETUP      },
+                 { "now",                 no_argument,       NULL, ARG_NOW                 },
+                 { "message",             required_argument, NULL, ARG_MESSAGE             },
++                { "show-transaction",    no_argument,       NULL, 'T'                     },
+                 {}
+         };
+ 
+@@ -7494,7 +7563,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
+         /* we default to allowing interactive authorization only in systemctl (not in the legacy commands) */
+         arg_ask_password = true;
+ 
+-        while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:ir", options, NULL)) >= 0)
++        while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:iTr", options, NULL)) >= 0)
+ 
+                 switch (c) {
+ 
+@@ -7815,6 +7884,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
+                                 return log_oom();
+                         break;
+ 
++                case 'T':
++                        arg_show_transaction = true;
++                        break;
++
+                 case '?':
+                         return -EINVAL;
+ 
diff --git a/SOURCES/0451-test-add-some-basic-testing-that-systemctl-start-T-d.patch b/SOURCES/0451-test-add-some-basic-testing-that-systemctl-start-T-d.patch
new file mode 100644
index 0000000..13c3808
--- /dev/null
+++ b/SOURCES/0451-test-add-some-basic-testing-that-systemctl-start-T-d.patch
@@ -0,0 +1,31 @@
+From f31afbfd2fa68e20a10a8432fb4714a6d4e1170a Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Tue, 26 Mar 2019 17:39:36 +0100
+Subject: [PATCH] test: add some basic testing that "systemctl start -T" does
+ something
+
+(cherry picked from commit f087c7e072bb338d5c7c0781c9fbc900612efd18)
+
+Related: #846319
+---
+ test/TEST-03-JOBS/test-jobs.sh | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/test/TEST-03-JOBS/test-jobs.sh b/test/TEST-03-JOBS/test-jobs.sh
+index e66ea53621..42190cf478 100755
+--- a/test/TEST-03-JOBS/test-jobs.sh
++++ b/test/TEST-03-JOBS/test-jobs.sh
+@@ -26,6 +26,13 @@ grep 'sleep\.service.*running' /root/list-jobs.txt
+ grep 'hello\.service' /root/list-jobs.txt && exit 1
+ systemctl stop sleep.service hello-after-sleep.target
+ 
++# Some basic testing that --show-transaction does something useful
++! systemctl is-active systemd-importd
++systemctl -T start systemd-importd
++systemctl is-active systemd-importd
++systemctl --show-transaction stop systemd-importd
++! systemctl is-active systemd-importd
++
+ # Test for a crash when enqueuing a JOB_NOP when other job already exists
+ systemctl start --no-block hello-after-sleep.target
+ # hello.service should still be waiting, so these try-restarts will collapse
diff --git a/SOURCES/0452-man-document-the-new-systemctl-show-transaction-opti.patch b/SOURCES/0452-man-document-the-new-systemctl-show-transaction-opti.patch
new file mode 100644
index 0000000..1f8b8ce
--- /dev/null
+++ b/SOURCES/0452-man-document-the-new-systemctl-show-transaction-opti.patch
@@ -0,0 +1,37 @@
+From 588e3e8008d24021ec025d54318fb07d2212293c Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Tue, 26 Mar 2019 18:02:49 +0100
+Subject: [PATCH] man: document the new systemctl --show-transaction option
+
+(cherry picked from commit df4a7cb7323c8cf00553d766913312c5b7ccd508)
+
+Related: #846319
+---
+ man/systemctl.xml | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/man/systemctl.xml b/man/systemctl.xml
+index 6145486123..fa08ab6c0a 100644
+--- a/man/systemctl.xml
++++ b/man/systemctl.xml
+@@ -298,6 +298,20 @@
+ 
+       </varlistentry>
+ 
++      <varlistentry>
++        <term><option>-T</option></term>
++        <term><option>--show-transaction</option></term>
++
++        <listitem>
++          <para>When enqueuing a unit job (for example as effect of a <command>systemctl start</command>
++          invocation or similar), show brief information about all jobs enqueued, covering both the requested
++          job and any added because of unit dependencies. Note that the output will only include jobs
++          immediately part of the transaction requested. It is possible that service start-up program code
++          run as effect of the enqueued jobs might request further jobs to be pulled in. This means that
++          completion of the listed jobs might ultimately entail more jobs than the listed ones.</para>
++        </listitem>
++      </varlistentry>
++
+       <varlistentry>
+         <term><option>--fail</option></term>
+ 
diff --git a/SOURCES/0453-socket-New-option-FlushPending-boolean-to-flush-sock.patch b/SOURCES/0453-socket-New-option-FlushPending-boolean-to-flush-sock.patch
new file mode 100644
index 0000000..357f076
--- /dev/null
+++ b/SOURCES/0453-socket-New-option-FlushPending-boolean-to-flush-sock.patch
@@ -0,0 +1,153 @@
+From 262544a451c11c38e92c45047ec2adeaeb2a0a7e Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
+Date: Thu, 20 Aug 2020 13:00:37 +0200
+Subject: [PATCH] socket: New option 'FlushPending' (boolean) to flush socket
+ before entering listening state
+
+Disabled by default. When Enabled, before listening on the socket, flush the content.
+Applies when Accept=no only.
+
+(cherry picked from commit 3e5f04bf6468fcb79c080f02b0eab08f258bff0c)
+
+Resolves: #1870638
+---
+ doc/TRANSIENT-SETTINGS.md             |  1 +
+ man/systemd.socket.xml                | 12 ++++++++++++
+ src/core/dbus-socket.c                |  4 ++++
+ src/core/load-fragment-gperf.gperf.m4 |  1 +
+ src/core/socket.c                     | 11 +++++++++++
+ src/core/socket.h                     |  1 +
+ src/shared/bus-unit-util.c            |  3 ++-
+ 7 files changed, 32 insertions(+), 1 deletion(-)
+
+diff --git a/doc/TRANSIENT-SETTINGS.md b/doc/TRANSIENT-SETTINGS.md
+index 1a4e79190a..995b8797ef 100644
+--- a/doc/TRANSIENT-SETTINGS.md
++++ b/doc/TRANSIENT-SETTINGS.md
+@@ -388,6 +388,7 @@ Most socket unit settings are available to transient units.
+ ✓ SocketMode=
+ ✓ DirectoryMode=
+ ✓ Accept=
++✓ FlushPending=
+ ✓ Writable=
+ ✓ MaxConnections=
+ ✓ MaxConnectionsPerSource=
+diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml
+index 19c2ca9907..8676b4e03f 100644
+--- a/man/systemd.socket.xml
++++ b/man/systemd.socket.xml
+@@ -425,6 +425,18 @@
+         false, in read-only mode. Defaults to false.</para></listitem>
+       </varlistentry>
+ 
++      <varlistentry>
++        <term><varname>FlushPending=</varname></term>
++        <listitem><para>Takes a boolean argument. May only be used when
++        <option>Accept=no</option>. If yes, the socket's buffers are cleared after the
++        triggered service exited. This causes any pending data to be
++        flushed and any pending incoming connections to be rejected. If no, the
++        socket's buffers won't be cleared, permitting the service to handle any
++        pending connections after restart, which is the usually expected behaviour.
++        Defaults to <option>no</option>.
++        </para></listitem>
++      </varlistentry>
++
+       <varlistentry>
+         <term><varname>MaxConnections=</varname></term>
+         <listitem><para>The maximum number of connections to
+diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c
+index 913cc74918..bb77539030 100644
+--- a/src/core/dbus-socket.c
++++ b/src/core/dbus-socket.c
+@@ -85,6 +85,7 @@ const sd_bus_vtable bus_socket_vtable[] = {
+         SD_BUS_PROPERTY("SocketMode", "u", bus_property_get_mode, offsetof(Socket, socket_mode), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Socket, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("Accept", "b", bus_property_get_bool, offsetof(Socket, accept), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("FlushPending", "b", bus_property_get_bool, offsetof(Socket, flush_pending), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("Writable", "b", bus_property_get_bool, offsetof(Socket, writable), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("KeepAlive", "b", bus_property_get_bool, offsetof(Socket, keep_alive), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("KeepAliveTimeUSec", "t", bus_property_get_usec, offsetof(Socket, keep_alive_time), SD_BUS_VTABLE_PROPERTY_CONST),
+@@ -177,6 +178,9 @@ static int bus_socket_set_transient_property(
+         if (streq(name, "Accept"))
+                 return bus_set_transient_bool(u, name, &s->accept, message, flags, error);
+ 
++        if (streq(name, "FlushPending"))
++                return bus_set_transient_bool(u, name, &s->flush_pending, message, flags, error);
++
+         if (streq(name, "Writable"))
+                 return bus_set_transient_bool(u, name, &s->writable, message, flags, error);
+ 
+diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
+index 6d21b2e433..24ee5ae6fe 100644
+--- a/src/core/load-fragment-gperf.gperf.m4
++++ b/src/core/load-fragment-gperf.gperf.m4
+@@ -359,6 +359,7 @@ Socket.SocketGroup,              config_parse_user_group,            0,
+ Socket.SocketMode,               config_parse_mode,                  0,                             offsetof(Socket, socket_mode)
+ Socket.DirectoryMode,            config_parse_mode,                  0,                             offsetof(Socket, directory_mode)
+ Socket.Accept,                   config_parse_bool,                  0,                             offsetof(Socket, accept)
++Socket.FlushPending,             config_parse_bool,                  0,                             offsetof(Socket, flush_pending)
+ Socket.Writable,                 config_parse_bool,                  0,                             offsetof(Socket, writable)
+ Socket.MaxConnections,           config_parse_unsigned,              0,                             offsetof(Socket, max_connections)
+ Socket.MaxConnectionsPerSource,  config_parse_unsigned,              0,                             offsetof(Socket, max_connections_per_source)
+diff --git a/src/core/socket.c b/src/core/socket.c
+index fe061eb73b..97c3a7fc9a 100644
+--- a/src/core/socket.c
++++ b/src/core/socket.c
+@@ -70,6 +70,7 @@ static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = {
+ 
+ static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
+ static int socket_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
++static void flush_ports(Socket *s);
+ 
+ static void socket_init(Unit *u) {
+         Socket *s = SOCKET(u);
+@@ -703,6 +704,11 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
+                         prefix, s->n_connections,
+                         prefix, s->max_connections,
+                         prefix, s->max_connections_per_source);
++        else
++                fprintf(f,
++                        "%sFlushPending: %s\n",
++                         prefix, yes_no(s->flush_pending));
++
+ 
+         if (s->priority >= 0)
+                 fprintf(f,
+@@ -2111,6 +2117,11 @@ static void socket_enter_listening(Socket *s) {
+         int r;
+         assert(s);
+ 
++        if (!s->accept && s->flush_pending) {
++                log_unit_debug(UNIT(s), "Flushing socket before listening.");
++                flush_ports(s);
++        }
++
+         r = socket_watch_fds(s);
+         if (r < 0) {
+                 log_unit_warning_errno(UNIT(s), r, "Failed to watch sockets: %m");
+diff --git a/src/core/socket.h b/src/core/socket.h
+index c4e25db1fc..b7a25d91fd 100644
+--- a/src/core/socket.h
++++ b/src/core/socket.h
+@@ -109,6 +109,7 @@ struct Socket {
+         bool accept;
+         bool remove_on_stop;
+         bool writable;
++        bool flush_pending;
+ 
+         int socket_protocol;
+ 
+diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
+index 77788f0fe2..7029aa5615 100644
+--- a/src/shared/bus-unit-util.c
++++ b/src/shared/bus-unit-util.c
+@@ -1468,7 +1468,8 @@ static int bus_append_socket_property(sd_bus_message *m, const char *field, cons
+ 
+         if (STR_IN_SET(field,
+                        "Accept", "Writable", "KeepAlive", "NoDelay", "FreeBind", "Transparent", "Broadcast",
+-                       "PassCredentials", "PassSecurity", "ReusePort", "RemoveOnStop", "SELinuxContextFromNet"))
++                       "PassCredentials", "PassSecurity", "ReusePort", "RemoveOnStop", "SELinuxContextFromNet",
++                       "FlushPending"))
+ 
+                 return bus_append_parse_boolean(m, field, eq);
+ 
diff --git a/SOURCES/0454-core-remove-support-for-API-bus-started-outside-our-.patch b/SOURCES/0454-core-remove-support-for-API-bus-started-outside-our-.patch
new file mode 100644
index 0000000..2d454d8
--- /dev/null
+++ b/SOURCES/0454-core-remove-support-for-API-bus-started-outside-our-.patch
@@ -0,0 +1,62 @@
+From 9c0ed82f661a2296784970678746b0b4f130870e Mon Sep 17 00:00:00 2001
+From: Alan Jenkins <alan.christopher.jenkins@gmail.com>
+Date: Thu, 21 Jun 2018 14:12:30 +0100
+Subject: [PATCH] core: remove support for API bus "started outside our own
+ logic"
+
+Looking at a recent Bad Day, my log contains over 100 lines of
+
+    systemd[23895]: Failed to connect to API bus: Connection refused
+
+It is due to "systemd --user" retrying to connect to an API bus.[*]  I
+would prefer to avoid spamming the logs.  I don't think it is good for us
+to retry so much like this.
+
+systemd was mislead by something setting DBUS_SESSION_BUS_ADDRESS.  My best
+guess is an unfortunate series of events caused gdm to set this.  gdm has
+code to start a session dbus if there is not a bus available already (and
+in this case it exports the environment variable).  I believe it does not
+normally do this when running under systemd, because "systemd --user" and
+hence "dbus.service" would already have been started by pam_systemd.
+
+I see two possibilities
+
+1. Rip out the check for DBUS_SESSION_BUS_ADDRESS entirely.
+2. Only check for DBUS_SESSION_BUS_ADDRESS on startup.  Not in the
+   "recheck" logic.
+
+The justification for 2), is that the recheck is called from unit_notify(),
+this is used to check whether the service just started (or stopped) was
+"dbus.service".  This reason for rechecking does not apply if we think
+the session bus was started outside our logic.
+
+But I think we can justify 1).  dbus-daemon ships a statically-enabled
+/usr/lib/systemd/user/dbus.service, which would conflict with an attempt to
+use an external dbus.  Also "systemd --user" is started from user@.service;
+if you try to start it manually so that it inherits an environment
+variable, it will conflict if user@.service was started by pam_systemd
+(or loginctl enable-linger).
+
+(cherry picked from commit d3243f55ca9b5f305306ba4105ab29768e372a78)
+
+Resolves: #1764282
+---
+ src/core/manager.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+diff --git a/src/core/manager.c b/src/core/manager.c
+index 012615e537..3c44ad3dbc 100644
+--- a/src/core/manager.c
++++ b/src/core/manager.c
+@@ -1519,11 +1519,6 @@ static bool manager_dbus_is_running(Manager *m, bool deserialized) {
+         if (m->test_run_flags != 0)
+                 return false;
+ 
+-        /* If we are in the user instance, and the env var is already set for us, then this means D-Bus is ran
+-         * somewhere outside of our own logic. Let's use it */
+-        if (MANAGER_IS_USER(m) && getenv("DBUS_SESSION_BUS_ADDRESS"))
+-                return true;
+-
+         u = manager_get_unit(m, SPECIAL_DBUS_SOCKET);
+         if (!u)
+                 return false;
diff --git a/SOURCES/0455-mount-setup-fix-segfault-in-mount_cgroup_controllers.patch b/SOURCES/0455-mount-setup-fix-segfault-in-mount_cgroup_controllers.patch
new file mode 100644
index 0000000..a99e7de
--- /dev/null
+++ b/SOURCES/0455-mount-setup-fix-segfault-in-mount_cgroup_controllers.patch
@@ -0,0 +1,56 @@
+From 1c8d1c3bbdf8bdfb2ee4f85b9f559f54c6e4cac4 Mon Sep 17 00:00:00 2001
+From: Wen Yang <wenyang@linux.alibaba.com>
+Date: Wed, 1 Jul 2020 04:45:33 +0800
+Subject: [PATCH] mount-setup: fix segfault in mount_cgroup_controllers when
+ using gcc9 compiler
+
+According to the documentation:
+https://gcc.gnu.org/gcc-9/porting_to.html#complit
+
+The 'join_controllers' that relied on the extended lifetime needs
+to be fixed, move the compound literals to the function scope it
+need to accessible in.
+
+Resolves: #1868877
+---
+ src/core/mount-setup.c | 24 +++++++++++++-----------
+ 1 file changed, 13 insertions(+), 11 deletions(-)
+
+diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c
+index 16880e6157..a6594580e5 100644
+--- a/src/core/mount-setup.c
++++ b/src/core/mount-setup.c
+@@ -237,20 +237,22 @@ int mount_cgroup_controllers(char ***join_controllers) {
+         if (!cg_is_legacy_wanted())
+                 return 0;
+ 
++        /* The defaults:
++         * mount "cpu" + "cpuacct" together, and "net_cls" + "net_prio".
++         *
++         * We'd like to add "cpuset" to the mix, but "cpuset" doesn't really
++         * work for groups with no initialized attributes.
++         */
++        char ***default_join_controllers = (char**[]) {
++                STRV_MAKE("cpu", "cpuacct"),
++                STRV_MAKE("net_cls", "net_prio"),
++                NULL,
++        };
++
+         /* Mount all available cgroup controllers that are built into the kernel. */
+ 
+         if (!has_argument)
+-                /* The defaults:
+-                 * mount "cpu" + "cpuacct" together, and "net_cls" + "net_prio".
+-                 *
+-                 * We'd like to add "cpuset" to the mix, but "cpuset" doesn't really
+-                 * work for groups with no initialized attributes.
+-                 */
+-                join_controllers = (char**[]) {
+-                        STRV_MAKE("cpu", "cpuacct"),
+-                        STRV_MAKE("net_cls", "net_prio"),
+-                        NULL,
+-                };
++                join_controllers = default_join_controllers;
+ 
+         r = cg_kernel_controllers(&controllers);
+         if (r < 0)
diff --git a/SOURCES/0456-dbus-execute-make-transfer-of-CPUAffinity-endian-saf.patch b/SOURCES/0456-dbus-execute-make-transfer-of-CPUAffinity-endian-saf.patch
new file mode 100644
index 0000000..71758ee
--- /dev/null
+++ b/SOURCES/0456-dbus-execute-make-transfer-of-CPUAffinity-endian-saf.patch
@@ -0,0 +1,39 @@
+From 1730f7bb306e13689a7684fd93ae5b8383a28d2f Mon Sep 17 00:00:00 2001
+From: Michal Sekletar <msekletar@users.noreply.github.com>
+Date: Fri, 31 May 2019 15:23:23 +0200
+Subject: [PATCH] dbus-execute: make transfer of CPUAffinity endian safe
+ (#12711)
+
+We store the affinity mask in the native endian. However, over D-Bus we
+must transfer the mask in little endian byte order.
+
+This is the second part of c367f996f5f091a63f812f0140b304c649be77fc.
+
+(cherry picked from commit 75e40119a471454516ad0acc96f6f4094e7fb652)
+
+Related: #1740657
+---
+ src/core/dbus-execute.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
+index f9527e56b2..d5acca384f 100644
+--- a/src/core/dbus-execute.c
++++ b/src/core/dbus-execute.c
+@@ -215,12 +215,15 @@ static int property_get_cpu_affinity(
+                 sd_bus_error *error) {
+ 
+         ExecContext *c = userdata;
++        _cleanup_free_ uint8_t *array = NULL;
++        size_t allocated;
+ 
+         assert(bus);
+         assert(reply);
+         assert(c);
+ 
+-        return sd_bus_message_append_array(reply, 'y', c->cpu_set.set, c->cpu_set.allocated);
++        (void) cpu_set_to_dbus(&c->cpu_set, &array, &allocated);
++        return sd_bus_message_append_array(reply, 'y', array, allocated);
+ }
+ 
+ static int property_get_numa_mask(
diff --git a/SOURCES/0457-core-add-support-for-setting-CPUAffinity-to-special-.patch b/SOURCES/0457-core-add-support-for-setting-CPUAffinity-to-special-.patch
new file mode 100644
index 0000000..3118171
--- /dev/null
+++ b/SOURCES/0457-core-add-support-for-setting-CPUAffinity-to-special-.patch
@@ -0,0 +1,426 @@
+From 1a822dbe19ab6634ffb2c0d3ce92b27b503e1612 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20Sekleta=CC=81r?= <msekleta@redhat.com>
+Date: Mon, 17 Feb 2020 13:50:31 +0100
+Subject: [PATCH] core: add support for setting CPUAffinity= to special "numa"
+ value
+
+systemd will automatically derive CPU affinity mask from NUMA node
+mask.
+
+Fixes #13248
+
+(cherry picked from commit e2b2fb7f566d13a3de61952b5356cd4d2eaee917)
+
+Resolves: #1740657
+---
+ man/systemd.exec.xml                 |  9 +++---
+ src/basic/cpu-set-util.c             | 43 ++++++++++++++++++++++++--
+ src/basic/cpu-set-util.h             |  1 +
+ src/core/dbus-execute.c              | 30 +++++++++++++++++-
+ src/core/execute.c                   | 46 ++++++++++++++++++++++++++--
+ src/core/execute.h                   |  3 ++
+ src/core/load-fragment.c             | 14 ++++++++-
+ src/shared/bus-unit-util.c           |  9 ++++++
+ src/test/test-cpu-set-util.c         |  6 ++--
+ test/TEST-36-NUMAPOLICY/testsuite.sh | 18 +++++++++++
+ 10 files changed, 166 insertions(+), 13 deletions(-)
+
+diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
+index e2a5ede968..696438c4ef 100644
+--- a/man/systemd.exec.xml
++++ b/man/systemd.exec.xml
+@@ -706,10 +706,11 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
+         <term><varname>CPUAffinity=</varname></term>
+ 
+         <listitem><para>Controls the CPU affinity of the executed processes. Takes a list of CPU indices or ranges
+-        separated by either whitespace or commas. CPU ranges are specified by the lower and upper CPU indices separated
+-        by a dash. This option may be specified more than once, in which case the specified CPU affinity masks are
+-        merged. If the empty string is assigned, the mask is reset, all assignments prior to this will have no
+-        effect. See
++        separated by either whitespace or commas. Alternatively, takes a special "numa" value in which case systemd
++        automatically derives allowed CPU range based on the value of <varname>NUMAMask=</varname> option. CPU ranges
++        are specified by the lower and upper CPU indices separated by a dash. This option may be specified more than
++        once, in which case the specified CPU affinity masks are merged. If the empty string is assigned, the mask
++        is reset, all assignments prior to this will have no effect. See
+         <citerefentry><refentrytitle>sched_setaffinity</refentrytitle><manvolnum>2</manvolnum></citerefentry> for
+         details.</para></listitem>
+       </varlistentry>
+diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c
+index 51752ad1a6..1922c95864 100644
+--- a/src/basic/cpu-set-util.c
++++ b/src/basic/cpu-set-util.c
+@@ -12,12 +12,14 @@
+ #include "cpu-set-util.h"
+ #include "dirent-util.h"
+ #include "extract-word.h"
++#include "fileio.h"
+ #include "fd-util.h"
+ #include "log.h"
+ #include "macro.h"
+ #include "missing.h"
+ #include "parse-util.h"
+ #include "stat-util.h"
++#include "stdio-util.h"
+ #include "string-util.h"
+ #include "string-table.h"
+ #include "strv.h"
+@@ -179,7 +181,7 @@ int cpu_set_add_all(CPUSet *a, const CPUSet *b) {
+                                 return r;
+                 }
+ 
+-        return 0;
++        return 1;
+ }
+ 
+ int parse_cpu_set_full(
+@@ -264,7 +266,7 @@ int parse_cpu_set_extend(
+         if (!old->set) {
+                 *old = cpuset;
+                 cpuset = (CPUSet) {};
+-                return 0;
++                return 1;
+         }
+ 
+         return cpu_set_add_all(old, &cpuset);
+@@ -417,6 +419,43 @@ int apply_numa_policy(const NUMAPolicy *policy) {
+         return 0;
+ }
+ 
++int numa_to_cpu_set(const NUMAPolicy *policy, CPUSet *ret) {
++        int r;
++        size_t i;
++        _cleanup_(cpu_set_reset) CPUSet s = {};
++
++        assert(policy);
++        assert(ret);
++
++        for (i = 0; i < policy->nodes.allocated * 8; i++) {
++                _cleanup_free_ char *l = NULL;
++                char p[STRLEN("/sys/devices/system/node/node//cpulist") + DECIMAL_STR_MAX(size_t) + 1];
++                _cleanup_(cpu_set_reset) CPUSet part = {};
++
++                if (!CPU_ISSET_S(i, policy->nodes.allocated, policy->nodes.set))
++                        continue;
++
++                xsprintf(p, "/sys/devices/system/node/node%zu/cpulist", i);
++
++                r = read_one_line_file(p, &l);
++                if (r < 0)
++                        return r;
++
++                r = parse_cpu_set(l, &part);
++                if (r < 0)
++                        return r;
++
++                r = cpu_set_add_all(&s, &part);
++                if (r < 0)
++                        return r;
++        }
++
++        *ret = s;
++        s = (CPUSet) {};
++
++        return 0;
++}
++
+ static const char* const mpol_table[] = {
+         [MPOL_DEFAULT]    = "default",
+         [MPOL_PREFERRED]  = "preferred",
+diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h
+index 8519a9b6c8..795be807af 100644
+--- a/src/basic/cpu-set-util.h
++++ b/src/basic/cpu-set-util.h
+@@ -78,6 +78,7 @@ static inline void numa_policy_reset(NUMAPolicy *p) {
+ }
+ 
+ int apply_numa_policy(const NUMAPolicy *policy);
++int numa_to_cpu_set(const NUMAPolicy *policy, CPUSet *ret);
+ 
+ const char* mpol_to_string(int i) _const_;
+ int mpol_from_string(const char *s) _pure_;
+diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
+index d5acca384f..0fe4c14e48 100644
+--- a/src/core/dbus-execute.c
++++ b/src/core/dbus-execute.c
+@@ -58,6 +58,8 @@ static BUS_DEFINE_PROPERTY_GET2(property_get_ioprio_priority, "i", ExecContext,
+ static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_empty_string, "s", NULL);
+ static BUS_DEFINE_PROPERTY_GET_REF(property_get_syslog_level, "i", int, LOG_PRI);
+ static BUS_DEFINE_PROPERTY_GET_REF(property_get_syslog_facility, "i", int, LOG_FAC);
++static BUS_DEFINE_PROPERTY_GET(property_get_cpu_affinity_from_numa, "b", ExecContext, exec_context_get_cpu_affinity_from_numa);
++
+ 
+ static int property_get_environment_files(
+                 sd_bus *bus,
+@@ -215,6 +217,7 @@ static int property_get_cpu_affinity(
+                 sd_bus_error *error) {
+ 
+         ExecContext *c = userdata;
++        _cleanup_(cpu_set_reset) CPUSet s = {};
+         _cleanup_free_ uint8_t *array = NULL;
+         size_t allocated;
+ 
+@@ -222,7 +225,16 @@ static int property_get_cpu_affinity(
+         assert(reply);
+         assert(c);
+ 
+-        (void) cpu_set_to_dbus(&c->cpu_set, &array, &allocated);
++        if (c->cpu_affinity_from_numa) {
++                int r;
++
++                r = numa_to_cpu_set(&c->numa_policy, &s);
++                if (r < 0)
++                        return r;
++        }
++
++        (void) cpu_set_to_dbus(c->cpu_affinity_from_numa ? &s : &c->cpu_set,  &array, &allocated);
++
+         return sd_bus_message_append_array(reply, 'y', array, allocated);
+ }
+ 
+@@ -743,6 +755,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
+         SD_BUS_PROPERTY("CPUSchedulingPolicy", "i", property_get_cpu_sched_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("CPUSchedulingPriority", "i", property_get_cpu_sched_priority, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("CPUAffinity", "ay", property_get_cpu_affinity, 0, SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("CPUAffinityFromNUMA", "b", property_get_cpu_affinity_from_numa, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("NUMAPolicy", "i", property_get_numa_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("NUMAMask", "ay", property_get_numa_mask, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+@@ -1639,6 +1652,20 @@ int bus_exec_context_set_transient_property(
+ 
+                 return 1;
+ 
++        } else if (streq(name, "CPUAffinityFromNUMA")) {
++                int q;
++
++                r = sd_bus_message_read_basic(message, 'b', &q);
++                if (r < 0)
++                        return r;
++
++                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
++                        c->cpu_affinity_from_numa = q;
++                        unit_write_settingf(u, flags, name, "%s=%s", "CPUAffinity", "numa");
++                }
++
++                return 1;
++
+         } else if (streq(name, "NUMAPolicy")) {
+                 int32_t type;
+ 
+@@ -1653,6 +1680,7 @@ int bus_exec_context_set_transient_property(
+                         c->numa_policy.type = type;
+ 
+                 return 1;
++
+         } else if (streq(name, "IOSchedulingClass")) {
+                 int32_t q;
+ 
+diff --git a/src/core/execute.c b/src/core/execute.c
+index 3c54ac1110..d528d08830 100644
+--- a/src/core/execute.c
++++ b/src/core/execute.c
+@@ -2750,6 +2750,33 @@ static int compile_suggested_paths(const ExecContext *c, const ExecParameters *p
+ 
+ static char *exec_command_line(char **argv);
+ 
++static int exec_context_cpu_affinity_from_numa(const ExecContext *c, CPUSet *ret) {
++        _cleanup_(cpu_set_reset) CPUSet s = {};
++        int r;
++
++        assert(c);
++        assert(ret);
++
++        if (!c->numa_policy.nodes.set) {
++                log_debug("Can't derive CPU affinity mask from NUMA mask because NUMA mask is not set, ignoring");
++                return 0;
++        }
++
++        r = numa_to_cpu_set(&c->numa_policy, &s);
++        if (r < 0)
++                return r;
++
++        cpu_set_reset(ret);
++
++        return cpu_set_add_all(ret, &s);
++}
++
++bool exec_context_get_cpu_affinity_from_numa(const ExecContext *c) {
++        assert(c);
++
++        return c->cpu_affinity_from_numa;
++}
++
+ static int exec_child(
+                 Unit *unit,
+                 const ExecCommand *command,
+@@ -3012,11 +3039,26 @@ static int exec_child(
+                 }
+         }
+ 
+-        if (context->cpu_set.set)
+-                if (sched_setaffinity(0, context->cpu_set.allocated, context->cpu_set.set) < 0) {
++        if (context->cpu_affinity_from_numa || context->cpu_set.set) {
++                _cleanup_(cpu_set_reset) CPUSet converted_cpu_set = {};
++                const CPUSet *cpu_set;
++
++                if (context->cpu_affinity_from_numa) {
++                        r = exec_context_cpu_affinity_from_numa(context, &converted_cpu_set);
++                        if (r < 0) {
++                                *exit_status = EXIT_CPUAFFINITY;
++                                return log_unit_error_errno(unit, r, "Failed to derive CPU affinity mask from NUMA mask: %m");
++                        }
++
++                        cpu_set = &converted_cpu_set;
++                } else
++                        cpu_set = &context->cpu_set;
++
++                if (sched_setaffinity(0, cpu_set->allocated, cpu_set->set) < 0) {
+                         *exit_status = EXIT_CPUAFFINITY;
+                         return log_unit_error_errno(unit, errno, "Failed to set up CPU affinity: %m");
+                 }
++        }
+ 
+         if (mpol_is_valid(numa_policy_get_type(&context->numa_policy))) {
+                 r = apply_numa_policy(&context->numa_policy);
+diff --git a/src/core/execute.h b/src/core/execute.h
+index 86c1cee84c..62c6229621 100644
+--- a/src/core/execute.h
++++ b/src/core/execute.h
+@@ -152,6 +152,7 @@ struct ExecContext {
+ 
+         CPUSet cpu_set;
+         NUMAPolicy numa_policy;
++        bool cpu_affinity_from_numa;
+ 
+         ExecInput std_input;
+         ExecOutput std_output;
+@@ -375,6 +376,8 @@ int exec_runtime_deserialize_compat(Unit *u, const char *key, const char *value,
+ void exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds);
+ void exec_runtime_vacuum(Manager *m);
+ 
++bool exec_context_get_cpu_affinity_from_numa(const ExecContext *c);
++
+ const char* exec_output_to_string(ExecOutput i) _const_;
+ ExecOutput exec_output_from_string(const char *s) _pure_;
+ 
+diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
+index 33fdb82754..740401a582 100644
+--- a/src/core/load-fragment.c
++++ b/src/core/load-fragment.c
+@@ -1251,13 +1251,25 @@ int config_parse_exec_cpu_affinity(const char *unit,
+                                    void *userdata) {
+ 
+         ExecContext *c = data;
++        int r;
+ 
+         assert(filename);
+         assert(lvalue);
+         assert(rvalue);
+         assert(data);
+ 
+-        return parse_cpu_set_extend(rvalue, &c->cpu_set, true, unit, filename, line, lvalue);
++        if (streq(rvalue, "numa")) {
++                c->cpu_affinity_from_numa = true;
++                cpu_set_reset(&c->cpu_set);
++
++                return 0;
++        }
++
++        r = parse_cpu_set_extend(rvalue, &c->cpu_set, true, unit, filename, line, lvalue);
++        if (r >= 0)
++                c->cpu_affinity_from_numa = false;
++
++        return r;
+ }
+ 
+ int config_parse_capability_set(
+diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
+index 7029aa5615..daa2c2dce5 100644
+--- a/src/shared/bus-unit-util.c
++++ b/src/shared/bus-unit-util.c
+@@ -26,6 +26,8 @@
+ #include "securebits-util.h"
+ #include "signal-util.h"
+ #include "socket-protocol-list.h"
++#include "socket-util.h"
++#include "stdio-util.h"
+ #include "string-util.h"
+ #include "syslog-util.h"
+ #include "terminal-util.h"
+@@ -997,6 +999,13 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
+                 _cleanup_free_ uint8_t *array = NULL;
+                 size_t allocated;
+ 
++                if (eq && streq(eq, "numa")) {
++                        r = sd_bus_message_append(m, "(sv)", "CPUAffinityFromNUMA", "b", true);
++                        if (r < 0)
++                                return bus_log_create_error(r);
++                        return r;
++                }
++
+                 r = parse_cpu_set(eq, &cpuset);
+                 if (r < 0)
+                         return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
+diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c
+index 136eaca82d..1b7be5df4e 100644
+--- a/src/test/test-cpu-set-util.c
++++ b/src/test/test-cpu-set-util.c
+@@ -218,12 +218,12 @@ static void test_parse_cpu_set_extend(void) {
+ 
+         log_info("/* %s */", __func__);
+ 
+-        assert_se(parse_cpu_set_extend("1 3", &c, true, NULL, "fake", 1, "CPUAffinity") == 0);
++        assert_se(parse_cpu_set_extend("1 3", &c, true, NULL, "fake", 1, "CPUAffinity") == 1);
+         assert_se(CPU_COUNT_S(c.allocated, c.set) == 2);
+         assert_se(s1 = cpu_set_to_string(&c));
+         log_info("cpu_set_to_string: %s", s1);
+ 
+-        assert_se(parse_cpu_set_extend("4", &c, true, NULL, "fake", 1, "CPUAffinity") == 0);
++        assert_se(parse_cpu_set_extend("4", &c, true, NULL, "fake", 1, "CPUAffinity") == 1);
+         assert_se(CPU_COUNT_S(c.allocated, c.set) == 3);
+         assert_se(s2 = cpu_set_to_string(&c));
+         log_info("cpu_set_to_string: %s", s2);
+@@ -240,7 +240,7 @@ static void test_cpu_set_to_from_dbus(void) {
+ 
+         log_info("/* %s */", __func__);
+ 
+-        assert_se(parse_cpu_set_extend("1 3 8 100-200", &c, true, NULL, "fake", 1, "CPUAffinity") == 0);
++        assert_se(parse_cpu_set_extend("1 3 8 100-200", &c, true, NULL, "fake", 1, "CPUAffinity") == 1);
+         assert_se(s = cpu_set_to_string(&c));
+         log_info("cpu_set_to_string: %s", s);
+         assert_se(CPU_COUNT_S(c.allocated, c.set) == 104);
+diff --git a/test/TEST-36-NUMAPOLICY/testsuite.sh b/test/TEST-36-NUMAPOLICY/testsuite.sh
+index bffac4ffe6..7ccaa5b412 100755
+--- a/test/TEST-36-NUMAPOLICY/testsuite.sh
++++ b/test/TEST-36-NUMAPOLICY/testsuite.sh
+@@ -279,6 +279,18 @@ else
+     # Maks must be ignored
+     grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" $straceLog
+ 
++    echo "Unit file CPUAffinity=NUMA support"
++    writeTestUnitNUMAPolicy "bind" "0"
++    echo "CPUAffinity=numa" >> $testUnitNUMAConf
++    systemctl daemon-reload
++    systemctl start $testUnit
++    systemctlCheckNUMAProperties $testUnit "bind" "0"
++    pid=$(systemctl show --value -p MainPID $testUnit)
++    cpulist=$(cat /sys/devices/system/node/node0/cpulist)
++    affinity_systemd=$(systemctl show --value -p CPUAffinity $testUnit)
++    [ $cpulist = $affinity_systemd ]
++    pid1StopUnit $testUnit
++
+     echo "systemd-run NUMAPolicy support"
+     runUnit='numa-systemd-run-test.service'
+ 
+@@ -309,6 +321,12 @@ else
+     systemd-run -p NUMAPolicy=local -p NUMAMask=0 --unit $runUnit sleep 1000
+     systemctlCheckNUMAProperties $runUnit "local" ""
+     pid1StopUnit $runUnit
++
++    systemd-run -p NUMAPolicy=local -p NUMAMask=0 -p CPUAffinity=numa --unit $runUnit sleep 1000
++    systemctlCheckNUMAProperties $runUnit "local" ""
++    systemctl cat $runUnit | grep -q 'CPUAffinity=numa'
++    pid1StopUnit $runUnit
++
+ fi
+ 
+ # Cleanup
diff --git a/SOURCES/0458-basic-user-util-always-use-base-10-for-user-group-nu.patch b/SOURCES/0458-basic-user-util-always-use-base-10-for-user-group-nu.patch
new file mode 100644
index 0000000..59daa5f
--- /dev/null
+++ b/SOURCES/0458-basic-user-util-always-use-base-10-for-user-group-nu.patch
@@ -0,0 +1,93 @@
+From 57d2e6e64ba490054f8de1a2aad4ffae7778eddc Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Sun, 31 May 2020 18:21:09 +0200
+Subject: [PATCH] basic/user-util: always use base 10 for user/group numbers
+
+We would parse numbers with base prefixes as user identifiers. For example,
+"0x2b3bfa0" would be interpreted as UID==45334432 and "01750" would be
+interpreted as UID==1000. This parsing was used also in cases where either a
+user/group name or number may be specified. This means that names like
+0x2b3bfa0 would be ambiguous: they are a valid user name according to our
+documented relaxed rules, but they would also be parsed as numeric uids.
+
+This behaviour is definitely not expected by users, since tools generally only
+accept decimal numbers (e.g. id, getent passwd), while other tools only accept
+user names and thus will interpret such strings as user names without even
+attempting to convert them to numbers (su, ssh). So let's follow suit and only
+accept numbers in decimal notation. Effectively this means that we will reject
+such strings as a username/uid/groupname/gid where strict mode is used, and try
+to look up a user/group with such a name in relaxed mode.
+
+Since the function changed is fairly low-level and fairly widely used, this
+affects multiple tools: loginctl show-user/enable-linger/disable-linger foo',
+the third argument in sysusers.d, fourth and fifth arguments in tmpfiles.d,
+etc.
+
+Fixes #15985.
+
+(cherry picked from commit 156a5fd297b61bce31630d7a52c15614bf784843)
+
+Resolves: #1848373
+---
+ src/basic/parse-util.h    |  8 ++++++--
+ src/basic/user-util.c     |  2 +-
+ src/test/test-user-util.c | 10 ++++++++++
+ 3 files changed, 17 insertions(+), 3 deletions(-)
+
+diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h
+index f3267f4cfe..1fc1af7615 100644
+--- a/src/basic/parse-util.h
++++ b/src/basic/parse-util.h
+@@ -50,9 +50,13 @@ static inline int safe_atoux16(const char *s, uint16_t *ret) {
+ 
+ int safe_atoi16(const char *s, int16_t *ret);
+ 
+-static inline int safe_atou32(const char *s, uint32_t *ret_u) {
++static inline int safe_atou32_full(const char *s, unsigned base, uint32_t *ret_u) {
+         assert_cc(sizeof(uint32_t) == sizeof(unsigned));
+-        return safe_atou(s, (unsigned*) ret_u);
++        return safe_atou_full(s, base, (unsigned*) ret_u);
++}
++
++static inline int safe_atou32(const char *s, uint32_t *ret_u) {
++        return safe_atou32_full(s, 0, (unsigned*) ret_u);
+ }
+ 
+ static inline int safe_atoi32(const char *s, int32_t *ret_i) {
+diff --git a/src/basic/user-util.c b/src/basic/user-util.c
+index d92969c966..10eeb256cd 100644
+--- a/src/basic/user-util.c
++++ b/src/basic/user-util.c
+@@ -49,7 +49,7 @@ int parse_uid(const char *s, uid_t *ret) {
+         assert(s);
+ 
+         assert_cc(sizeof(uid_t) == sizeof(uint32_t));
+-        r = safe_atou32(s, &uid);
++        r = safe_atou32_full(s, 10, &uid);
+         if (r < 0)
+                 return r;
+ 
+diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c
+index 9114d30b8c..8bf3dcd567 100644
+--- a/src/test/test-user-util.c
++++ b/src/test/test-user-util.c
+@@ -46,9 +46,19 @@ static void test_parse_uid(void) {
+ 
+         r = parse_uid("65535", &uid);
+         assert_se(r == -ENXIO);
++        assert_se(uid == 100);
++
++        r = parse_uid("0x1234", &uid);
++        assert_se(r == -EINVAL);
++        assert_se(uid == 100);
++
++        r = parse_uid("01234", &uid);
++        assert_se(r == 0);
++        assert_se(uid == 1234);
+ 
+         r = parse_uid("asdsdas", &uid);
+         assert_se(r == -EINVAL);
++        assert_se(uid == 1234);
+ }
+ 
+ static void test_uid_ptr(void) {
diff --git a/SOURCES/0459-parse-util-sometimes-it-is-useful-to-check-if-a-stri.patch b/SOURCES/0459-parse-util-sometimes-it-is-useful-to-check-if-a-stri.patch
new file mode 100644
index 0000000..7d41bb9
--- /dev/null
+++ b/SOURCES/0459-parse-util-sometimes-it-is-useful-to-check-if-a-stri.patch
@@ -0,0 +1,149 @@
+From 2fd9a21a8b6a93c4fb2747839766adca15faa008 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Thu, 14 Nov 2019 14:49:40 +0100
+Subject: [PATCH] parse-util: sometimes it is useful to check if a string is a
+ valid integer, but not actually parse it
+
+(cherry picked from commit 22810041c2200fe72b0e0c985d0e404f8b80f9e2)
+
+Related: #1848373
+---
+ src/basic/parse-util.c | 34 ++++++++++++++++++++--------------
+ 1 file changed, 20 insertions(+), 14 deletions(-)
+
+diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
+index 6becf85878..056e56765e 100644
+--- a/src/basic/parse-util.c
++++ b/src/basic/parse-util.c
+@@ -383,7 +383,6 @@ int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
+         unsigned long l;
+ 
+         assert(s);
+-        assert(ret_u);
+         assert(base <= 16);
+ 
+         /* strtoul() is happy to parse negative values, and silently
+@@ -407,7 +406,9 @@ int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
+         if ((unsigned long) (unsigned) l != l)
+                 return -ERANGE;
+ 
+-        *ret_u = (unsigned) l;
++        if (ret_u)
++                *ret_u = (unsigned) l;
++
+         return 0;
+ }
+ 
+@@ -416,7 +417,6 @@ int safe_atoi(const char *s, int *ret_i) {
+         long l;
+ 
+         assert(s);
+-        assert(ret_i);
+ 
+         errno = 0;
+         l = strtol(s, &x, 0);
+@@ -427,7 +427,9 @@ int safe_atoi(const char *s, int *ret_i) {
+         if ((long) (int) l != l)
+                 return -ERANGE;
+ 
+-        *ret_i = (int) l;
++        if (ret_i)
++                *ret_i = (int) l;
++
+         return 0;
+ }
+ 
+@@ -436,7 +438,6 @@ int safe_atollu(const char *s, long long unsigned *ret_llu) {
+         unsigned long long l;
+ 
+         assert(s);
+-        assert(ret_llu);
+ 
+         s += strspn(s, WHITESPACE);
+ 
+@@ -449,7 +450,9 @@ int safe_atollu(const char *s, long long unsigned *ret_llu) {
+         if (*s == '-')
+                 return -ERANGE;
+ 
+-        *ret_llu = l;
++        if (ret_llu)
++                *ret_llu = l;
++
+         return 0;
+ }
+ 
+@@ -458,7 +461,6 @@ int safe_atolli(const char *s, long long int *ret_lli) {
+         long long l;
+ 
+         assert(s);
+-        assert(ret_lli);
+ 
+         errno = 0;
+         l = strtoll(s, &x, 0);
+@@ -467,7 +469,9 @@ int safe_atolli(const char *s, long long int *ret_lli) {
+         if (!x || x == s || *x != 0)
+                 return -EINVAL;
+ 
+-        *ret_lli = l;
++        if (ret_lli)
++                *ret_lli = l;
++
+         return 0;
+ }
+ 
+@@ -476,7 +480,6 @@ int safe_atou8(const char *s, uint8_t *ret) {
+         unsigned long l;
+ 
+         assert(s);
+-        assert(ret);
+ 
+         s += strspn(s, WHITESPACE);
+ 
+@@ -491,7 +494,8 @@ int safe_atou8(const char *s, uint8_t *ret) {
+         if ((unsigned long) (uint8_t) l != l)
+                 return -ERANGE;
+ 
+-        *ret = (uint8_t) l;
++        if (ret)
++                *ret = (uint8_t) l;
+         return 0;
+ }
+ 
+@@ -525,7 +529,6 @@ int safe_atoi16(const char *s, int16_t *ret) {
+         long l;
+ 
+         assert(s);
+-        assert(ret);
+ 
+         errno = 0;
+         l = strtol(s, &x, 0);
+@@ -536,7 +539,9 @@ int safe_atoi16(const char *s, int16_t *ret) {
+         if ((long) (int16_t) l != l)
+                 return -ERANGE;
+ 
+-        *ret = (int16_t) l;
++        if (ret)
++                *ret = (int16_t) l;
++
+         return 0;
+ }
+ 
+@@ -546,7 +551,6 @@ int safe_atod(const char *s, double *ret_d) {
+         double d = 0;
+ 
+         assert(s);
+-        assert(ret_d);
+ 
+         loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
+         if (loc == (locale_t) 0)
+@@ -559,7 +563,9 @@ int safe_atod(const char *s, double *ret_d) {
+         if (!x || x == s || *x != 0)
+                 return -EINVAL;
+ 
+-        *ret_d = (double) d;
++        if (ret_d)
++                *ret_d = (double) d;
++
+         return 0;
+ }
+ 
diff --git a/SOURCES/0460-basic-parse-util-add-safe_atoux64.patch b/SOURCES/0460-basic-parse-util-add-safe_atoux64.patch
new file mode 100644
index 0000000..0405582
--- /dev/null
+++ b/SOURCES/0460-basic-parse-util-add-safe_atoux64.patch
@@ -0,0 +1,130 @@
+From bd47a98d3ce2c5e1d74deb7bc384e416a9070b96 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Thu, 9 Apr 2020 11:18:26 +0200
+Subject: [PATCH] basic/parse-util: add safe_atoux64()
+
+(cherry picked from commit ce51632a357d347737bf40d3817df331cd8874cb)
+
+Related: #1848373
+---
+ src/basic/parse-util.c     |  4 ++--
+ src/basic/parse-util.h     | 12 +++++++++++-
+ src/test/test-parse-util.c | 39 ++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 52 insertions(+), 3 deletions(-)
+
+diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
+index 056e56765e..67056c0434 100644
+--- a/src/basic/parse-util.c
++++ b/src/basic/parse-util.c
+@@ -433,7 +433,7 @@ int safe_atoi(const char *s, int *ret_i) {
+         return 0;
+ }
+ 
+-int safe_atollu(const char *s, long long unsigned *ret_llu) {
++int safe_atollu_full(const char *s, unsigned base, long long unsigned *ret_llu) {
+         char *x = NULL;
+         unsigned long long l;
+ 
+@@ -442,7 +442,7 @@ int safe_atollu(const char *s, long long unsigned *ret_llu) {
+         s += strspn(s, WHITESPACE);
+ 
+         errno = 0;
+-        l = strtoull(s, &x, 0);
++        l = strtoull(s, &x, base);
+         if (errno > 0)
+                 return -errno;
+         if (!x || x == s || *x != 0)
+diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h
+index 1fc1af7615..8a49257050 100644
+--- a/src/basic/parse-util.h
++++ b/src/basic/parse-util.h
+@@ -33,7 +33,6 @@ static inline int safe_atou(const char *s, unsigned *ret_u) {
+ }
+ 
+ int safe_atoi(const char *s, int *ret_i);
+-int safe_atollu(const char *s, unsigned long long *ret_u);
+ int safe_atolli(const char *s, long long int *ret_i);
+ 
+ int safe_atou8(const char *s, uint8_t *ret);
+@@ -64,6 +63,12 @@ static inline int safe_atoi32(const char *s, int32_t *ret_i) {
+         return safe_atoi(s, (int*) ret_i);
+ }
+ 
++int safe_atollu_full(const char *s, unsigned base, long long unsigned *ret_llu);
++
++static inline int safe_atollu(const char *s, long long unsigned *ret_llu) {
++        return safe_atollu_full(s, 0, ret_llu);
++}
++
+ static inline int safe_atou64(const char *s, uint64_t *ret_u) {
+         assert_cc(sizeof(uint64_t) == sizeof(unsigned long long));
+         return safe_atollu(s, (unsigned long long*) ret_u);
+@@ -74,6 +79,11 @@ static inline int safe_atoi64(const char *s, int64_t *ret_i) {
+         return safe_atolli(s, (long long int*) ret_i);
+ }
+ 
++static inline int safe_atoux64(const char *s, uint64_t *ret) {
++        assert_cc(sizeof(int64_t) == sizeof(long long unsigned));
++        return safe_atollu_full(s, 16, (long long unsigned*) ret);
++}
++
+ #if LONG_MAX == INT_MAX
+ static inline int safe_atolu(const char *s, unsigned long *ret_u) {
+         assert_cc(sizeof(unsigned long) == sizeof(unsigned));
+diff --git a/src/test/test-parse-util.c b/src/test/test-parse-util.c
+index e9aef5e882..8b182d9bdc 100644
+--- a/src/test/test-parse-util.c
++++ b/src/test/test-parse-util.c
+@@ -561,6 +561,44 @@ static void test_safe_atoi64(void) {
+         assert_se(r == -EINVAL);
+ }
+ 
++static void test_safe_atoux64(void) {
++        int r;
++        uint64_t l;
++
++        r = safe_atoux64("12345", &l);
++        assert_se(r == 0);
++        assert_se(l == 0x12345);
++
++        r = safe_atoux64("  12345", &l);
++        assert_se(r == 0);
++        assert_se(l == 0x12345);
++
++        r = safe_atoux64("0x12345", &l);
++        assert_se(r == 0);
++        assert_se(l == 0x12345);
++
++        r = safe_atoux64("18446744073709551617", &l);
++        assert_se(r == -ERANGE);
++
++        r = safe_atoux64("-1", &l);
++        assert_se(r == -ERANGE);
++
++        r = safe_atoux64("  -1", &l);
++        assert_se(r == -ERANGE);
++
++        r = safe_atoux64("junk", &l);
++        assert_se(r == -EINVAL);
++
++        r = safe_atoux64("123x", &l);
++        assert_se(r == -EINVAL);
++
++        r = safe_atoux64("12.3", &l);
++        assert_se(r == -EINVAL);
++
++        r = safe_atoux64("", &l);
++        assert_se(r == -EINVAL);
++}
++
+ static void test_safe_atod(void) {
+         int r;
+         double d;
+@@ -836,6 +874,7 @@ int main(int argc, char *argv[]) {
+         test_safe_atoux16();
+         test_safe_atou64();
+         test_safe_atoi64();
++        test_safe_atoux64();
+         test_safe_atod();
+         test_parse_percent();
+         test_parse_percent_unbounded();
diff --git a/SOURCES/0461-parse-util-allow-tweaking-how-to-parse-integers.patch b/SOURCES/0461-parse-util-allow-tweaking-how-to-parse-integers.patch
new file mode 100644
index 0000000..3e97f8b
--- /dev/null
+++ b/SOURCES/0461-parse-util-allow-tweaking-how-to-parse-integers.patch
@@ -0,0 +1,137 @@
+From 1d11e79fefea34b4395043e8e951414c5b7817ba Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Mon, 1 Jun 2020 17:06:19 +0200
+Subject: [PATCH] parse-util: allow tweaking how to parse integers
+
+This allows disabling a few alternative ways to decode integers
+formatted as strings, for safety reasons.
+
+See: #15991
+(cherry picked from commit 707e93aff8f358f8a62117e54b857530d6594e4b)
+
+Related: #1848373
+---
+ src/basic/parse-util.c | 65 +++++++++++++++++++++++++++++++++---------
+ src/basic/parse-util.h |  6 ++++
+ 2 files changed, 58 insertions(+), 13 deletions(-)
+
+diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
+index 67056c0434..6cc4fc3e57 100644
+--- a/src/basic/parse-util.c
++++ b/src/basic/parse-util.c
+@@ -383,20 +383,35 @@ int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
+         unsigned long l;
+ 
+         assert(s);
+-        assert(base <= 16);
++        assert(SAFE_ATO_MASK_FLAGS(base) <= 16);
+ 
+-        /* strtoul() is happy to parse negative values, and silently
+-         * converts them to unsigned values without generating an
+-         * error. We want a clean error, hence let's look for the "-"
+-         * prefix on our own, and generate an error. But let's do so
+-         * only after strtoul() validated that the string is clean
+-         * otherwise, so that we return EINVAL preferably over
+-         * ERANGE. */
++        /* strtoul() is happy to parse negative values, and silently converts them to unsigned values without
++         * generating an error. We want a clean error, hence let's look for the "-" prefix on our own, and
++         * generate an error. But let's do so only after strtoul() validated that the string is clean
++         * otherwise, so that we return EINVAL preferably over ERANGE. */
++
++        if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_WHITESPACE) &&
++            strchr(WHITESPACE, s[0]))
++                return -EINVAL;
+ 
+         s += strspn(s, WHITESPACE);
+ 
++        if (FLAGS_SET(base, SAFE_ATO_REFUSE_PLUS_MINUS) &&
++            IN_SET(s[0], '+', '-'))
++                return -EINVAL; /* Note that we check the "-" prefix again a second time below, but return a
++                                 * different error. I.e. if the SAFE_ATO_REFUSE_PLUS_MINUS flag is set we
++                                 * blanket refuse +/- prefixed integers, while if it is missing we'll just
++                                 * return ERANGE, because the string actually parses correctly, but doesn't
++                                 * fit in the return type. */
++
++        if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_ZERO) &&
++            s[0] == '0' && !streq(s, "0"))
++                return -EINVAL; /* This is particularly useful to avoid ambiguities between C's octal
++                                 * notation and assumed-to-be-decimal integers with a leading zero. */
++
+         errno = 0;
+-        l = strtoul(s, &x, base);
++        l = strtoul(s, &x, SAFE_ATO_MASK_FLAGS(base) /* Let's mask off the flags bits so that only the actual
++                                                      * base is left */);
+         if (errno > 0)
+                 return -errno;
+         if (!x || x == s || *x != 0)
+@@ -438,11 +453,24 @@ int safe_atollu_full(const char *s, unsigned base, long long unsigned *ret_llu)
+         unsigned long long l;
+ 
+         assert(s);
++        assert(SAFE_ATO_MASK_FLAGS(base) <= 16);
++
++        if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_WHITESPACE) &&
++            strchr(WHITESPACE, s[0]))
++                return -EINVAL;
+ 
+         s += strspn(s, WHITESPACE);
+ 
++        if (FLAGS_SET(base, SAFE_ATO_REFUSE_PLUS_MINUS) &&
++            IN_SET(s[0], '+', '-'))
++                return -EINVAL;
++
++        if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_ZERO) &&
++            s[0] == '0' && s[1] != 0)
++                return -EINVAL;
++
+         errno = 0;
+-        l = strtoull(s, &x, base);
++        l = strtoull(s, &x, SAFE_ATO_MASK_FLAGS(base));
+         if (errno > 0)
+                 return -errno;
+         if (!x || x == s || *x != 0)
+@@ -504,13 +532,24 @@ int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) {
+         unsigned long l;
+ 
+         assert(s);
+-        assert(ret);
+-        assert(base <= 16);
++        assert(SAFE_ATO_MASK_FLAGS(base) <= 16);
++
++        if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_WHITESPACE) &&
++            strchr(WHITESPACE, s[0]))
++                return -EINVAL;
+ 
+         s += strspn(s, WHITESPACE);
+ 
++        if (FLAGS_SET(base, SAFE_ATO_REFUSE_PLUS_MINUS) &&
++            IN_SET(s[0], '+', '-'))
++                return -EINVAL;
++
++        if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_ZERO) &&
++            s[0] == '0' && s[1] != 0)
++                return -EINVAL;
++
+         errno = 0;
+-        l = strtoul(s, &x, base);
++        l = strtoul(s, &x, SAFE_ATO_MASK_FLAGS(base));
+         if (errno > 0)
+                 return -errno;
+         if (!x || x == s || *x != 0)
+diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h
+index 8a49257050..c6bbc98dff 100644
+--- a/src/basic/parse-util.h
++++ b/src/basic/parse-util.h
+@@ -26,6 +26,12 @@ int parse_syscall_and_errno(const char *in, char **name, int *error);
+ #define FORMAT_BYTES_MAX 8
+ char *format_bytes(char *buf, size_t l, uint64_t t);
+ 
++#define SAFE_ATO_REFUSE_PLUS_MINUS (1U << 30)
++#define SAFE_ATO_REFUSE_LEADING_ZERO (1U << 29)
++#define SAFE_ATO_REFUSE_LEADING_WHITESPACE (1U << 28)
++#define SAFE_ATO_ALL_FLAGS (SAFE_ATO_REFUSE_PLUS_MINUS|SAFE_ATO_REFUSE_LEADING_ZERO|SAFE_ATO_REFUSE_LEADING_WHITESPACE)
++#define SAFE_ATO_MASK_FLAGS(base) ((base) & ~SAFE_ATO_ALL_FLAGS)
++
+ int safe_atou_full(const char *s, unsigned base, unsigned *ret_u);
+ 
+ static inline int safe_atou(const char *s, unsigned *ret_u) {
diff --git a/SOURCES/0462-parse-util-allow-0-as-alternative-to-0-and-0.patch b/SOURCES/0462-parse-util-allow-0-as-alternative-to-0-and-0.patch
new file mode 100644
index 0000000..29884dc
--- /dev/null
+++ b/SOURCES/0462-parse-util-allow-0-as-alternative-to-0-and-0.patch
@@ -0,0 +1,60 @@
+From 1c8e5070d8a88f35b5577e091de66727fa785ef7 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Mon, 1 Jun 2020 17:08:38 +0200
+Subject: [PATCH] parse-util: allow '-0' as alternative to '0' and '+0'
+
+Let's allow "-0" as alternative to "+0" and "0" when parsing integers,
+unless the new SAFE_ATO_REFUSE_PLUS_MINUS flag is specified.
+
+In cases where allowing the +/- syntax shall not be allowed
+SAFE_ATO_REFUSE_PLUS_MINUS is the right flag to use, but this also means
+that -0 as only negative integer that fits into an unsigned value should
+be acceptable if the flag is not specified.
+
+(cherry picked from commit c78eefc13562a8fc0c22c00a6d3001af89860258)
+
+Related: #1848373
+---
+ src/basic/parse-util.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
+index 6cc4fc3e57..53d181dd60 100644
+--- a/src/basic/parse-util.c
++++ b/src/basic/parse-util.c
+@@ -416,7 +416,7 @@ int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
+                 return -errno;
+         if (!x || x == s || *x != 0)
+                 return -EINVAL;
+-        if (s[0] == '-')
++        if (l != 0 && s[0] == '-')
+                 return -ERANGE;
+         if ((unsigned long) (unsigned) l != l)
+                 return -ERANGE;
+@@ -475,7 +475,7 @@ int safe_atollu_full(const char *s, unsigned base, long long unsigned *ret_llu)
+                 return -errno;
+         if (!x || x == s || *x != 0)
+                 return -EINVAL;
+-        if (*s == '-')
++        if (l != 0 && s[0] == '-')
+                 return -ERANGE;
+ 
+         if (ret_llu)
+@@ -517,7 +517,7 @@ int safe_atou8(const char *s, uint8_t *ret) {
+                 return -errno;
+         if (!x || x == s || *x != 0)
+                 return -EINVAL;
+-        if (s[0] == '-')
++        if (l != 0 && s[0] == '-')
+                 return -ERANGE;
+         if ((unsigned long) (uint8_t) l != l)
+                 return -ERANGE;
+@@ -554,7 +554,7 @@ int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) {
+                 return -errno;
+         if (!x || x == s || *x != 0)
+                 return -EINVAL;
+-        if (s[0] == '-')
++        if (l != 0 && s[0] == '-')
+                 return -ERANGE;
+         if ((unsigned long) (uint16_t) l != l)
+                 return -ERANGE;
diff --git a/SOURCES/0463-parse-util-make-return-parameter-optional-in-safe_at.patch b/SOURCES/0463-parse-util-make-return-parameter-optional-in-safe_at.patch
new file mode 100644
index 0000000..8cb4a65
--- /dev/null
+++ b/SOURCES/0463-parse-util-make-return-parameter-optional-in-safe_at.patch
@@ -0,0 +1,31 @@
+From 91ed5edcdea79773f6918e739637521e47129b07 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Mon, 1 Jun 2020 17:10:27 +0200
+Subject: [PATCH] parse-util: make return parameter optional in
+ safe_atou16_full()
+
+All other safe_atoXYZ_full() functions have the parameter optional,
+let's make it optoinal here, too.
+
+(cherry picked from commit aa85e4d3cef8ca8436e480bce9fa4ce72876b636)
+
+Related: #1848373
+---
+ src/basic/parse-util.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
+index 53d181dd60..7a7cefe6ff 100644
+--- a/src/basic/parse-util.c
++++ b/src/basic/parse-util.c
+@@ -559,7 +559,9 @@ int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) {
+         if ((unsigned long) (uint16_t) l != l)
+                 return -ERANGE;
+ 
+-        *ret = (uint16_t) l;
++        if (ret)
++                *ret = (uint16_t) l;
++
+         return 0;
+ }
+ 
diff --git a/SOURCES/0464-parse-util-rewrite-parse_mode-on-top-of-safe_atou_fu.patch b/SOURCES/0464-parse-util-rewrite-parse_mode-on-top-of-safe_atou_fu.patch
new file mode 100644
index 0000000..318e18b
--- /dev/null
+++ b/SOURCES/0464-parse-util-rewrite-parse_mode-on-top-of-safe_atou_fu.patch
@@ -0,0 +1,59 @@
+From 147a3696b45a872e0e21fb74e1497f02543ce871 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Mon, 1 Jun 2020 17:16:04 +0200
+Subject: [PATCH] parse-util: rewrite parse_mode() on top of safe_atou_full()
+
+Parsing is hard, hence let's use our own careful wrappers wherever
+possible.
+
+(cherry picked from commit c44702a8bd8cc8b7f2f1df21db9308d9af7dda5b)
+
+Related: #1848373
+---
+ src/basic/parse-util.c | 28 +++++++++++++---------------
+ 1 file changed, 13 insertions(+), 15 deletions(-)
+
+diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
+index 7a7cefe6ff..68c156c543 100644
+--- a/src/basic/parse-util.c
++++ b/src/basic/parse-util.c
+@@ -54,26 +54,24 @@ int parse_pid(const char *s, pid_t* ret_pid) {
+ }
+ 
+ int parse_mode(const char *s, mode_t *ret) {
+-        char *x;
+-        long l;
++        unsigned m;
++        int r;
+ 
+         assert(s);
+-        assert(ret);
+ 
+-        s += strspn(s, WHITESPACE);
+-        if (s[0] == '-')
+-                return -ERANGE;
+-
+-        errno = 0;
+-        l = strtol(s, &x, 8);
+-        if (errno > 0)
+-                return -errno;
+-        if (!x || x == s || *x != 0)
+-                return -EINVAL;
+-        if (l < 0 || l  > 07777)
++        r = safe_atou_full(s, 8 |
++                           SAFE_ATO_REFUSE_PLUS_MINUS, /* Leading '+' or even '-' char? that's just weird,
++                                                        * refuse. User might have wanted to add mode flags or
++                                                        * so, but this parser doesn't allow that, so let's
++                                                        * better be safe. */
++                           &m);
++        if (r < 0)
++                return r;
++        if (m > 07777)
+                 return -ERANGE;
+ 
+-        *ret = (mode_t) l;
++        if (ret)
++                *ret = m;
+         return 0;
+ }
+ 
diff --git a/SOURCES/0465-user-util-be-stricter-in-parse_uid.patch b/SOURCES/0465-user-util-be-stricter-in-parse_uid.patch
new file mode 100644
index 0000000..79cb570
--- /dev/null
+++ b/SOURCES/0465-user-util-be-stricter-in-parse_uid.patch
@@ -0,0 +1,78 @@
+From 87c22d3bb794118d25bc138108fd5bdd607365ef Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Mon, 1 Jun 2020 17:16:46 +0200
+Subject: [PATCH] user-util: be stricter in parse_uid()
+
+Let's refuse "+" and "-" prefixed UIDs. Let's refuse whitespace-prefixed
+UIDS, Let's refuse zero-prefixed UIDs. Let's be safe than sorry.
+
+(cherry picked from commit f5979b63cc305ba217dfd174b1bf0583bcf75a73)
+
+Related: #1848373
+---
+ src/basic/user-util.c     | 10 +++++++++-
+ src/test/test-user-util.c | 26 +++++++++++++++++++++++---
+ 2 files changed, 32 insertions(+), 4 deletions(-)
+
+diff --git a/src/basic/user-util.c b/src/basic/user-util.c
+index 10eeb256cd..40f4e45db6 100644
+--- a/src/basic/user-util.c
++++ b/src/basic/user-util.c
+@@ -49,7 +49,15 @@ int parse_uid(const char *s, uid_t *ret) {
+         assert(s);
+ 
+         assert_cc(sizeof(uid_t) == sizeof(uint32_t));
+-        r = safe_atou32_full(s, 10, &uid);
++
++        /* We are very strict when parsing UIDs, and prohibit +/- as prefix, leading zero as prefix, and
++         * whitespace. We do this, since this call is often used in a context where we parse things as UID
++         * first, and if that doesn't work we fall back to NSS. Thus we really want to make sure that UIDs
++         * are parsed as UIDs only if they really really look like UIDs. */
++        r = safe_atou32_full(s, 10
++                             | SAFE_ATO_REFUSE_PLUS_MINUS
++                             | SAFE_ATO_REFUSE_LEADING_ZERO
++                             | SAFE_ATO_REFUSE_LEADING_WHITESPACE, &uid);
+         if (r < 0)
+                 return r;
+ 
+diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c
+index 8bf3dcd567..99203f7e48 100644
+--- a/src/test/test-user-util.c
++++ b/src/test/test-user-util.c
+@@ -52,13 +52,33 @@ static void test_parse_uid(void) {
+         assert_se(r == -EINVAL);
+         assert_se(uid == 100);
+ 
++        r = parse_uid("+1234", &uid);
++        assert_se(r == -EINVAL);
++        assert_se(uid == 100);
++
++        r = parse_uid("-1234", &uid);
++        assert_se(r == -EINVAL);
++        assert_se(uid == 100);
++
++        r = parse_uid(" 1234", &uid);
++        assert_se(r == -EINVAL);
++        assert_se(uid == 100);
++
+         r = parse_uid("01234", &uid);
+-        assert_se(r == 0);
+-        assert_se(uid == 1234);
++        assert_se(r == -EINVAL);
++        assert_se(uid == 100);
++
++        r = parse_uid("-0", &uid);
++        assert_se(r == -EINVAL);
++        assert_se(uid == 100);
++
++        r = parse_uid("+0", &uid);
++        assert_se(r == -EINVAL);
++        assert_se(uid == 100);
+ 
+         r = parse_uid("asdsdas", &uid);
+         assert_se(r == -EINVAL);
+-        assert_se(uid == 1234);
++        assert_se(uid == 100);
+ }
+ 
+ static void test_uid_ptr(void) {
diff --git a/SOURCES/0466-strv-add-new-macro-STARTSWITH_SET.patch b/SOURCES/0466-strv-add-new-macro-STARTSWITH_SET.patch
new file mode 100644
index 0000000..58a4b5a
--- /dev/null
+++ b/SOURCES/0466-strv-add-new-macro-STARTSWITH_SET.patch
@@ -0,0 +1,75 @@
+From 50b103a982dfd6f1b2bf98bbc98a8063fa153e89 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Fri, 23 Nov 2018 16:27:15 +0100
+Subject: [PATCH] strv: add new macro STARTSWITH_SET()
+
+This is to startswith() what PATH_STARTSWITH_SET() is to
+path_startswith().
+
+Or in other words, checks if the specified string has any of the listed
+prefixes, and if so, returns the remainder of the string.
+
+(cherry picked from commit 52f1552073047195d51901f7e5a5a4fa3189034e)
+
+Related: #1848373
+---
+ src/basic/strv.h     | 12 ++++++++++++
+ src/test/test-strv.c | 15 +++++++++++++++
+ 2 files changed, 27 insertions(+)
+
+diff --git a/src/basic/strv.h b/src/basic/strv.h
+index 51d03db940..c1e4c973b6 100644
+--- a/src/basic/strv.h
++++ b/src/basic/strv.h
+@@ -136,6 +136,18 @@ void strv_print(char **l);
+                 _x && strv_contains(STRV_MAKE(__VA_ARGS__), _x); \
+         })
+ 
++#define STARTSWITH_SET(p, ...)                                  \
++        ({                                                      \
++                const char *_p = (p);                           \
++                char  *_found = NULL, **_i;                     \
++                STRV_FOREACH(_i, STRV_MAKE(__VA_ARGS__)) {      \
++                        _found = startswith(_p, *_i);           \
++                        if (_found)                             \
++                                break;                          \
++                }                                               \
++                _found;                                         \
++        })
++
+ #define FOREACH_STRING(x, ...)                               \
+         for (char **_l = ({                                  \
+                 char **_ll = STRV_MAKE(__VA_ARGS__);         \
+diff --git a/src/test/test-strv.c b/src/test/test-strv.c
+index 1c192239a2..79d999d3ed 100644
+--- a/src/test/test-strv.c
++++ b/src/test/test-strv.c
+@@ -56,6 +56,20 @@ static void test_strptr_in_set(void) {
+         assert_se(!STRPTR_IN_SET(NULL, NULL));
+ }
+ 
++static void test_startswith_set(void) {
++        assert_se(!STARTSWITH_SET("foo", "bar", "baz", "waldo"));
++        assert_se(!STARTSWITH_SET("foo", "bar"));
++
++        assert_se(STARTSWITH_SET("abc", "a", "ab", "abc"));
++        assert_se(STARTSWITH_SET("abc", "ax", "ab", "abc"));
++        assert_se(STARTSWITH_SET("abc", "ax", "abx", "abc"));
++        assert_se(!STARTSWITH_SET("abc", "ax", "abx", "abcx"));
++
++        assert_se(streq_ptr(STARTSWITH_SET("foobar", "hhh", "kkk", "foo", "zzz"), "bar"));
++        assert_se(streq_ptr(STARTSWITH_SET("foobar", "hhh", "kkk", "", "zzz"), "foobar"));
++        assert_se(streq_ptr(STARTSWITH_SET("", "hhh", "kkk", "zzz", ""), ""));
++}
++
+ static const char* const input_table_multiple[] = {
+         "one",
+         "two",
+@@ -700,6 +714,7 @@ int main(int argc, char *argv[]) {
+         test_specifier_printf();
+         test_str_in_set();
+         test_strptr_in_set();
++        test_startswith_set();
+         test_strv_foreach();
+         test_strv_foreach_backwards();
+         test_strv_foreach_pair();
diff --git a/SOURCES/0467-parse-util-also-parse-integers-prefixed-with-0b-and-.patch b/SOURCES/0467-parse-util-also-parse-integers-prefixed-with-0b-and-.patch
new file mode 100644
index 0000000..d088a5a
--- /dev/null
+++ b/SOURCES/0467-parse-util-also-parse-integers-prefixed-with-0b-and-.patch
@@ -0,0 +1,164 @@
+From e67e29d91a1ef90af545e4130c7b4c4cfde6202a Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Mon, 1 Jun 2020 17:31:51 +0200
+Subject: [PATCH] parse-util: also parse integers prefixed with 0b and 0o
+
+Let's adopt Python 3 style 0b and 0x syntaxes, because it makes a ton of
+sense, in particular in bitmask settings.
+
+(cherry picked from commit fc80cabcf584a8b486bdff5be0c074fec4059cdc)
+
+Related: #1848373
+---
+ src/basic/parse-util.c | 56 ++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 51 insertions(+), 5 deletions(-)
+
+diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
+index 68c156c543..992ea3605b 100644
+--- a/src/basic/parse-util.c
++++ b/src/basic/parse-util.c
+@@ -17,6 +17,7 @@
+ #include "parse-util.h"
+ #include "process-util.h"
+ #include "string-util.h"
++#include "strv.h"
+ 
+ int parse_boolean(const char *v) {
+         assert(v);
+@@ -373,7 +374,32 @@ char *format_bytes(char *buf, size_t l, uint64_t t) {
+ finish:
+         buf[l-1] = 0;
+         return buf;
++}
++
++static const char *mangle_base(const char *s, unsigned *base) {
++        const char *k;
++
++        assert(s);
++        assert(base);
++
++        /* Base already explicitly specified, then don't do anything. */
++        if (SAFE_ATO_MASK_FLAGS(*base) != 0)
++                return s;
+ 
++        /* Support Python 3 style "0b" and 0x" prefixes, because they truly make sense, much more than C's "0" prefix for octal. */
++        k = STARTSWITH_SET(s, "0b", "0B");
++        if (k) {
++                *base = 2 | (*base & SAFE_ATO_ALL_FLAGS);
++                return k;
++        }
++
++        k = STARTSWITH_SET(s, "0o", "0O");
++        if (k) {
++                *base = 8 | (*base & SAFE_ATO_ALL_FLAGS);
++                return k;
++        }
++
++        return s;
+ }
+ 
+ int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
+@@ -407,6 +433,8 @@ int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
+                 return -EINVAL; /* This is particularly useful to avoid ambiguities between C's octal
+                                  * notation and assumed-to-be-decimal integers with a leading zero. */
+ 
++        s = mangle_base(s, &base);
++
+         errno = 0;
+         l = strtoul(s, &x, SAFE_ATO_MASK_FLAGS(base) /* Let's mask off the flags bits so that only the actual
+                                                       * base is left */);
+@@ -426,13 +454,17 @@ int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
+ }
+ 
+ int safe_atoi(const char *s, int *ret_i) {
++        unsigned base = 0;
+         char *x = NULL;
+         long l;
+ 
+         assert(s);
+ 
++        s += strspn(s, WHITESPACE);
++        s = mangle_base(s, &base);
++
+         errno = 0;
+-        l = strtol(s, &x, 0);
++        l = strtol(s, &x, base);
+         if (errno > 0)
+                 return -errno;
+         if (!x || x == s || *x != 0)
+@@ -467,6 +499,8 @@ int safe_atollu_full(const char *s, unsigned base, long long unsigned *ret_llu)
+             s[0] == '0' && s[1] != 0)
+                 return -EINVAL;
+ 
++        s = mangle_base(s, &base);
++
+         errno = 0;
+         l = strtoull(s, &x, SAFE_ATO_MASK_FLAGS(base));
+         if (errno > 0)
+@@ -483,13 +517,17 @@ int safe_atollu_full(const char *s, unsigned base, long long unsigned *ret_llu)
+ }
+ 
+ int safe_atolli(const char *s, long long int *ret_lli) {
++        unsigned base = 0;
+         char *x = NULL;
+         long long l;
+ 
+         assert(s);
+ 
++        s += strspn(s, WHITESPACE);
++        s = mangle_base(s, &base);
++
+         errno = 0;
+-        l = strtoll(s, &x, 0);
++        l = strtoll(s, &x, base);
+         if (errno > 0)
+                 return -errno;
+         if (!x || x == s || *x != 0)
+@@ -502,15 +540,17 @@ int safe_atolli(const char *s, long long int *ret_lli) {
+ }
+ 
+ int safe_atou8(const char *s, uint8_t *ret) {
+-        char *x = NULL;
++        unsigned base = 0;
+         unsigned long l;
++        char *x = NULL;
+ 
+         assert(s);
+ 
+         s += strspn(s, WHITESPACE);
++        s = mangle_base(s, &base);
+ 
+         errno = 0;
+-        l = strtoul(s, &x, 0);
++        l = strtoul(s, &x, base);
+         if (errno > 0)
+                 return -errno;
+         if (!x || x == s || *x != 0)
+@@ -546,6 +586,8 @@ int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) {
+             s[0] == '0' && s[1] != 0)
+                 return -EINVAL;
+ 
++        s = mangle_base(s, &base);
++
+         errno = 0;
+         l = strtoul(s, &x, SAFE_ATO_MASK_FLAGS(base));
+         if (errno > 0)
+@@ -564,13 +606,17 @@ int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) {
+ }
+ 
+ int safe_atoi16(const char *s, int16_t *ret) {
++        unsigned base = 0;
+         char *x = NULL;
+         long l;
+ 
+         assert(s);
+ 
++        s += strspn(s, WHITESPACE);
++        s = mangle_base(s, &base);
++
+         errno = 0;
+-        l = strtol(s, &x, 0);
++        l = strtol(s, &x, base);
+         if (errno > 0)
+                 return -errno;
+         if (!x || x == s || *x != 0)
diff --git a/SOURCES/0468-tests-beef-up-integer-parsing-tests.patch b/SOURCES/0468-tests-beef-up-integer-parsing-tests.patch
new file mode 100644
index 0000000..c33c38f
--- /dev/null
+++ b/SOURCES/0468-tests-beef-up-integer-parsing-tests.patch
@@ -0,0 +1,204 @@
+From 457eada27f606e39f0efc6adc226542fd11eb815 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Mon, 1 Jun 2020 17:48:41 +0200
+Subject: [PATCH] tests: beef up integer parsing tests
+
+(cherry picked from commit 53c6db99fa4b52f97e19977f21d3133f8ceb3dcd)
+
+Related: #1848373
+---
+ src/test/test-parse-util.c | 58 ++++++++++++++++++++++++++++++++++++++
+ src/test/test-user-util.c  | 40 ++++++++++++++++++++++++++
+ 2 files changed, 98 insertions(+)
+
+diff --git a/src/test/test-parse-util.c b/src/test/test-parse-util.c
+index 8b182d9bdc..699499b665 100644
+--- a/src/test/test-parse-util.c
++++ b/src/test/test-parse-util.c
+@@ -75,14 +75,22 @@ static void test_parse_mode(void) {
+         mode_t m;
+ 
+         assert_se(parse_mode("-1", &m) < 0);
++        assert_se(parse_mode("+1", &m) < 0);
+         assert_se(parse_mode("", &m) < 0);
+         assert_se(parse_mode("888", &m) < 0);
+         assert_se(parse_mode("77777", &m) < 0);
+ 
+         assert_se(parse_mode("544", &m) >= 0 && m == 0544);
++        assert_se(parse_mode("0544", &m) >= 0 && m == 0544);
++        assert_se(parse_mode("00544", &m) >= 0 && m == 0544);
+         assert_se(parse_mode("777", &m) >= 0 && m == 0777);
++        assert_se(parse_mode("0777", &m) >= 0 && m == 0777);
++        assert_se(parse_mode("00777", &m) >= 0 && m == 0777);
+         assert_se(parse_mode("7777", &m) >= 0 && m == 07777);
++        assert_se(parse_mode("07777", &m) >= 0 && m == 07777);
++        assert_se(parse_mode("007777", &m) >= 0 && m == 07777);
+         assert_se(parse_mode("0", &m) >= 0 && m == 0);
++        assert_se(parse_mode(" 1", &m) >= 0 && m == 1);
+ }
+ 
+ static void test_parse_size(void) {
+@@ -358,6 +366,18 @@ static void test_safe_atolli(void) {
+         assert_se(r == 0);
+         assert_se(l == -12345);
+ 
++        r = safe_atolli("0x5", &l);
++        assert_se(r == 0);
++        assert_se(l == 5);
++
++        r = safe_atolli("0o6", &l);
++        assert_se(r == 0);
++        assert_se(l == 6);
++
++        r = safe_atolli("0B101", &l);
++        assert_se(r == 0);
++        assert_se(l == 5);
++
+         r = safe_atolli("12345678901234567890", &l);
+         assert_se(r == -ERANGE);
+ 
+@@ -431,6 +451,14 @@ static void test_safe_atoi16(void) {
+         assert_se(r == 0);
+         assert_se(l == 32767);
+ 
++        r = safe_atoi16("0o11", &l);
++        assert_se(r == 0);
++        assert_se(l == 9);
++
++        r = safe_atoi16("0B110", &l);
++        assert_se(r == 0);
++        assert_se(l == 6);
++
+         r = safe_atoi16("36536", &l);
+         assert_se(r == -ERANGE);
+ 
+@@ -475,6 +503,13 @@ static void test_safe_atoux16(void) {
+         r = safe_atoux16("  -1", &l);
+         assert_se(r == -ERANGE);
+ 
++        r = safe_atoux16("0b1", &l);
++        assert_se(r == 0);
++        assert_se(l == 177);
++
++        r = safe_atoux16("0o70", &l);
++        assert_se(r == -EINVAL);
++
+         r = safe_atoux16("junk", &l);
+         assert_se(r == -EINVAL);
+ 
+@@ -500,6 +535,14 @@ static void test_safe_atou64(void) {
+         assert_se(r == 0);
+         assert_se(l == 12345);
+ 
++        r = safe_atou64("0o11", &l);
++        assert_se(r == 0);
++        assert_se(l == 9);
++
++        r = safe_atou64("0b11", &l);
++        assert_se(r == 0);
++        assert_se(l == 3);
++
+         r = safe_atou64("18446744073709551617", &l);
+         assert_se(r == -ERANGE);
+ 
+@@ -542,6 +585,14 @@ static void test_safe_atoi64(void) {
+         assert_se(r == 0);
+         assert_se(l == 32767);
+ 
++        r = safe_atoi64("  0o20", &l);
++        assert_se(r == 0);
++        assert_se(l == 16);
++
++        r = safe_atoi64("  0b01010", &l);
++        assert_se(r == 0);
++        assert_se(l == 10);
++
+         r = safe_atoi64("9223372036854775813", &l);
+         assert_se(r == -ERANGE);
+ 
+@@ -577,6 +628,13 @@ static void test_safe_atoux64(void) {
+         assert_se(r == 0);
+         assert_se(l == 0x12345);
+ 
++        r = safe_atoux64("0b11011", &l);
++        assert_se(r == 0);
++        assert_se(l == 11603985);
++
++        r = safe_atoux64("0o11011", &l);
++        assert_se(r == -EINVAL);
++
+         r = safe_atoux64("18446744073709551617", &l);
+         assert_se(r == -ERANGE);
+ 
+diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c
+index 99203f7e48..04e86f5ac3 100644
+--- a/src/test/test-user-util.c
++++ b/src/test/test-user-util.c
+@@ -40,6 +40,22 @@ static void test_parse_uid(void) {
+ 
+         log_info("/* %s */", __func__);
+ 
++        r = parse_uid("0", &uid);
++        assert_se(r == 0);
++        assert_se(uid == 0);
++
++        r = parse_uid("1", &uid);
++        assert_se(r == 0);
++        assert_se(uid == 1);
++
++        r = parse_uid("01", &uid);
++        assert_se(r == -EINVAL);
++        assert_se(uid == 1);
++
++        r = parse_uid("001", &uid);
++        assert_se(r == -EINVAL);
++        assert_se(uid == 1);
++
+         r = parse_uid("100", &uid);
+         assert_se(r == 0);
+         assert_se(uid == 100);
+@@ -52,6 +68,14 @@ static void test_parse_uid(void) {
+         assert_se(r == -EINVAL);
+         assert_se(uid == 100);
+ 
++        r = parse_uid("0o1234", &uid);
++        assert_se(r == -EINVAL);
++        assert_se(uid == 100);
++
++        r = parse_uid("0b1234", &uid);
++        assert_se(r == -EINVAL);
++        assert_se(uid == 100);
++
+         r = parse_uid("+1234", &uid);
+         assert_se(r == -EINVAL);
+         assert_se(uid == 100);
+@@ -68,6 +92,14 @@ static void test_parse_uid(void) {
+         assert_se(r == -EINVAL);
+         assert_se(uid == 100);
+ 
++        r = parse_uid("001234", &uid);
++        assert_se(r == -EINVAL);
++        assert_se(uid == 100);
++
++        r = parse_uid("0001234", &uid);
++        assert_se(r == -EINVAL);
++        assert_se(uid == 100);
++
+         r = parse_uid("-0", &uid);
+         assert_se(r == -EINVAL);
+         assert_se(uid == 100);
+@@ -76,6 +108,14 @@ static void test_parse_uid(void) {
+         assert_se(r == -EINVAL);
+         assert_se(uid == 100);
+ 
++        r = parse_uid("00", &uid);
++        assert_se(r == -EINVAL);
++        assert_se(uid == 100);
++
++        r = parse_uid("000", &uid);
++        assert_se(r == -EINVAL);
++        assert_se(uid == 100);
++
+         r = parse_uid("asdsdas", &uid);
+         assert_se(r == -EINVAL);
+         assert_se(uid == 100);
diff --git a/SOURCES/0469-shared-user-util-add-compat-forms-of-user-name-check.patch b/SOURCES/0469-shared-user-util-add-compat-forms-of-user-name-check.patch
new file mode 100644
index 0000000..eefc47b
--- /dev/null
+++ b/SOURCES/0469-shared-user-util-add-compat-forms-of-user-name-check.patch
@@ -0,0 +1,270 @@
+From 1e4ec1b29d15684a305bbc9ab54c6c8321504e7b Mon Sep 17 00:00:00 2001
+From: David Tardon <dtardon@redhat.com>
+Date: Tue, 27 Oct 2020 10:31:05 +0100
+Subject: [PATCH] shared/user-util: add compat forms of user name checking
+ functions
+
+New functions are called valid_user_group_name_compat() and
+valid_user_group_name_or_id_compat() and accept dots in the user
+or group name. No functional change except the tests.
+
+(cherry picked from commit 1a29610f5fa1bcb2eeb37d2c6b79d8d1a6dbb865)
+
+This completes previous partial cherry-pick of the same commit (commit
+76176de0889c3e8b9b3a176da24e4f8dbbd380a3).
+
+Related: #1848373
+---
+ src/basic/user-util.c     | 32 +++++++-------
+ src/basic/user-util.h     | 16 ++++++-
+ src/test/test-user-util.c | 91 +++++++++++++++++++++++++++++++++++++--
+ 3 files changed, 117 insertions(+), 22 deletions(-)
+
+diff --git a/src/basic/user-util.c b/src/basic/user-util.c
+index 40f4e45db6..03cbbc2503 100644
+--- a/src/basic/user-util.c
++++ b/src/basic/user-util.c
+@@ -576,7 +576,7 @@ int take_etc_passwd_lock(const char *root) {
+         return fd;
+ }
+ 
+-bool valid_user_group_name(const char *u) {
++bool valid_user_group_name_full(const char *u, bool strict) {
+         const char *i;
+         long sz;
+ 
+@@ -585,12 +585,12 @@ bool valid_user_group_name(const char *u) {
+          *
+          * - We require that names fit into the appropriate utmp field
+          * - We don't allow empty user names
++         * - No dots or digits in the first character
+          *
+-         * Note that other systems are even more restrictive, and don't permit underscores or uppercase characters.
++         * If strict==true, additionally:
++         * - We don't allow any dots (this conflicts with chown syntax which permits dots as user/group name separator)
+          *
+-         * jsynacek: We now allow dots in user names. The checks are not exhaustive as user names like "..." are allowed
+-         * and valid according to POSIX, but can't be created using useradd. However, ".user" can be created. Let's not
+-         * complicate the code by adding additional checks for weird corner cases like these,  as they don't really matter here.
++         * Note that other systems are even more restrictive, and don't permit underscores or uppercase characters.
+          */
+ 
+         if (isempty(u))
+@@ -598,16 +598,16 @@ bool valid_user_group_name(const char *u) {
+ 
+         if (!(u[0] >= 'a' && u[0] <= 'z') &&
+             !(u[0] >= 'A' && u[0] <= 'Z') &&
+-            u[0] != '_' && u[0] != '.')
++            u[0] != '_')
+                 return false;
+ 
+-        for (i = u+1; *i; i++) {
+-                if (!(*i >= 'a' && *i <= 'z') &&
+-                    !(*i >= 'A' && *i <= 'Z') &&
+-                    !(*i >= '0' && *i <= '9') &&
+-                    !IN_SET(*i, '_', '-', '.'))
++        for (i = u+1; *i; i++)
++                if (!((*i >= 'a' && *i <= 'z') ||
++                      (*i >= 'A' && *i <= 'Z') ||
++                      (*i >= '0' && *i <= '9') ||
++                      IN_SET(*i, '_', '-') ||
++                      (!strict && *i == '.')))
+                         return false;
+-        }
+ 
+         sz = sysconf(_SC_LOGIN_NAME_MAX);
+         assert_se(sz > 0);
+@@ -621,15 +621,15 @@ bool valid_user_group_name(const char *u) {
+         return true;
+ }
+ 
+-bool valid_user_group_name_or_id(const char *u) {
++bool valid_user_group_name_or_id_full(const char *u, bool strict) {
+ 
+-        /* Similar as above, but is also fine with numeric UID/GID specifications, as long as they are in the right
+-         * range, and not the invalid user ids. */
++        /* Similar as above, but is also fine with numeric UID/GID specifications, as long as they are in the
++         * right range, and not the invalid user ids. */
+ 
+         if (isempty(u))
+                 return false;
+ 
+-        if (valid_user_group_name(u))
++        if (valid_user_group_name_full(u, strict))
+                 return true;
+ 
+         return parse_uid(u, NULL) >= 0;
+diff --git a/src/basic/user-util.h b/src/basic/user-util.h
+index b74f168859..5ad0b2a2f9 100644
+--- a/src/basic/user-util.h
++++ b/src/basic/user-util.h
+@@ -78,8 +78,20 @@ static inline bool userns_supported(void) {
+         return access("/proc/self/uid_map", F_OK) >= 0;
+ }
+ 
+-bool valid_user_group_name(const char *u);
+-bool valid_user_group_name_or_id(const char *u);
++bool valid_user_group_name_full(const char *u, bool strict);
++bool valid_user_group_name_or_id_full(const char *u, bool strict);
++static inline bool valid_user_group_name(const char *u) {
++        return valid_user_group_name_full(u, true);
++}
++static inline bool valid_user_group_name_or_id(const char *u) {
++        return valid_user_group_name_or_id_full(u, true);
++}
++static inline bool valid_user_group_name_compat(const char *u) {
++        return valid_user_group_name_full(u, false);
++}
++static inline bool valid_user_group_name_or_id_compat(const char *u) {
++        return valid_user_group_name_or_id_full(u, false);
++}
+ bool valid_gecos(const char *d);
+ bool valid_home(const char *p);
+ 
+diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c
+index 04e86f5ac3..3a4211655d 100644
+--- a/src/test/test-user-util.c
++++ b/src/test/test-user-util.c
+@@ -131,6 +131,43 @@ static void test_uid_ptr(void) {
+         assert_se(PTR_TO_UID(UID_TO_PTR(1000)) == 1000);
+ }
+ 
++static void test_valid_user_group_name_compat(void) {
++        log_info("/* %s */", __func__);
++
++        assert_se(!valid_user_group_name_compat(NULL));
++        assert_se(!valid_user_group_name_compat(""));
++        assert_se(!valid_user_group_name_compat("1"));
++        assert_se(!valid_user_group_name_compat("65535"));
++        assert_se(!valid_user_group_name_compat("-1"));
++        assert_se(!valid_user_group_name_compat("-kkk"));
++        assert_se(!valid_user_group_name_compat("rööt"));
++        assert_se(!valid_user_group_name_compat("."));
++        assert_se(!valid_user_group_name_compat(".eff"));
++        assert_se(!valid_user_group_name_compat("foo\nbar"));
++        assert_se(!valid_user_group_name_compat("0123456789012345678901234567890123456789"));
++        assert_se(!valid_user_group_name_or_id_compat("aaa:bbb"));
++        assert_se(!valid_user_group_name_compat("."));
++        assert_se(!valid_user_group_name_compat(".1"));
++        assert_se(!valid_user_group_name_compat(".65535"));
++        assert_se(!valid_user_group_name_compat(".-1"));
++        assert_se(!valid_user_group_name_compat(".-kkk"));
++        assert_se(!valid_user_group_name_compat(".rööt"));
++        assert_se(!valid_user_group_name_or_id_compat(".aaa:bbb"));
++
++        assert_se(valid_user_group_name_compat("root"));
++        assert_se(valid_user_group_name_compat("lennart"));
++        assert_se(valid_user_group_name_compat("LENNART"));
++        assert_se(valid_user_group_name_compat("_kkk"));
++        assert_se(valid_user_group_name_compat("kkk-"));
++        assert_se(valid_user_group_name_compat("kk-k"));
++        assert_se(valid_user_group_name_compat("eff.eff"));
++        assert_se(valid_user_group_name_compat("eff."));
++
++        assert_se(valid_user_group_name_compat("some5"));
++        assert_se(!valid_user_group_name_compat("5some"));
++        assert_se(valid_user_group_name_compat("INNER5NUMBER"));
++}
++
+ static void test_valid_user_group_name(void) {
+         log_info("/* %s */", __func__);
+ 
+@@ -141,9 +178,18 @@ static void test_valid_user_group_name(void) {
+         assert_se(!valid_user_group_name("-1"));
+         assert_se(!valid_user_group_name("-kkk"));
+         assert_se(!valid_user_group_name("rööt"));
++        assert_se(!valid_user_group_name("."));
++        assert_se(!valid_user_group_name(".eff"));
+         assert_se(!valid_user_group_name("foo\nbar"));
+         assert_se(!valid_user_group_name("0123456789012345678901234567890123456789"));
+         assert_se(!valid_user_group_name_or_id("aaa:bbb"));
++        assert_se(!valid_user_group_name("."));
++        assert_se(!valid_user_group_name(".1"));
++        assert_se(!valid_user_group_name(".65535"));
++        assert_se(!valid_user_group_name(".-1"));
++        assert_se(!valid_user_group_name(".-kkk"));
++        assert_se(!valid_user_group_name(".rööt"));
++        assert_se(!valid_user_group_name_or_id(".aaa:bbb"));
+ 
+         assert_se(valid_user_group_name("root"));
+         assert_se(valid_user_group_name("lennart"));
+@@ -151,14 +197,47 @@ static void test_valid_user_group_name(void) {
+         assert_se(valid_user_group_name("_kkk"));
+         assert_se(valid_user_group_name("kkk-"));
+         assert_se(valid_user_group_name("kk-k"));
+-        assert_se(valid_user_group_name(".moo"));
+-        assert_se(valid_user_group_name("eff.eff"));
++        assert_se(!valid_user_group_name("eff.eff"));
++        assert_se(!valid_user_group_name("eff."));
+ 
+         assert_se(valid_user_group_name("some5"));
+         assert_se(!valid_user_group_name("5some"));
+         assert_se(valid_user_group_name("INNER5NUMBER"));
+ }
+ 
++static void test_valid_user_group_name_or_id_compat(void) {
++        log_info("/* %s */", __func__);
++
++        assert_se(!valid_user_group_name_or_id_compat(NULL));
++        assert_se(!valid_user_group_name_or_id_compat(""));
++        assert_se(valid_user_group_name_or_id_compat("0"));
++        assert_se(valid_user_group_name_or_id_compat("1"));
++        assert_se(valid_user_group_name_or_id_compat("65534"));
++        assert_se(!valid_user_group_name_or_id_compat("65535"));
++        assert_se(valid_user_group_name_or_id_compat("65536"));
++        assert_se(!valid_user_group_name_or_id_compat("-1"));
++        assert_se(!valid_user_group_name_or_id_compat("-kkk"));
++        assert_se(!valid_user_group_name_or_id_compat("rööt"));
++        assert_se(!valid_user_group_name_or_id_compat("."));
++        assert_se(!valid_user_group_name_or_id_compat(".eff"));
++        assert_se(valid_user_group_name_or_id_compat("eff.eff"));
++        assert_se(valid_user_group_name_or_id_compat("eff."));
++        assert_se(!valid_user_group_name_or_id_compat("foo\nbar"));
++        assert_se(!valid_user_group_name_or_id_compat("0123456789012345678901234567890123456789"));
++        assert_se(!valid_user_group_name_or_id_compat("aaa:bbb"));
++
++        assert_se(valid_user_group_name_or_id_compat("root"));
++        assert_se(valid_user_group_name_or_id_compat("lennart"));
++        assert_se(valid_user_group_name_or_id_compat("LENNART"));
++        assert_se(valid_user_group_name_or_id_compat("_kkk"));
++        assert_se(valid_user_group_name_or_id_compat("kkk-"));
++        assert_se(valid_user_group_name_or_id_compat("kk-k"));
++
++        assert_se(valid_user_group_name_or_id_compat("some5"));
++        assert_se(!valid_user_group_name_or_id_compat("5some"));
++        assert_se(valid_user_group_name_or_id_compat("INNER5NUMBER"));
++}
++
+ static void test_valid_user_group_name_or_id(void) {
+         log_info("/* %s */", __func__);
+ 
+@@ -172,6 +251,10 @@ static void test_valid_user_group_name_or_id(void) {
+         assert_se(!valid_user_group_name_or_id("-1"));
+         assert_se(!valid_user_group_name_or_id("-kkk"));
+         assert_se(!valid_user_group_name_or_id("rööt"));
++        assert_se(!valid_user_group_name_or_id("."));
++        assert_se(!valid_user_group_name_or_id(".eff"));
++        assert_se(!valid_user_group_name_or_id("eff.eff"));
++        assert_se(!valid_user_group_name_or_id("eff."));
+         assert_se(!valid_user_group_name_or_id("foo\nbar"));
+         assert_se(!valid_user_group_name_or_id("0123456789012345678901234567890123456789"));
+         assert_se(!valid_user_group_name_or_id("aaa:bbb"));
+@@ -182,8 +265,6 @@ static void test_valid_user_group_name_or_id(void) {
+         assert_se(valid_user_group_name_or_id("_kkk"));
+         assert_se(valid_user_group_name_or_id("kkk-"));
+         assert_se(valid_user_group_name_or_id("kk-k"));
+-        assert_se(valid_user_group_name_or_id(".moo"));
+-        assert_se(valid_user_group_name_or_id("eff.eff"));
+ 
+         assert_se(valid_user_group_name_or_id("some5"));
+         assert_se(!valid_user_group_name_or_id("5some"));
+@@ -286,7 +367,9 @@ int main(int argc, char*argv[]) {
+         test_parse_uid();
+         test_uid_ptr();
+ 
++        test_valid_user_group_name_compat();
+         test_valid_user_group_name();
++        test_valid_user_group_name_or_id_compat();
+         test_valid_user_group_name_or_id();
+         test_valid_gecos();
+         test_valid_home();
diff --git a/SOURCES/0470-shared-user-util-emit-a-warning-on-names-with-dots.patch b/SOURCES/0470-shared-user-util-emit-a-warning-on-names-with-dots.patch
new file mode 100644
index 0000000..83422bc
--- /dev/null
+++ b/SOURCES/0470-shared-user-util-emit-a-warning-on-names-with-dots.patch
@@ -0,0 +1,50 @@
+From fa1fa19951fdadd63f2b5df6224678f91753f260 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Wed, 28 Aug 2019 12:05:52 +0200
+Subject: [PATCH] shared/user-util: emit a warning on names with dots
+
+(cherry picked from commit 88e2ed0b5bf6f08f5a2d4d64b1fefdc7192b9aac)
+
+Related: #1848373
+---
+ src/basic/user-util.c | 27 ++++++++++++++++++++-------
+ 1 file changed, 20 insertions(+), 7 deletions(-)
+
+diff --git a/src/basic/user-util.c b/src/basic/user-util.c
+index 03cbbc2503..359da08a83 100644
+--- a/src/basic/user-util.c
++++ b/src/basic/user-util.c
+@@ -601,13 +601,26 @@ bool valid_user_group_name_full(const char *u, bool strict) {
+             u[0] != '_')
+                 return false;
+ 
+-        for (i = u+1; *i; i++)
+-                if (!((*i >= 'a' && *i <= 'z') ||
+-                      (*i >= 'A' && *i <= 'Z') ||
+-                      (*i >= '0' && *i <= '9') ||
+-                      IN_SET(*i, '_', '-') ||
+-                      (!strict && *i == '.')))
+-                        return false;
++        bool warned = false;
++
++        for (i = u+1; *i; i++) {
++                if (((*i >= 'a' && *i <= 'z') ||
++                     (*i >= 'A' && *i <= 'Z') ||
++                     (*i >= '0' && *i <= '9') ||
++                     IN_SET(*i, '_', '-')))
++                        continue;
++
++                if (*i == '.' && !strict) {
++                        if (!warned) {
++                                log_warning("Bad user or group name \"%s\", accepting for compatibility.", u);
++                                warned = true;
++                        }
++
++                        continue;
++                }
++
++                return false;
++        }
+ 
+         sz = sysconf(_SC_LOGIN_NAME_MAX);
+         assert_se(sz > 0);
diff --git a/SOURCES/0471-user-util-Allow-names-starting-with-a-digit.patch b/SOURCES/0471-user-util-Allow-names-starting-with-a-digit.patch
new file mode 100644
index 0000000..52a315a
--- /dev/null
+++ b/SOURCES/0471-user-util-Allow-names-starting-with-a-digit.patch
@@ -0,0 +1,103 @@
+From f06434cc51eedd72f7d4a640a1fa118f57a5e68e Mon Sep 17 00:00:00 2001
+From: Balint Reczey <balint.reczey@canonical.com>
+Date: Wed, 18 Mar 2020 18:29:02 +0100
+Subject: [PATCH] user-util: Allow names starting with a digit
+
+In 1a29610f5fa1bcb2eeb37d2c6b79d8d1a6dbb865 the change inadvertedly
+disabled names with digit as the first character. This follow-up change
+allows a digit as the first character in compat mode.
+
+Fixes: #15141
+(cherry picked from commit 93c23c9297e48e594785e0bb9c51504aae5fbe3e)
+
+Related: #1848373
+---
+ src/basic/user-util.c     | 20 +++++++++++++++++---
+ src/test/test-user-util.c |  4 ++--
+ 2 files changed, 19 insertions(+), 5 deletions(-)
+
+diff --git a/src/basic/user-util.c b/src/basic/user-util.c
+index 359da08a83..7dd2bb2c84 100644
+--- a/src/basic/user-util.c
++++ b/src/basic/user-util.c
+@@ -579,16 +579,18 @@ int take_etc_passwd_lock(const char *root) {
+ bool valid_user_group_name_full(const char *u, bool strict) {
+         const char *i;
+         long sz;
++        bool warned = false;
+ 
+         /* Checks if the specified name is a valid user/group name. Also see POSIX IEEE Std 1003.1-2008, 2016 Edition,
+          * 3.437. We are a bit stricter here however. Specifically we deviate from POSIX rules:
+          *
+          * - We require that names fit into the appropriate utmp field
+          * - We don't allow empty user names
+-         * - No dots or digits in the first character
++         * - No dots in the first character
+          *
+          * If strict==true, additionally:
+          * - We don't allow any dots (this conflicts with chown syntax which permits dots as user/group name separator)
++         * - We don't allow a digit as the first character
+          *
+          * Note that other systems are even more restrictive, and don't permit underscores or uppercase characters.
+          */
+@@ -598,17 +600,26 @@ bool valid_user_group_name_full(const char *u, bool strict) {
+ 
+         if (!(u[0] >= 'a' && u[0] <= 'z') &&
+             !(u[0] >= 'A' && u[0] <= 'Z') &&
++            !(u[0] >= '0' && u[0] <= '9' && !strict) &&
+             u[0] != '_')
+                 return false;
+ 
+-        bool warned = false;
++        bool only_digits_seen = u[0] >= '0' && u[0] <= '9';
++
++        if (only_digits_seen) {
++                log_warning("User or group name \"%s\" starts with a digit, accepting for compatibility.", u);
++                warned = true;
++        }
+ 
+         for (i = u+1; *i; i++) {
+                 if (((*i >= 'a' && *i <= 'z') ||
+                      (*i >= 'A' && *i <= 'Z') ||
+                      (*i >= '0' && *i <= '9') ||
+-                     IN_SET(*i, '_', '-')))
++                     IN_SET(*i, '_', '-'))) {
++                        if (!(*i >= '0' && *i <= '9'))
++                                only_digits_seen = false;
+                         continue;
++                        }
+ 
+                 if (*i == '.' && !strict) {
+                         if (!warned) {
+@@ -622,6 +633,9 @@ bool valid_user_group_name_full(const char *u, bool strict) {
+                 return false;
+         }
+ 
++        if (only_digits_seen)
++                return false;
++
+         sz = sysconf(_SC_LOGIN_NAME_MAX);
+         assert_se(sz > 0);
+ 
+diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c
+index 3a4211655d..56079f1486 100644
+--- a/src/test/test-user-util.c
++++ b/src/test/test-user-util.c
+@@ -164,7 +164,7 @@ static void test_valid_user_group_name_compat(void) {
+         assert_se(valid_user_group_name_compat("eff."));
+ 
+         assert_se(valid_user_group_name_compat("some5"));
+-        assert_se(!valid_user_group_name_compat("5some"));
++        assert_se(valid_user_group_name_compat("5some"));
+         assert_se(valid_user_group_name_compat("INNER5NUMBER"));
+ }
+ 
+@@ -234,7 +234,7 @@ static void test_valid_user_group_name_or_id_compat(void) {
+         assert_se(valid_user_group_name_or_id_compat("kk-k"));
+ 
+         assert_se(valid_user_group_name_or_id_compat("some5"));
+-        assert_se(!valid_user_group_name_or_id_compat("5some"));
++        assert_se(valid_user_group_name_or_id_compat("5some"));
+         assert_se(valid_user_group_name_or_id_compat("INNER5NUMBER"));
+ }
+ 
diff --git a/SOURCES/0472-shared-user-util-allow-usernames-with-dots-in-specif.patch b/SOURCES/0472-shared-user-util-allow-usernames-with-dots-in-specif.patch
new file mode 100644
index 0000000..37544d6
--- /dev/null
+++ b/SOURCES/0472-shared-user-util-allow-usernames-with-dots-in-specif.patch
@@ -0,0 +1,193 @@
+From 40dff18947fa198810db4cd3e5291349fc84a0e8 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Thu, 1 Aug 2019 10:02:14 +0200
+Subject: [PATCH] shared/user-util: allow usernames with dots in specific
+ fields
+
+People do have usernames with dots, and it makes them very unhappy that systemd
+doesn't like their that. It seems that there is no actual problem with allowing
+dots in the username. In particular chown declares ":" as the official
+separator, and internally in systemd we never rely on "." as the seperator
+between user and group (nor do we call chown directly). Using dots in the name
+is probably not a very good idea, but we don't need to care. Debian tools
+(adduser) do not allow users with dots to be created.
+
+This patch allows *existing* names with dots to be used in User, Group,
+SupplementaryGroups, SocketUser, SocketGroup fields, both in unit files and on
+the command line. DynamicUsers and sysusers still follow the strict policy.
+user@.service and tmpfiles already allowed arbitrary user names, and this
+remains unchanged.
+
+Fixes #12754.
+
+(cherry picked from commit ae480f0b09aec815b64579bb1828ea935d8ee236)
+
+Related: #1848373
+---
+ src/core/dbus-execute.c               | 12 ++++++------
+ src/core/dbus-socket.c                |  4 ++--
+ src/core/dbus-util.c                  |  2 +-
+ src/core/dbus-util.h                  |  2 +-
+ src/core/load-fragment-gperf.gperf.m4 | 10 +++++-----
+ src/core/load-fragment.c              |  8 ++++----
+ src/core/load-fragment.h              |  4 ++--
+ 7 files changed, 21 insertions(+), 21 deletions(-)
+
+diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
+index 0fe4c14e48..e004fb55c9 100644
+--- a/src/core/dbus-execute.c
++++ b/src/core/dbus-execute.c
+@@ -1113,10 +1113,10 @@ int bus_exec_context_set_transient_property(
+         flags |= UNIT_PRIVATE;
+ 
+         if (streq(name, "User"))
+-                return bus_set_transient_user(u, name, &c->user, message, flags, error);
++                return bus_set_transient_user_compat(u, name, &c->user, message, flags, error);
+ 
+         if (streq(name, "Group"))
+-                return bus_set_transient_user(u, name, &c->group, message, flags, error);
++                return bus_set_transient_user_compat(u, name, &c->group, message, flags, error);
+ 
+         if (streq(name, "TTYPath"))
+                 return bus_set_transient_path(u, name, &c->tty_path, message, flags, error);
+@@ -1297,10 +1297,10 @@ int bus_exec_context_set_transient_property(
+                 if (r < 0)
+                         return r;
+ 
+-                STRV_FOREACH(p, l) {
+-                        if (!isempty(*p) && !valid_user_group_name_or_id(*p))
+-                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid supplementary group names");
+-                }
++                STRV_FOREACH(p, l)
++                        if (!isempty(*p) && !valid_user_group_name_or_id_compat(*p))
++                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
++                                                         "Invalid supplementary group names");
+ 
+                 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+                         if (strv_isempty(l)) {
+diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c
+index bb77539030..8fdbc05409 100644
+--- a/src/core/dbus-socket.c
++++ b/src/core/dbus-socket.c
+@@ -281,10 +281,10 @@ static int bus_socket_set_transient_property(
+                 return bus_set_transient_fdname(u, name, &s->fdname, message, flags, error);
+ 
+         if (streq(name, "SocketUser"))
+-                return bus_set_transient_user(u, name, &s->user, message, flags, error);
++                return bus_set_transient_user_compat(u, name, &s->user, message, flags, error);
+ 
+         if (streq(name, "SocketGroup"))
+-                return bus_set_transient_user(u, name, &s->group, message, flags, error);
++                return bus_set_transient_user_compat(u, name, &s->group, message, flags, error);
+ 
+         if (streq(name, "BindIPv6Only"))
+                 return bus_set_transient_bind_ipv6_only(u, name, &s->bind_ipv6_only, message, flags, error);
+diff --git a/src/core/dbus-util.c b/src/core/dbus-util.c
+index f4fbb72cb9..7862beaacb 100644
+--- a/src/core/dbus-util.c
++++ b/src/core/dbus-util.c
+@@ -30,7 +30,7 @@ int bus_property_get_triggered_unit(
+ 
+ BUS_DEFINE_SET_TRANSIENT(mode_t, "u", uint32_t, mode_t, "%040o");
+ BUS_DEFINE_SET_TRANSIENT(unsigned, "u", uint32_t, unsigned, "%" PRIu32);
+-BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(user, valid_user_group_name_or_id);
++BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(user_compat, valid_user_group_name_or_id_compat);
+ BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(path, path_is_absolute);
+ 
+ int bus_set_transient_string(
+diff --git a/src/core/dbus-util.h b/src/core/dbus-util.h
+index 12b055e4ac..a3316c6701 100644
+--- a/src/core/dbus-util.h
++++ b/src/core/dbus-util.h
+@@ -235,7 +235,7 @@ int bus_property_get_triggered_unit(sd_bus *bus, const char *path, const char *i
+ 
+ int bus_set_transient_mode_t(Unit *u, const char *name, mode_t *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
+ int bus_set_transient_unsigned(Unit *u, const char *name, unsigned *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
+-int bus_set_transient_user(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
++int bus_set_transient_user_compat(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
+ int bus_set_transient_path(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
+ int bus_set_transient_string(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
+ int bus_set_transient_bool(Unit *u, const char *name, bool *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
+diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
+index 24ee5ae6fe..156a4d0a6d 100644
+--- a/src/core/load-fragment-gperf.gperf.m4
++++ b/src/core/load-fragment-gperf.gperf.m4
+@@ -25,9 +25,9 @@ m4_define(`EXEC_CONTEXT_CONFIG_ITEMS',
+ `$1.WorkingDirectory,            config_parse_working_directory,     0,                             offsetof($1, exec_context)
+ $1.RootDirectory,                config_parse_unit_path_printf,      true,                          offsetof($1, exec_context.root_directory)
+ $1.RootImage,                    config_parse_unit_path_printf,      true,                          offsetof($1, exec_context.root_image)
+-$1.User,                         config_parse_user_group,            0,                             offsetof($1, exec_context.user)
+-$1.Group,                        config_parse_user_group,            0,                             offsetof($1, exec_context.group)
+-$1.SupplementaryGroups,          config_parse_user_group_strv,       0,                             offsetof($1, exec_context.supplementary_groups)
++$1.User,                         config_parse_user_group_compat,     0,                             offsetof($1, exec_context.user)
++$1.Group,                        config_parse_user_group_compat,     0,                             offsetof($1, exec_context.group)
++$1.SupplementaryGroups,          config_parse_user_group_strv_compat, 0,                            offsetof($1, exec_context.supplementary_groups)
+ $1.Nice,                         config_parse_exec_nice,             0,                             offsetof($1, exec_context)
+ $1.OOMScoreAdjust,               config_parse_exec_oom_score_adjust, 0,                             offsetof($1, exec_context)
+ $1.IOSchedulingClass,            config_parse_exec_io_class,         0,                             offsetof($1, exec_context)
+@@ -354,8 +354,8 @@ Socket.ExecStartPost,            config_parse_exec,                  SOCKET_EXEC
+ Socket.ExecStopPre,              config_parse_exec,                  SOCKET_EXEC_STOP_PRE,          offsetof(Socket, exec_command)
+ Socket.ExecStopPost,             config_parse_exec,                  SOCKET_EXEC_STOP_POST,         offsetof(Socket, exec_command)
+ Socket.TimeoutSec,               config_parse_sec_fix_0,             0,                             offsetof(Socket, timeout_usec)
+-Socket.SocketUser,               config_parse_user_group,            0,                             offsetof(Socket, user)
+-Socket.SocketGroup,              config_parse_user_group,            0,                             offsetof(Socket, group)
++Socket.SocketUser,               config_parse_user_group_compat,     0,                             offsetof(Socket, user)
++Socket.SocketGroup,              config_parse_user_group_compat,     0,                             offsetof(Socket, group)
+ Socket.SocketMode,               config_parse_mode,                  0,                             offsetof(Socket, socket_mode)
+ Socket.DirectoryMode,            config_parse_mode,                  0,                             offsetof(Socket, directory_mode)
+ Socket.Accept,                   config_parse_bool,                  0,                             offsetof(Socket, accept)
+diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
+index 740401a582..ba81d94504 100644
+--- a/src/core/load-fragment.c
++++ b/src/core/load-fragment.c
+@@ -1899,7 +1899,7 @@ int config_parse_sec_fix_0(
+         return 0;
+ }
+ 
+-int config_parse_user_group(
++int config_parse_user_group_compat(
+                 const char *unit,
+                 const char *filename,
+                 unsigned line,
+@@ -1932,7 +1932,7 @@ int config_parse_user_group(
+                 return -ENOEXEC;
+         }
+ 
+-        if (!valid_user_group_name_or_id(k)) {
++        if (!valid_user_group_name_or_id_compat(k)) {
+                 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID: %s", k);
+                 return -ENOEXEC;
+         }
+@@ -1940,7 +1940,7 @@ int config_parse_user_group(
+         return free_and_replace(*user, k);
+ }
+ 
+-int config_parse_user_group_strv(
++int config_parse_user_group_strv_compat(
+                 const char *unit,
+                 const char *filename,
+                 unsigned line,
+@@ -1986,7 +1986,7 @@ int config_parse_user_group_strv(
+                         return -ENOEXEC;
+                 }
+ 
+-                if (!valid_user_group_name_or_id(k)) {
++                if (!valid_user_group_name_or_id_compat(k)) {
+                         log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID: %s", k);
+                         return -ENOEXEC;
+                 }
+diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
+index 65a94d53cc..f9d34d484d 100644
+--- a/src/core/load-fragment.h
++++ b/src/core/load-fragment.h
+@@ -96,8 +96,8 @@ CONFIG_PARSER_PROTOTYPE(config_parse_exec_utmp_mode);
+ CONFIG_PARSER_PROTOTYPE(config_parse_working_directory);
+ CONFIG_PARSER_PROTOTYPE(config_parse_fdname);
+ CONFIG_PARSER_PROTOTYPE(config_parse_sec_fix_0);
+-CONFIG_PARSER_PROTOTYPE(config_parse_user_group);
+-CONFIG_PARSER_PROTOTYPE(config_parse_user_group_strv);
++CONFIG_PARSER_PROTOTYPE(config_parse_user_group_compat);
++CONFIG_PARSER_PROTOTYPE(config_parse_user_group_strv_compat);
+ CONFIG_PARSER_PROTOTYPE(config_parse_restrict_namespaces);
+ CONFIG_PARSER_PROTOTYPE(config_parse_bind_paths);
+ CONFIG_PARSER_PROTOTYPE(config_parse_exec_keyring_mode);
diff --git a/SOURCES/0473-user-util-switch-order-of-checks-in-valid_user_group.patch b/SOURCES/0473-user-util-switch-order-of-checks-in-valid_user_group.patch
new file mode 100644
index 0000000..b982f8c
--- /dev/null
+++ b/SOURCES/0473-user-util-switch-order-of-checks-in-valid_user_group.patch
@@ -0,0 +1,38 @@
+From 7569168bea3d7e11cd3afe6167fcf4a3ac65a1a6 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Mon, 30 Mar 2020 21:46:01 +0200
+Subject: [PATCH] user-util: switch order of checks in
+ valid_user_group_name_or_id_full()
+
+When we are supposed to accept numeric UIDs formatted as string, then
+let's check that first, before passing things on to
+valid_user_group_name_full(), since that might log about, and not the
+other way round.
+
+See: #15201
+Follow-up for: 93c23c9297e48e594785e0bb9c51504aae5fbe3e
+
+(cherry picked from commit a85daa0dfb3eb03be9845760e90e54b9af8fb00e)
+
+Related: #1848373
+---
+ src/basic/user-util.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/basic/user-util.c b/src/basic/user-util.c
+index 7dd2bb2c84..68a924770b 100644
+--- a/src/basic/user-util.c
++++ b/src/basic/user-util.c
+@@ -656,10 +656,10 @@ bool valid_user_group_name_or_id_full(const char *u, bool strict) {
+         if (isempty(u))
+                 return false;
+ 
+-        if (valid_user_group_name_full(u, strict))
++        if (parse_uid(u, NULL) >= 0)
+                 return true;
+ 
+-        return parse_uid(u, NULL) >= 0;
++        return valid_user_group_name_full(u, strict);
+ }
+ 
+ bool valid_gecos(const char *d) {
diff --git a/SOURCES/0474-user-util-rework-how-we-validate-user-names.patch b/SOURCES/0474-user-util-rework-how-we-validate-user-names.patch
new file mode 100644
index 0000000..9607f81
--- /dev/null
+++ b/SOURCES/0474-user-util-rework-how-we-validate-user-names.patch
@@ -0,0 +1,803 @@
+From 33b851f0c30e47fe71a293e2c990ef26573efe86 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Sat, 4 Apr 2020 12:23:02 +0200
+Subject: [PATCH] user-util: rework how we validate user names
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This reworks the user validation infrastructure. There are now two
+modes. In regular mode we are strict and test against a strict set of
+valid chars. And in "relaxed" mode we just filter out some really
+obvious, dangerous stuff. i.e. strict is whitelisting what is OK, but
+"relaxed" is blacklisting what is really not OK.
+
+The idea is that we use strict mode whenver we allocate a new user
+(i.e. in sysusers.d or homed), while "relaxed" mode is when we process
+users registered elsewhere, (i.e. userdb, logind, …)
+
+The requirements on user name validity vary wildly. SSSD thinks its fine
+to embedd "@" for example, while the suggested NAME_REGEX field on
+Debian does not even allow uppercase chars…
+
+This effectively liberaralizes a lot what we expect from usernames.
+
+The code that warns about questionnable user names is now optional and
+only used at places such as unit file parsing, so that it doesn't show
+up on every userdb query, but only when processing configuration files
+that know better.
+
+Fixes: #15149 #15090
+(cherry picked from commit 7a8867abfab10e5bbca10590ec2aa40c5b27d8fb)
+
+Resolves: #1848373
+---
+ src/basic/user-util.c         | 185 +++++++++++++----------
+ src/basic/user-util.h         |  21 +--
+ src/core/dbus-execute.c       |   6 +-
+ src/core/dbus-manager.c       |   2 +-
+ src/core/dbus-socket.c        |   4 +-
+ src/core/dbus-util.c          |   7 +-
+ src/core/dbus-util.h          |   2 +-
+ src/core/dynamic-user.c       |   2 +-
+ src/core/load-fragment.c      |   4 +-
+ src/core/unit.c               |   2 +-
+ src/nss-systemd/nss-systemd.c |   6 +-
+ src/systemd/sd-messages.h     |   3 +
+ src/sysusers/sysusers.c       |   4 +-
+ src/test/test-user-util.c     | 271 ++++++++++++++++++----------------
+ 14 files changed, 287 insertions(+), 232 deletions(-)
+
+diff --git a/src/basic/user-util.c b/src/basic/user-util.c
+index 68a924770b..cd870c4361 100644
+--- a/src/basic/user-util.c
++++ b/src/basic/user-util.c
+@@ -14,6 +14,8 @@
+ #include <unistd.h>
+ #include <utmp.h>
+ 
++#include "sd-messages.h"
++
+ #include "alloc-util.h"
+ #include "fd-util.h"
+ #include "fileio.h"
+@@ -576,92 +578,125 @@ int take_etc_passwd_lock(const char *root) {
+         return fd;
+ }
+ 
+-bool valid_user_group_name_full(const char *u, bool strict) {
++bool valid_user_group_name(const char *u, ValidUserFlags flags) {
+         const char *i;
+-        long sz;
+-        bool warned = false;
+ 
+-        /* Checks if the specified name is a valid user/group name. Also see POSIX IEEE Std 1003.1-2008, 2016 Edition,
+-         * 3.437. We are a bit stricter here however. Specifically we deviate from POSIX rules:
+-         *
+-         * - We require that names fit into the appropriate utmp field
+-         * - We don't allow empty user names
+-         * - No dots in the first character
++        /* Checks if the specified name is a valid user/group name. There are two flavours of this call:
++         * strict mode is the default which is POSIX plus some extra rules; and relaxed mode where we accept
++         * pretty much everything except the really worst offending names.
+          *
+-         * If strict==true, additionally:
+-         * - We don't allow any dots (this conflicts with chown syntax which permits dots as user/group name separator)
+-         * - We don't allow a digit as the first character
+-         *
+-         * Note that other systems are even more restrictive, and don't permit underscores or uppercase characters.
+-         */
++         * Whenever we synthesize users ourselves we should use the strict mode. But when we process users
++         * created by other stuff, let's be more liberal. */
+ 
+-        if (isempty(u))
++        if (isempty(u)) /* An empty user name is never valid */
+                 return false;
+ 
+-        if (!(u[0] >= 'a' && u[0] <= 'z') &&
+-            !(u[0] >= 'A' && u[0] <= 'Z') &&
+-            !(u[0] >= '0' && u[0] <= '9' && !strict) &&
+-            u[0] != '_')
+-                return false;
+-
+-        bool only_digits_seen = u[0] >= '0' && u[0] <= '9';
+-
+-        if (only_digits_seen) {
+-                log_warning("User or group name \"%s\" starts with a digit, accepting for compatibility.", u);
+-                warned = true;
+-        }
+-
+-        for (i = u+1; *i; i++) {
+-                if (((*i >= 'a' && *i <= 'z') ||
+-                     (*i >= 'A' && *i <= 'Z') ||
+-                     (*i >= '0' && *i <= '9') ||
+-                     IN_SET(*i, '_', '-'))) {
+-                        if (!(*i >= '0' && *i <= '9'))
+-                                only_digits_seen = false;
+-                        continue;
+-                        }
+-
+-                if (*i == '.' && !strict) {
+-                        if (!warned) {
+-                                log_warning("Bad user or group name \"%s\", accepting for compatibility.", u);
+-                                warned = true;
+-                        }
+-
+-                        continue;
+-                }
+-
+-                return false;
++        if (parse_uid(u, NULL) >= 0) /* Something that parses as numeric UID string is valid exactly when the
++                                      * flag for it is set */
++                return FLAGS_SET(flags, VALID_USER_ALLOW_NUMERIC);
++
++        if (FLAGS_SET(flags, VALID_USER_RELAX)) {
++
++                /* In relaxed mode we just check very superficially. Apparently SSSD and other stuff is
++                 * extremely liberal (way too liberal if you ask me, even inserting "@" in user names, which
++                 * is bound to cause problems for example when used with an MTA), hence only filter the most
++                 * obvious cases, or where things would result in an invalid entry if such a user name would
++                 * show up in /etc/passwd (or equivalent getent output).
++                 *
++                 * Note that we stepped far out of POSIX territory here. It's not our fault though, but
++                 * SSSD's, Samba's and everybody else who ignored POSIX on this. (I mean, I am happy to step
++                 * outside of POSIX' bounds any day, but I must say in this case I probably wouldn't
++                 * have...) */
++
++                if (startswith(u, " ") || endswith(u, " ")) /* At least expect whitespace padding is removed
++                                                             * at front and back (accept in the middle, since
++                                                             * that's apparently a thing on Windows). Note
++                                                             * that this also blocks usernames consisting of
++                                                             * whitespace only. */
++                        return false;
++
++                if (!utf8_is_valid(u)) /* We want to synthesize JSON from this, hence insist on UTF-8 */
++                        return false;
++
++                if (string_has_cc(u, NULL)) /* CC characters are just dangerous (and \n in particular is the
++                                             * record separator in /etc/passwd), so we can't allow that. */
++                        return false;
++
++                if (strpbrk(u, ":/")) /* Colons are the field separator in /etc/passwd, we can't allow
++                                       * that. Slashes are special to file systems paths and user names
++                                       * typically show up in the file system as home directories, hence
++                                       * don't allow slashes. */
++                        return false;
++
++                if (in_charset(u, "0123456789")) /* Don't allow fully numeric strings, they might be confused
++                                                  * with with UIDs (note that this test is more broad than
++                                                  * the parse_uid() test above, as it will cover more than
++                                                  * the 32bit range, and it will detect 65535 (which is in
++                                                  * invalid UID, even though in the unsigned 32 bit range) */
++                        return false;
++
++                if (u[0] == '-' && in_charset(u + 1, "0123456789")) /* Don't allow negative fully numeric
++                                                                     * strings either. After all some people
++                                                                     * write 65535 as -1 (even though that's
++                                                                     * not even true on 32bit uid_t
++                                                                     * anyway) */
++                        return false;
++
++                if (dot_or_dot_dot(u)) /* User names typically become home directory names, and these two are
++                                        * special in that context, don't allow that. */
++                        return false;
++
++                /* Compare with strict result and warn if result doesn't match */
++                if (FLAGS_SET(flags, VALID_USER_WARN) && !valid_user_group_name(u, 0))
++                        log_struct(LOG_NOTICE,
++                                   "MESSAGE=Accepting user/group name '%s', which does not match strict user/group name rules.", u,
++                                   "USER_GROUP_NAME=%s", u,
++                                   "MESSAGE_ID=" SD_MESSAGE_UNSAFE_USER_NAME_STR);
++
++                /* Note that we make no restrictions on the length in relaxed mode! */
++        } else {
++                long sz;
++                size_t l;
++
++                /* Also see POSIX IEEE Std 1003.1-2008, 2016 Edition, 3.437. We are a bit stricter here
++                 * however. Specifically we deviate from POSIX rules:
++                 *
++                 * - We don't allow empty user names (see above)
++                 * - We require that names fit into the appropriate utmp field
++                 * - We don't allow any dots (this conflicts with chown syntax which permits dots as user/group name separator)
++                 * - We don't allow dashes or digit as the first character
++                 *
++                 * Note that other systems are even more restrictive, and don't permit underscores or uppercase characters.
++                 */
++
++                if (!(u[0] >= 'a' && u[0] <= 'z') &&
++                    !(u[0] >= 'A' && u[0] <= 'Z') &&
++                    u[0] != '_')
++                        return false;
++
++                for (i = u+1; *i; i++)
++                        if (!(*i >= 'a' && *i <= 'z') &&
++                            !(*i >= 'A' && *i <= 'Z') &&
++                            !(*i >= '0' && *i <= '9') &&
++                            !IN_SET(*i, '_', '-'))
++                                return false;
++
++                l = i - u;
++
++                sz = sysconf(_SC_LOGIN_NAME_MAX);
++                assert_se(sz > 0);
++
++                if (l > (size_t) sz)
++                        return false;
++                if (l > FILENAME_MAX)
++                        return false;
++                if (l > UT_NAMESIZE - 1)
++                        return false;
+         }
+ 
+-        if (only_digits_seen)
+-                return false;
+-
+-        sz = sysconf(_SC_LOGIN_NAME_MAX);
+-        assert_se(sz > 0);
+-
+-        if ((size_t) (i-u) > (size_t) sz)
+-                return false;
+-
+-        if ((size_t) (i-u) > UT_NAMESIZE - 1)
+-                return false;
+-
+         return true;
+ }
+ 
+-bool valid_user_group_name_or_id_full(const char *u, bool strict) {
+-
+-        /* Similar as above, but is also fine with numeric UID/GID specifications, as long as they are in the
+-         * right range, and not the invalid user ids. */
+-
+-        if (isempty(u))
+-                return false;
+-
+-        if (parse_uid(u, NULL) >= 0)
+-                return true;
+-
+-        return valid_user_group_name_full(u, strict);
+-}
+-
+ bool valid_gecos(const char *d) {
+ 
+         if (!d)
+diff --git a/src/basic/user-util.h b/src/basic/user-util.h
+index 5ad0b2a2f9..939bded40d 100644
+--- a/src/basic/user-util.h
++++ b/src/basic/user-util.h
+@@ -78,20 +78,13 @@ static inline bool userns_supported(void) {
+         return access("/proc/self/uid_map", F_OK) >= 0;
+ }
+ 
+-bool valid_user_group_name_full(const char *u, bool strict);
+-bool valid_user_group_name_or_id_full(const char *u, bool strict);
+-static inline bool valid_user_group_name(const char *u) {
+-        return valid_user_group_name_full(u, true);
+-}
+-static inline bool valid_user_group_name_or_id(const char *u) {
+-        return valid_user_group_name_or_id_full(u, true);
+-}
+-static inline bool valid_user_group_name_compat(const char *u) {
+-        return valid_user_group_name_full(u, false);
+-}
+-static inline bool valid_user_group_name_or_id_compat(const char *u) {
+-        return valid_user_group_name_or_id_full(u, false);
+-}
++typedef enum ValidUserFlags {
++        VALID_USER_RELAX         = 1 << 0,
++        VALID_USER_WARN          = 1 << 1,
++        VALID_USER_ALLOW_NUMERIC = 1 << 2,
++} ValidUserFlags;
++
++bool valid_user_group_name(const char *u, ValidUserFlags flags);
+ bool valid_gecos(const char *d);
+ bool valid_home(const char *p);
+ 
+diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
+index e004fb55c9..8348663000 100644
+--- a/src/core/dbus-execute.c
++++ b/src/core/dbus-execute.c
+@@ -1113,10 +1113,10 @@ int bus_exec_context_set_transient_property(
+         flags |= UNIT_PRIVATE;
+ 
+         if (streq(name, "User"))
+-                return bus_set_transient_user_compat(u, name, &c->user, message, flags, error);
++                return bus_set_transient_user_relaxed(u, name, &c->user, message, flags, error);
+ 
+         if (streq(name, "Group"))
+-                return bus_set_transient_user_compat(u, name, &c->group, message, flags, error);
++                return bus_set_transient_user_relaxed(u, name, &c->group, message, flags, error);
+ 
+         if (streq(name, "TTYPath"))
+                 return bus_set_transient_path(u, name, &c->tty_path, message, flags, error);
+@@ -1298,7 +1298,7 @@ int bus_exec_context_set_transient_property(
+                         return r;
+ 
+                 STRV_FOREACH(p, l)
+-                        if (!isempty(*p) && !valid_user_group_name_or_id_compat(*p))
++                        if (!isempty(*p) && !valid_user_group_name(*p, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX|VALID_USER_WARN))
+                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                                          "Invalid supplementary group names");
+ 
+diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
+index 0a1d3df42f..7488f22116 100644
+--- a/src/core/dbus-manager.c
++++ b/src/core/dbus-manager.c
+@@ -1762,7 +1762,7 @@ static int method_lookup_dynamic_user_by_name(sd_bus_message *message, void *use
+ 
+         if (!MANAGER_IS_SYSTEM(m))
+                 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Dynamic users are only supported in the system instance.");
+-        if (!valid_user_group_name(name))
++        if (!valid_user_group_name(name, VALID_USER_RELAX))
+                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User name invalid: %s", name);
+ 
+         r = dynamic_user_lookup_name(m, name, &uid);
+diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c
+index 8fdbc05409..fa6bbe2c6f 100644
+--- a/src/core/dbus-socket.c
++++ b/src/core/dbus-socket.c
+@@ -281,10 +281,10 @@ static int bus_socket_set_transient_property(
+                 return bus_set_transient_fdname(u, name, &s->fdname, message, flags, error);
+ 
+         if (streq(name, "SocketUser"))
+-                return bus_set_transient_user_compat(u, name, &s->user, message, flags, error);
++                return bus_set_transient_user_relaxed(u, name, &s->user, message, flags, error);
+ 
+         if (streq(name, "SocketGroup"))
+-                return bus_set_transient_user_compat(u, name, &s->group, message, flags, error);
++                return bus_set_transient_user_relaxed(u, name, &s->group, message, flags, error);
+ 
+         if (streq(name, "BindIPv6Only"))
+                 return bus_set_transient_bind_ipv6_only(u, name, &s->bind_ipv6_only, message, flags, error);
+diff --git a/src/core/dbus-util.c b/src/core/dbus-util.c
+index 7862beaacb..951450e53d 100644
+--- a/src/core/dbus-util.c
++++ b/src/core/dbus-util.c
+@@ -30,7 +30,12 @@ int bus_property_get_triggered_unit(
+ 
+ BUS_DEFINE_SET_TRANSIENT(mode_t, "u", uint32_t, mode_t, "%040o");
+ BUS_DEFINE_SET_TRANSIENT(unsigned, "u", uint32_t, unsigned, "%" PRIu32);
+-BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(user_compat, valid_user_group_name_or_id_compat);
++
++static inline bool valid_user_group_name_or_id_relaxed(const char *u) {
++        return valid_user_group_name(u, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX);
++}
++
++BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(user_relaxed, valid_user_group_name_or_id_relaxed);
+ BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(path, path_is_absolute);
+ 
+ int bus_set_transient_string(
+diff --git a/src/core/dbus-util.h b/src/core/dbus-util.h
+index a3316c6701..713b464dd9 100644
+--- a/src/core/dbus-util.h
++++ b/src/core/dbus-util.h
+@@ -235,7 +235,7 @@ int bus_property_get_triggered_unit(sd_bus *bus, const char *path, const char *i
+ 
+ int bus_set_transient_mode_t(Unit *u, const char *name, mode_t *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
+ int bus_set_transient_unsigned(Unit *u, const char *name, unsigned *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
+-int bus_set_transient_user_compat(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
++int bus_set_transient_user_relaxed(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
+ int bus_set_transient_path(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
+ int bus_set_transient_string(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
+ int bus_set_transient_bool(Unit *u, const char *name, bool *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
+diff --git a/src/core/dynamic-user.c b/src/core/dynamic-user.c
+index 021fd93a76..548b3cc9df 100644
+--- a/src/core/dynamic-user.c
++++ b/src/core/dynamic-user.c
+@@ -108,7 +108,7 @@ static int dynamic_user_acquire(Manager *m, const char *name, DynamicUser** ret)
+                 return 0;
+         }
+ 
+-        if (!valid_user_group_name_or_id(name))
++        if (!valid_user_group_name(name, VALID_USER_ALLOW_NUMERIC))
+                 return -EINVAL;
+ 
+         if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, storage_socket) < 0)
+diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
+index ba81d94504..e0d7b8f7f8 100644
+--- a/src/core/load-fragment.c
++++ b/src/core/load-fragment.c
+@@ -1932,7 +1932,7 @@ int config_parse_user_group_compat(
+                 return -ENOEXEC;
+         }
+ 
+-        if (!valid_user_group_name_or_id_compat(k)) {
++        if (!valid_user_group_name(k, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX|VALID_USER_WARN)) {
+                 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID: %s", k);
+                 return -ENOEXEC;
+         }
+@@ -1986,7 +1986,7 @@ int config_parse_user_group_strv_compat(
+                         return -ENOEXEC;
+                 }
+ 
+-                if (!valid_user_group_name_or_id_compat(k)) {
++                if (!valid_user_group_name(k, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX|VALID_USER_WARN)) {
+                         log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID: %s", k);
+                         return -ENOEXEC;
+                 }
+diff --git a/src/core/unit.c b/src/core/unit.c
+index ffbf3cfd48..cd3e7c806d 100644
+--- a/src/core/unit.c
++++ b/src/core/unit.c
+@@ -4088,7 +4088,7 @@ static int user_from_unit_name(Unit *u, char **ret) {
+         if (r < 0)
+                 return r;
+ 
+-        if (valid_user_group_name(n)) {
++        if (valid_user_group_name(n, 0)) {
+                 *ret = TAKE_PTR(n);
+                 return 0;
+         }
+diff --git a/src/nss-systemd/nss-systemd.c b/src/nss-systemd/nss-systemd.c
+index f8db27ae27..615c710257 100644
+--- a/src/nss-systemd/nss-systemd.c
++++ b/src/nss-systemd/nss-systemd.c
+@@ -123,7 +123,7 @@ static int direct_lookup_uid(uid_t uid, char **ret) {
+         r = readlink_malloc(path, &s);
+         if (r < 0)
+                 return r;
+-        if (!valid_user_group_name(s)) { /* extra safety check */
++        if (!valid_user_group_name(s, VALID_USER_RELAX)) { /* extra safety check */
+                 free(s);
+                 return -EINVAL;
+         }
+@@ -153,7 +153,7 @@ enum nss_status _nss_systemd_getpwnam_r(
+ 
+         /* If the username is not valid, then we don't know it. Ideally libc would filter these for us anyway. We don't
+          * generate EINVAL here, because it isn't really out business to complain about invalid user names. */
+-        if (!valid_user_group_name(name))
++        if (!valid_user_group_name(name, VALID_USER_RELAX))
+                 return NSS_STATUS_NOTFOUND;
+ 
+         /* Synthesize entries for the root and nobody users, in case they are missing in /etc/passwd */
+@@ -356,7 +356,7 @@ enum nss_status _nss_systemd_getgrnam_r(
+         assert(name);
+         assert(gr);
+ 
+-        if (!valid_user_group_name(name))
++        if (!valid_user_group_name(name, VALID_USER_RELAX))
+                 return NSS_STATUS_NOTFOUND;
+ 
+         /* Synthesize records for root and nobody, in case they are missing form /etc/group */
+diff --git a/src/systemd/sd-messages.h b/src/systemd/sd-messages.h
+index bdd4fd3974..847b698ba4 100644
+--- a/src/systemd/sd-messages.h
++++ b/src/systemd/sd-messages.h
+@@ -152,6 +152,9 @@ _SD_BEGIN_DECLARATIONS;
+ #define SD_MESSAGE_DNSSEC_DOWNGRADE       SD_ID128_MAKE(36,db,2d,fa,5a,90,45,e1,bd,4a,f5,f9,3e,1c,f0,57)
+ #define SD_MESSAGE_DNSSEC_DOWNGRADE_STR   SD_ID128_MAKE_STR(36,db,2d,fa,5a,90,45,e1,bd,4a,f5,f9,3e,1c,f0,57)
+ 
++#define SD_MESSAGE_UNSAFE_USER_NAME       SD_ID128_MAKE(b6,1f,da,c6,12,e9,4b,91,82,28,5b,99,88,43,06,1f)
++#define SD_MESSAGE_UNSAFE_USER_NAME_STR   SD_ID128_MAKE_STR(b6,1f,da,c6,12,e9,4b,91,82,28,5b,99,88,43,06,1f)
++
+ _SD_END_DECLARATIONS;
+ 
+ #endif
+diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c
+index 33959d3c11..a374ebaaf4 100644
+--- a/src/sysusers/sysusers.c
++++ b/src/sysusers/sysusers.c
+@@ -1413,7 +1413,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
+                         return r;
+                 }
+ 
+-                if (!valid_user_group_name(resolved_name)) {
++                if (!valid_user_group_name(resolved_name, 0)) {
+                         log_error("[%s:%u] '%s' is not a valid user or group name.", fname, line, resolved_name);
+                         return -EINVAL;
+                 }
+@@ -1524,7 +1524,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
+                         return -EINVAL;
+                 }
+ 
+-                if (!valid_user_group_name(resolved_id)) {
++                if (!valid_user_group_name(resolved_id, 0)) {
+                         log_error("[%s:%u] '%s' is not a valid user or group name.", fname, line, resolved_id);
+                         return -EINVAL;
+                 }
+diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c
+index 56079f1486..31ac018da9 100644
+--- a/src/test/test-user-util.c
++++ b/src/test/test-user-util.c
+@@ -131,144 +131,163 @@ static void test_uid_ptr(void) {
+         assert_se(PTR_TO_UID(UID_TO_PTR(1000)) == 1000);
+ }
+ 
+-static void test_valid_user_group_name_compat(void) {
++static void test_valid_user_group_name_relaxed(void) {
+         log_info("/* %s */", __func__);
+ 
+-        assert_se(!valid_user_group_name_compat(NULL));
+-        assert_se(!valid_user_group_name_compat(""));
+-        assert_se(!valid_user_group_name_compat("1"));
+-        assert_se(!valid_user_group_name_compat("65535"));
+-        assert_se(!valid_user_group_name_compat("-1"));
+-        assert_se(!valid_user_group_name_compat("-kkk"));
+-        assert_se(!valid_user_group_name_compat("rööt"));
+-        assert_se(!valid_user_group_name_compat("."));
+-        assert_se(!valid_user_group_name_compat(".eff"));
+-        assert_se(!valid_user_group_name_compat("foo\nbar"));
+-        assert_se(!valid_user_group_name_compat("0123456789012345678901234567890123456789"));
+-        assert_se(!valid_user_group_name_or_id_compat("aaa:bbb"));
+-        assert_se(!valid_user_group_name_compat("."));
+-        assert_se(!valid_user_group_name_compat(".1"));
+-        assert_se(!valid_user_group_name_compat(".65535"));
+-        assert_se(!valid_user_group_name_compat(".-1"));
+-        assert_se(!valid_user_group_name_compat(".-kkk"));
+-        assert_se(!valid_user_group_name_compat(".rööt"));
+-        assert_se(!valid_user_group_name_or_id_compat(".aaa:bbb"));
+-
+-        assert_se(valid_user_group_name_compat("root"));
+-        assert_se(valid_user_group_name_compat("lennart"));
+-        assert_se(valid_user_group_name_compat("LENNART"));
+-        assert_se(valid_user_group_name_compat("_kkk"));
+-        assert_se(valid_user_group_name_compat("kkk-"));
+-        assert_se(valid_user_group_name_compat("kk-k"));
+-        assert_se(valid_user_group_name_compat("eff.eff"));
+-        assert_se(valid_user_group_name_compat("eff."));
+-
+-        assert_se(valid_user_group_name_compat("some5"));
+-        assert_se(valid_user_group_name_compat("5some"));
+-        assert_se(valid_user_group_name_compat("INNER5NUMBER"));
++        assert_se(!valid_user_group_name(NULL, VALID_USER_RELAX));
++        assert_se(!valid_user_group_name("", VALID_USER_RELAX));
++        assert_se(!valid_user_group_name("1", VALID_USER_RELAX));
++        assert_se(!valid_user_group_name("65535", VALID_USER_RELAX));
++        assert_se(!valid_user_group_name("-1", VALID_USER_RELAX));
++        assert_se(!valid_user_group_name("foo\nbar", VALID_USER_RELAX));
++        assert_se(!valid_user_group_name("0123456789012345678901234567890123456789", VALID_USER_RELAX));
++        assert_se(!valid_user_group_name("aaa:bbb", VALID_USER_RELAX|VALID_USER_ALLOW_NUMERIC));
++        assert_se(!valid_user_group_name(".aaa:bbb", VALID_USER_RELAX|VALID_USER_ALLOW_NUMERIC));
++        assert_se(!valid_user_group_name(".", VALID_USER_RELAX));
++        assert_se(!valid_user_group_name("..", VALID_USER_RELAX));
++
++        assert_se(valid_user_group_name("root", VALID_USER_RELAX));
++        assert_se(valid_user_group_name("lennart", VALID_USER_RELAX));
++        assert_se(valid_user_group_name("LENNART", VALID_USER_RELAX));
++        assert_se(valid_user_group_name("_kkk", VALID_USER_RELAX));
++        assert_se(valid_user_group_name("kkk-", VALID_USER_RELAX));
++        assert_se(valid_user_group_name("kk-k", VALID_USER_RELAX));
++        assert_se(valid_user_group_name("eff.eff", VALID_USER_RELAX));
++        assert_se(valid_user_group_name("eff.", VALID_USER_RELAX));
++        assert_se(valid_user_group_name("-kkk", VALID_USER_RELAX));
++        assert_se(valid_user_group_name("rööt", VALID_USER_RELAX));
++        assert_se(valid_user_group_name(".eff", VALID_USER_RELAX));
++        assert_se(valid_user_group_name(".1", VALID_USER_RELAX));
++        assert_se(valid_user_group_name(".65535", VALID_USER_RELAX));
++        assert_se(valid_user_group_name(".-1", VALID_USER_RELAX));
++        assert_se(valid_user_group_name(".-kkk", VALID_USER_RELAX));
++        assert_se(valid_user_group_name(".rööt", VALID_USER_RELAX));
++        assert_se(valid_user_group_name("...", VALID_USER_RELAX));
++
++        assert_se(valid_user_group_name("some5", VALID_USER_RELAX));
++        assert_se(valid_user_group_name("5some", VALID_USER_RELAX));
++        assert_se(valid_user_group_name("INNER5NUMBER", VALID_USER_RELAX));
++
++        assert_se(valid_user_group_name("piff.paff@ad.domain.example", VALID_USER_RELAX));
++        assert_se(valid_user_group_name("Dāvis", VALID_USER_RELAX));
+ }
+ 
+ static void test_valid_user_group_name(void) {
+         log_info("/* %s */", __func__);
+ 
+-        assert_se(!valid_user_group_name(NULL));
+-        assert_se(!valid_user_group_name(""));
+-        assert_se(!valid_user_group_name("1"));
+-        assert_se(!valid_user_group_name("65535"));
+-        assert_se(!valid_user_group_name("-1"));
+-        assert_se(!valid_user_group_name("-kkk"));
+-        assert_se(!valid_user_group_name("rööt"));
+-        assert_se(!valid_user_group_name("."));
+-        assert_se(!valid_user_group_name(".eff"));
+-        assert_se(!valid_user_group_name("foo\nbar"));
+-        assert_se(!valid_user_group_name("0123456789012345678901234567890123456789"));
+-        assert_se(!valid_user_group_name_or_id("aaa:bbb"));
+-        assert_se(!valid_user_group_name("."));
+-        assert_se(!valid_user_group_name(".1"));
+-        assert_se(!valid_user_group_name(".65535"));
+-        assert_se(!valid_user_group_name(".-1"));
+-        assert_se(!valid_user_group_name(".-kkk"));
+-        assert_se(!valid_user_group_name(".rööt"));
+-        assert_se(!valid_user_group_name_or_id(".aaa:bbb"));
+-
+-        assert_se(valid_user_group_name("root"));
+-        assert_se(valid_user_group_name("lennart"));
+-        assert_se(valid_user_group_name("LENNART"));
+-        assert_se(valid_user_group_name("_kkk"));
+-        assert_se(valid_user_group_name("kkk-"));
+-        assert_se(valid_user_group_name("kk-k"));
+-        assert_se(!valid_user_group_name("eff.eff"));
+-        assert_se(!valid_user_group_name("eff."));
+-
+-        assert_se(valid_user_group_name("some5"));
+-        assert_se(!valid_user_group_name("5some"));
+-        assert_se(valid_user_group_name("INNER5NUMBER"));
++        assert_se(!valid_user_group_name(NULL, 0));
++        assert_se(!valid_user_group_name("", 0));
++        assert_se(!valid_user_group_name("1", 0));
++        assert_se(!valid_user_group_name("65535", 0));
++        assert_se(!valid_user_group_name("-1", 0));
++        assert_se(!valid_user_group_name("-kkk", 0));
++        assert_se(!valid_user_group_name("rööt", 0));
++        assert_se(!valid_user_group_name(".", 0));
++        assert_se(!valid_user_group_name(".eff", 0));
++        assert_se(!valid_user_group_name("foo\nbar", 0));
++        assert_se(!valid_user_group_name("0123456789012345678901234567890123456789", 0));
++        assert_se(!valid_user_group_name("aaa:bbb", VALID_USER_ALLOW_NUMERIC));
++        assert_se(!valid_user_group_name(".", 0));
++        assert_se(!valid_user_group_name("..", 0));
++        assert_se(!valid_user_group_name("...", 0));
++        assert_se(!valid_user_group_name(".1", 0));
++        assert_se(!valid_user_group_name(".65535", 0));
++        assert_se(!valid_user_group_name(".-1", 0));
++        assert_se(!valid_user_group_name(".-kkk", 0));
++        assert_se(!valid_user_group_name(".rööt", 0));
++        assert_se(!valid_user_group_name(".aaa:bbb", VALID_USER_ALLOW_NUMERIC));
++
++        assert_se(valid_user_group_name("root", 0));
++        assert_se(valid_user_group_name("lennart", 0));
++        assert_se(valid_user_group_name("LENNART", 0));
++        assert_se(valid_user_group_name("_kkk", 0));
++        assert_se(valid_user_group_name("kkk-", 0));
++        assert_se(valid_user_group_name("kk-k", 0));
++        assert_se(!valid_user_group_name("eff.eff", 0));
++        assert_se(!valid_user_group_name("eff.", 0));
++
++        assert_se(valid_user_group_name("some5", 0));
++        assert_se(!valid_user_group_name("5some", 0));
++        assert_se(valid_user_group_name("INNER5NUMBER", 0));
++
++        assert_se(!valid_user_group_name("piff.paff@ad.domain.example", 0));
++        assert_se(!valid_user_group_name("Dāvis", 0));
+ }
+ 
+-static void test_valid_user_group_name_or_id_compat(void) {
++static void test_valid_user_group_name_or_numeric_relaxed(void) {
+         log_info("/* %s */", __func__);
+ 
+-        assert_se(!valid_user_group_name_or_id_compat(NULL));
+-        assert_se(!valid_user_group_name_or_id_compat(""));
+-        assert_se(valid_user_group_name_or_id_compat("0"));
+-        assert_se(valid_user_group_name_or_id_compat("1"));
+-        assert_se(valid_user_group_name_or_id_compat("65534"));
+-        assert_se(!valid_user_group_name_or_id_compat("65535"));
+-        assert_se(valid_user_group_name_or_id_compat("65536"));
+-        assert_se(!valid_user_group_name_or_id_compat("-1"));
+-        assert_se(!valid_user_group_name_or_id_compat("-kkk"));
+-        assert_se(!valid_user_group_name_or_id_compat("rööt"));
+-        assert_se(!valid_user_group_name_or_id_compat("."));
+-        assert_se(!valid_user_group_name_or_id_compat(".eff"));
+-        assert_se(valid_user_group_name_or_id_compat("eff.eff"));
+-        assert_se(valid_user_group_name_or_id_compat("eff."));
+-        assert_se(!valid_user_group_name_or_id_compat("foo\nbar"));
+-        assert_se(!valid_user_group_name_or_id_compat("0123456789012345678901234567890123456789"));
+-        assert_se(!valid_user_group_name_or_id_compat("aaa:bbb"));
+-
+-        assert_se(valid_user_group_name_or_id_compat("root"));
+-        assert_se(valid_user_group_name_or_id_compat("lennart"));
+-        assert_se(valid_user_group_name_or_id_compat("LENNART"));
+-        assert_se(valid_user_group_name_or_id_compat("_kkk"));
+-        assert_se(valid_user_group_name_or_id_compat("kkk-"));
+-        assert_se(valid_user_group_name_or_id_compat("kk-k"));
+-
+-        assert_se(valid_user_group_name_or_id_compat("some5"));
+-        assert_se(valid_user_group_name_or_id_compat("5some"));
+-        assert_se(valid_user_group_name_or_id_compat("INNER5NUMBER"));
++        assert_se(!valid_user_group_name(NULL, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++        assert_se(!valid_user_group_name("", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++        assert_se(valid_user_group_name("0", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++        assert_se(valid_user_group_name("1", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++        assert_se(valid_user_group_name("65534", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++        assert_se(!valid_user_group_name("65535", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++        assert_se(valid_user_group_name("65536", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++        assert_se(!valid_user_group_name("-1", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++        assert_se(!valid_user_group_name("foo\nbar", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++        assert_se(!valid_user_group_name("0123456789012345678901234567890123456789", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++        assert_se(!valid_user_group_name("aaa:bbb", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++        assert_se(!valid_user_group_name(".", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++        assert_se(!valid_user_group_name("..", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++
++        assert_se(valid_user_group_name("root", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++        assert_se(valid_user_group_name("lennart", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++        assert_se(valid_user_group_name("LENNART", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++        assert_se(valid_user_group_name("_kkk", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++        assert_se(valid_user_group_name("kkk-", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++        assert_se(valid_user_group_name("kk-k", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++        assert_se(valid_user_group_name("-kkk", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++        assert_se(valid_user_group_name("rööt", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++        assert_se(valid_user_group_name(".eff", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++        assert_se(valid_user_group_name("eff.eff", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++        assert_se(valid_user_group_name("eff.", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++        assert_se(valid_user_group_name("...", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++
++        assert_se(valid_user_group_name("some5", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++        assert_se(valid_user_group_name("5some", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++        assert_se(valid_user_group_name("INNER5NUMBER", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++
++        assert_se(valid_user_group_name("piff.paff@ad.domain.example", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
++        assert_se(valid_user_group_name("Dāvis", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ }
+ 
+-static void test_valid_user_group_name_or_id(void) {
++static void test_valid_user_group_name_or_numeric(void) {
+         log_info("/* %s */", __func__);
+ 
+-        assert_se(!valid_user_group_name_or_id(NULL));
+-        assert_se(!valid_user_group_name_or_id(""));
+-        assert_se(valid_user_group_name_or_id("0"));
+-        assert_se(valid_user_group_name_or_id("1"));
+-        assert_se(valid_user_group_name_or_id("65534"));
+-        assert_se(!valid_user_group_name_or_id("65535"));
+-        assert_se(valid_user_group_name_or_id("65536"));
+-        assert_se(!valid_user_group_name_or_id("-1"));
+-        assert_se(!valid_user_group_name_or_id("-kkk"));
+-        assert_se(!valid_user_group_name_or_id("rööt"));
+-        assert_se(!valid_user_group_name_or_id("."));
+-        assert_se(!valid_user_group_name_or_id(".eff"));
+-        assert_se(!valid_user_group_name_or_id("eff.eff"));
+-        assert_se(!valid_user_group_name_or_id("eff."));
+-        assert_se(!valid_user_group_name_or_id("foo\nbar"));
+-        assert_se(!valid_user_group_name_or_id("0123456789012345678901234567890123456789"));
+-        assert_se(!valid_user_group_name_or_id("aaa:bbb"));
+-
+-        assert_se(valid_user_group_name_or_id("root"));
+-        assert_se(valid_user_group_name_or_id("lennart"));
+-        assert_se(valid_user_group_name_or_id("LENNART"));
+-        assert_se(valid_user_group_name_or_id("_kkk"));
+-        assert_se(valid_user_group_name_or_id("kkk-"));
+-        assert_se(valid_user_group_name_or_id("kk-k"));
+-
+-        assert_se(valid_user_group_name_or_id("some5"));
+-        assert_se(!valid_user_group_name_or_id("5some"));
+-        assert_se(valid_user_group_name_or_id("INNER5NUMBER"));
++        assert_se(!valid_user_group_name(NULL, VALID_USER_ALLOW_NUMERIC));
++        assert_se(!valid_user_group_name("", VALID_USER_ALLOW_NUMERIC));
++        assert_se(valid_user_group_name("0", VALID_USER_ALLOW_NUMERIC));
++        assert_se(valid_user_group_name("1", VALID_USER_ALLOW_NUMERIC));
++        assert_se(valid_user_group_name("65534", VALID_USER_ALLOW_NUMERIC));
++        assert_se(!valid_user_group_name("65535", VALID_USER_ALLOW_NUMERIC));
++        assert_se(valid_user_group_name("65536", VALID_USER_ALLOW_NUMERIC));
++        assert_se(!valid_user_group_name("-1", VALID_USER_ALLOW_NUMERIC));
++        assert_se(!valid_user_group_name("-kkk", VALID_USER_ALLOW_NUMERIC));
++        assert_se(!valid_user_group_name("rööt", VALID_USER_ALLOW_NUMERIC));
++        assert_se(!valid_user_group_name(".", VALID_USER_ALLOW_NUMERIC));
++        assert_se(!valid_user_group_name("..", VALID_USER_ALLOW_NUMERIC));
++        assert_se(!valid_user_group_name("...", VALID_USER_ALLOW_NUMERIC));
++        assert_se(!valid_user_group_name(".eff", VALID_USER_ALLOW_NUMERIC));
++        assert_se(!valid_user_group_name("eff.eff", VALID_USER_ALLOW_NUMERIC));
++        assert_se(!valid_user_group_name("eff.", VALID_USER_ALLOW_NUMERIC));
++        assert_se(!valid_user_group_name("foo\nbar", VALID_USER_ALLOW_NUMERIC));
++        assert_se(!valid_user_group_name("0123456789012345678901234567890123456789", VALID_USER_ALLOW_NUMERIC));
++        assert_se(!valid_user_group_name("aaa:bbb", VALID_USER_ALLOW_NUMERIC));
++
++        assert_se(valid_user_group_name("root", VALID_USER_ALLOW_NUMERIC));
++        assert_se(valid_user_group_name("lennart", VALID_USER_ALLOW_NUMERIC));
++        assert_se(valid_user_group_name("LENNART", VALID_USER_ALLOW_NUMERIC));
++        assert_se(valid_user_group_name("_kkk", VALID_USER_ALLOW_NUMERIC));
++        assert_se(valid_user_group_name("kkk-", VALID_USER_ALLOW_NUMERIC));
++        assert_se(valid_user_group_name("kk-k", VALID_USER_ALLOW_NUMERIC));
++
++        assert_se(valid_user_group_name("some5", VALID_USER_ALLOW_NUMERIC));
++        assert_se(!valid_user_group_name("5some", VALID_USER_ALLOW_NUMERIC));
++        assert_se(valid_user_group_name("INNER5NUMBER", VALID_USER_ALLOW_NUMERIC));
++
++        assert_se(!valid_user_group_name("piff.paff@ad.domain.example", VALID_USER_ALLOW_NUMERIC));
++        assert_se(!valid_user_group_name("Dāvis", VALID_USER_ALLOW_NUMERIC));
+ }
+ 
+ static void test_valid_gecos(void) {
+@@ -367,10 +386,10 @@ int main(int argc, char*argv[]) {
+         test_parse_uid();
+         test_uid_ptr();
+ 
+-        test_valid_user_group_name_compat();
++        test_valid_user_group_name_relaxed();
+         test_valid_user_group_name();
+-        test_valid_user_group_name_or_id_compat();
+-        test_valid_user_group_name_or_id();
++        test_valid_user_group_name_or_numeric_relaxed();
++        test_valid_user_group_name_or_numeric();
+         test_valid_gecos();
+         test_valid_home();
+ 
diff --git a/SPECS/systemd.spec b/SPECS/systemd.spec
index a8be922..5147231 100644
--- a/SPECS/systemd.spec
+++ b/SPECS/systemd.spec
@@ -13,7 +13,7 @@
 Name:           systemd
 Url:            http://www.freedesktop.org/wiki/Software/systemd
 Version:        239
-Release:        40%{?dist}
+Release:        42%{?dist}
 # For a breakdown of the licensing, see README
 License:        LGPLv2+ and MIT and GPLv2+
 Summary:        System and Service Manager
@@ -484,6 +484,46 @@ Patch0431: 0431-device-don-t-emit-PropetiesChanged-needlessly.patch
 Patch0432: 0432-units-add-generic-boot-complete.target.patch
 Patch0433: 0433-man-document-new-boot-complete.target-unit.patch
 Patch0434: 0434-core-make-sure-to-restore-the-control-command-id-too.patch
+Patch0435: 0435-cgroup-freezer-action-must-be-NOP-when-cgroup-v2-fre.patch
+Patch0436: 0436-logind-don-t-print-warning-when-user-.service-templa.patch
+Patch0437: 0437-build-use-simple-project-version-in-pkgconfig-files.patch
+Patch0438: 0438-basic-virt-try-the-proc-1-sched-hack-also-for-PID1.patch
+Patch0439: 0439-seccomp-rework-how-the-S-UG-ID-filter-is-installed.patch
+Patch0440: 0440-vconsole-setup-downgrade-log-message-when-setting-fo.patch
+Patch0441: 0441-units-fix-systemd.special-man-page-reference-in-syst.patch
+Patch0442: 0442-units-drop-reference-to-sushell-man-page.patch
+Patch0443: 0443-sd-bus-break-the-loop-in-bus_ensure_running-if-the-b.patch
+Patch0444: 0444-core-add-new-API-for-enqueing-a-job-with-returning-t.patch
+Patch0445: 0445-systemctl-replace-switch-statement-by-table-of-struc.patch
+Patch0446: 0446-systemctl-reindent-table.patch
+Patch0447: 0447-systemctl-Only-wait-when-there-s-something-to-wait-f.patch
+Patch0448: 0448-systemctl-clean-up-start_unit_one-error-handling.patch
+Patch0449: 0449-systemctl-split-out-extra-args-generation-into-helpe.patch
+Patch0450: 0450-systemctl-add-new-show-transaction-switch.patch
+Patch0451: 0451-test-add-some-basic-testing-that-systemctl-start-T-d.patch
+Patch0452: 0452-man-document-the-new-systemctl-show-transaction-opti.patch
+Patch0453: 0453-socket-New-option-FlushPending-boolean-to-flush-sock.patch
+Patch0454: 0454-core-remove-support-for-API-bus-started-outside-our-.patch
+Patch0455: 0455-mount-setup-fix-segfault-in-mount_cgroup_controllers.patch
+Patch0456: 0456-dbus-execute-make-transfer-of-CPUAffinity-endian-saf.patch
+Patch0457: 0457-core-add-support-for-setting-CPUAffinity-to-special-.patch
+Patch0458: 0458-basic-user-util-always-use-base-10-for-user-group-nu.patch
+Patch0459: 0459-parse-util-sometimes-it-is-useful-to-check-if-a-stri.patch
+Patch0460: 0460-basic-parse-util-add-safe_atoux64.patch
+Patch0461: 0461-parse-util-allow-tweaking-how-to-parse-integers.patch
+Patch0462: 0462-parse-util-allow-0-as-alternative-to-0-and-0.patch
+Patch0463: 0463-parse-util-make-return-parameter-optional-in-safe_at.patch
+Patch0464: 0464-parse-util-rewrite-parse_mode-on-top-of-safe_atou_fu.patch
+Patch0465: 0465-user-util-be-stricter-in-parse_uid.patch
+Patch0466: 0466-strv-add-new-macro-STARTSWITH_SET.patch
+Patch0467: 0467-parse-util-also-parse-integers-prefixed-with-0b-and-.patch
+Patch0468: 0468-tests-beef-up-integer-parsing-tests.patch
+Patch0469: 0469-shared-user-util-add-compat-forms-of-user-name-check.patch
+Patch0470: 0470-shared-user-util-emit-a-warning-on-names-with-dots.patch
+Patch0471: 0471-user-util-Allow-names-starting-with-a-digit.patch
+Patch0472: 0472-shared-user-util-allow-usernames-with-dots-in-specif.patch
+Patch0473: 0473-user-util-switch-order-of-checks-in-valid_user_group.patch
+Patch0474: 0474-user-util-rework-how-we-validate-user-names.patch
 
 
 %ifarch %{ix86} x86_64 aarch64
@@ -1112,6 +1152,50 @@ fi
 %files tests -f .file-list-tests
 
 %changelog
+* Tue Nov 03 2020 systemd maintenance team <systemd-maint@redhat.com> - 239-42
+- logind: don't print warning when user@.service template is masked (#1880270)
+- build: use simple project version in pkgconfig files (#1862714)
+- basic/virt: try the /proc/1/sched hack also for PID1 (#1868877)
+- seccomp: rework how the S[UG]ID filter is installed (#1860374)
+- vconsole-setup: downgrade log message when setting font fails on dummy console (#1889996)
+- units: fix systemd.special man page reference in system-update-cleanup.service (#1871827)
+- units: drop reference to sushell man page (#1871827)
+- sd-bus: break the loop in bus_ensure_running() if the bus is not connecting (#1885553)
+- core: add new API for enqueing a job with returning the transaction data (#846319)
+- systemctl: replace switch statement by table of structures (#846319)
+- systemctl: reindent table (#846319)
+- systemctl: Only wait when there's something to wait for. (#846319)
+- systemctl: clean up start_unit_one() error handling (#846319)
+- systemctl: split out extra args generation into helper function of its own (#846319)
+- systemctl: add new --show-transaction switch (#846319)
+- test: add some basic testing that "systemctl start -T" does something (#846319)
+- man: document the new systemctl --show-transaction option (#846319)
+- socket: New option 'FlushPending' (boolean) to flush socket before entering listening state (#1870638)
+- core: remove support for API bus "started outside our own logic" (#1764282)
+- mount-setup: fix segfault in mount_cgroup_controllers when using gcc9 compiler (#1868877)
+- dbus-execute: make transfer of CPUAffinity endian safe (#12711) (#1740657)
+- core: add support for setting CPUAffinity= to special "numa" value (#1740657)
+- basic/user-util: always use base 10 for user/group numbers (#1848373)
+- parse-util: sometimes it is useful to check if a string is a valid integer, but not actually parse it (#1848373)
+- basic/parse-util: add safe_atoux64() (#1848373)
+- parse-util: allow tweaking how to parse integers (#1848373)
+- parse-util: allow '-0' as alternative to '0' and '+0' (#1848373)
+- parse-util: make return parameter optional in safe_atou16_full() (#1848373)
+- parse-util: rewrite parse_mode() on top of safe_atou_full() (#1848373)
+- user-util: be stricter in parse_uid() (#1848373)
+- strv: add new macro STARTSWITH_SET() (#1848373)
+- parse-util: also parse integers prefixed with 0b and 0o (#1848373)
+- tests: beef up integer parsing tests (#1848373)
+- shared/user-util: add compat forms of user name checking functions (#1848373)
+- shared/user-util: emit a warning on names with dots (#1848373)
+- user-util: Allow names starting with a digit (#1848373)
+- shared/user-util: allow usernames with dots in specific fields (#1848373)
+- user-util: switch order of checks in valid_user_group_name_or_id_full() (#1848373)
+- user-util: rework how we validate user names (#1848373)
+
+* Wed Oct 07 2020 systemd maintenance team <systemd-maint@redhat.com> - 239-41
+- cgroup: freezer action must be NOP when cgroup v2 freezer is not available (#1868831)
+
 * Fri Aug 28 2020 systemd maintenance team <systemd-maint@redhat.com> - 239-40
 - units: add generic boot-complete.target (#1872243)
 - man: document new "boot-complete.target" unit (#1872243)