diff --git a/.gitignore b/.gitignore
index c7cdfa3..c2407cd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-SOURCES/systemd-219.tar.xz
+SOURCES/systemd-219.tar.gz
diff --git a/.systemd.metadata b/.systemd.metadata
index 188314b..5bfe07e 100644
--- a/.systemd.metadata
+++ b/.systemd.metadata
@@ -1 +1 @@
-307d1c3e48b3bca1039cb66df2d7def074efe2ef SOURCES/systemd-219.tar.xz
+7568c7d785970e7b5a5872ab69570dddd6a2312e SOURCES/systemd-219.tar.gz
diff --git a/SOURCES/0408-If-the-notification-message-length-is-0-ignore-the-m.patch b/SOURCES/0408-If-the-notification-message-length-is-0-ignore-the-m.patch
index 5d58940..570e7e5 100644
--- a/SOURCES/0408-If-the-notification-message-length-is-0-ignore-the-m.patch
+++ b/SOURCES/0408-If-the-notification-message-length-is-0-ignore-the-m.patch
@@ -1,4 +1,4 @@
-From 3ee0d3abc55571bdc13f1897688443a1538db367 Mon Sep 17 00:00:00 2001
+From cd238111a7980917e04cfdc5dae144d1fb4c0a49 Mon Sep 17 00:00:00 2001
 From: Jorge Niedbalski <jorge.niedbalski@canonical.com>
 Date: Wed, 28 Sep 2016 18:25:50 -0300
 Subject: [PATCH] If the notification message length is 0, ignore the message
@@ -9,7 +9,7 @@ Fixes #4234.
 Signed-off-by: Jorge Niedbalski <jnr@metaklass.org>
 
 Cherry-picked from: 531ac2b2349da02acc9c382849758e07eb92b020
-Resolves: #1381573
+Resolves: #1380175
 ---
  src/core/manager.c | 4 ++++
  1 file changed, 4 insertions(+)
diff --git a/SOURCES/0409-systemctl-suppress-errors-with-show-for-nonexistent-.patch b/SOURCES/0409-systemctl-suppress-errors-with-show-for-nonexistent-.patch
index 2cc6250..ef419ce 100644
--- a/SOURCES/0409-systemctl-suppress-errors-with-show-for-nonexistent-.patch
+++ b/SOURCES/0409-systemctl-suppress-errors-with-show-for-nonexistent-.patch
@@ -1,4 +1,4 @@
-From aa23eb11cab247e713a19957eaaa80f7b5454ddc Mon Sep 17 00:00:00 2001
+From 6d590cc99d696e9b0bf5b6edf7582b824f5177ab Mon Sep 17 00:00:00 2001
 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
 Date: Sat, 24 Sep 2016 20:58:04 -0400
 Subject: [PATCH] systemctl: suppress errors with "show" for nonexistent units
@@ -20,7 +20,7 @@ We might consider adding an explicit switch to fail on missing units/properties
 --ensure-exists --property=foobar.
 
 Cherry-picked from: bd5b9f0a12dd9c1947b11534e99c395ddf44caa9
-Resolves: #1380686
+Resolves: #1380259
 ---
  src/systemctl/systemctl.c | 9 ++++++---
  1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/SOURCES/0410-40-redhat.rules-disable-auto-online-of-hot-plugged-m.patch b/SOURCES/0410-40-redhat.rules-disable-auto-online-of-hot-plugged-m.patch
index 54f4ad7..91508f2 100644
--- a/SOURCES/0410-40-redhat.rules-disable-auto-online-of-hot-plugged-m.patch
+++ b/SOURCES/0410-40-redhat.rules-disable-auto-online-of-hot-plugged-m.patch
@@ -1,10 +1,10 @@
-From 48e2af5667e67a7a7f58eb17aaf5349379b2484a Mon Sep 17 00:00:00 2001
+From 2cd738ce220e0dd11d3b19cf593e159a7e31ddc4 Mon Sep 17 00:00:00 2001
 From: Michal Sekletar <msekleta@redhat.com>
 Date: Fri, 16 Sep 2016 14:45:01 +0200
 Subject: [PATCH] 40-redhat.rules: disable auto-online of hot-plugged memory on
  IBM z Systems
 
-Resolves: #1381123
+Related: #1375603
 ---
  rules/40-redhat.rules | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/SOURCES/0411-pid1-don-t-return-any-error-in-manager_dispatch_noti.patch b/SOURCES/0411-pid1-don-t-return-any-error-in-manager_dispatch_noti.patch
index 4508403..fae1ff4 100644
--- a/SOURCES/0411-pid1-don-t-return-any-error-in-manager_dispatch_noti.patch
+++ b/SOURCES/0411-pid1-don-t-return-any-error-in-manager_dispatch_noti.patch
@@ -1,4 +1,4 @@
-From 7b00eff77b5606ff5563e374020d554a40bca833 Mon Sep 17 00:00:00 2001
+From 93c5087eed9abf8012dc5b0ccd2dd7ead1323899 Mon Sep 17 00:00:00 2001
 From: Franck Bui <fbui@suse.com>
 Date: Thu, 29 Sep 2016 19:44:34 +0200
 Subject: [PATCH] pid1: don't return any error in manager_dispatch_notify_fd()
@@ -10,7 +10,7 @@ service notifications will be disabled entirely leading to a compromised system.
 For example pid1 won't be able to receive the WATCHDOG messages anymore and
 will kill all services supposed to send such messages.
 Cherry-picked from: 9987750e7a4c62e0eb8473603150596ba7c3a015
-Resolves: #1381573
+Resolves: #1380259
 ---
  src/core/manager.c | 13 +++++++++----
  1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/SOURCES/0412-pid1-process-zero-length-notification-messages-again.patch b/SOURCES/0412-pid1-process-zero-length-notification-messages-again.patch
index 663ca63..6c592ed 100644
--- a/SOURCES/0412-pid1-process-zero-length-notification-messages-again.patch
+++ b/SOURCES/0412-pid1-process-zero-length-notification-messages-again.patch
@@ -1,4 +1,4 @@
-From 79e0852a6a3f20cba92ac18aa6ac61d24d04d3c7 Mon Sep 17 00:00:00 2001
+From c7bcd6cf1967e401225c3d6057e0ee62cdc29f8c Mon Sep 17 00:00:00 2001
 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
 Date: Thu, 29 Sep 2016 16:06:02 +0200
 Subject: [PATCH] pid1: process zero-length notification messages again
@@ -9,8 +9,11 @@ carefully enough. There are two problems:
 - in principle empty notification messages are valid, and we should
   process them as usual, including logging using log_unit_debug().
 
+Cherry-picked from: 8523bf7dd514a3a2c6114b7b8fb8f308b4f09fc4
+Resolves: #1380259
+
 Cherry-picked from: a86b767
-Resolves: #1381573
+Resolves: #1380259
 ---
  src/core/manager.c | 15 ++++++---------
  1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/SOURCES/0413-pid1-more-informative-error-message-for-ignored-noti.patch b/SOURCES/0413-pid1-more-informative-error-message-for-ignored-noti.patch
index f273805..8e4c381 100644
--- a/SOURCES/0413-pid1-more-informative-error-message-for-ignored-noti.patch
+++ b/SOURCES/0413-pid1-more-informative-error-message-for-ignored-noti.patch
@@ -1,4 +1,4 @@
-From 339ce6209591d0c6b240f6d94c1d2997405352a2 Mon Sep 17 00:00:00 2001
+From f441ddae6363a10b1e8d8764bc906866f6ee6f48 Mon Sep 17 00:00:00 2001
 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
 Date: Thu, 29 Sep 2016 16:07:41 +0200
 Subject: [PATCH] pid1: more informative error message for ignored
@@ -11,7 +11,7 @@ contents are printed. But still, do anything only if debugging is on.
 	src/core/manager.c
 
 Cherry-picked from: a86b76753d7868c2d05f046f601bc7dc89fc2203
-Resolves: #1381573
+Resolves: #1380259
 ---
  src/core/manager.c | 8 ++++++++
  1 file changed, 8 insertions(+)
diff --git a/SOURCES/0414-manager-219-needs-u-id-in-log_unit_debug.patch b/SOURCES/0414-manager-219-needs-u-id-in-log_unit_debug.patch
index 21c7e48..5bee81c 100644
--- a/SOURCES/0414-manager-219-needs-u-id-in-log_unit_debug.patch
+++ b/SOURCES/0414-manager-219-needs-u-id-in-log_unit_debug.patch
@@ -1,10 +1,10 @@
-From f5bf6f4c0d1857ce3c8a68e862e29ab7fb6684ee Mon Sep 17 00:00:00 2001
+From 7dbaab7b61fb25d91178f097cf7474d855d0ae29 Mon Sep 17 00:00:00 2001
 From: Lukas Nykryn <lnykryn@redhat.com>
 Date: Fri, 7 Oct 2016 14:05:40 +0200
 Subject: [PATCH] manager: 219 needs u->id in log_unit_debug
 
 RHEL-only
-Related: #1381573
+Related: #1380259
 ---
  src/core/manager.c | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/SOURCES/0415-mtd_probe-add-include-for-stdint.patch b/SOURCES/0415-mtd_probe-add-include-for-stdint.patch
deleted file mode 100644
index e9e2d0b..0000000
--- a/SOURCES/0415-mtd_probe-add-include-for-stdint.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-From 7d78e4a96b47b16330b2d28ff0cc5a51936e9fe9 Mon Sep 17 00:00:00 2001
-From: Lukas Nykryn <lnykryn@redhat.com>
-Date: Fri, 7 Oct 2016 15:17:12 +0200
-Subject: [PATCH] mtd_probe: add include for stdint
-
-The missing include is causing troubles on arm
-
-RHEL-only
-Related: #1381573
----
- src/udev/mtd_probe/mtd_probe.h | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/src/udev/mtd_probe/mtd_probe.h b/src/udev/mtd_probe/mtd_probe.h
-index d99be9a..cead374 100644
---- a/src/udev/mtd_probe/mtd_probe.h
-+++ b/src/udev/mtd_probe/mtd_probe.h
-@@ -20,6 +20,7 @@
- #pragma once
- 
- #include <mtd/mtd-user.h>
-+#include <stdint.h>
- 
- /* Full oob structure as written on the flash */
- struct sm_oob {
diff --git a/SOURCES/0415-virt-add-possibility-to-skip-the-check-for-chroot.patch b/SOURCES/0415-virt-add-possibility-to-skip-the-check-for-chroot.patch
new file mode 100644
index 0000000..bc15271
--- /dev/null
+++ b/SOURCES/0415-virt-add-possibility-to-skip-the-check-for-chroot.patch
@@ -0,0 +1,55 @@
+From f3750cbfd21b2e5f6f46077082f60e3a74ee4807 Mon Sep 17 00:00:00 2001
+From: Lukas Nykryn <lnykryn@redhat.com>
+Date: Mon, 17 Oct 2016 08:09:58 +0200
+Subject: [PATCH] virt: add possibility to skip the check for chroot
+
+Cherry-picked from: 08a28eeca70eeefb55af61191b63e4c938daca73
+Resolves: #1379852
+---
+ src/shared/env-util.c | 10 ++++++++++
+ src/shared/env-util.h |  2 ++
+ src/shared/util.c     |  3 +++
+ 3 files changed, 15 insertions(+)
+
+diff --git a/src/shared/env-util.c b/src/shared/env-util.c
+index 038246d..e8da4c9 100644
+--- a/src/shared/env-util.c
++++ b/src/shared/env-util.c
+@@ -449,3 +449,13 @@ char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const cha
+ 
+         return e;
+ }
++
++int getenv_bool(const char *p) {
++        const char *e;
++
++        e = getenv(p);
++        if (!e)
++                return -ENXIO;
++
++        return parse_boolean(e);
++}
+diff --git a/src/shared/env-util.h b/src/shared/env-util.h
+index 618441a..252d87b 100644
+--- a/src/shared/env-util.h
++++ b/src/shared/env-util.h
+@@ -45,3 +45,5 @@ char **strv_env_unset_many(char **l, ...) _sentinel_;
+ 
+ char *strv_env_get_n(char **l, const char *name, size_t k) _pure_;
+ char *strv_env_get(char **x, const char *n) _pure_;
++
++int getenv_bool(const char *p);
+diff --git a/src/shared/util.c b/src/shared/util.c
+index 357fbfe..eab5ab8 100644
+--- a/src/shared/util.c
++++ b/src/shared/util.c
+@@ -3776,6 +3776,9 @@ int files_same(const char *filea, const char *fileb) {
+ int running_in_chroot(void) {
+         int ret;
+ 
++        if (getenv_bool("SYSTEMD_IGNORE_CHROOT") > 0)
++                return 0;
++
+         ret = files_same("/proc/1/root", "/");
+         if (ret < 0)
+                 return ret;
diff --git a/SOURCES/0416-load-fragment-fix-parsing-values-in-bytes-and-preven.patch b/SOURCES/0416-load-fragment-fix-parsing-values-in-bytes-and-preven.patch
new file mode 100644
index 0000000..fe342de
--- /dev/null
+++ b/SOURCES/0416-load-fragment-fix-parsing-values-in-bytes-and-preven.patch
@@ -0,0 +1,51 @@
+From 38d00b8a0453d38aecb725342ddd89a7c3dcb134 Mon Sep 17 00:00:00 2001
+From: Michal Sekletar <msekleta@redhat.com>
+Date: Fri, 18 Nov 2016 14:00:57 +0100
+Subject: [PATCH] load-fragment: fix parsing values in bytes and prevent
+ returning -ERANGE incorrectly
+
+We didn't port our code base to use uint64_t instead of off_t as
+upstream did. RLIMIT_INIFINITY is -1ULL and if we cast to off_t (64 bit
+signed int on arches we support) then we get -1 and that is always
+smaller than correct value returned by parse_size().
+
+To make code changes as minimal as possible (i.e. not port everything
+to uint64_t) let's cast off_t to uint64_t and not the other way
+around.
+
+RHEL-only
+
+Resolves: #1396277
+---
+ src/core/load-fragment.c  | 2 +-
+ src/test/test-unit-file.c | 4 ++++
+ 2 files changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
+index 2f6209e..83b6e7e 100644
+--- a/src/core/load-fragment.c
++++ b/src/core/load-fragment.c
+@@ -1105,7 +1105,7 @@ static int rlim_parse_size(const char *val, rlim_t *res) {
+                 off_t u;
+ 
+                 r = parse_size(val, 1024, &u);
+-                if (r >= 0 && u >= (off_t) RLIM_INFINITY)
++                if (r >= 0 && (uint64_t) u >= RLIM_INFINITY)
+                         r = -ERANGE;
+                 if (r == 0)
+                         *res = (rlim_t) u;
+diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c
+index 8acf071..0384305 100644
+--- a/src/test/test-unit-file.c
++++ b/src/test/test-unit-file.c
+@@ -554,6 +554,10 @@ static void test_config_parse_rlimit(void) {
+         assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55);
+         assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
+ 
++        assert_se(config_parse_bytes_limit(NULL, "fake", 1, "section", 1, "LimitSTACK", RLIMIT_STACK, "55", rl, NULL) >= 0);
++        assert_se(rl[RLIMIT_STACK]);
++        assert_se(rl[RLIMIT_STACK]->rlim_cur == 55);
++        assert_se(rl[RLIMIT_STACK]->rlim_cur == rl[RLIMIT_STACK]->rlim_max);
+ 
+         assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55:66", rl, NULL) >= 0);
+         assert_se(rl[RLIMIT_NOFILE]);
diff --git a/SOURCES/0416-virt-add-possibility-to-skip-the-check-for-chroot.patch b/SOURCES/0416-virt-add-possibility-to-skip-the-check-for-chroot.patch
deleted file mode 100644
index a1bdd66..0000000
--- a/SOURCES/0416-virt-add-possibility-to-skip-the-check-for-chroot.patch
+++ /dev/null
@@ -1,55 +0,0 @@
-From c13f7b8e88f12f1a7e01e2094d7c648aaffc8c6c Mon Sep 17 00:00:00 2001
-From: Lukas Nykryn <lnykryn@redhat.com>
-Date: Mon, 17 Oct 2016 08:09:58 +0200
-Subject: [PATCH] virt: add possibility to skip the check for chroot
-
-Cherry-picked from: 08a28eeca70eeefb55af61191b63e4c938daca73
-Resolves: #1379852
----
- src/shared/env-util.c | 10 ++++++++++
- src/shared/env-util.h |  2 ++
- src/shared/util.c     |  3 +++
- 3 files changed, 15 insertions(+)
-
-diff --git a/src/shared/env-util.c b/src/shared/env-util.c
-index 038246d..e8da4c9 100644
---- a/src/shared/env-util.c
-+++ b/src/shared/env-util.c
-@@ -449,3 +449,13 @@ char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const cha
- 
-         return e;
- }
-+
-+int getenv_bool(const char *p) {
-+        const char *e;
-+
-+        e = getenv(p);
-+        if (!e)
-+                return -ENXIO;
-+
-+        return parse_boolean(e);
-+}
-diff --git a/src/shared/env-util.h b/src/shared/env-util.h
-index 618441a..252d87b 100644
---- a/src/shared/env-util.h
-+++ b/src/shared/env-util.h
-@@ -45,3 +45,5 @@ char **strv_env_unset_many(char **l, ...) _sentinel_;
- 
- char *strv_env_get_n(char **l, const char *name, size_t k) _pure_;
- char *strv_env_get(char **x, const char *n) _pure_;
-+
-+int getenv_bool(const char *p);
-diff --git a/src/shared/util.c b/src/shared/util.c
-index 357fbfe..eab5ab8 100644
---- a/src/shared/util.c
-+++ b/src/shared/util.c
-@@ -3776,6 +3776,9 @@ int files_same(const char *filea, const char *fileb) {
- int running_in_chroot(void) {
-         int ret;
- 
-+        if (getenv_bool("SYSTEMD_IGNORE_CHROOT") > 0)
-+                return 0;
-+
-         ret = files_same("/proc/1/root", "/");
-         if (ret < 0)
-                 return ret;
diff --git a/SOURCES/0417-core-fix-assertion-check.patch b/SOURCES/0417-core-fix-assertion-check.patch
new file mode 100644
index 0000000..7f42948
--- /dev/null
+++ b/SOURCES/0417-core-fix-assertion-check.patch
@@ -0,0 +1,26 @@
+From efd1250249494b7501578da7de7830659b65c98b Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Tue, 16 Feb 2016 13:18:36 +0100
+Subject: [PATCH] core: fix assertion check
+
+Fixes: #2632
+
+Cherry-picked from: 3f51aec8647fe13f4b1e46b2f75ff635403adf91
+Resolves: #1396312
+---
+ src/core/timer.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/core/timer.c b/src/core/timer.c
+index 972dd73..f318dc6 100644
+--- a/src/core/timer.c
++++ b/src/core/timer.c
+@@ -321,7 +321,7 @@ static void add_random(Timer *t, usec_t *v) {
+         usec_t add;
+ 
+         assert(t);
+-        assert(*v);
++        assert(v);
+ 
+         if (t->random_usec == 0)
+                 return;
diff --git a/SOURCES/0417-load-fragment-fix-parsing-values-in-bytes-and-preven.patch b/SOURCES/0417-load-fragment-fix-parsing-values-in-bytes-and-preven.patch
deleted file mode 100644
index 1505a7f..0000000
--- a/SOURCES/0417-load-fragment-fix-parsing-values-in-bytes-and-preven.patch
+++ /dev/null
@@ -1,51 +0,0 @@
-From d8edaa8a9e542a8bcd92a6a2b2ce9103dc8b9074 Mon Sep 17 00:00:00 2001
-From: Michal Sekletar <msekleta@redhat.com>
-Date: Fri, 18 Nov 2016 14:00:57 +0100
-Subject: [PATCH] load-fragment: fix parsing values in bytes and prevent
- returning -ERANGE incorrectly
-
-We didn't port our code base to use uint64_t instead of off_t as
-upstream did. RLIMIT_INIFINITY is -1ULL and if we cast to off_t (64 bit
-signed int on arches we support) then we get -1 and that is always
-smaller than correct value returned by parse_size().
-
-To make code changes as minimal as possible (i.e. not port everything
-to uint64_t) let's cast off_t to uint64_t and not the other way
-around.
-
-RHEL-only
-
-Resolves: #1396277
----
- src/core/load-fragment.c  | 2 +-
- src/test/test-unit-file.c | 4 ++++
- 2 files changed, 5 insertions(+), 1 deletion(-)
-
-diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
-index 2f6209e..83b6e7e 100644
---- a/src/core/load-fragment.c
-+++ b/src/core/load-fragment.c
-@@ -1105,7 +1105,7 @@ static int rlim_parse_size(const char *val, rlim_t *res) {
-                 off_t u;
- 
-                 r = parse_size(val, 1024, &u);
--                if (r >= 0 && u >= (off_t) RLIM_INFINITY)
-+                if (r >= 0 && (uint64_t) u >= RLIM_INFINITY)
-                         r = -ERANGE;
-                 if (r == 0)
-                         *res = (rlim_t) u;
-diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c
-index 8acf071..0384305 100644
---- a/src/test/test-unit-file.c
-+++ b/src/test/test-unit-file.c
-@@ -554,6 +554,10 @@ static void test_config_parse_rlimit(void) {
-         assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55);
-         assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
- 
-+        assert_se(config_parse_bytes_limit(NULL, "fake", 1, "section", 1, "LimitSTACK", RLIMIT_STACK, "55", rl, NULL) >= 0);
-+        assert_se(rl[RLIMIT_STACK]);
-+        assert_se(rl[RLIMIT_STACK]->rlim_cur == 55);
-+        assert_se(rl[RLIMIT_STACK]->rlim_cur == rl[RLIMIT_STACK]->rlim_max);
- 
-         assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55:66", rl, NULL) >= 0);
-         assert_se(rl[RLIMIT_NOFILE]);
diff --git a/SOURCES/0418-core-fix-assertion-check.patch b/SOURCES/0418-core-fix-assertion-check.patch
deleted file mode 100644
index d23c6c7..0000000
--- a/SOURCES/0418-core-fix-assertion-check.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From 5e5f05f7f8ea6beb1f9fd7ac7586798c33e8ba6f Mon Sep 17 00:00:00 2001
-From: Lennart Poettering <lennart@poettering.net>
-Date: Tue, 16 Feb 2016 13:18:36 +0100
-Subject: [PATCH] core: fix assertion check
-
-Fixes: #2632
-
-Cherry-picked from: 3f51aec8647fe13f4b1e46b2f75ff635403adf91
-Resolves: #1396312
----
- src/core/timer.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/core/timer.c b/src/core/timer.c
-index 972dd73..f318dc6 100644
---- a/src/core/timer.c
-+++ b/src/core/timer.c
-@@ -321,7 +321,7 @@ static void add_random(Timer *t, usec_t *v) {
-         usec_t add;
- 
-         assert(t);
--        assert(*v);
-+        assert(v);
- 
-         if (t->random_usec == 0)
-                 return;
diff --git a/SOURCES/0418-tmp.mount.hm4-After-swap.target-3087.patch b/SOURCES/0418-tmp.mount.hm4-After-swap.target-3087.patch
new file mode 100644
index 0000000..304755b
--- /dev/null
+++ b/SOURCES/0418-tmp.mount.hm4-After-swap.target-3087.patch
@@ -0,0 +1,24 @@
+From 81c1781b3d148fb3853af8cc72bb403846a2b7ed Mon Sep 17 00:00:00 2001
+From: frankheckenbach <fjf@gmx.de>
+Date: Fri, 22 Apr 2016 14:21:30 +0200
+Subject: [PATCH] tmp.mount.hm4: After swap.target (#3087)
+
+fix issue #2930
+Cherry-picked from: a11fe93e04e775c3ce2ace92be761d5ff9fce2d9
+Resolves: #1298355
+---
+ units/tmp.mount | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/units/tmp.mount b/units/tmp.mount
+index af0cf4a..8c53a87 100644
+--- a/units/tmp.mount
++++ b/units/tmp.mount
+@@ -13,6 +13,7 @@ ConditionPathIsSymbolicLink=!/tmp
+ DefaultDependencies=no
+ Conflicts=umount.target
+ Before=local-fs.target umount.target
++After=swap.target
+ 
+ [Mount]
+ What=tmpfs
diff --git a/SOURCES/0419-make-sure-all-swap-units-are-ordered-before-the-swap.patch b/SOURCES/0419-make-sure-all-swap-units-are-ordered-before-the-swap.patch
new file mode 100644
index 0000000..29c733b
--- /dev/null
+++ b/SOURCES/0419-make-sure-all-swap-units-are-ordered-before-the-swap.patch
@@ -0,0 +1,56 @@
+From 4fec67c88f7ddd02fecf711996f42ed4c9d24da6 Mon Sep 17 00:00:00 2001
+From: Franck Bui <fbui@suse.com>
+Date: Mon, 23 Nov 2015 11:14:10 +0100
+Subject: [PATCH] make sure all swap units are ordered before the swap target
+
+When shutting down the system, the swap devices can be disabled long
+time before the swap target is stopped. They're actually the first
+units systemd turns off on my system.
+
+This is incorrect and due to swap devices having multiple associated
+swap unit files. The main one is usually created by the fstab
+generator and is used to start the swap device.
+
+Once done, systemd creates some 'alias' units for the same swap
+device, one for each swap dev link. But those units are missing an
+ordering dependencies which was created by the fstab generator for the
+main swap unit.
+
+Therefore during shutdown those 'alias' units can be stopped at
+anytime before unmount.target target.
+
+This patch makes sure that all swap units are stopped after the
+swap.target target.
+
+Cherry-picked from: 8bf23dc757dacaaf5a8d2c21aabf71aee08d1a04
+Resolves: #1298355
+---
+ src/core/swap.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/src/core/swap.c b/src/core/swap.c
+index 42f9959..984be2d 100644
+--- a/src/core/swap.c
++++ b/src/core/swap.c
+@@ -210,6 +210,8 @@ static int swap_add_device_links(Swap *s) {
+ }
+ 
+ static int swap_add_default_dependencies(Swap *s) {
++        int r;
++
+         assert(s);
+ 
+         if (UNIT(s)->manager->running_as != SYSTEMD_SYSTEM)
+@@ -218,6 +220,12 @@ static int swap_add_default_dependencies(Swap *s) {
+         if (detect_container(NULL) > 0)
+                 return 0;
+ 
++        /* swap units generated for the swap dev links are missing the
++         * ordering dep against the swap target. */
++        r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SWAP_TARGET, NULL, true);
++        if (r < 0)
++                return r;
++
+         return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
+ }
+ 
diff --git a/SOURCES/0419-tmp.mount.hm4-After-swap.target-3087.patch b/SOURCES/0419-tmp.mount.hm4-After-swap.target-3087.patch
deleted file mode 100644
index 8c8ecb5..0000000
--- a/SOURCES/0419-tmp.mount.hm4-After-swap.target-3087.patch
+++ /dev/null
@@ -1,24 +0,0 @@
-From b52366a2098f7bcef31ef8ad912096949a2d40dd Mon Sep 17 00:00:00 2001
-From: frankheckenbach <fjf@gmx.de>
-Date: Fri, 22 Apr 2016 14:21:30 +0200
-Subject: [PATCH] tmp.mount.hm4: After swap.target (#3087)
-
-fix issue #2930
-Cherry-picked from: a11fe93e04e775c3ce2ace92be761d5ff9fce2d9
-Resolves: #1298355
----
- units/tmp.mount | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/units/tmp.mount b/units/tmp.mount
-index af0cf4a..8c53a87 100644
---- a/units/tmp.mount
-+++ b/units/tmp.mount
-@@ -13,6 +13,7 @@ ConditionPathIsSymbolicLink=!/tmp
- DefaultDependencies=no
- Conflicts=umount.target
- Before=local-fs.target umount.target
-+After=swap.target
- 
- [Mount]
- What=tmpfs
diff --git a/SOURCES/0420-Recognise-Lustre-as-a-remote-file-system-4530.patch b/SOURCES/0420-Recognise-Lustre-as-a-remote-file-system-4530.patch
new file mode 100644
index 0000000..83cd46d
--- /dev/null
+++ b/SOURCES/0420-Recognise-Lustre-as-a-remote-file-system-4530.patch
@@ -0,0 +1,30 @@
+From f1cb9320c6aca21b17c9a120eb70a788df8ac6d5 Mon Sep 17 00:00:00 2001
+From: "Brian J. Murrell" <brian@interlinx.bc.ca>
+Date: Mon, 31 Oct 2016 23:48:00 -0400
+Subject: [PATCH] Recognise Lustre as a remote file system (#4530)
+
+Lustre is also a remote file system that wants the network to be up before it is mounted.
+
+Cherry-picked from: 67ae43665e7e03becba197e98df5b3ce40269567
+Resolves: #1390542
+---
+ src/shared/util.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/src/shared/util.c b/src/shared/util.c
+index eab5ab8..66729f7 100644
+--- a/src/shared/util.c
++++ b/src/shared/util.c
+@@ -1924,7 +1924,11 @@ bool fstype_is_network(const char *fstype) {
+                 "nfs4\0"
+                 "gfs\0"
+                 "gfs2\0"
+-                "glusterfs\0";
++                "glusterfs\0"
++                "pvfs2\0" /* OrangeFS */
++                "ocfs2\0"
++                "lustre\0"
++                ;
+ 
+         const char *x;
+ 
diff --git a/SOURCES/0420-make-sure-all-swap-units-are-ordered-before-the-swap.patch b/SOURCES/0420-make-sure-all-swap-units-are-ordered-before-the-swap.patch
deleted file mode 100644
index 6287377..0000000
--- a/SOURCES/0420-make-sure-all-swap-units-are-ordered-before-the-swap.patch
+++ /dev/null
@@ -1,56 +0,0 @@
-From fb85550c9fafacbd8c07b611d6f129dc341f9e28 Mon Sep 17 00:00:00 2001
-From: Franck Bui <fbui@suse.com>
-Date: Mon, 23 Nov 2015 11:14:10 +0100
-Subject: [PATCH] make sure all swap units are ordered before the swap target
-
-When shutting down the system, the swap devices can be disabled long
-time before the swap target is stopped. They're actually the first
-units systemd turns off on my system.
-
-This is incorrect and due to swap devices having multiple associated
-swap unit files. The main one is usually created by the fstab
-generator and is used to start the swap device.
-
-Once done, systemd creates some 'alias' units for the same swap
-device, one for each swap dev link. But those units are missing an
-ordering dependencies which was created by the fstab generator for the
-main swap unit.
-
-Therefore during shutdown those 'alias' units can be stopped at
-anytime before unmount.target target.
-
-This patch makes sure that all swap units are stopped after the
-swap.target target.
-
-Cherry-picked from: 8bf23dc757dacaaf5a8d2c21aabf71aee08d1a04
-Resolves: #1298355
----
- src/core/swap.c | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
-diff --git a/src/core/swap.c b/src/core/swap.c
-index 42f9959..984be2d 100644
---- a/src/core/swap.c
-+++ b/src/core/swap.c
-@@ -210,6 +210,8 @@ static int swap_add_device_links(Swap *s) {
- }
- 
- static int swap_add_default_dependencies(Swap *s) {
-+        int r;
-+
-         assert(s);
- 
-         if (UNIT(s)->manager->running_as != SYSTEMD_SYSTEM)
-@@ -218,6 +220,12 @@ static int swap_add_default_dependencies(Swap *s) {
-         if (detect_container(NULL) > 0)
-                 return 0;
- 
-+        /* swap units generated for the swap dev links are missing the
-+         * ordering dep against the swap target. */
-+        r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SWAP_TARGET, NULL, true);
-+        if (r < 0)
-+                return r;
-+
-         return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
- }
- 
diff --git a/SOURCES/0421-core-reinstate-propagation-of-stop-restart-jobs-via-.patch b/SOURCES/0421-core-reinstate-propagation-of-stop-restart-jobs-via-.patch
deleted file mode 100644
index 0fa7815..0000000
--- a/SOURCES/0421-core-reinstate-propagation-of-stop-restart-jobs-via-.patch
+++ /dev/null
@@ -1,84 +0,0 @@
-From c552d788919808b1279bc42c9cd4b9e69878f4da Mon Sep 17 00:00:00 2001
-From: Lennart Poettering <lennart@poettering.net>
-Date: Tue, 19 May 2015 17:40:50 +0200
-Subject: [PATCH] core: reinstate propagation of stop/restart jobs via
- RequsiteOf dependencies
-
-This reverts the primary effect of be7d9ff730cb88d7c6a869dd5c47754c78ceaef2.
-
-After all Requisite= should be close to Requires=, without the one
-exception that it doesn't pull in dependencies on start. However,
-reverse deps on stop/restart should be treated the same way as for
-Restart=, and this is already documented in the man page, hence stick to
-it.
-
-http://lists.freedesktop.org/archives/systemd-devel/2015-May/032049.html
-(cherry picked from commit ce74e76920dca603a12ef4bf605567965e9e7e45)
-
-[msekleta: we didn't backport be7d9ff730cb88d7c6a869dd5c47754c78ceaef2
-and hence we don't have UNIT_REQUISITE_OF. Note that this patch was
-backported because it makes backports of followup patches easier]
-
-Related: #1436021
----
- src/core/transaction.c | 41 +++++++++++++----------------------------
- 1 file changed, 13 insertions(+), 28 deletions(-)
-
-diff --git a/src/core/transaction.c b/src/core/transaction.c
-index 57e9cb3..428b767 100644
---- a/src/core/transaction.c
-+++ b/src/core/transaction.c
-@@ -1008,40 +1008,25 @@ int transaction_add_job_and_dependencies(
-                 }
- 
-                 if (type == JOB_STOP || type == JOB_RESTART) {
-+                        static const UnitDependency propagate_deps[] = {
-+                                UNIT_REQUIRED_BY,
-+                                UNIT_BOUND_BY,
-+                                UNIT_CONSISTS_OF,
-+                        };
- 
--                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRED_BY], i) {
--                                r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
--                                if (r < 0) {
--                                        if (r != -EBADR)
--                                                goto fail;
--
--                                        if (e)
--                                                sd_bus_error_free(e);
--                                }
--                        }
--
--                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_BOUND_BY], i) {
--                                r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
--                                if (r < 0) {
--                                        if (r != -EBADR)
--                                                goto fail;
-+                        unsigned j;
- 
--                                        if (e)
--                                                sd_bus_error_free(e);
--                                }
--                        }
-+                        for (j = 0; j < ELEMENTSOF(propagate_deps); j++)
-+                                SET_FOREACH(dep, ret->unit->dependencies[propagate_deps[j]], i) {
- 
--                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONSISTS_OF], i) {
--                                r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
--                                if (r < 0) {
--                                        if (r != -EBADR)
--                                                goto fail;
-+                                        r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
-+                                        if (r < 0) {
-+                                                if (r != -EBADR)
-+                                                        goto fail;
- 
--                                        if (e)
-                                                 sd_bus_error_free(e);
-+                                        }
-                                 }
--                        }
--
-                 }
- 
-                 if (type == JOB_RELOAD) {
diff --git a/SOURCES/0421-unit-don-t-add-Requires-for-tmp.mount.patch b/SOURCES/0421-unit-don-t-add-Requires-for-tmp.mount.patch
new file mode 100644
index 0000000..2c52dc8
--- /dev/null
+++ b/SOURCES/0421-unit-don-t-add-Requires-for-tmp.mount.patch
@@ -0,0 +1,24 @@
+From a0adbe08c612f1330221c1a8bcad3cb5aedcb71b Mon Sep 17 00:00:00 2001
+From: Lukas Nykryn <lnykryn@redhat.com>
+Date: Mon, 5 Sep 2016 12:47:09 +0200
+Subject: [PATCH] unit: don't add Requires for tmp.mount
+
+rhel-only
+Resolves: #1372249
+---
+ src/core/unit.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/core/unit.c b/src/core/unit.c
+index 0e90d13..a7d6d2f 100644
+--- a/src/core/unit.c
++++ b/src/core/unit.c
+@@ -1155,7 +1155,7 @@ static int unit_add_mount_dependencies(Unit *u) {
+                         if (r < 0)
+                                 return r;
+ 
+-                        if (m->fragment_path) {
++                        if (m->fragment_path && !streq(m->id, "tmp.mount")) {
+                                 r = unit_add_dependency(u, UNIT_REQUIRES, m, true);
+                                 if (r < 0)
+                                         return r;
diff --git a/SOURCES/0422-core-return-0-from-device_serialize.patch b/SOURCES/0422-core-return-0-from-device_serialize.patch
new file mode 100644
index 0000000..15aa10a
--- /dev/null
+++ b/SOURCES/0422-core-return-0-from-device_serialize.patch
@@ -0,0 +1,32 @@
+From 16ea84cf76e69975336fc347226ee3f58be25bc2 Mon Sep 17 00:00:00 2001
+From: Daniel Mack <daniel@zonque.org>
+Date: Fri, 24 Apr 2015 16:14:48 +0200
+Subject: [PATCH] core: return 0 from device_serialize()
+
+Fixes:
+
+  CC       src/core/libsystemd_core_la-device.lo
+src/core/device.c: In function 'device_serialize':
+src/core/device.c:169:1: warning: control reaches end of non-void function [-Wreturn-type]
+ }
+ ^
+
+Cherry-picked from: 0108f6ecc85eccc0177579f575d7bc3d56d43bc6
+Resolves: #1403249
+---
+ src/core/device.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/src/core/device.c b/src/core/device.c
+index bdc8466..befbae8 100644
+--- a/src/core/device.c
++++ b/src/core/device.c
+@@ -168,6 +168,8 @@ static int device_serialize(Unit *u, FILE *f, FDSet *fds) {
+         assert(fds);
+ 
+         unit_serialize_item(u, f, "state", device_state_to_string(d->state));
++
++        return 0;
+ }
+ 
+ static int device_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
diff --git a/SOURCES/0422-core-when-propagating-restart-requests-due-to-deps-d.patch b/SOURCES/0422-core-when-propagating-restart-requests-due-to-deps-d.patch
deleted file mode 100644
index f228bd6..0000000
--- a/SOURCES/0422-core-when-propagating-restart-requests-due-to-deps-d.patch
+++ /dev/null
@@ -1,142 +0,0 @@
-From 936aef312eb93eb84a872cae4e3cc98b7ac9305c Mon Sep 17 00:00:00 2001
-From: Lennart Poettering <lennart@poettering.net>
-Date: Tue, 19 May 2015 18:13:22 +0200
-Subject: [PATCH] core: when propagating restart requests due to deps,
- downgrade restart to try-restart
-
-Previously, if a service A depended on a service B via Requires=, and A
-was not running and B restarted this would trigger a start of A as well,
-since the restart was propagated as restart independently of the state
-of A.
-
-This patch ensures that a restart of B would be propagated as a
-try-restart to A, thus not changing its state if it isn't up.
-
-http://lists.freedesktop.org/archives/systemd-devel/2015-May/032061.html
-(cherry picked from commit c6497ccb7153af9a1252c48918e380b5134314de)
-
-Resolves: #1436021
----
- src/core/job.c         | 28 ++++++++++++++--------------
- src/core/job.h         |  2 +-
- src/core/manager.c     |  2 +-
- src/core/transaction.c | 11 ++++++++---
- 4 files changed, 24 insertions(+), 19 deletions(-)
-
-diff --git a/src/core/job.c b/src/core/job.c
-index c2876de..e2b7375 100644
---- a/src/core/job.c
-+++ b/src/core/job.c
-@@ -392,38 +392,38 @@ bool job_type_is_redundant(JobType a, UnitActiveState b) {
-         }
- }
- 
--void job_type_collapse(JobType *t, Unit *u) {
-+JobType job_type_collapse(JobType t, Unit *u) {
-         UnitActiveState s;
- 
--        switch (*t) {
-+        switch (t) {
- 
-         case JOB_TRY_RESTART:
-                 s = unit_active_state(u);
-                 if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
--                        *t = JOB_NOP;
--                else
--                        *t = JOB_RESTART;
--                break;
-+                        return JOB_NOP;
-+
-+                return JOB_RESTART;
- 
-         case JOB_RELOAD_OR_START:
-                 s = unit_active_state(u);
-                 if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
--                        *t = JOB_START;
--                else
--                        *t = JOB_RELOAD;
--                break;
-+                        return JOB_START;
-+
-+                return JOB_RELOAD;
- 
-         default:
--                ;
-+                return t;
-         }
- }
- 
- int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u) {
--        JobType t = job_type_lookup_merge(*a, b);
-+        JobType t;
-+
-+        t = job_type_lookup_merge(*a, b);
-         if (t < 0)
-                 return -EEXIST;
--        *a = t;
--        job_type_collapse(a, u);
-+
-+        *a = job_type_collapse(t, u);
-         return 0;
- }
- 
-diff --git a/src/core/job.h b/src/core/job.h
-index e4191ee..ce81607 100644
---- a/src/core/job.h
-+++ b/src/core/job.h
-@@ -210,7 +210,7 @@ bool job_type_is_redundant(JobType a, UnitActiveState b) _pure_;
- 
- /* Collapses a state-dependent job type into a simpler type by observing
-  * the state of the unit which it is going to be applied to. */
--void job_type_collapse(JobType *t, Unit *u);
-+JobType job_type_collapse(JobType t, Unit *u);
- 
- int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u);
- 
-diff --git a/src/core/manager.c b/src/core/manager.c
-index 6d045fd..329e0bf 100644
---- a/src/core/manager.c
-+++ b/src/core/manager.c
-@@ -1303,7 +1303,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove
-                        "Trying to enqueue job %s/%s/%s", unit->id,
-                        job_type_to_string(type), job_mode_to_string(mode));
- 
--        job_type_collapse(&type, unit);
-+        type = job_type_collapse(type, unit);
- 
-         tr = transaction_new(mode == JOB_REPLACE_IRREVERSIBLY);
-         if (!tr)
-diff --git a/src/core/transaction.c b/src/core/transaction.c
-index 428b767..34df157 100644
---- a/src/core/transaction.c
-+++ b/src/core/transaction.c
-@@ -855,8 +855,7 @@ int transaction_add_job_and_dependencies(
-         /*           by ? job_type_to_string(by->type) : "NA"); */
- 
-         if (!IN_SET(unit->load_state, UNIT_LOADED, UNIT_ERROR, UNIT_NOT_FOUND, UNIT_MASKED))
--                return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
--                                         "Unit %s is not loaded properly.", unit->id);
-+                return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id);
- 
-         if (type != JOB_STOP) {
-                 r = bus_unit_check_load_state(unit, e);
-@@ -1014,12 +1013,18 @@ int transaction_add_job_and_dependencies(
-                                 UNIT_CONSISTS_OF,
-                         };
- 
-+                        JobType ptype;
-                         unsigned j;
- 
-+                        /* We propagate STOP as STOP, but RESTART only
-+                         * as TRY_RESTART, in order not to start
-+                         * dependencies that are not around. */
-+                        ptype = type == JOB_RESTART ? JOB_TRY_RESTART : type;
-+
-                         for (j = 0; j < ELEMENTSOF(propagate_deps); j++)
-                                 SET_FOREACH(dep, ret->unit->dependencies[propagate_deps[j]], i) {
- 
--                                        r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
-+                                        r = transaction_add_job_and_dependencies(tr, job_type_collapse(ptype, dep), dep, ret, true, override, false, false, ignore_order, e);
-                                         if (r < 0) {
-                                                 if (r != -EBADR)
-                                                         goto fail;
diff --git a/SOURCES/0423-core-properly-handle-jobs-that-are-suppressed-to-JOB.patch b/SOURCES/0423-core-properly-handle-jobs-that-are-suppressed-to-JOB.patch
deleted file mode 100644
index 96c2229..0000000
--- a/SOURCES/0423-core-properly-handle-jobs-that-are-suppressed-to-JOB.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From 4179d6e6796a65738e9859a9e60c82f5c7573497 Mon Sep 17 00:00:00 2001
-From: Lennart Poettering <lennart@poettering.net>
-Date: Thu, 21 May 2015 20:39:23 +0200
-Subject: [PATCH] core: properly handle jobs that are suppressed to JOB_NOPs
- when propagating restarts
-
-Cherry-picked from: 48894cd0
-Resolves: #1436021
----
- src/core/transaction.c | 7 ++++++-
- 1 file changed, 6 insertions(+), 1 deletion(-)
-
-diff --git a/src/core/transaction.c b/src/core/transaction.c
-index 34df157..66bbb60 100644
---- a/src/core/transaction.c
-+++ b/src/core/transaction.c
-@@ -1023,8 +1023,13 @@ int transaction_add_job_and_dependencies(
- 
-                         for (j = 0; j < ELEMENTSOF(propagate_deps); j++)
-                                 SET_FOREACH(dep, ret->unit->dependencies[propagate_deps[j]], i) {
-+                                        JobType nt;
- 
--                                        r = transaction_add_job_and_dependencies(tr, job_type_collapse(ptype, dep), dep, ret, true, override, false, false, ignore_order, e);
-+                                        nt = job_type_collapse(ptype, dep);
-+                                        if (nt == JOB_NOP)
-+                                                continue;
-+
-+                                        r = transaction_add_job_and_dependencies(tr, nt, dep, ret, true, override, false, false, ignore_order, e);
-                                         if (r < 0) {
-                                                 if (r != -EBADR)
-                                                         goto fail;
diff --git a/SOURCES/0423-mtd_probe-include-stdint.patch b/SOURCES/0423-mtd_probe-include-stdint.patch
new file mode 100644
index 0000000..a4938d0
--- /dev/null
+++ b/SOURCES/0423-mtd_probe-include-stdint.patch
@@ -0,0 +1,23 @@
+From 5c1473ccbbcdf4f1ec3b18609adb351946ed74b5 Mon Sep 17 00:00:00 2001
+From: Lukas Nykryn <lnykryn@redhat.com>
+Date: Tue, 13 Dec 2016 14:25:38 +0100
+Subject: [PATCH] mtd_probe: include stdint
+
+rhel-only
+Resolves: #1404251
+---
+ src/udev/mtd_probe/mtd_probe.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/udev/mtd_probe/mtd_probe.h b/src/udev/mtd_probe/mtd_probe.h
+index d99be9a..cead374 100644
+--- a/src/udev/mtd_probe/mtd_probe.h
++++ b/src/udev/mtd_probe/mtd_probe.h
+@@ -20,6 +20,7 @@
+ #pragma once
+ 
+ #include <mtd/mtd-user.h>
++#include <stdint.h>
+ 
+ /* Full oob structure as written on the flash */
+ struct sm_oob {
diff --git a/SOURCES/0424-tests-fix-failure-of-test-execute-if-dev-mem-is-not-.patch b/SOURCES/0424-tests-fix-failure-of-test-execute-if-dev-mem-is-not-.patch
new file mode 100644
index 0000000..dd6503e
--- /dev/null
+++ b/SOURCES/0424-tests-fix-failure-of-test-execute-if-dev-mem-is-not-.patch
@@ -0,0 +1,41 @@
+From 0f3a67a0e4d243952e9ae4965a30e704885f03ef Mon Sep 17 00:00:00 2001
+From: Michal Sekletar <msekletar@users.noreply.github.com>
+Date: Fri, 6 Jan 2017 10:27:35 +0100
+Subject: [PATCH] tests: fix failure of test-execute if /dev/mem is not
+ available (#5028)
+
+/dev/mem isn't necessarily available. Recently, I've encountered arm64
+systems that didn't provide raw memory access via /dev/mem. Instead,
+let's use /dev/kmsg since we don't support systems w/o it anyway.
+
+Cherry-picked from: 01349f5d01e0b59168722403b0c1c2325b15512c
+Resolves: #1410056
+---
+ test/exec-privatedevices-no.service  | 2 +-
+ test/exec-privatedevices-yes.service | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/test/exec-privatedevices-no.service b/test/exec-privatedevices-no.service
+index cf4f275..af1daf7 100644
+--- a/test/exec-privatedevices-no.service
++++ b/test/exec-privatedevices-no.service
+@@ -2,6 +2,6 @@
+ Description=Test for PrivateDev=no
+ 
+ [Service]
+-ExecStart=/bin/sh -c 'exit $(test -c /dev/mem)'
++ExecStart=/bin/sh -c 'exit $(test -c /dev/kmsg)'
+ Type=oneshot
+ PrivateDevices=no
+diff --git a/test/exec-privatedevices-yes.service b/test/exec-privatedevices-yes.service
+index 85b3f4f..384a7b0 100644
+--- a/test/exec-privatedevices-yes.service
++++ b/test/exec-privatedevices-yes.service
+@@ -2,6 +2,6 @@
+ Description=Test for PrivateDev=yes
+ 
+ [Service]
+-ExecStart=/bin/sh -c 'exit $(test ! -c /dev/mem)'
++ExecStart=/bin/sh -c 'exit $(test ! -c /dev/kmsg)'
+ Type=oneshot
+ PrivateDevices=yes
diff --git a/SOURCES/0425-sd-journal-properly-export-has_-persistent-runtime-_.patch b/SOURCES/0425-sd-journal-properly-export-has_-persistent-runtime-_.patch
new file mode 100644
index 0000000..c5c75e1
--- /dev/null
+++ b/SOURCES/0425-sd-journal-properly-export-has_-persistent-runtime-_.patch
@@ -0,0 +1,28 @@
+From 0bf93125d4833bcdb7d187543581e4a6c14de159 Mon Sep 17 00:00:00 2001
+From: Michal Sekletar <msekleta@redhat.com>
+Date: Wed, 21 Dec 2016 18:04:57 +0100
+Subject: [PATCH] sd-journal: properly export has_{persistent|runtime}_files()
+
+Cherry-picked from: 9a07f779bbeacc3358d405f6cf583506aaf655ae
+Resolves: #1409527
+---
+ src/libsystemd/libsystemd.sym.m4 | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/src/libsystemd/libsystemd.sym.m4 b/src/libsystemd/libsystemd.sym.m4
+index 76a8c92..b1c2b43 100644
+--- a/src/libsystemd/libsystemd.sym.m4
++++ b/src/libsystemd/libsystemd.sym.m4
+@@ -163,6 +163,12 @@ global:
+         sd_pid_notify_with_fds;
+ } LIBSYSTEMD_217;
+ 
++LIBSYSTEMD_229 {
++global:
++        sd_journal_has_runtime_files;
++        sd_journal_has_persistent_files;
++} LIBSYSTEMD_219;
++
+ m4_ifdef(`ENABLE_KDBUS',
+ LIBSYSTEMD_FUTURE {
+ global:
diff --git a/SOURCES/0426-core-add-possibility-to-set-action-for-ctrl-alt-del-.patch b/SOURCES/0426-core-add-possibility-to-set-action-for-ctrl-alt-del-.patch
new file mode 100644
index 0000000..5469980
--- /dev/null
+++ b/SOURCES/0426-core-add-possibility-to-set-action-for-ctrl-alt-del-.patch
@@ -0,0 +1,201 @@
+From be9fad86ae9ab721cd295210962da85706b839e9 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Nykr=C3=BDn?= <lnykryn@redhat.com>
+Date: Fri, 7 Oct 2016 03:08:21 +0200
+Subject: [PATCH] core: add possibility to set action for ctrl-alt-del burst
+ (#4105)
+
+For some certification, it should not be possible to reboot the machine through ctrl-alt-delete. Currently we suggest our customers to mask the ctrl-alt-delete target, but that is obviously not enough.
+
+Patching the keymaps to disable that is really not a way to go for them, because the settings need to be easily checked by some SCAP tools.
+
+Cherry-picked from: 24dd31c19ede505143833346ff850af942694aa6
+Resolves: #1353028
+---
+ man/systemd-system.conf.xml | 11 ++++++++++
+ src/core/main.c             |  5 +++++
+ src/core/manager.c          | 51 +++++++++++++++++++++++++++++++++------------
+ src/core/manager.h          | 14 ++++++++++++-
+ src/core/system.conf        |  1 +
+ 5 files changed, 68 insertions(+), 14 deletions(-)
+
+diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml
+index 39d19bc..236c20d 100644
+--- a/man/systemd-system.conf.xml
++++ b/man/systemd-system.conf.xml
+@@ -102,6 +102,17 @@
+       </varlistentry>
+ 
+       <varlistentry>
++        <term><varname>CtrlAltDelBurstAction=</varname></term>
++
++        <listitem><para>Defines what action will be performed
++        if user presses Ctr-Alt-Delete more than 7 times in 2s.
++        Can be set to <literal>reboot-force</literal>, <literal>poweroff-force</literal>
++        or disabled with <literal>ignore</literal>. Defaults to
++        <literal>reboot-force</literal>.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
+         <term><varname>CPUAffinity=</varname></term>
+ 
+         <listitem><para>Configures the initial CPU affinity for the
+diff --git a/src/core/main.c b/src/core/main.c
+index c9d8ce4..6ac9c9d 100644
+--- a/src/core/main.c
++++ b/src/core/main.c
+@@ -115,6 +115,7 @@ static FILE* arg_serialization = NULL;
+ static bool arg_default_cpu_accounting = false;
+ static bool arg_default_blockio_accounting = false;
+ static bool arg_default_memory_accounting = false;
++static CADBurstAction arg_cad_burst_action = CAD_BURST_ACTION_REBOOT;
+ 
+ static void nop_handler(int sig) {}
+ 
+@@ -625,6 +626,8 @@ static int config_parse_join_controllers(const char *unit,
+         return 0;
+ }
+ 
++static DEFINE_CONFIG_PARSE_ENUM(config_parse_cad_burst_action, cad_burst_action, CADBurstAction, "Failed to parse service restart specifier");
++
+ static int parse_config_file(void) {
+ 
+         const ConfigTableItem items[] = {
+@@ -673,6 +676,7 @@ static int parse_config_file(void) {
+                 { "Manager", "DefaultCPUAccounting",      config_parse_bool,             0, &arg_default_cpu_accounting            },
+                 { "Manager", "DefaultBlockIOAccounting",  config_parse_bool,             0, &arg_default_blockio_accounting        },
+                 { "Manager", "DefaultMemoryAccounting",   config_parse_bool,             0, &arg_default_memory_accounting         },
++                { "Manager", "CtrlAltDelBurstAction",     config_parse_cad_burst_action, 0, &arg_cad_burst_action},
+                 {}
+         };
+ 
+@@ -1690,6 +1694,7 @@ int main(int argc, char *argv[]) {
+         m->initrd_timestamp = initrd_timestamp;
+         m->security_start_timestamp = security_start_timestamp;
+         m->security_finish_timestamp = security_finish_timestamp;
++        m->cad_burst_action = arg_cad_burst_action;
+ 
+         manager_set_default_rlimits(m, arg_default_rlimit);
+         manager_environment_add(m, NULL, arg_default_environment);
+diff --git a/src/core/manager.c b/src/core/manager.c
+index 6d045fd..9048dde 100644
+--- a/src/core/manager.c
++++ b/src/core/manager.c
+@@ -1859,6 +1859,35 @@ static int manager_start_target(Manager *m, const char *name, JobMode mode) {
+         return r;
+ }
+ 
++static void manager_handle_ctrl_alt_del(Manager *m) {
++        /* If the user presses C-A-D more than
++         * 7 times within 2s, we reboot/shutdown immediately,
++         * unless it was disabled in system.conf */
++
++        if (ratelimit_test(&m->ctrl_alt_del_ratelimit) || m->cad_burst_action == CAD_BURST_ACTION_IGNORE)
++                manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE_IRREVERSIBLY);
++        else {
++                switch (m->cad_burst_action) {
++
++                case CAD_BURST_ACTION_REBOOT:
++                        m->exit_code = MANAGER_REBOOT;
++                        break;
++
++                case CAD_BURST_ACTION_POWEROFF:
++                        m->exit_code = MANAGER_POWEROFF;
++                        break;
++
++                default:
++                        assert_not_reached("Unknown action.");
++                }
++
++                log_notice("Ctrl-Alt-Del was pressed more than 7 times within 2s, performing immediate %s.",
++                                cad_burst_action_to_string(m->cad_burst_action));
++                status_printf(NULL, true, false, "Ctrl-Alt-Del was pressed more than 7 times within 2s, performing immediate %s.",
++                                cad_burst_action_to_string(m->cad_burst_action));
++        }
++}
++
+ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
+         Manager *m = userdata;
+         ssize_t n;
+@@ -1909,19 +1938,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
+ 
+                 case SIGINT:
+                         if (m->running_as == SYSTEMD_SYSTEM) {
+-
+-                                /* If the user presses C-A-D more than
+-                                 * 7 times within 2s, we reboot
+-                                 * immediately. */
+-
+-                                if (ratelimit_test(&m->ctrl_alt_del_ratelimit))
+-                                        manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE_IRREVERSIBLY);
+-                                else {
+-                                        log_notice("Ctrl-Alt-Del was pressed more than 7 times within 2s, rebooting immediately.");
+-                                        status_printf(NULL, true, false, "Ctrl-Alt-Del was pressed more than 7 times within 2s, rebooting immediately.");
+-                                        m->exit_code = MANAGER_REBOOT;
+-                                }
+-
++                                manager_handle_ctrl_alt_del(m);
+                                 break;
+                         }
+ 
+@@ -3319,3 +3336,11 @@ static const char *const manager_state_table[_MANAGER_STATE_MAX] = {
+ };
+ 
+ DEFINE_STRING_TABLE_LOOKUP(manager_state, ManagerState);
++
++static const char *const cad_burst_action_table[_CAD_BURST_ACTION_MAX] = {
++        [CAD_BURST_ACTION_IGNORE] = "ignore",
++        [CAD_BURST_ACTION_REBOOT] = "reboot-force",
++        [CAD_BURST_ACTION_POWEROFF] = "poweroff-force",
++};
++
++DEFINE_STRING_TABLE_LOOKUP(cad_burst_action, CADBurstAction);
+diff --git a/src/core/manager.h b/src/core/manager.h
+index 3e855db..42be1fc 100644
+--- a/src/core/manager.h
++++ b/src/core/manager.h
+@@ -64,6 +64,14 @@ typedef enum ManagerExitCode {
+         _MANAGER_EXIT_CODE_INVALID = -1
+ } ManagerExitCode;
+ 
++typedef enum CADBurstAction {
++        CAD_BURST_ACTION_IGNORE,
++        CAD_BURST_ACTION_REBOOT,
++        CAD_BURST_ACTION_POWEROFF,
++        _CAD_BURST_ACTION_MAX,
++        _CAD_BURST_ACTION_INVALID = -1
++} CADBurstAction;
++
+ typedef enum StatusType {
+         STATUS_TYPE_EPHEMERAL,
+         STATUS_TYPE_NORMAL,
+@@ -300,8 +308,9 @@ struct Manager {
+         /* Used for processing polkit authorization responses */
+         Hashmap *polkit_registry;
+ 
+-        /* When the user hits C-A-D more than 7 times per 2s, reboot immediately... */
++        /* When the user hits C-A-D more than 7 times per 2s, do something immediately... */
+         RateLimit ctrl_alt_del_ratelimit;
++        CADBurstAction cad_burst_action;
+ };
+ 
+ int manager_new(SystemdRunningAs running_as, bool test_run, Manager **m);
+@@ -372,3 +381,6 @@ ManagerState manager_state(Manager *m);
+ 
+ const char *manager_state_to_string(ManagerState m) _const_;
+ ManagerState manager_state_from_string(const char *s) _pure_;
++
++const char *cad_burst_action_to_string(CADBurstAction a) _const_;
++CADBurstAction cad_burst_action_from_string(const char *s) _pure_;
+diff --git a/src/core/system.conf b/src/core/system.conf
+index 2316090..a11f599 100644
+--- a/src/core/system.conf
++++ b/src/core/system.conf
+@@ -20,6 +20,7 @@
+ #CrashShell=no
+ #ShowStatus=yes
+ #CrashChVT=1
++#CtrlAltDelBurstAction=reboot-force
+ #CPUAffinity=1 2
+ #JoinControllers=cpu,cpuacct net_cls,net_prio
+ #RuntimeWatchdogSec=0
diff --git a/SOURCES/0427-failure-action-generalize-failure-action-to-emergenc.patch b/SOURCES/0427-failure-action-generalize-failure-action-to-emergenc.patch
new file mode 100644
index 0000000..402b175
--- /dev/null
+++ b/SOURCES/0427-failure-action-generalize-failure-action-to-emergenc.patch
@@ -0,0 +1,461 @@
+From 2b787d523662b91334da24f1c77a7d803e53fab9 Mon Sep 17 00:00:00 2001
+From: Lukas Nykryn <lnykryn@redhat.com>
+Date: Tue, 3 Jan 2017 16:05:42 +0100
+Subject: [PATCH] failure-action: generalize failure action to emergency action
+
+Cherry-picked from: 87a47f99bc8e576a63581ad2593c62eb10a53814
+Resolves: #1353028
+---
+ Makefile.am                                       |  4 +-
+ src/core/dbus-service.c                           |  6 +--
+ src/core/dbus-unit.c                              |  4 +-
+ src/core/{failure-action.c => emergency-action.c} | 65 ++++++++++++-----------
+ src/core/{failure-action.h => emergency-action.h} | 28 +++++-----
+ src/core/job.c                                    |  2 +-
+ src/core/load-fragment-gperf.gperf.m4             |  6 +--
+ src/core/load-fragment.c                          |  4 +-
+ src/core/load-fragment.h                          |  2 +-
+ src/core/manager.h                                |  2 +-
+ src/core/service.c                                |  4 +-
+ src/core/service.h                                |  6 +--
+ src/core/unit.c                                   |  4 +-
+ src/core/unit.h                                   |  4 +-
+ src/test/test-tables.c                            |  2 +-
+ 15 files changed, 72 insertions(+), 71 deletions(-)
+ rename src/core/{failure-action.c => emergency-action.c} (63%)
+ rename src/core/{failure-action.h => emergency-action.h} (58%)
+
+diff --git a/Makefile.am b/Makefile.am
+index 3848338..b347aed 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -1182,8 +1182,8 @@ libsystemd_core_la_SOURCES = \
+ 	src/core/audit-fd.h \
+ 	src/core/show-status.c \
+ 	src/core/show-status.h \
+-	src/core/failure-action.c \
+-	src/core/failure-action.h
++	src/core/emergency-action.c \
++	src/core/emergency-action.h
+ 
+ nodist_libsystemd_core_la_SOURCES = \
+ 	src/core/load-fragment-gperf.c \
+diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c
+index 6d4713b..325ed13 100644
+--- a/src/core/dbus-service.c
++++ b/src/core/dbus-service.c
+@@ -34,7 +34,7 @@ static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, service_type, ServiceType
+ static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, service_result, ServiceResult);
+ static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_restart, service_restart, ServiceRestart);
+ static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_notify_access, notify_access, NotifyAccess);
+-static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_failure_action, failure_action, FailureAction);
++static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_emergency_action, emergency_action, EmergencyAction);
+ 
+ const sd_bus_vtable bus_service_vtable[] = {
+         SD_BUS_VTABLE_START(0),
+@@ -49,9 +49,9 @@ const sd_bus_vtable bus_service_vtable[] = {
+         BUS_PROPERTY_DUAL_TIMESTAMP("WatchdogTimestamp", offsetof(Service, watchdog_timestamp), 0),
+         SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Service, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Service, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
+-        SD_BUS_PROPERTY("StartLimitAction", "s", property_get_failure_action, offsetof(Service, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("StartLimitAction", "s", property_get_emergency_action, offsetof(Service, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Service, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
+-        SD_BUS_PROPERTY("FailureAction", "s", property_get_failure_action, offsetof(Service, failure_action), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("FailureAction", "s", property_get_emergency_action, offsetof(Service, emergency_action), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("PermissionsStartOnly", "b", bus_property_get_bool, offsetof(Service, permissions_start_only), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("RootDirectoryStartOnly", "b", bus_property_get_bool, offsetof(Service, root_directory_start_only), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("RemainAfterExit", "b", bus_property_get_bool, offsetof(Service, remain_after_exit), SD_BUS_VTABLE_PROPERTY_CONST),
+diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
+index c3654db..89b00e9 100644
+--- a/src/core/dbus-unit.c
++++ b/src/core/dbus-unit.c
+@@ -33,7 +33,7 @@
+ 
+ static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState);
+ static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode);
+-static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_failure_action, failure_action, FailureAction);
++static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_emergency_action, emergency_action, EmergencyAction);
+ 
+ static int property_get_names(
+                 sd_bus *bus,
+@@ -595,7 +595,7 @@ const sd_bus_vtable bus_unit_vtable[] = {
+         SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool, offsetof(Unit, ignore_on_snapshot), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
+-        SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_failure_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_emergency_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL, offsetof(Unit, job_timeout_reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+         SD_BUS_PROPERTY("AssertResult", "b", bus_property_get_bool, offsetof(Unit, assert_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+diff --git a/src/core/failure-action.c b/src/core/emergency-action.c
+similarity index 63%
+rename from src/core/failure-action.c
+rename to src/core/emergency-action.c
+index ce522a4..f07b125 100644
+--- a/src/core/failure-action.c
++++ b/src/core/emergency-action.c
+@@ -27,44 +27,45 @@
+ #include "bus-util.h"
+ #include "bus-error.h"
+ #include "special.h"
+-#include "failure-action.h"
++#include "emergency-action.h"
+ 
+-static void log_and_status(Manager *m, const char *message) {
+-        log_warning("%s", message);
++static void log_and_status(Manager *m, const char *message, const char *reason) {
++        log_warning("%s: %s", message, reason);
+         manager_status_printf(m, STATUS_TYPE_EMERGENCY,
+                               ANSI_HIGHLIGHT_RED_ON " !!  " ANSI_HIGHLIGHT_OFF,
+-                              "%s", message);
++                              "%s: %s", message, reason);
+ }
+ 
+-int failure_action(
++int emergency_action(
+                 Manager *m,
+-                FailureAction action,
+-                const char *reboot_arg) {
++                EmergencyAction action,
++                const char *reboot_arg,
++                const char *reason) {
+ 
+         int r;
+ 
+         assert(m);
+         assert(action >= 0);
+-        assert(action < _FAILURE_ACTION_MAX);
++        assert(action < _EMERGENCY_ACTION_MAX);
+ 
+-        if (action == FAILURE_ACTION_NONE)
++        if (action == EMERGENCY_ACTION_NONE)
+                 return -ECANCELED;
+ 
+         if (m->running_as == SYSTEMD_USER) {
+                 /* Downgrade all options to simply exiting if we run
+                  * in user mode */
+ 
+-                log_warning("Exiting as result of failure.");
++                log_warning("Exiting: %s", reason);
+                 m->exit_code = MANAGER_EXIT;
+                 return -ECANCELED;
+         }
+ 
+         switch (action) {
+ 
+-        case FAILURE_ACTION_REBOOT: {
++        case EMERGENCY_ACTION_REBOOT: {
+                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ 
+-                log_and_status(m, "Rebooting as result of failure.");
++                log_and_status(m, "Rebooting", reason);
+ 
+                 update_reboot_param_file(reboot_arg);
+                 r = manager_add_job_by_name(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE, true, &error, NULL);
+@@ -74,15 +75,15 @@ int failure_action(
+                 break;
+         }
+ 
+-        case FAILURE_ACTION_REBOOT_FORCE:
+-                log_and_status(m, "Forcibly rebooting as result of failure.");
++        case EMERGENCY_ACTION_REBOOT_FORCE:
++                log_and_status(m, "Forcibly rebooting", reason);
+ 
+                 update_reboot_param_file(reboot_arg);
+                 m->exit_code = MANAGER_REBOOT;
+                 break;
+ 
+-        case FAILURE_ACTION_REBOOT_IMMEDIATE:
+-                log_and_status(m, "Rebooting immediately as result of failure.");
++        case EMERGENCY_ACTION_REBOOT_IMMEDIATE:
++                log_and_status(m, "Rebooting immediately", reason);
+ 
+                 sync();
+ 
+@@ -95,10 +96,10 @@ int failure_action(
+                 reboot(RB_AUTOBOOT);
+                 break;
+ 
+-        case FAILURE_ACTION_POWEROFF: {
++        case EMERGENCY_ACTION_POWEROFF: {
+                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ 
+-                log_and_status(m, "Powering off as result of failure.");
++                log_and_status(m, "Powering off", reason);
+ 
+                 r = manager_add_job_by_name(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE, true, &error, NULL);
+                 if (r < 0)
+@@ -107,13 +108,13 @@ int failure_action(
+                 break;
+         }
+ 
+-        case FAILURE_ACTION_POWEROFF_FORCE:
+-                log_and_status(m, "Forcibly powering off as result of failure.");
++        case EMERGENCY_ACTION_POWEROFF_FORCE:
++                log_and_status(m, "Forcibly powering off", reason);
+                 m->exit_code = MANAGER_POWEROFF;
+                 break;
+ 
+-        case FAILURE_ACTION_POWEROFF_IMMEDIATE:
+-                log_and_status(m, "Powering off immediately as result of failure.");
++        case EMERGENCY_ACTION_POWEROFF_IMMEDIATE:
++                log_and_status(m, "Powering off immediately", reason);
+ 
+                 sync();
+ 
+@@ -122,19 +123,19 @@ int failure_action(
+                 break;
+ 
+         default:
+-                assert_not_reached("Unknown failure action");
++                assert_not_reached("Unknown emergency action");
+         }
+ 
+         return -ECANCELED;
+ }
+ 
+-static const char* const failure_action_table[_FAILURE_ACTION_MAX] = {
+-        [FAILURE_ACTION_NONE] = "none",
+-        [FAILURE_ACTION_REBOOT] = "reboot",
+-        [FAILURE_ACTION_REBOOT_FORCE] = "reboot-force",
+-        [FAILURE_ACTION_REBOOT_IMMEDIATE] = "reboot-immediate",
+-        [FAILURE_ACTION_POWEROFF] = "poweroff",
+-        [FAILURE_ACTION_POWEROFF_FORCE] = "poweroff-force",
+-        [FAILURE_ACTION_POWEROFF_IMMEDIATE] = "poweroff-immediate"
++static const char* const emergency_action_table[_EMERGENCY_ACTION_MAX] = {
++        [EMERGENCY_ACTION_NONE] = "none",
++        [EMERGENCY_ACTION_REBOOT] = "reboot",
++        [EMERGENCY_ACTION_REBOOT_FORCE] = "reboot-force",
++        [EMERGENCY_ACTION_REBOOT_IMMEDIATE] = "reboot-immediate",
++        [EMERGENCY_ACTION_POWEROFF] = "poweroff",
++        [EMERGENCY_ACTION_POWEROFF_FORCE] = "poweroff-force",
++        [EMERGENCY_ACTION_POWEROFF_IMMEDIATE] = "poweroff-immediate"
+ };
+-DEFINE_STRING_TABLE_LOOKUP(failure_action, FailureAction);
++DEFINE_STRING_TABLE_LOOKUP(emergency_action, EmergencyAction);
+diff --git a/src/core/failure-action.h b/src/core/emergency-action.h
+similarity index 58%
+rename from src/core/failure-action.h
+rename to src/core/emergency-action.h
+index 1af4dd9..d3ac0f3 100644
+--- a/src/core/failure-action.h
++++ b/src/core/emergency-action.h
+@@ -22,22 +22,22 @@
+   along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ ***/
+ 
+-typedef enum FailureAction {
+-        FAILURE_ACTION_NONE,
+-        FAILURE_ACTION_REBOOT,
+-        FAILURE_ACTION_REBOOT_FORCE,
+-        FAILURE_ACTION_REBOOT_IMMEDIATE,
+-        FAILURE_ACTION_POWEROFF,
+-        FAILURE_ACTION_POWEROFF_FORCE,
+-        FAILURE_ACTION_POWEROFF_IMMEDIATE,
+-        _FAILURE_ACTION_MAX,
+-        _FAILURE_ACTION_INVALID = -1
+-} FailureAction;
++typedef enum EmergencyAction {
++        EMERGENCY_ACTION_NONE,
++        EMERGENCY_ACTION_REBOOT,
++        EMERGENCY_ACTION_REBOOT_FORCE,
++        EMERGENCY_ACTION_REBOOT_IMMEDIATE,
++        EMERGENCY_ACTION_POWEROFF,
++        EMERGENCY_ACTION_POWEROFF_FORCE,
++        EMERGENCY_ACTION_POWEROFF_IMMEDIATE,
++        _EMERGENCY_ACTION_MAX,
++        _EMERGENCY_ACTION_INVALID = -1
++} EmergencyAction;
+ 
+ #include "macro.h"
+ #include "manager.h"
+ 
+-int failure_action(Manager *m, FailureAction action, const char *reboot_arg);
++int emergency_action(Manager *m, EmergencyAction action, const char *reboot_arg, const char *reason);
+ 
+-const char* failure_action_to_string(FailureAction i) _const_;
+-FailureAction failure_action_from_string(const char *s) _pure_;
++const char* emergency_action_to_string(EmergencyAction i) _const_;
++EmergencyAction emergency_action_from_string(const char *s) _pure_;
+diff --git a/src/core/job.c b/src/core/job.c
+index c2876de..7032864 100644
+--- a/src/core/job.c
++++ b/src/core/job.c
+@@ -916,7 +916,7 @@ static int job_dispatch_timer(sd_event_source *s, uint64_t monotonic, void *user
+         u = j->unit;
+         job_finish_and_invalidate(j, JOB_TIMEOUT, true, false);
+ 
+-        failure_action(u->manager, u->job_timeout_action, u->job_timeout_reboot_arg);
++        emergency_action(u->manager, u->job_timeout_action, u->job_timeout_reboot_arg, "job timed out");
+ 
+         return 0;
+ }
+diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
+index ce1397c..45d1ead 100644
+--- a/src/core/load-fragment-gperf.gperf.m4
++++ b/src/core/load-fragment-gperf.gperf.m4
+@@ -156,7 +156,7 @@ Unit.OnFailureIsolate,           config_parse_job_mode_isolate,      0,
+ Unit.IgnoreOnIsolate,            config_parse_bool,                  0,                             offsetof(Unit, ignore_on_isolate)
+ Unit.IgnoreOnSnapshot,           config_parse_bool,                  0,                             offsetof(Unit, ignore_on_snapshot)
+ Unit.JobTimeoutSec,              config_parse_sec,                   0,                             offsetof(Unit, job_timeout)
+-Unit.JobTimeoutAction,           config_parse_failure_action,        0,                             offsetof(Unit, job_timeout_action)
++Unit.JobTimeoutAction,           config_parse_emergency_action,        0,                             offsetof(Unit, job_timeout_action)
+ Unit.JobTimeoutRebootArgument,   config_parse_string,                0,                             offsetof(Unit, job_timeout_reboot_arg)
+ Unit.ConditionPathExists,        config_parse_unit_condition_path,   CONDITION_PATH_EXISTS,         offsetof(Unit, conditions)
+ Unit.ConditionPathExistsGlob,    config_parse_unit_condition_path,   CONDITION_PATH_EXISTS_GLOB,    offsetof(Unit, conditions)
+@@ -211,9 +211,9 @@ Service.TimeoutStopSec,          config_parse_service_timeout,       0,
+ Service.WatchdogSec,             config_parse_sec,                   0,                             offsetof(Service, watchdog_usec)
+ Service.StartLimitInterval,      config_parse_sec,                   0,                             offsetof(Service, start_limit.interval)
+ Service.StartLimitBurst,         config_parse_unsigned,              0,                             offsetof(Service, start_limit.burst)
+-Service.StartLimitAction,        config_parse_failure_action,        0,                             offsetof(Service, start_limit_action)
++Service.StartLimitAction,        config_parse_emergency_action,      0,                             offsetof(Service, start_limit_action)
+ Service.RebootArgument,          config_parse_string,                0,                             offsetof(Service, reboot_arg)
+-Service.FailureAction,           config_parse_failure_action,        0,                             offsetof(Service, failure_action)
++Service.FailureAction,           config_parse_emergency_action,      0,                             offsetof(Service, emergency_action)
+ Service.Type,                    config_parse_service_type,          0,                             offsetof(Service, type)
+ Service.Restart,                 config_parse_service_restart,       0,                             offsetof(Service, restart)
+ Service.PermissionsStartOnly,    config_parse_bool,                  0,                             offsetof(Service, permissions_start_only)
+diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
+index 83b6e7e..4fecb83 100644
+--- a/src/core/load-fragment.c
++++ b/src/core/load-fragment.c
+@@ -2382,7 +2382,7 @@ int config_parse_unit_condition_null(
+ }
+ 
+ DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
+-DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
++DEFINE_CONFIG_PARSE_ENUM(config_parse_emergency_action, emergency_action, EmergencyAction, "Failed to parse failure action specifier");
+ 
+ int config_parse_unit_requires_mounts_for(
+                 const char *unit,
+@@ -3931,7 +3931,7 @@ void unit_dump_config_items(FILE *f) {
+                 { config_parse_unit_slice,            "SLICE" },
+                 { config_parse_documentation,         "URL" },
+                 { config_parse_service_timeout,       "SECONDS" },
+-                { config_parse_failure_action,        "ACTION" },
++                { config_parse_emergency_action,      "ACTION" },
+                 { config_parse_set_status,            "STATUS" },
+                 { config_parse_service_sockets,       "SOCKETS" },
+                 { config_parse_environ,               "ENVIRON" },
+diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
+index 359794d..6114796 100644
+--- a/src/core/load-fragment.h
++++ b/src/core/load-fragment.h
+@@ -78,7 +78,7 @@ int config_parse_unit_condition_string(const char *unit, const char *filename, u
+ int config_parse_unit_condition_null(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+ int config_parse_kill_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+ int config_parse_notify_access(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+-int config_parse_failure_action(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
++int config_parse_emergency_action(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+ int config_parse_unit_requires_mounts_for(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+ int config_parse_syscall_filter(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+ int config_parse_syscall_archs(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+diff --git a/src/core/manager.h b/src/core/manager.h
+index 42be1fc..59913f4 100644
+--- a/src/core/manager.h
++++ b/src/core/manager.h
+@@ -85,7 +85,7 @@ typedef enum StatusType {
+ #include "unit-name.h"
+ #include "exit-status.h"
+ #include "show-status.h"
+-#include "failure-action.h"
++#include "emergency-action.h"
+ 
+ struct Manager {
+         /* Note that the set of units we know of is allowed to be
+diff --git a/src/core/service.c b/src/core/service.c
+index babd3c5..6e7baa7 100644
+--- a/src/core/service.c
++++ b/src/core/service.c
+@@ -1280,7 +1280,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
+ 
+         if (s->result != SERVICE_SUCCESS) {
+                 log_unit_warning(UNIT(s)->id, "%s failed.", UNIT(s)->id);
+-                failure_action(UNIT(s)->manager, s->failure_action, s->reboot_arg);
++                emergency_action(UNIT(s)->manager, s->emergency_action, s->reboot_arg, "service failed");
+         }
+ 
+         if (allow_restart &&
+@@ -1821,7 +1821,7 @@ static int service_start_limit_test(Service *s) {
+ 
+         log_unit_warning(UNIT(s)->id, "start request repeated too quickly for %s", UNIT(s)->id);
+ 
+-        return failure_action(UNIT(s)->manager, s->start_limit_action, s->reboot_arg);
++        return emergency_action(UNIT(s)->manager, s->start_limit_action, s->reboot_arg, "service failed");
+ }
+ 
+ static int service_start(Unit *u) {
+diff --git a/src/core/service.h b/src/core/service.h
+index dfeee6a..1f937df 100644
+--- a/src/core/service.h
++++ b/src/core/service.h
+@@ -29,7 +29,7 @@ typedef struct ServiceFDStore ServiceFDStore;
+ #include "ratelimit.h"
+ #include "kill.h"
+ #include "exit-status.h"
+-#include "failure-action.h"
++#include "emergency-action.h"
+ 
+ typedef enum ServiceState {
+         SERVICE_DEAD,
+@@ -197,8 +197,8 @@ struct Service {
+         int status_errno;
+ 
+         RateLimit start_limit;
+-        FailureAction start_limit_action;
+-        FailureAction failure_action;
++        EmergencyAction start_limit_action;
++        EmergencyAction emergency_action;
+         char *reboot_arg;
+ 
+         UnitRef accept_socket;
+diff --git a/src/core/unit.c b/src/core/unit.c
+index a7d6d2f..4eb0d78 100644
+--- a/src/core/unit.c
++++ b/src/core/unit.c
+@@ -937,8 +937,8 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
+         if (u->job_timeout > 0)
+                 fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout, 0));
+ 
+-        if (u->job_timeout_action != FAILURE_ACTION_NONE)
+-                fprintf(f, "%s\tJob Timeout Action: %s\n", prefix, failure_action_to_string(u->job_timeout_action));
++        if (u->job_timeout_action != EMERGENCY_ACTION_NONE)
++                fprintf(f, "%s\tJob Timeout Action: %s\n", prefix, emergency_action_to_string(u->job_timeout_action));
+ 
+         if (u->job_timeout_reboot_arg)
+                 fprintf(f, "%s\tJob Timeout Reboot Argument: %s\n", prefix, u->job_timeout_reboot_arg);
+diff --git a/src/core/unit.h b/src/core/unit.h
+index 35287a5..85f52df 100644
+--- a/src/core/unit.h
++++ b/src/core/unit.h
+@@ -41,7 +41,7 @@ typedef struct UnitStatusMessageFormats UnitStatusMessageFormats;
+ #include "condition.h"
+ #include "install.h"
+ #include "unit-name.h"
+-#include "failure-action.h"
++#include "emergency-action.h"
+ 
+ enum UnitActiveState {
+         UNIT_ACTIVE,
+@@ -121,7 +121,7 @@ struct Unit {
+ 
+         /* Job timeout and action to take */
+         usec_t job_timeout;
+-        FailureAction job_timeout_action;
++        EmergencyAction job_timeout_action;
+         char *job_timeout_reboot_arg;
+ 
+         /* References to this */
+diff --git a/src/test/test-tables.c b/src/test/test-tables.c
+index bda224b..e409790 100644
+--- a/src/test/test-tables.c
++++ b/src/test/test-tables.c
+@@ -67,7 +67,7 @@ int main(int argc, char **argv) {
+         test_table(device_state, DEVICE_STATE);
+         test_table(exec_input, EXEC_INPUT);
+         test_table(exec_output, EXEC_OUTPUT);
+-        test_table(failure_action, FAILURE_ACTION);
++        test_table(emergency_action, EMERGENCY_ACTION);
+         test_table(job_mode, JOB_MODE);
+         test_table(job_result, JOB_RESULT);
+         test_table(job_state, JOB_STATE);
diff --git a/SOURCES/0428-core-use-emergency_action-for-ctr-alt-del-burst.patch b/SOURCES/0428-core-use-emergency_action-for-ctr-alt-del-burst.patch
new file mode 100644
index 0000000..e7ca328
--- /dev/null
+++ b/SOURCES/0428-core-use-emergency_action-for-ctr-alt-del-burst.patch
@@ -0,0 +1,157 @@
+From 2170d1e510a9c30e71bc642b54d8b71fb01b47bc Mon Sep 17 00:00:00 2001
+From: Lukas Nykryn <lnykryn@redhat.com>
+Date: Tue, 18 Oct 2016 12:16:32 +0200
+Subject: [PATCH] core: use emergency_action for ctr+alt+del burst
+
+Fixes #4306
+
+Cherry-picked from: ae8c7939df962cbf660b2b9517fe46be272f58b9
+Resolves: #1353028
+---
+ man/systemd-system.conf.xml |  7 ++++---
+ src/core/main.c             |  7 +++----
+ src/core/manager.c          | 33 ++++-----------------------------
+ src/core/manager.h          | 13 +------------
+ 4 files changed, 12 insertions(+), 48 deletions(-)
+
+diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml
+index 236c20d..57b3b90 100644
+--- a/man/systemd-system.conf.xml
++++ b/man/systemd-system.conf.xml
+@@ -105,9 +105,10 @@
+         <term><varname>CtrlAltDelBurstAction=</varname></term>
+ 
+         <listitem><para>Defines what action will be performed
+-        if user presses Ctr-Alt-Delete more than 7 times in 2s.
+-        Can be set to <literal>reboot-force</literal>, <literal>poweroff-force</literal>
+-        or disabled with <literal>ignore</literal>. Defaults to
++        if user presses Ctrl-Alt-Delete more than 7 times in 2s.
++        Can be set to <literal>reboot-force</literal>, <literal>poweroff-force</literal>,
++        <literal>reboot-immediate</literal>, <literal>poweroff-immediate</literal>
++        or disabled with <literal>none</literal>. Defaults to
+         <literal>reboot-force</literal>.
+         </para></listitem>
+       </varlistentry>
+diff --git a/src/core/main.c b/src/core/main.c
+index 6ac9c9d..6f83676 100644
+--- a/src/core/main.c
++++ b/src/core/main.c
+@@ -77,6 +77,7 @@
+ #include "ima-setup.h"
+ #include "smack-setup.h"
+ #include "kmod-setup.h"
++#include "emergency-action.h"
+ 
+ static enum {
+         ACTION_RUN,
+@@ -115,7 +116,7 @@ static FILE* arg_serialization = NULL;
+ static bool arg_default_cpu_accounting = false;
+ static bool arg_default_blockio_accounting = false;
+ static bool arg_default_memory_accounting = false;
+-static CADBurstAction arg_cad_burst_action = CAD_BURST_ACTION_REBOOT;
++static EmergencyAction arg_cad_burst_action = EMERGENCY_ACTION_REBOOT_FORCE;
+ 
+ static void nop_handler(int sig) {}
+ 
+@@ -626,8 +627,6 @@ static int config_parse_join_controllers(const char *unit,
+         return 0;
+ }
+ 
+-static DEFINE_CONFIG_PARSE_ENUM(config_parse_cad_burst_action, cad_burst_action, CADBurstAction, "Failed to parse service restart specifier");
+-
+ static int parse_config_file(void) {
+ 
+         const ConfigTableItem items[] = {
+@@ -676,7 +675,7 @@ static int parse_config_file(void) {
+                 { "Manager", "DefaultCPUAccounting",      config_parse_bool,             0, &arg_default_cpu_accounting            },
+                 { "Manager", "DefaultBlockIOAccounting",  config_parse_bool,             0, &arg_default_blockio_accounting        },
+                 { "Manager", "DefaultMemoryAccounting",   config_parse_bool,             0, &arg_default_memory_accounting         },
+-                { "Manager", "CtrlAltDelBurstAction",     config_parse_cad_burst_action, 0, &arg_cad_burst_action},
++                { "Manager", "CtrlAltDelBurstAction",     config_parse_emergency_action, 0, &arg_cad_burst_action                  },
+                 {}
+         };
+ 
+diff --git a/src/core/manager.c b/src/core/manager.c
+index 9048dde..8bd80e6 100644
+--- a/src/core/manager.c
++++ b/src/core/manager.c
+@@ -1864,28 +1864,11 @@ static void manager_handle_ctrl_alt_del(Manager *m) {
+          * 7 times within 2s, we reboot/shutdown immediately,
+          * unless it was disabled in system.conf */
+ 
+-        if (ratelimit_test(&m->ctrl_alt_del_ratelimit) || m->cad_burst_action == CAD_BURST_ACTION_IGNORE)
++        if (ratelimit_test(&m->ctrl_alt_del_ratelimit) || m->cad_burst_action == EMERGENCY_ACTION_NONE)
+                 manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE_IRREVERSIBLY);
+-        else {
+-                switch (m->cad_burst_action) {
+-
+-                case CAD_BURST_ACTION_REBOOT:
+-                        m->exit_code = MANAGER_REBOOT;
+-                        break;
+-
+-                case CAD_BURST_ACTION_POWEROFF:
+-                        m->exit_code = MANAGER_POWEROFF;
+-                        break;
+-
+-                default:
+-                        assert_not_reached("Unknown action.");
+-                }
+-
+-                log_notice("Ctrl-Alt-Del was pressed more than 7 times within 2s, performing immediate %s.",
+-                                cad_burst_action_to_string(m->cad_burst_action));
+-                status_printf(NULL, true, false, "Ctrl-Alt-Del was pressed more than 7 times within 2s, performing immediate %s.",
+-                                cad_burst_action_to_string(m->cad_burst_action));
+-        }
++        else
++                emergency_action(m, m->cad_burst_action, NULL,
++                                "Ctrl-Alt-Del was pressed more than 7 times within 2s");
+ }
+ 
+ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
+@@ -3336,11 +3319,3 @@ static const char *const manager_state_table[_MANAGER_STATE_MAX] = {
+ };
+ 
+ DEFINE_STRING_TABLE_LOOKUP(manager_state, ManagerState);
+-
+-static const char *const cad_burst_action_table[_CAD_BURST_ACTION_MAX] = {
+-        [CAD_BURST_ACTION_IGNORE] = "ignore",
+-        [CAD_BURST_ACTION_REBOOT] = "reboot-force",
+-        [CAD_BURST_ACTION_POWEROFF] = "poweroff-force",
+-};
+-
+-DEFINE_STRING_TABLE_LOOKUP(cad_burst_action, CADBurstAction);
+diff --git a/src/core/manager.h b/src/core/manager.h
+index 59913f4..231c076 100644
+--- a/src/core/manager.h
++++ b/src/core/manager.h
+@@ -64,14 +64,6 @@ typedef enum ManagerExitCode {
+         _MANAGER_EXIT_CODE_INVALID = -1
+ } ManagerExitCode;
+ 
+-typedef enum CADBurstAction {
+-        CAD_BURST_ACTION_IGNORE,
+-        CAD_BURST_ACTION_REBOOT,
+-        CAD_BURST_ACTION_POWEROFF,
+-        _CAD_BURST_ACTION_MAX,
+-        _CAD_BURST_ACTION_INVALID = -1
+-} CADBurstAction;
+-
+ typedef enum StatusType {
+         STATUS_TYPE_EPHEMERAL,
+         STATUS_TYPE_NORMAL,
+@@ -310,7 +302,7 @@ struct Manager {
+ 
+         /* When the user hits C-A-D more than 7 times per 2s, do something immediately... */
+         RateLimit ctrl_alt_del_ratelimit;
+-        CADBurstAction cad_burst_action;
++        EmergencyAction cad_burst_action;
+ };
+ 
+ int manager_new(SystemdRunningAs running_as, bool test_run, Manager **m);
+@@ -381,6 +373,3 @@ ManagerState manager_state(Manager *m);
+ 
+ const char *manager_state_to_string(ManagerState m) _const_;
+ ManagerState manager_state_from_string(const char *s) _pure_;
+-
+-const char *cad_burst_action_to_string(CADBurstAction a) _const_;
+-CADBurstAction cad_burst_action_from_string(const char *s) _pure_;
diff --git a/SOURCES/0429-udev-path_id-introduce-support-for-NVMe-devices-4169.patch b/SOURCES/0429-udev-path_id-introduce-support-for-NVMe-devices-4169.patch
new file mode 100644
index 0000000..0ed438d
--- /dev/null
+++ b/SOURCES/0429-udev-path_id-introduce-support-for-NVMe-devices-4169.patch
@@ -0,0 +1,40 @@
+From ee5aadde983315e72a82241dee95c0e041af15f4 Mon Sep 17 00:00:00 2001
+From: Michal Sekletar <msekleta@redhat.com>
+Date: Fri, 6 Jan 2017 17:30:53 +0100
+Subject: [PATCH] udev/path_id: introduce support for NVMe devices (#4169)
+
+This appends the nvme name and namespace identifier attribute the the
+PCI path for by-path links. Symlinks like the following are now present:
+
+lrwxrwxrwx. 1 root root 13 Sep 16 12:12 pci-0000:01:00.0-nvme-1 -> ../../nvme0n1
+lrwxrwxrwx. 1 root root 15 Sep 16 12:12 pci-0000:01:00.0-nvme-1-part1 -> ../../nvme0n1p1
+
+Cc: Michal Sekletar <sekletar.m@gmail.com>
+Signed-off-by: Keith Busch <keith.busch@intel.com>
+
+Cherry-picked from: b4c6f71b827d41a4af8007b735edf21ef7609f99
+Resolves: #1373150
+---
+ src/udev/udev-builtin-path_id.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c
+index a3b019b..88a812f 100644
+--- a/src/udev/udev-builtin-path_id.c
++++ b/src/udev/udev-builtin-path_id.c
+@@ -709,6 +709,15 @@ restart:
+                         parent = skip_subsystem(parent, "scm");
+                         supported_transport = true;
+                         supported_parent = true;
++                } else if (streq(subsys, "nvme")) {
++                        const char *nsid = udev_device_get_sysattr_value(dev, "nsid");
++
++                        if (nsid) {
++                                path_prepend(&path, "nvme-%s", nsid);
++                                parent = skip_subsystem(parent, "nvme");
++                                supported_parent = true;
++                                supported_transport = true;
++                        }
+                 }
+ 
+                 parent = udev_device_get_parent(parent);
diff --git a/SOURCES/0430-core-fix-CapabilityBoundingSet-merging.patch b/SOURCES/0430-core-fix-CapabilityBoundingSet-merging.patch
new file mode 100644
index 0000000..73d8027
--- /dev/null
+++ b/SOURCES/0430-core-fix-CapabilityBoundingSet-merging.patch
@@ -0,0 +1,40 @@
+From 5c7d92d36bd1b608ccba0adc3fdc5446e6575623 Mon Sep 17 00:00:00 2001
+From: Evgeny Vereshchagin <evvers@ya.ru>
+Date: Tue, 27 Oct 2015 14:40:28 +0300
+Subject: [PATCH] core: fix CapabilityBoundingSet merging
+
+Fixes: #1221
+
+Cherry-picked from: b9d345b
+Resolves: #1409586
+---
+ src/core/load-fragment.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
+index 4fecb83..90d42b0 100644
+--- a/src/core/load-fragment.c
++++ b/src/core/load-fragment.c
+@@ -1027,6 +1027,7 @@ int config_parse_bounding_set(const char *unit,
+                               void *userdata) {
+ 
+         uint64_t *capability_bounding_set_drop = data;
++        uint64_t capability_bounding_set;
+         const char *word, *state;
+         size_t l;
+         bool invert = false;
+@@ -1067,10 +1068,11 @@ int config_parse_bounding_set(const char *unit,
+                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                            "Trailing garbage, ignoring.");
+ 
+-        if (invert)
+-                *capability_bounding_set_drop |= sum;
++        capability_bounding_set = invert ? ~sum : sum;
++        if (*capability_bounding_set_drop)
++                *capability_bounding_set_drop = ~(~*capability_bounding_set_drop | capability_bounding_set);
+         else
+-                *capability_bounding_set_drop |= ~sum;
++                *capability_bounding_set_drop = ~capability_bounding_set;
+ 
+         return 0;
+ }
diff --git a/SOURCES/0431-core-fix-capability-bounding-set-parsing.patch b/SOURCES/0431-core-fix-capability-bounding-set-parsing.patch
new file mode 100644
index 0000000..e7bb490
--- /dev/null
+++ b/SOURCES/0431-core-fix-capability-bounding-set-parsing.patch
@@ -0,0 +1,26 @@
+From 13b70c13553c94c444f149bd086bd3e8d9cc39b6 Mon Sep 17 00:00:00 2001
+From: Evgeny Vereshchagin <evvers@ya.ru>
+Date: Thu, 29 Oct 2015 14:13:04 +0300
+Subject: [PATCH] core: fix capability bounding set parsing
+
+bug: CapabilityBoundingSet= doesn't reset all caps
+
+Cherry-picked from: 661b37b
+Resolves: #1409586
+---
+ src/core/load-fragment.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
+index 90d42b0..7056419 100644
+--- a/src/core/load-fragment.c
++++ b/src/core/load-fragment.c
+@@ -1069,7 +1069,7 @@ int config_parse_bounding_set(const char *unit,
+                            "Trailing garbage, ignoring.");
+ 
+         capability_bounding_set = invert ? ~sum : sum;
+-        if (*capability_bounding_set_drop)
++        if (*capability_bounding_set_drop && capability_bounding_set)
+                 *capability_bounding_set_drop = ~(~*capability_bounding_set_drop | capability_bounding_set);
+         else
+                 *capability_bounding_set_drop = ~capability_bounding_set;
diff --git a/SOURCES/0432-core-make-parsing-of-RLIMIT_NICE-aware-of-actual-nic.patch b/SOURCES/0432-core-make-parsing-of-RLIMIT_NICE-aware-of-actual-nic.patch
new file mode 100644
index 0000000..a879e38
--- /dev/null
+++ b/SOURCES/0432-core-make-parsing-of-RLIMIT_NICE-aware-of-actual-nic.patch
@@ -0,0 +1,163 @@
+From c56c1f6c2b683d6f20a7e8caeecec6c3cb76798f Mon Sep 17 00:00:00 2001
+From: Lukas Nykryn <lnykryn@redhat.com>
+Date: Tue, 3 Jan 2017 14:21:25 +0100
+Subject: [PATCH] core: make parsing of RLIMIT_NICE aware of actual nice levels
+
+RHEL-only
+(most of code taken from 29857001854a02c292f1f3b324e7a66831e859c8)
+
+Resolves: #1409588
+---
+ man/systemd.exec.xml                  |  7 +++-
+ src/core/load-fragment-gperf.gperf.m4 |  2 +-
+ src/core/load-fragment.c              | 72 +++++++++++++++++++++++++++++++++++
+ src/core/load-fragment.h              |  1 +
+ src/core/main.c                       |  2 +-
+ 5 files changed, 81 insertions(+), 3 deletions(-)
+
+diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
+index 0cd469c..c5199d3 100644
+--- a/man/systemd.exec.xml
++++ b/man/systemd.exec.xml
+@@ -575,7 +575,12 @@
+         granularity of the limits might influence their
+         enforcement. For example, time limits specified for
+         <varname>LimitCPU=</varname> will be rounded up implicitly to
+-        multiples of 1s.</para>
++        multiples of 1s. For <varname>LimitNICE=</varname> the value
++        may be specified in two syntaxes: if prefixed with <literal>+</literal>
++        or <literal>-</literal>, the value is understood as regular Linux
++        nice value in the range -20..19. If not prefixed like this the value
++        is understood as raw resource limit parameter in the range 0..40 (with 0 being
++        equivalent to 1).</para>
+ 
+         <para>Note that most process resource limits configured with
+         these options are per-process, and processes may fork in order
+diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
+index 45d1ead..f3a6e13 100644
+--- a/src/core/load-fragment-gperf.gperf.m4
++++ b/src/core/load-fragment-gperf.gperf.m4
+@@ -71,7 +71,7 @@ $1.LimitMEMLOCK,                 config_parse_bytes_limit,           RLIMIT_MEML
+ $1.LimitLOCKS,                   config_parse_limit,                 RLIMIT_LOCKS,                  offsetof($1, exec_context.rlimit)
+ $1.LimitSIGPENDING,              config_parse_limit,                 RLIMIT_SIGPENDING,             offsetof($1, exec_context.rlimit)
+ $1.LimitMSGQUEUE,                config_parse_bytes_limit,           RLIMIT_MSGQUEUE,               offsetof($1, exec_context.rlimit)
+-$1.LimitNICE,                    config_parse_limit,                 RLIMIT_NICE,                   offsetof($1, exec_context.rlimit)
++$1.LimitNICE,                    config_parse_nice_limit,            RLIMIT_NICE,                   offsetof($1, exec_context.rlimit)
+ $1.LimitRTPRIO,                  config_parse_limit,                 RLIMIT_RTPRIO,                 offsetof($1, exec_context.rlimit)
+ $1.LimitRTTIME,                  config_parse_usec_limit,            RLIMIT_RTTIME,                 offsetof($1, exec_context.rlimit)
+ $1.ReadWriteDirectories,         config_parse_namespace_path_strv,   0,                             offsetof($1, exec_context.read_write_dirs)
+diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
+index 7056419..3a3c456 100644
+--- a/src/core/load-fragment.c
++++ b/src/core/load-fragment.c
+@@ -1154,6 +1154,56 @@ static int rlim_parse_usec(const char *val, rlim_t *res) {
+         return r;
+ }
+ 
++static int rlim_parse_nice(const char *val, rlim_t *ret) {
++        uint64_t rl;
++        int r;
++
++        /* So, Linux is weird. The range for RLIMIT_NICE is 40..1, mapping to the nice levels -20..19. However, the
++         * RLIMIT_NICE limit defaults to 0 by the kernel, i.e. a value that maps to nice level 20, which of course is
++         * bogus and does not exist. In order to permit parsing the RLIMIT_NICE of 0 here we hence implement a slight
++         * asymmetry: when parsing as positive nice level we permit 0..19. When parsing as negative nice level, we
++         * permit -20..0. But when parsing as raw resource limit value then we also allow the special value 0.
++         *
++         * Yeah, Linux is quality engineering sometimes... */
++
++        if (val[0] == '+') {
++
++                /* Prefixed with "+": Parse as positive user-friendly nice value */
++                r = safe_atou64(val + 1, &rl);
++                if (r < 0)
++                        return r;
++
++                if (rl >= PRIO_MAX)
++                        return -ERANGE;
++
++                rl = 20 - rl;
++
++        } else if (val[0] == '-') {
++
++                /* Prefixed with "-": Parse as negative user-friendly nice value */
++                r = safe_atou64(val + 1, &rl);
++                if (r < 0)
++                        return r;
++
++                if (rl > (uint64_t) (-PRIO_MIN))
++                        return -ERANGE;
++
++                rl = 20 + rl;
++        } else {
++
++                /* Not prefixed: parse as raw resource limit value */
++                r = safe_atou64(val, &rl);
++                if (r < 0)
++                        return r;
++
++                if (rl > (uint64_t) (20 - PRIO_MIN))
++                        return -ERANGE;
++        }
++
++        *ret = (rlim_t) rl;
++        return 0;
++}
++
+ static int parse_rlimit_range(
+                 const char *unit,
+                 const char *filename,
+@@ -1286,6 +1336,28 @@ int config_parse_usec_limit(
+         return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_usec);
+ }
+ 
++int config_parse_nice_limit(
++                const char *unit,
++                const char *filename,
++                unsigned line,
++                const char *section,
++                unsigned section_line,
++                const char *lvalue,
++                int ltype,
++                const char *rvalue,
++                void *data,
++                void *userdata) {
++
++        struct rlimit **rl = data;
++
++        assert(filename);
++        assert(lvalue);
++        assert(rvalue);
++        assert(data);
++
++        rl += ltype;
++        return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_nice);
++}
+ 
+ #ifdef HAVE_SYSV_COMPAT
+ int config_parse_sysv_priority(const char *unit,
+diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
+index 6114796..7c69e53 100644
+--- a/src/core/load-fragment.h
++++ b/src/core/load-fragment.h
+@@ -59,6 +59,7 @@ int config_parse_limit(const char *unit, const char *filename, unsigned line, co
+ int config_parse_bytes_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+ int config_parse_sec_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+ int config_parse_usec_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
++int config_parse_nice_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+ int config_parse_sysv_priority(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+ int config_parse_kill_signal(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+ int config_parse_exec_mount_flags(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+diff --git a/src/core/main.c b/src/core/main.c
+index 6f83676..820cbc3 100644
+--- a/src/core/main.c
++++ b/src/core/main.c
+@@ -669,7 +669,7 @@ static int parse_config_file(void) {
+                 { "Manager", "DefaultLimitLOCKS",         config_parse_limit,            0, &arg_default_rlimit[RLIMIT_LOCKS]      },
+                 { "Manager", "DefaultLimitSIGPENDING",    config_parse_limit,            0, &arg_default_rlimit[RLIMIT_SIGPENDING] },
+                 { "Manager", "DefaultLimitMSGQUEUE",      config_parse_bytes_limit,      0, &arg_default_rlimit[RLIMIT_MSGQUEUE]   },
+-                { "Manager", "DefaultLimitNICE",          config_parse_limit,            0, &arg_default_rlimit[RLIMIT_NICE]       },
++                { "Manager", "DefaultLimitNICE",          config_parse_nice_limit,       0, &arg_default_rlimit[RLIMIT_NICE]       },
+                 { "Manager", "DefaultLimitRTPRIO",        config_parse_limit,            0, &arg_default_rlimit[RLIMIT_RTPRIO]     },
+                 { "Manager", "DefaultLimitRTTIME",        config_parse_limit,            0, &arg_default_rlimit[RLIMIT_RTTIME]     },
+                 { "Manager", "DefaultCPUAccounting",      config_parse_bool,             0, &arg_default_cpu_accounting            },
diff --git a/SOURCES/0433-shared-fix-double-free-in-unmask-5005.patch b/SOURCES/0433-shared-fix-double-free-in-unmask-5005.patch
new file mode 100644
index 0000000..cf8fa4f
--- /dev/null
+++ b/SOURCES/0433-shared-fix-double-free-in-unmask-5005.patch
@@ -0,0 +1,42 @@
+From 45f3c8e04093a1ed871eb67aa4c1c28b11d3346c Mon Sep 17 00:00:00 2001
+From: Jan Synacek <jan.synacek@gmail.com>
+Date: Tue, 3 Jan 2017 21:34:36 +0100
+Subject: [PATCH] shared: fix double free in unmask (#5005)
+
+Easily reproducible:
+1) systemctl mask foo
+2) systemctl unmask foo foo
+
+The problem here is that the *i that is put into todo[] is later freed
+in strv_uniq(), which is not directly visible from this patch. Somewhere
+further in the code, the string that *i pointed to is freed again. That
+happens only when multiple services with the same name/path are specified.
+
+(cherry picked from commit dc7dd61de610e9330abe7014860acfa733887d5e)
+Resolves: #1409997
+---
+ src/shared/install.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/shared/install.c b/src/shared/install.c
+index f01a212..1b59a96 100644
+--- a/src/shared/install.c
++++ b/src/shared/install.c
+@@ -1602,7 +1602,7 @@ int unit_file_unmask(
+ 
+         _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
+         _cleanup_free_ char *config_path = NULL;
+-        _cleanup_free_ char **todo = NULL;
++        _cleanup_strv_free_ char **todo = NULL;
+         size_t n_todo = 0, n_allocated = 0;
+         char **i;
+         int r, q;
+@@ -1639,7 +1639,7 @@ int unit_file_unmask(
+                 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
+                         return -ENOMEM;
+ 
+-                todo[n_todo++] = *i;
++                todo[n_todo++] = strdup(*i);
+         }
+ 
+         strv_uniq(todo);
diff --git a/SOURCES/0434-shared-fix-double-free-in-link.patch b/SOURCES/0434-shared-fix-double-free-in-link.patch
new file mode 100644
index 0000000..3bde215
--- /dev/null
+++ b/SOURCES/0434-shared-fix-double-free-in-link.patch
@@ -0,0 +1,118 @@
+From 7ac4fc60181cfc7ff06e696da78e1b2819580745 Mon Sep 17 00:00:00 2001
+From: Evgeny Vereshchagin <evvers@ya.ru>
+Date: Mon, 9 Jan 2017 04:46:11 +0000
+Subject: [PATCH] shared: fix double free in link
+
+Fixes:
+```
+touch hola.service
+systemctl link $(pwd)/hola.service $(pwd)/hola.service
+```
+
+```
+==1==ERROR: AddressSanitizer: attempting double-free on 0x60300002c560 in thread T0 (systemd):
+    #0 0x7fc8c961cb00 in free (/lib64/libasan.so.3+0xc6b00)
+    #1 0x7fc8c90ebd3b in strv_clear src/basic/strv.c:83
+    #2 0x7fc8c90ebdb6 in strv_free src/basic/strv.c:89
+    #3 0x55637c758c77 in strv_freep src/basic/strv.h:37
+    #4 0x55637c763ba9 in method_enable_unit_files_generic src/core/dbus-manager.c:1960
+    #5 0x55637c763d16 in method_link_unit_files src/core/dbus-manager.c:2001
+    #6 0x7fc8c92537ec in method_callbacks_run src/libsystemd/sd-bus/bus-objects.c:418
+    #7 0x7fc8c9258830 in object_find_and_run src/libsystemd/sd-bus/bus-objects.c:1255
+    #8 0x7fc8c92594d7 in bus_process_object src/libsystemd/sd-bus/bus-objects.c:1371
+    #9 0x7fc8c91e7553 in process_message src/libsystemd/sd-bus/sd-bus.c:2563
+    #10 0x7fc8c91e78ce in process_running src/libsystemd/sd-bus/sd-bus.c:2605
+    #11 0x7fc8c91e8f61 in bus_process_internal src/libsystemd/sd-bus/sd-bus.c:2837
+    #12 0x7fc8c91e90d2 in sd_bus_process src/libsystemd/sd-bus/sd-bus.c:2856
+    #13 0x7fc8c91ea8f9 in io_callback src/libsystemd/sd-bus/sd-bus.c:3126
+    #14 0x7fc8c928333b in source_dispatch src/libsystemd/sd-event/sd-event.c:2268
+    #15 0x7fc8c9285cf7 in sd_event_dispatch src/libsystemd/sd-event/sd-event.c:2627
+    #16 0x7fc8c92865fa in sd_event_run src/libsystemd/sd-event/sd-event.c:2686
+    #17 0x55637c6b5257 in manager_loop src/core/manager.c:2274
+    #18 0x55637c6a2194 in main src/core/main.c:1920
+    #19 0x7fc8c7ac7400 in __libc_start_main (/lib64/libc.so.6+0x20400)
+    #20 0x55637c697339 in _start (/usr/lib/systemd/systemd+0xcd339)
+
+0x60300002c560 is located 0 bytes inside of 19-byte region [0x60300002c560,0x60300002c573)
+freed by thread T0 (systemd) here:
+    #0 0x7fc8c961cb00 in free (/lib64/libasan.so.3+0xc6b00)
+    #1 0x7fc8c90ee320 in strv_remove src/basic/strv.c:630
+    #2 0x7fc8c90ee190 in strv_uniq src/basic/strv.c:602
+    #3 0x7fc8c9180533 in unit_file_link src/shared/install.c:1996
+    #4 0x55637c763b25 in method_enable_unit_files_generic src/core/dbus-manager.c:1985
+    #5 0x55637c763d16 in method_link_unit_files src/core/dbus-manager.c:2001
+    #6 0x7fc8c92537ec in method_callbacks_run src/libsystemd/sd-bus/bus-objects.c:418
+    #7 0x7fc8c9258830 in object_find_and_run src/libsystemd/sd-bus/bus-objects.c:1255
+    #8 0x7fc8c92594d7 in bus_process_object src/libsystemd/sd-bus/bus-objects.c:1371
+    #9 0x7fc8c91e7553 in process_message src/libsystemd/sd-bus/sd-bus.c:2563
+    #10 0x7fc8c91e78ce in process_running src/libsystemd/sd-bus/sd-bus.c:2605
+    #11 0x7fc8c91e8f61 in bus_process_internal src/libsystemd/sd-bus/sd-bus.c:2837
+    #12 0x7fc8c91e90d2 in sd_bus_process src/libsystemd/sd-bus/sd-bus.c:2856
+    #13 0x7fc8c91ea8f9 in io_callback src/libsystemd/sd-bus/sd-bus.c:3126
+    #14 0x7fc8c928333b in source_dispatch src/libsystemd/sd-event/sd-event.c:2268
+    #15 0x7fc8c9285cf7 in sd_event_dispatch src/libsystemd/sd-event/sd-event.c:2627
+    #16 0x7fc8c92865fa in sd_event_run src/libsystemd/sd-event/sd-event.c:2686
+    #17 0x55637c6b5257 in manager_loop src/core/manager.c:2274
+    #18 0x55637c6a2194 in main src/core/main.c:1920
+        #19 0x7fc8c7ac7400 in __libc_start_main (/lib64/libc.so.6+0x20400)
+
+previously allocated by thread T0 (systemd) here:
+    #0 0x7fc8c95b0160 in strdup (/lib64/libasan.so.3+0x5a160)
+    #1 0x7fc8c90edf32 in strv_extend src/basic/strv.c:552
+    #2 0x7fc8c923ae41 in bus_message_read_strv_extend src/libsystemd/sd-bus/bus-message.c:5578
+    #3 0x7fc8c923b0de in sd_bus_message_read_strv src/libsystemd/sd-bus/bus-message.c:5600
+    #4 0x55637c7639d1 in method_enable_unit_files_generic src/core/dbus-manager.c:1969
+    #5 0x55637c763d16 in method_link_unit_files src/core/dbus-manager.c:2001
+    #6 0x7fc8c92537ec in method_callbacks_run src/libsystemd/sd-bus/bus-objects.c:418
+    #7 0x7fc8c9258830 in object_find_and_run src/libsystemd/sd-bus/bus-objects.c:1255
+    #8 0x7fc8c92594d7 in bus_process_object src/libsystemd/sd-bus/bus-objects.c:1371
+    #9 0x7fc8c91e7553 in process_message src/libsystemd/sd-bus/sd-bus.c:2563
+    #10 0x7fc8c91e78ce in process_running src/libsystemd/sd-bus/sd-bus.c:2605
+    #11 0x7fc8c91e8f61 in bus_process_internal src/libsystemd/sd-bus/sd-bus.c:2837
+    #12 0x7fc8c91e90d2 in sd_bus_process src/libsystemd/sd-bus/sd-bus.c:2856
+    #13 0x7fc8c91ea8f9 in io_callback src/libsystemd/sd-bus/sd-bus.c:3126
+    #14 0x7fc8c928333b in source_dispatch src/libsystemd/sd-event/sd-event.c:2268
+    #15 0x7fc8c9285cf7 in sd_event_dispatch src/libsystemd/sd-event/sd-event.c:2627
+    #16 0x7fc8c92865fa in sd_event_run src/libsystemd/sd-event/sd-event.c:2686
+    #17 0x55637c6b5257 in manager_loop src/core/manager.c:2274
+    #18 0x55637c6a2194 in main src/core/main.c:1920
+    #19 0x7fc8c7ac7400 in __libc_start_main (/lib64/libc.so.6+0x20400)
+
+SUMMARY: AddressSanitizer: double-free (/lib64/libasan.so.3+0xc6b00) in free
+==1==ABORTING
+```
+
+Closes #5015
+
+(cherry picked from commit 8af35ba681116eb79a46e3dbd65b166c1efd6164)
+Related: #1409997
+---
+ src/shared/install.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/src/shared/install.c b/src/shared/install.c
+index 1b59a96..87d805c 100644
+--- a/src/shared/install.c
++++ b/src/shared/install.c
+@@ -1682,7 +1682,7 @@ int unit_file_link(
+ 
+         _cleanup_lookup_paths_free_ LookupPaths paths = {};
+         _cleanup_free_ char *config_path = NULL;
+-        _cleanup_free_ char **todo = NULL;
++        _cleanup_strv_free_ char **todo = NULL;
+         size_t n_todo = 0, n_allocated = 0;
+         char **i;
+         int r,q;
+@@ -1736,7 +1736,11 @@ int unit_file_link(
+                 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
+                         return -ENOMEM;
+ 
+-                todo[n_todo++] = *i;
++                todo[n_todo] = strdup(*i);
++                if (!todo[n_todo])
++                        return -ENOMEM;
++
++                n_todo++;
+         }
+ 
+         strv_uniq(todo);
diff --git a/SOURCES/0435-shared-check-strdup-NULL.patch b/SOURCES/0435-shared-check-strdup-NULL.patch
new file mode 100644
index 0000000..0cf5a0e
--- /dev/null
+++ b/SOURCES/0435-shared-check-strdup-NULL.patch
@@ -0,0 +1,30 @@
+From eb591ab12405209edb498c9c57ddf76862c237c5 Mon Sep 17 00:00:00 2001
+From: Evgeny Vereshchagin <evvers@ya.ru>
+Date: Mon, 9 Jan 2017 22:45:41 +0000
+Subject: [PATCH] shared: check strdup != NULL
+
+This is a follow-up for dc7dd61de610e9330
+
+(cherry picked from commit d054eae6c954baa857170bb60072c8a2ecea0d6b)
+Related: #1409997
+---
+ src/shared/install.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/src/shared/install.c b/src/shared/install.c
+index 87d805c..62bdf67 100644
+--- a/src/shared/install.c
++++ b/src/shared/install.c
+@@ -1639,7 +1639,11 @@ int unit_file_unmask(
+                 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
+                         return -ENOMEM;
+ 
+-                todo[n_todo++] = strdup(*i);
++                todo[n_todo] = strdup(*i);
++                if (!todo[n_todo])
++                        return -ENOMEM;
++
++                n_todo++;
+         }
+ 
+         strv_uniq(todo);
diff --git a/SOURCES/0436-core-improve-error-message-when-RefuseManualStart-St.patch b/SOURCES/0436-core-improve-error-message-when-RefuseManualStart-St.patch
new file mode 100644
index 0000000..1f9b9bc
--- /dev/null
+++ b/SOURCES/0436-core-improve-error-message-when-RefuseManualStart-St.patch
@@ -0,0 +1,39 @@
+From 92ff0ade63ae85c6b6170af7b1209aaf37298ab1 Mon Sep 17 00:00:00 2001
+From: Jan Synacek <jan.synacek@gmail.com>
+Date: Tue, 24 Jan 2017 04:06:05 +0100
+Subject: [PATCH] core: improve error message when RefuseManualStart(Stop) is
+ hit (#5132)
+
+(cherry picked from commit 7e974e8530e3605db8186bd0c33bf36087e24e22)
+Resolves: #1026648
+---
+ src/core/dbus-unit.c | 2 +-
+ src/core/dbus.c      | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
+index 89b00e9..056a17a 100644
+--- a/src/core/dbus-unit.c
++++ b/src/core/dbus-unit.c
+@@ -843,7 +843,7 @@ int bus_unit_queue_job(
+         if ((type == JOB_START && u->refuse_manual_start) ||
+             (type == JOB_STOP && u->refuse_manual_stop) ||
+             ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)))
+-                return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id);
++                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, true, error, &j);
+         if (r < 0)
+diff --git a/src/core/dbus.c b/src/core/dbus.c
+index 29524d4..0061211 100644
+--- a/src/core/dbus.c
++++ b/src/core/dbus.c
+@@ -187,7 +187,7 @@ static int signal_activation_request(sd_bus *bus, sd_bus_message *message, void
+                 goto failed;
+ 
+         if (u->refuse_manual_start) {
+-                r = sd_bus_error_setf(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, %s may be requested by dependency only.", u->id);
++                r = sd_bus_error_setf(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, %s may be requested by dependency only (it is configured to refuse manual start/stop).", u->id);
+                 goto failed;
+         }
+ 
diff --git a/SOURCES/0437-systemctl-fix-is-enabled-exit-status-on-failure-when.patch b/SOURCES/0437-systemctl-fix-is-enabled-exit-status-on-failure-when.patch
new file mode 100644
index 0000000..132dc06
--- /dev/null
+++ b/SOURCES/0437-systemctl-fix-is-enabled-exit-status-on-failure-when.patch
@@ -0,0 +1,25 @@
+From e8507d683bce9dd61adc3fa5d19ec35e3caadff9 Mon Sep 17 00:00:00 2001
+From: Franck Bui <fbui@suse.com>
+Date: Wed, 30 Nov 2016 18:27:42 +0100
+Subject: [PATCH] systemctl: fix 'is-enabled' exit status on failure when
+ executed in chroot (#4773)
+
+(cherry picked from commit c5024cd05c194b93ae960bf38e567d3d998f2a03)
+Resolves: #1413964
+---
+ 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 a578897..1e1009f 100644
+--- a/src/systemctl/systemctl.c
++++ b/src/systemctl/systemctl.c
+@@ -5739,7 +5739,7 @@ static int unit_is_enabled(sd_bus *bus, char **args) {
+ 
+                         r = unit_file_get_state(arg_scope, arg_root, *name, &state);
+                         if (r < 0)
+-                                return log_error_errno(state, "Failed to get unit file state for %s: %m", *name);
++                                return log_error_errno(r, "Failed to get unit file state for %s: %m", *name);
+ 
+                         if (state == UNIT_FILE_ENABLED ||
+                             state == UNIT_FILE_ENABLED_RUNTIME ||
diff --git a/SOURCES/0438-man-document-that-the-automatic-journal-limits-are-c.patch b/SOURCES/0438-man-document-that-the-automatic-journal-limits-are-c.patch
new file mode 100644
index 0000000..68cbd5c
--- /dev/null
+++ b/SOURCES/0438-man-document-that-the-automatic-journal-limits-are-c.patch
@@ -0,0 +1,26 @@
+From 4464cd08f503af0459d779d92fb943aa3ef3f9a5 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Sat, 3 Oct 2015 11:34:11 +0200
+Subject: [PATCH] man: document that the automatic journal limits are capped to
+ 4G by default
+
+(cherry picked from commit 32252660954804747ae6b64c3921d5cb9a1c09c9)
+Resolves: #1418547
+---
+ man/journald.conf.xml | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/man/journald.conf.xml b/man/journald.conf.xml
+index c4f71e8..46a498b 100644
+--- a/man/journald.conf.xml
++++ b/man/journald.conf.xml
+@@ -210,7 +210,8 @@
+         and use the smaller of the two values.</para>
+ 
+         <para>The first pair defaults to 10% and the second to 15% of
+-        the size of the respective file system. If the file system is
++        the size of the respective file system, but each value
++        is capped to 4G. If the file system is
+         nearly full and either <varname>SystemKeepFree=</varname> or
+         <varname>RuntimeKeepFree=</varname> is violated when
+         systemd-journald is started, the value will be raised to
diff --git a/SOURCES/0439-random-seed-raise-POOL_SIZE_MIN-to-1024.patch b/SOURCES/0439-random-seed-raise-POOL_SIZE_MIN-to-1024.patch
new file mode 100644
index 0000000..f5492ba
--- /dev/null
+++ b/SOURCES/0439-random-seed-raise-POOL_SIZE_MIN-to-1024.patch
@@ -0,0 +1,23 @@
+From 6a4ea99f07b32659362c9a1a38be8bec2bb0964c Mon Sep 17 00:00:00 2001
+From: Jan Synacek <jsynacek@redhat.com>
+Date: Wed, 25 Jan 2017 08:39:15 +0100
+Subject: [PATCH] random-seed: raise POOL_SIZE_MIN to 1024
+
+Resolves: #1386824
+---
+ src/random-seed/random-seed.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/random-seed/random-seed.c b/src/random-seed/random-seed.c
+index ce1bd19..3ccc8f6 100644
+--- a/src/random-seed/random-seed.c
++++ b/src/random-seed/random-seed.c
+@@ -29,7 +29,7 @@
+ #include "util.h"
+ #include "mkdir.h"
+ 
+-#define POOL_SIZE_MIN 512
++#define POOL_SIZE_MIN 1024
+ 
+ int main(int argc, char *argv[]) {
+         _cleanup_close_ int seed_fd = -1, random_fd = -1;
diff --git a/SOURCES/0440-bash-completion-add-support-for-now-5155.patch b/SOURCES/0440-bash-completion-add-support-for-now-5155.patch
new file mode 100644
index 0000000..b8449e6
--- /dev/null
+++ b/SOURCES/0440-bash-completion-add-support-for-now-5155.patch
@@ -0,0 +1,24 @@
+From 88cc61d44a1567fd81e073defa01fc351051fec5 Mon Sep 17 00:00:00 2001
+From: Jan Synacek <jan.synacek@gmail.com>
+Date: Wed, 25 Jan 2017 13:44:04 +0100
+Subject: [PATCH] bash-completion: add support for --now (#5155)
+
+(cherry picked from commit 0067c7b29ab996bf99cf1bafe63c118b9b6d5b56)
+Resolves: #1351806
+---
+ shell-completion/bash/systemctl.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/shell-completion/bash/systemctl.in b/shell-completion/bash/systemctl.in
+index 0a022c4..a1dde32 100644
+--- a/shell-completion/bash/systemctl.in
++++ b/shell-completion/bash/systemctl.in
+@@ -91,7 +91,7 @@ _systemctl () {
+ 
+         local -A OPTS=(
+                [STANDALONE]='--all -a --reverse --after --before --defaults --fail --ignore-dependencies --failed --force -f --full -l --global
+-                             --help -h --no-ask-password --no-block --no-legend --no-pager --no-reload --no-wall
++                             --help -h --no-ask-password --no-block --no-legend --no-pager --no-reload --no-wall --now
+                              --quiet -q --privileged -P --system --version --runtime --recursive -r'
+                       [ARG]='--host -H --kill-who --property -p --signal -s --type -t --state --root'
+         )
diff --git a/SOURCES/0441-basic-fix-touch-creating-files-with-07777-mode.patch b/SOURCES/0441-basic-fix-touch-creating-files-with-07777-mode.patch
new file mode 100644
index 0000000..0477fc7
--- /dev/null
+++ b/SOURCES/0441-basic-fix-touch-creating-files-with-07777-mode.patch
@@ -0,0 +1,30 @@
+From 616db6ddcacd25e4c3a771cd317373971c9055ed Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Mantas=20Mikul=C4=97nas?= <grawity@gmail.com>
+Date: Fri, 29 Jan 2016 23:36:08 +0200
+Subject: [PATCH] basic: fix touch() creating files with 07777 mode
+
+mode_t is unsigned, so MODE_INVALID < 0 can never be true.
+
+This fixes a possible DoS where any user could fill /run by writing to
+a world-writable /run/systemd/show-status.
+
+Cherry-picked from: 06eeacb6fe029804f296b065b3ce91e796e1cd0e
+Resolves: #1416062
+---
+ src/shared/util.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/src/shared/util.c b/src/shared/util.c
+index 66729f7..1070e32 100644
+--- a/src/shared/util.c
++++ b/src/shared/util.c
+@@ -3908,7 +3908,8 @@ int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gi
+         if (parents)
+                 mkdir_parents(path, 0755);
+ 
+-        fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode > 0 ? mode : 0644);
++        fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY,
++                        (mode == 0 || mode == MODE_INVALID) ? 0644 : mode);
+         if (fd < 0)
+                 return -errno;
+ 
diff --git a/SOURCES/0442-udev-net_id-add-support-for-phys_port_name-attribute.patch b/SOURCES/0442-udev-net_id-add-support-for-phys_port_name-attribute.patch
new file mode 100644
index 0000000..f977bc4
--- /dev/null
+++ b/SOURCES/0442-udev-net_id-add-support-for-phys_port_name-attribute.patch
@@ -0,0 +1,97 @@
+From 192545bc67fed763ac54761ca067b9c2f93ecdd1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ji=C5=99=C3=AD=20P=C3=ADrko?= <jiri@resnulli.us>
+Date: Wed, 2 Nov 2016 03:46:01 +0100
+Subject: [PATCH] udev: net_id: add support for phys_port_name attribute
+ (#4506)
+
+Switch drivers uses phys_port_name attribute to pass front panel port
+name to user. Use it to generate netdev names.
+
+Signed-off-by: Jiri Pirko <jiri@mellanox.com>
+
+Cherry-picked from: 4887b656c22af059d4e833de7b56544f24951184
+Resolves: #1392426
+---
+ src/udev/udev-builtin-net_id.c | 24 ++++++++++++++++++------
+ 1 file changed, 18 insertions(+), 6 deletions(-)
+
+diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
+index 19e1f26..7c15435 100644
+--- a/src/udev/udev-builtin-net_id.c
++++ b/src/udev/udev-builtin-net_id.c
+@@ -38,7 +38,7 @@
+  *   o<index>[d<dev_port>]                 -- on-board device index number
+  *   s<slot>[f<function>][d<dev_port>]     -- hotplug slot index number
+  *   x<MAC>                                -- MAC address
+- *   [P<domain>]p<bus>s<slot>[f<function>][d<dev_id>/<dev_port>]
++ *   [P<domain>]p<bus>s<slot>[f<function>][n<phys_port_name>|d<dev_id>/<dev_port>]
+  *                                         -- PCI geographical location
+  *   [P<domain>]p<bus>s<slot>[f<function>][u<port>][..][c<config>][i<interface>]
+  *                                         -- USB port number chain
+@@ -134,7 +134,7 @@ static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) {
+         unsigned dev_port = 0;
+         size_t l;
+         char *s;
+-        const char *attr;
++        const char *attr, *port_name;
+         int idx;
+ 
+         /* ACPI _DSM  -- device specific method for naming a PCI or PCI Express device */
+@@ -161,10 +161,15 @@ static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) {
+         if (attr)
+                 dev_port = strtol(attr, NULL, 10);
+ 
++        /* kernel provided front panel port name for multiple port PCI device */
++        port_name = udev_device_get_sysattr_value(dev, "phys_port_name");
++
+         s = names->pci_onboard;
+         l = sizeof(names->pci_onboard);
+         l = strpcpyf(&s, l, "o%d", idx);
+-        if (dev_port > 0)
++        if (port_name)
++                l = strpcpyf(&s, l, "n%s", port_name);
++        else if (dev_port > 0)
+                 l = strpcpyf(&s, l, "d%d", dev_port);
+         if (l == 0)
+                 names->pci_onboard[0] = '\0';
+@@ -199,7 +204,7 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
+         unsigned domain, bus, slot, func, dev_id = 0;
+         size_t l;
+         char *s;
+-        const char *attr;
++        const char *attr, *port_name;
+         struct udev_device *pci = NULL;
+         char slots[256], str[256];
+         _cleanup_closedir_ DIR *dir = NULL;
+@@ -220,6 +225,9 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
+                 }
+         }
+ 
++        /* kernel provided front panel port name for multiple port PCI device */
++        port_name = udev_device_get_sysattr_value(dev, "phys_port_name");
++
+         /* compose a name based on the raw kernel's PCI bus, slot numbers */
+         s = names->pci_path;
+         l = sizeof(names->pci_path);
+@@ -228,7 +236,9 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
+         l = strpcpyf(&s, l, "p%us%u", bus, slot);
+         if (func > 0 || is_pci_multifunction(names->pcidev))
+                 l = strpcpyf(&s, l, "f%d", func);
+-        if (dev_id > 0)
++        if (port_name)
++                l = strpcpyf(&s, l, "n%s", port_name);
++        else if (dev_id > 0)
+                 l = strpcpyf(&s, l, "d%d", dev_id);
+         if (l == 0)
+                 names->pci_path[0] = '\0';
+@@ -278,7 +288,9 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
+                 l = strpcpyf(&s, l, "s%d", hotplug_slot);
+                 if (func > 0 || is_pci_multifunction(names->pcidev))
+                         l = strpcpyf(&s, l, "f%d", func);
+-                if (dev_id > 0)
++                if (port_name)
++                        l = strpcpyf(&s, l, "n%s", port_name);
++                else if (dev_id > 0)
+                         l = strpcpyf(&s, l, "d%d", dev_id);
+                 if (l == 0)
+                         names->pci_slot[0] = '\0';
diff --git a/SOURCES/0443-install-introduce-UnitFileFlags.patch b/SOURCES/0443-install-introduce-UnitFileFlags.patch
new file mode 100644
index 0000000..79c2e59
--- /dev/null
+++ b/SOURCES/0443-install-introduce-UnitFileFlags.patch
@@ -0,0 +1,988 @@
+From 111080b06c79e6bcbe9da4786f9c7229f1fb573e Mon Sep 17 00:00:00 2001
+From: Jan Synacek <jsynacek@redhat.com>
+Date: Thu, 20 Oct 2016 14:48:33 +0200
+Subject: [PATCH] install: introduce UnitFileFlags
+
+Introduce a new enum to get rid of some boolean arguments of unit_file_*
+functions. It unifies the code, makes it a bit cleaner and extensible.
+
+(cherry picked from commit b3796dd8349af4235143889e44522a730c1635c0)
+Related: #1413041
+---
+ src/core/dbus-manager.c      | 36 ++++++++++++++++++--------
+ src/core/main.c              |  2 +-
+ src/shared/install.c         | 61 ++++++++++++++++++++------------------------
+ src/shared/install.h         | 25 ++++++++++--------
+ src/systemctl/systemctl.c    | 28 ++++++++++++--------
+ src/test/test-install-root.c | 58 ++++++++++++++++++++---------------------
+ src/test/test-install.c      | 38 +++++++++++++--------------
+ 7 files changed, 135 insertions(+), 113 deletions(-)
+
+diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
+index c2067c0..5b40aa2 100644
+--- a/src/core/dbus-manager.c
++++ b/src/core/dbus-manager.c
+@@ -41,6 +41,11 @@
+ #include "dbus-execute.h"
+ #include "bus-common-errors.h"
+ 
++static UnitFileFlags unit_file_bools_to_flags(bool runtime, bool force) {
++        return (runtime ? UNIT_FILE_RUNTIME : 0) |
++               (force   ? UNIT_FILE_FORCE   : 0);
++}
++
+ static int property_get_version(
+                 sd_bus *bus,
+                 const char *path,
+@@ -1647,7 +1652,7 @@ static int method_enable_unit_files_generic(
+                 sd_bus_message *message,
+                 Manager *m,
+                 const char *verb,
+-                int (*call)(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes),
++                int (*call)(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes),
+                 bool carries_install_info,
+                 sd_bus_error *error) {
+ 
+@@ -1655,6 +1660,7 @@ static int method_enable_unit_files_generic(
+         UnitFileChange *changes = NULL;
+         unsigned n_changes = 0;
+         UnitFileScope scope;
++        UnitFileFlags flags;
+         int runtime, force, r;
+ 
+         assert(bus);
+@@ -1676,12 +1682,13 @@ static int method_enable_unit_files_generic(
+                 return r;
+ 
+         r = mac_selinux_unit_access_check_strv(l, message, m, verb, error);
++        flags = unit_file_bools_to_flags(runtime, force);
+         if (r < 0)
+                 return r;
+ 
+         scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
+ 
+-        r = call(scope, runtime, NULL, l, force, &changes, &n_changes);
++        r = call(scope, flags, NULL, l, &changes, &n_changes);
+         if (r < 0)
+                 return r;
+ 
+@@ -1700,8 +1707,8 @@ static int method_link_unit_files(sd_bus *bus, sd_bus_message *message, void *us
+         return method_enable_unit_files_generic(bus, message, userdata, "enable", unit_file_link, false, error);
+ }
+ 
+-static int unit_file_preset_without_mode(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes) {
+-        return unit_file_preset(scope, runtime, root_dir, files, UNIT_FILE_PRESET_FULL, force, changes, n_changes);
++static int unit_file_preset_without_mode(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes) {
++        return unit_file_preset(scope, flags, root_dir, files, UNIT_FILE_PRESET_FULL, changes, n_changes);
+ }
+ 
+ static int method_preset_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+@@ -1721,6 +1728,7 @@ static int method_preset_unit_files_with_mode(sd_bus *bus, sd_bus_message *messa
+         UnitFilePresetMode mm;
+         UnitFileScope scope;
+         int runtime, force, r;
++        UnitFileFlags flags;
+         const char *mode;
+ 
+         assert(bus);
+@@ -1741,6 +1749,8 @@ static int method_preset_unit_files_with_mode(sd_bus *bus, sd_bus_message *messa
+         if (r < 0)
+                 return r;
+ 
++        flags = unit_file_bools_to_flags(runtime, force);
++
+         if (isempty(mode))
+                 mm = UNIT_FILE_PRESET_FULL;
+         else {
+@@ -1755,7 +1765,7 @@ static int method_preset_unit_files_with_mode(sd_bus *bus, sd_bus_message *messa
+ 
+         scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
+ 
+-        r = unit_file_preset(scope, runtime, NULL, l, mm, force, &changes, &n_changes);
++        r = unit_file_preset(scope, flags, NULL, l, mm, &changes, &n_changes);
+         if (r < 0)
+                 return r;
+ 
+@@ -1767,7 +1777,7 @@ static int method_disable_unit_files_generic(
+                 sd_bus_message *message,
+                 Manager *m, const
+                 char *verb,
+-                int (*call)(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes),
++                int (*call)(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes),
+                 sd_bus_error *error) {
+ 
+         _cleanup_strv_free_ char **l = NULL;
+@@ -1800,7 +1810,7 @@ static int method_disable_unit_files_generic(
+ 
+         scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
+ 
+-        r = call(scope, runtime, NULL, l, &changes, &n_changes);
++        r = call(scope, runtime ? UNIT_FILE_RUNTIME : 0, NULL, l, &changes, &n_changes);
+         if (r < 0)
+                 return r;
+ 
+@@ -1843,7 +1853,7 @@ static int method_set_default_target(sd_bus *bus, sd_bus_message *message, void
+ 
+         scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
+ 
+-        r = unit_file_set_default(scope, NULL, name, force, &changes, &n_changes);
++        r = unit_file_set_default(scope, force ? UNIT_FILE_FORCE : 0, NULL, name, &changes, &n_changes);
+         if (r < 0)
+                 return r;
+ 
+@@ -1857,6 +1867,7 @@ static int method_preset_all_unit_files(sd_bus *bus, sd_bus_message *message, vo
+         UnitFilePresetMode mm;
+         UnitFileScope scope;
+         const char *mode;
++        UnitFileFlags flags;
+         int force, runtime, r;
+ 
+         assert(bus);
+@@ -1877,6 +1888,8 @@ static int method_preset_all_unit_files(sd_bus *bus, sd_bus_message *message, vo
+         if (r < 0)
+                 return r;
+ 
++        flags = unit_file_bools_to_flags(runtime, force);
++
+         if (isempty(mode))
+                 mm = UNIT_FILE_PRESET_FULL;
+         else {
+@@ -1887,7 +1900,7 @@ static int method_preset_all_unit_files(sd_bus *bus, sd_bus_message *message, vo
+ 
+         scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
+ 
+-        r = unit_file_preset_all(scope, runtime, NULL, mm, force, &changes, &n_changes);
++        r = unit_file_preset_all(scope, flags, NULL, mm, &changes, &n_changes);
+         if (r < 0) {
+                 unit_file_changes_free(changes, n_changes);
+                 return r;
+@@ -1906,6 +1919,7 @@ static int method_add_dependency_unit_files(sd_bus *bus, sd_bus_message *message
+         char *target;
+         char *type;
+         UnitDependency dep;
++        UnitFileFlags flags;
+ 
+         assert(bus);
+         assert(message);
+@@ -1925,6 +1939,8 @@ static int method_add_dependency_unit_files(sd_bus *bus, sd_bus_message *message
+         if (r < 0)
+                 return r;
+ 
++        flags = unit_file_bools_to_flags(runtime, force);
++
+         dep = unit_dependency_from_string(type);
+         if (dep < 0)
+                 return -EINVAL;
+@@ -1935,7 +1951,7 @@ static int method_add_dependency_unit_files(sd_bus *bus, sd_bus_message *message
+ 
+         scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
+ 
+-        r = unit_file_add_dependency(scope, runtime, NULL, l, target, dep, force, &changes, &n_changes);
++        r = unit_file_add_dependency(scope, flags, NULL, l, target, dep, &changes, &n_changes);
+         if (r < 0)
+                 return r;
+ 
+diff --git a/src/core/main.c b/src/core/main.c
+index 820cbc3..a0df1e5 100644
+--- a/src/core/main.c
++++ b/src/core/main.c
+@@ -1658,7 +1658,7 @@ int main(int argc, char *argv[]) {
+                 bump_rlimit_nofile(&saved_rlimit_nofile);
+ 
+                 if (empty_etc) {
+-                        r = unit_file_preset_all(UNIT_FILE_SYSTEM, false, NULL, UNIT_FILE_PRESET_FULL, false, NULL, 0);
++                        r = unit_file_preset_all(UNIT_FILE_SYSTEM, 0, NULL, UNIT_FILE_PRESET_FULL, NULL, 0);
+                         if (r < 0)
+                                 log_warning_errno(r, "Failed to populate /etc with preset unit settings, ignoring: %m");
+                         else
+diff --git a/src/shared/install.c b/src/shared/install.c
+index 62bdf67..b3df6b3 100644
+--- a/src/shared/install.c
++++ b/src/shared/install.c
+@@ -1549,10 +1549,9 @@ static int install_context_mark_for_removal(
+ 
+ int unit_file_mask(
+                 UnitFileScope scope,
+-                bool runtime,
++                UnitFileFlags flags,
+                 const char *root_dir,
+                 char **files,
+-                bool force,
+                 UnitFileChange **changes,
+                 unsigned *n_changes) {
+ 
+@@ -1567,7 +1566,7 @@ int unit_file_mask(
+         if (r < 0)
+                 return r;
+ 
+-        r = get_config_path(scope, runtime, root_dir, &prefix);
++        r = get_config_path(scope, flags & UNIT_FILE_RUNTIME, root_dir, &prefix);
+         if (r < 0)
+                 return r;
+ 
+@@ -1584,7 +1583,7 @@ int unit_file_mask(
+                 if (!path)
+                         return -ENOMEM;
+ 
+-                q = create_symlink("/dev/null", path, force, changes, n_changes);
++                q = create_symlink("/dev/null", path, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
+                 if (q < 0 && r >= 0)
+                         r = q;
+         }
+@@ -1594,7 +1593,7 @@ int unit_file_mask(
+ 
+ int unit_file_unmask(
+                 UnitFileScope scope,
+-                bool runtime,
++                UnitFileFlags flags,
+                 const char *root_dir,
+                 char **files,
+                 UnitFileChange **changes,
+@@ -1614,7 +1613,7 @@ int unit_file_unmask(
+         if (r < 0)
+                 return r;
+ 
+-        r = get_config_path(scope, runtime, root_dir, &config_path);
++        r = get_config_path(scope, flags & UNIT_FILE_RUNTIME, root_dir, &config_path);
+         if (r < 0)
+                 return r;
+ 
+@@ -1677,10 +1676,9 @@ int unit_file_unmask(
+ 
+ int unit_file_link(
+                 UnitFileScope scope,
+-                bool runtime,
++                UnitFileFlags flags,
+                 const char *root_dir,
+                 char **files,
+-                bool force,
+                 UnitFileChange **changes,
+                 unsigned *n_changes) {
+ 
+@@ -1702,7 +1700,7 @@ int unit_file_link(
+         if (r < 0)
+                 return r;
+ 
+-        r = get_config_path(scope, runtime, root_dir, &config_path);
++        r = get_config_path(scope, flags & UNIT_FILE_RUNTIME, root_dir, &config_path);
+         if (r < 0)
+                 return r;
+ 
+@@ -1757,7 +1755,7 @@ int unit_file_link(
+                 if (!path)
+                         return -ENOMEM;
+ 
+-                q = create_symlink(*i, path, force, changes, n_changes);
++                q = create_symlink(*i, path, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
+                 if (q < 0 && r >= 0)
+                         r = q;
+         }
+@@ -1767,12 +1765,11 @@ int unit_file_link(
+ 
+ int unit_file_add_dependency(
+                 UnitFileScope scope,
+-                bool runtime,
++                UnitFileFlags flags,
+                 const char *root_dir,
+                 char **files,
+                 const char *target,
+                 UnitDependency dep,
+-                bool force,
+                 UnitFileChange **changes,
+                 unsigned *n_changes) {
+ 
+@@ -1801,7 +1798,7 @@ int unit_file_add_dependency(
+         if (r < 0)
+                 return r;
+ 
+-        r = get_config_path(scope, runtime, root_dir, &config_path);
++        r = get_config_path(scope, flags & UNIT_FILE_RUNTIME, root_dir, &config_path);
+         if (r < 0)
+                 return r;
+ 
+@@ -1839,16 +1836,15 @@ int unit_file_add_dependency(
+                         return -ENOMEM;
+          }
+ 
+-        return install_context_apply(scope, &c, &paths, config_path, root_dir, force, SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes);
++        return install_context_apply(scope, &c, &paths, config_path, root_dir, !!(flags & UNIT_FILE_FORCE), SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes);
+ }
+ 
+ 
+ int unit_file_enable(
+                 UnitFileScope scope,
+-                bool runtime,
++                UnitFileFlags flags,
+                 const char *root_dir,
+                 char **files,
+-                bool force,
+                 UnitFileChange **changes,
+                 unsigned *n_changes) {
+ 
+@@ -1870,7 +1866,7 @@ int unit_file_enable(
+         if (r < 0)
+                 return r;
+ 
+-        r = get_config_path(scope, runtime, root_dir, &config_path);
++        r = get_config_path(scope, flags & UNIT_FILE_RUNTIME, root_dir, &config_path);
+         if (r < 0)
+                 return r;
+ 
+@@ -1889,12 +1885,12 @@ int unit_file_enable(
+         useful to determine whether the passed files had any
+         installation data at all. */
+ 
+-        return install_context_apply(scope, &c, &paths, config_path, root_dir, force, SEARCH_LOAD, changes, n_changes);
++        return install_context_apply(scope, &c, &paths, config_path, root_dir, !!(flags & UNIT_FILE_FORCE), SEARCH_LOAD, changes, n_changes);
+ }
+ 
+ int unit_file_disable(
+                 UnitFileScope scope,
+-                bool runtime,
++                UnitFileFlags flags,
+                 const char *root_dir,
+                 char **files,
+                 UnitFileChange **changes,
+@@ -1918,7 +1914,7 @@ int unit_file_disable(
+         if (r < 0)
+                 return r;
+ 
+-        r = get_config_path(scope, runtime, root_dir, &config_path);
++        r = get_config_path(scope, flags & UNIT_FILE_RUNTIME, root_dir, &config_path);
+         if (r < 0)
+                 return r;
+ 
+@@ -1940,10 +1936,9 @@ int unit_file_disable(
+ 
+ int unit_file_reenable(
+                 UnitFileScope scope,
+-                bool runtime,
++                UnitFileFlags flags,
+                 const char *root_dir,
+                 char **files,
+-                bool force,
+                 UnitFileChange **changes,
+                 unsigned *n_changes) {
+ 
+@@ -1958,19 +1953,19 @@ int unit_file_reenable(
+                 n[i] = basename(files[i]);
+         n[i] = NULL;
+ 
+-        r = unit_file_disable(scope, runtime, root_dir, n, changes, n_changes);
++        r = unit_file_disable(scope, flags, root_dir, n, changes, n_changes);
+         if (r < 0)
+                 return r;
+ 
+         /* But the enable command with the full name */
+-        return unit_file_enable(scope, runtime, root_dir, files, force, changes, n_changes);
++        return unit_file_enable(scope, flags, root_dir, files, changes, n_changes);
+ }
+ 
+ int unit_file_set_default(
+                 UnitFileScope scope,
++                UnitFileFlags flags,
+                 const char *root_dir,
+                 const char *name,
+-                bool force,
+                 UnitFileChange **changes,
+                 unsigned *n_changes) {
+ 
+@@ -2010,7 +2005,7 @@ int unit_file_set_default(
+ 
+         path = strjoina(config_path, "/" SPECIAL_DEFAULT_TARGET);
+ 
+-        return create_symlink(i->path, path, force, changes, n_changes);
++        return create_symlink(i->path, path, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
+ }
+ 
+ int unit_file_get_default(
+@@ -2311,11 +2306,10 @@ static int preset_prepare_one(
+ 
+ int unit_file_preset(
+                 UnitFileScope scope,
+-                bool runtime,
++                UnitFileFlags flags,
+                 const char *root_dir,
+                 char **files,
+                 UnitFilePresetMode mode,
+-                bool force,
+                 UnitFileChange **changes,
+                 unsigned *n_changes) {
+ 
+@@ -2337,7 +2331,7 @@ int unit_file_preset(
+         if (r < 0)
+                 return r;
+ 
+-        r = get_config_path(scope, runtime, root_dir, &config_path);
++        r = get_config_path(scope, flags & UNIT_FILE_RUNTIME, root_dir, &config_path);
+         if (r < 0)
+                 return r;
+ 
+@@ -2350,15 +2344,14 @@ int unit_file_preset(
+                         return r;
+         }
+ 
+-        return execute_preset(scope, &plus, &minus, &paths, config_path, root_dir, files, mode, force, changes, n_changes);
++        return execute_preset(scope, &plus, &minus, &paths, config_path, root_dir, files, mode, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
+ }
+ 
+ int unit_file_preset_all(
+                 UnitFileScope scope,
+-                bool runtime,
++                UnitFileFlags flags,
+                 const char *root_dir,
+                 UnitFilePresetMode mode,
+-                bool force,
+                 UnitFileChange **changes,
+                 unsigned *n_changes) {
+ 
+@@ -2380,7 +2373,7 @@ int unit_file_preset_all(
+         if (r < 0)
+                 return r;
+ 
+-        r = get_config_path(scope, runtime, root_dir, &config_path);
++        r = get_config_path(scope, flags & UNIT_FILE_RUNTIME, root_dir, &config_path);
+         if (r < 0)
+                 return r;
+ 
+@@ -2434,7 +2427,7 @@ int unit_file_preset_all(
+                 }
+         }
+ 
+-        return execute_preset(scope, &plus, &minus, &paths, config_path, root_dir, NULL, mode, force, changes, n_changes);
++        return execute_preset(scope, &plus, &minus, &paths, config_path, root_dir, NULL, mode, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
+ }
+ 
+ static void unit_file_list_free_one(UnitFileList *f) {
+diff --git a/src/shared/install.h b/src/shared/install.h
+index 7e40445..c961b53 100644
+--- a/src/shared/install.h
++++ b/src/shared/install.h
+@@ -66,6 +66,11 @@ typedef enum UnitFileChangeType {
+         _UNIT_FILE_CHANGE_TYPE_INVALID = -1
+ } UnitFileChangeType;
+ 
++typedef enum UnitFileFlags {
++        UNIT_FILE_RUNTIME = 1,
++        UNIT_FILE_FORCE = 1 << 1
++} UnitFileFlags;
++
+ static inline bool unit_file_change_is_modification(UnitFileChangeType type) {
+         return IN_SET(type, UNIT_FILE_SYMLINK, UNIT_FILE_UNLINK);
+ }
+@@ -120,17 +125,17 @@ static inline bool UNIT_FILE_INSTALL_INFO_HAS_ALSO(InstallInfo *i) {
+         return !strv_isempty(i->also);
+ }
+ 
+-int unit_file_enable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes);
+-int unit_file_disable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes);
+-int unit_file_reenable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes);
+-int unit_file_link(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes);
+-int unit_file_preset(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFilePresetMode mode, bool force, UnitFileChange **changes, unsigned *n_changes);
+-int unit_file_preset_all(UnitFileScope scope, bool runtime, const char *root_dir, UnitFilePresetMode mode, bool force, UnitFileChange **changes, unsigned *n_changes);
+-int unit_file_mask(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes);
+-int unit_file_unmask(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes);
+-int unit_file_set_default(UnitFileScope scope, const char *root_dir, const char *file, bool force, UnitFileChange **changes, unsigned *n_changes);
++int unit_file_enable(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes);
++int unit_file_disable(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes);
++int unit_file_reenable(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes);
++int unit_file_link(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes);
++int unit_file_preset(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFilePresetMode mode, UnitFileChange **changes, unsigned *n_changes);
++int unit_file_preset_all(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, UnitFilePresetMode mode, UnitFileChange **changes, unsigned *n_changes);
++int unit_file_mask(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes);
++int unit_file_unmask(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes);
++int unit_file_set_default(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, const char *file, UnitFileChange **changes, unsigned *n_changes);
+ int unit_file_get_default(UnitFileScope scope, const char *root_dir, char **name);
+-int unit_file_add_dependency(UnitFileScope scope, bool runtime, const char *root_dir, char **files, const char *target, UnitDependency dep, bool force, UnitFileChange **changes, unsigned *n_changes);
++int unit_file_add_dependency(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char **files, const char *target, UnitDependency dep, UnitFileChange **changes, unsigned *n_changes);
+ 
+ int unit_file_lookup_state(UnitFileScope scope, const char *root_dir,const LookupPaths *paths, const char *name, UnitFileState *ret);
+ int unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename, UnitFileState *ret);
+diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
+index 1e1009f..e0dbf0f 100644
+--- a/src/systemctl/systemctl.c
++++ b/src/systemctl/systemctl.c
+@@ -165,6 +165,11 @@ static int daemon_reload(sd_bus *bus, char **args);
+ static int halt_now(enum action a);
+ static int check_one_unit(sd_bus *bus, const char *name, const char *good_states, bool quiet);
+ 
++static UnitFileFlags args_to_flags(void) {
++        return (arg_runtime ? UNIT_FILE_RUNTIME : 0) |
++               (arg_force   ? UNIT_FILE_FORCE   : 0);
++}
++
+ static char** strv_skip_first(char **strv) {
+         if (strv_length(strv) > 0)
+                 return strv + 1;
+@@ -1974,7 +1979,7 @@ static int set_default(sd_bus *bus, char **args) {
+                 return log_oom();
+ 
+         if (!bus || avoid_bus()) {
+-                r = unit_file_set_default(arg_scope, arg_root, unit, true, &changes, &n_changes);
++                r = unit_file_set_default(arg_scope, UNIT_FILE_FORCE, arg_root, unit, &changes, &n_changes);
+                 if (r < 0)
+                         return log_error_errno(r, "Failed to set default target: %m");
+ 
+@@ -5407,22 +5412,25 @@ static int enable_unit(sd_bus *bus, char **args) {
+         }
+ 
+         if (!bus || avoid_bus()) {
++                UnitFileFlags flags;
++
++                flags = args_to_flags();
+                 if (streq(verb, "enable")) {
+-                        r = unit_file_enable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
++                        r = unit_file_enable(arg_scope, flags, arg_root, names, &changes, &n_changes);
+                         carries_install_info = r;
+                 } else if (streq(verb, "disable"))
+-                        r = unit_file_disable(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes);
++                        r = unit_file_disable(arg_scope, flags, arg_root, names, &changes, &n_changes);
+                 else if (streq(verb, "reenable")) {
+-                        r = unit_file_reenable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
++                        r = unit_file_reenable(arg_scope, flags, arg_root, names, &changes, &n_changes);
+                         carries_install_info = r;
+                 } else if (streq(verb, "link"))
+-                        r = unit_file_link(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
++                        r = unit_file_link(arg_scope, flags, arg_root, names, &changes, &n_changes);
+                 else if (streq(verb, "preset")) {
+-                        r = unit_file_preset(arg_scope, arg_runtime, arg_root, names, arg_preset_mode, arg_force, &changes, &n_changes);
++                        r = unit_file_preset(arg_scope, flags, arg_root, names, arg_preset_mode, &changes, &n_changes);
+                 } else if (streq(verb, "mask"))
+-                        r = unit_file_mask(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
++                        r = unit_file_mask(arg_scope, flags, arg_root, names, &changes, &n_changes);
+                 else if (streq(verb, "unmask"))
+-                        r = unit_file_unmask(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes);
++                        r = unit_file_unmask(arg_scope, flags, arg_root, names, &changes, &n_changes);
+                 else
+                         assert_not_reached("Unknown verb");
+ 
+@@ -5588,7 +5596,7 @@ static int add_dependency(sd_bus *bus, char **args) {
+                 UnitFileChange *changes = NULL;
+                 unsigned n_changes = 0;
+ 
+-                r = unit_file_add_dependency(arg_scope, arg_runtime, arg_root, names, target, dep, arg_force, &changes, &n_changes);
++                r = unit_file_add_dependency(arg_scope, args_to_flags(), arg_root, names, target, dep, &changes, &n_changes);
+ 
+                 if (r < 0)
+                         return log_error_errno(r, "Can't add dependency: %m");
+@@ -5652,7 +5660,7 @@ static int preset_all(sd_bus *bus, char **args) {
+ 
+         if (!bus || avoid_bus()) {
+ 
+-                r = unit_file_preset_all(arg_scope, arg_runtime, arg_root, arg_preset_mode, arg_force, &changes, &n_changes);
++                r = unit_file_preset_all(arg_scope, args_to_flags(), arg_root, arg_preset_mode, &changes, &n_changes);
+                 if (r < 0) {
+                         log_error_errno(r, "Operation failed: %m");
+                         goto finish;
+diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c
+index 667c374..cb417d4 100644
+--- a/src/test/test-install-root.c
++++ b/src/test/test-install-root.c
+@@ -62,7 +62,7 @@ static void test_basic_mask_and_enable(const char *root) {
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) >= 0);
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+ 
+-        assert_se(unit_file_mask(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) >= 0);
++        assert_se(unit_file_mask(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0);
+         assert_se(n_changes == 1);
+         assert_se(changes[0].type == UNIT_FILE_SYMLINK);
+         assert_se(streq(changes[0].source, "/dev/null"));
+@@ -78,11 +78,11 @@ static void test_basic_mask_and_enable(const char *root) {
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_MASKED);
+ 
+         /* Enabling a masked unit should fail! */
+-        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == -ESHUTDOWN);
++        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) == -ESHUTDOWN);
+         unit_file_changes_free(changes, n_changes);
+         changes = NULL; n_changes = 0;
+ 
+-        assert_se(unit_file_unmask(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0);
++        assert_se(unit_file_unmask(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0);
+         assert_se(n_changes == 1);
+         assert_se(changes[0].type == UNIT_FILE_UNLINK);
+         p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/a.service");
+@@ -90,7 +90,7 @@ static void test_basic_mask_and_enable(const char *root) {
+         unit_file_changes_free(changes, n_changes);
+         changes = NULL; n_changes = 0;
+ 
+-        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == 1);
++        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) == 1);
+         assert_se(n_changes == 1);
+         assert_se(changes[0].type == UNIT_FILE_SYMLINK);
+         assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service"));
+@@ -105,12 +105,12 @@ static void test_basic_mask_and_enable(const char *root) {
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+ 
+         /* Enabling it again should succeed but be a NOP */
+-        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == 1);
++        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) == 1);
+         assert_se(n_changes == 0);
+         unit_file_changes_free(changes, n_changes);
+         changes = NULL; n_changes = 0;
+ 
+-        assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0);
++        assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0);
+         assert_se(n_changes == 1);
+         assert_se(changes[0].type == UNIT_FILE_UNLINK);
+         p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service");
+@@ -124,13 +124,13 @@ static void test_basic_mask_and_enable(const char *root) {
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+ 
+         /* Disabling a disabled unit must suceed but be a NOP */
+-        assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0);
++        assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0);
+         assert_se(n_changes == 0);
+         unit_file_changes_free(changes, n_changes);
+         changes = NULL; n_changes = 0;
+ 
+         /* Let's enable this indirectly via a symlink */
+-        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("d.service"), false, &changes, &n_changes) >= 0);
++        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("d.service"), &changes, &n_changes) >= 0);
+         assert_se(n_changes == 1);
+         assert_se(changes[0].type == UNIT_FILE_SYMLINK);
+         assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service"));
+@@ -146,7 +146,7 @@ static void test_basic_mask_and_enable(const char *root) {
+ 
+         /* Let's try to reenable */
+ 
+-        assert_se(unit_file_reenable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("b.service"), false, &changes, &n_changes) >= 0);
++        assert_se(unit_file_reenable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("b.service"), &changes, &n_changes) >= 0);
+         assert_se(n_changes == 2);
+         assert_se(changes[0].type == UNIT_FILE_UNLINK);
+         p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service");
+@@ -215,7 +215,7 @@ static void test_linked_units(const char *root) {
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked3.service", &state) >= 0 && state == UNIT_FILE_LINKED);
+ 
+         /* First, let's link the unit into the search path */
+-        assert_se(unit_file_link(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("/opt/linked.service"), false, &changes, &n_changes) >= 0);
++        assert_se(unit_file_link(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("/opt/linked.service"), &changes, &n_changes) >= 0);
+         assert_se(n_changes == 1);
+         assert_se(changes[0].type == UNIT_FILE_SYMLINK);
+         assert_se(streq(changes[0].source, "/opt/linked.service"));
+@@ -227,7 +227,7 @@ static void test_linked_units(const char *root) {
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_LINKED);
+ 
+         /* Let's unlink it from the search path again */
+-        assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0);
++        assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0);
+         assert_se(n_changes == 1);
+         assert_se(changes[0].type == UNIT_FILE_UNLINK);
+         p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service");
+@@ -238,7 +238,7 @@ static void test_linked_units(const char *root) {
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT);
+ 
+         /* Now, let's not just link it, but also enable it */
+-        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("/opt/linked.service"), false, &changes, &n_changes) >= 0);
++        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("/opt/linked.service"), &changes, &n_changes) >= 0);
+         assert_se(n_changes == 2);
+         p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked.service");
+         q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service");
+@@ -260,7 +260,7 @@ static void test_linked_units(const char *root) {
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+ 
+         /* And let's unlink it again */
+-        assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0);
++        assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0);
+         assert_se(n_changes == 2);
+         p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked.service");
+         q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service");
+@@ -280,7 +280,7 @@ static void test_linked_units(const char *root) {
+ 
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT);
+ 
+-        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked2.service"), false, &changes, &n_changes) >= 0);
++        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked2.service"), &changes, &n_changes) >= 0);
+         assert_se(n_changes == 2);
+         p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked2.service");
+         q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked2.service");
+@@ -299,7 +299,7 @@ static void test_linked_units(const char *root) {
+         unit_file_changes_free(changes, n_changes);
+         changes = NULL; n_changes = 0;
+ 
+-        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked3.service"), false, &changes, &n_changes) == -ELOOP);
++        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked3.service"), &changes, &n_changes) == -ELOOP);
+         unit_file_changes_free(changes, n_changes);
+         changes = NULL; n_changes = 0;
+ }
+@@ -318,14 +318,14 @@ static void test_default(const char *root) {
+ 
+         assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) == -ENOENT);
+ 
+-        assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, root, "idontexist.target", false, &changes, &n_changes) == -ENOENT);
++        assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, 0, root, "idontexist.target", &changes, &n_changes) == -ENOENT);
+         assert_se(n_changes == 0);
+         unit_file_changes_free(changes, n_changes);
+         changes = NULL; n_changes = 0;
+ 
+         assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) == -ENOENT);
+ 
+-        assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, root, "test-default.target", false, &changes, &n_changes) >= 0);
++        assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, 0, root, "test-default.target", &changes, &n_changes) >= 0);
+         assert_se(n_changes == 1);
+         assert_se(changes[0].type == UNIT_FILE_SYMLINK);
+         assert_se(streq(changes[0].source, "/usr/lib/systemd/system/test-default-real.target"));
+@@ -355,7 +355,7 @@ static void test_add_dependency(const char *root) {
+         p = strjoina(root, "/usr/lib/systemd/system/add-dependency-test-service.service");
+         assert_se(symlink("real-add-dependency-test-service.service", p) >= 0);
+ 
+-        assert_se(unit_file_add_dependency(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("add-dependency-test-service.service"), "add-dependency-test-target.target", UNIT_WANTS, false, &changes, &n_changes) >= 0);
++        assert_se(unit_file_add_dependency(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("add-dependency-test-service.service"), "add-dependency-test-target.target", UNIT_WANTS, &changes, &n_changes) >= 0);
+         assert_se(n_changes == 1);
+         assert_se(changes[0].type == UNIT_FILE_SYMLINK);
+         assert_se(streq(changes[0].source, "/usr/lib/systemd/system/real-add-dependency-test-service.service"));
+@@ -392,7 +392,7 @@ static void test_template_enable(const char *root) {
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+ 
+-        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@.service"), false, &changes, &n_changes) >= 0);
++        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0);
+         assert_se(n_changes == 1);
+         assert_se(changes[0].type == UNIT_FILE_SYMLINK);
+         assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service"));
+@@ -408,7 +408,7 @@ static void test_template_enable(const char *root) {
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+ 
+-        assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0);
++        assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0);
+         assert_se(n_changes == 1);
+         assert_se(changes[0].type == UNIT_FILE_UNLINK);
+         assert_se(streq(changes[0].path, p));
+@@ -422,7 +422,7 @@ static void test_template_enable(const char *root) {
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+ 
+-        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@foo.service"), false, &changes, &n_changes) >= 0);
++        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0);
+         assert_se(changes[0].type == UNIT_FILE_SYMLINK);
+         assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service"));
+         p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@foo.service");
+@@ -437,7 +437,7 @@ static void test_template_enable(const char *root) {
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+ 
+-        assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0);
++        assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0);
+         assert_se(n_changes == 1);
+         assert_se(changes[0].type == UNIT_FILE_UNLINK);
+         assert_se(streq(changes[0].path, p));
+@@ -453,7 +453,7 @@ static void test_template_enable(const char *root) {
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+ 
+-        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template-symlink@quux.service"), false, &changes, &n_changes) >= 0);
++        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template-symlink@quux.service"), &changes, &n_changes) >= 0);
+         assert_se(changes[0].type == UNIT_FILE_SYMLINK);
+         assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service"));
+         p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@quux.service");
+@@ -498,7 +498,7 @@ static void test_indirect(const char *root) {
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
+ 
+-        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("indirectc.service"), false, &changes, &n_changes) >= 0);
++        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0);
+         assert_se(n_changes == 1);
+         assert_se(changes[0].type == UNIT_FILE_SYMLINK);
+         assert_se(streq(changes[0].source, "/usr/lib/systemd/system/indirectb.service"));
+@@ -511,7 +511,7 @@ static void test_indirect(const char *root) {
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
+ 
+-        assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0);
++        assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0);
+         assert_se(n_changes == 1);
+         assert_se(changes[0].type == UNIT_FILE_UNLINK);
+         p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/indirectb.service");
+@@ -551,7 +551,7 @@ static void test_preset_and_list(const char *root) {
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+ 
+-        assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0);
++        assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0);
+         assert_se(n_changes == 1);
+         assert_se(changes[0].type == UNIT_FILE_SYMLINK);
+         assert_se(streq(changes[0].source, "/usr/lib/systemd/system/preset-yes.service"));
+@@ -563,7 +563,7 @@ static void test_preset_and_list(const char *root) {
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+ 
+-        assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-yes.service"), &changes, &n_changes) >= 0);
++        assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("preset-yes.service"), &changes, &n_changes) >= 0);
+         assert_se(n_changes == 1);
+         assert_se(changes[0].type == UNIT_FILE_UNLINK);
+         p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service");
+@@ -574,7 +574,7 @@ static void test_preset_and_list(const char *root) {
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+ 
+-        assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-no.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0);
++        assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("preset-no.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0);
+         assert_se(n_changes == 0);
+         unit_file_changes_free(changes, n_changes);
+         changes = NULL; n_changes = 0;
+@@ -582,7 +582,7 @@ static void test_preset_and_list(const char *root) {
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+ 
+-        assert_se(unit_file_preset_all(UNIT_FILE_SYSTEM, false, root, UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0);
++        assert_se(unit_file_preset_all(UNIT_FILE_SYSTEM, 0, root, UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0);
+ 
+         assert_se(n_changes > 0);
+ 
+diff --git a/src/test/test-install.c b/src/test/test-install.c
+index 08a1faf..0cae0e7 100644
+--- a/src/test/test-install.c
++++ b/src/test/test-install.c
+@@ -73,12 +73,12 @@ int main(int argc, char* argv[]) {
+ 
+         log_error("enable");
+ 
+-        r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes);
++        r = unit_file_enable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
+         assert_se(r >= 0);
+ 
+         log_error("enable2");
+ 
+-        r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes);
++        r = unit_file_enable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
+         assert_se(r >= 0);
+ 
+         dump_changes(changes, n_changes);
+@@ -93,7 +93,7 @@ int main(int argc, char* argv[]) {
+         changes = NULL;
+         n_changes = 0;
+ 
+-        r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes);
++        r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
+         assert_se(r >= 0);
+ 
+         dump_changes(changes, n_changes);
+@@ -107,10 +107,10 @@ int main(int argc, char* argv[]) {
+         changes = NULL;
+         n_changes = 0;
+ 
+-        r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes);
++        r = unit_file_mask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
+         assert_se(r >= 0);
+         log_error("mask2");
+-        r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes);
++        r = unit_file_mask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
+         assert_se(r >= 0);
+ 
+         dump_changes(changes, n_changes);
+@@ -124,10 +124,10 @@ int main(int argc, char* argv[]) {
+         changes = NULL;
+         n_changes = 0;
+ 
+-        r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes);
++        r = unit_file_unmask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
+         assert_se(r >= 0);
+         log_error("unmask2");
+-        r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes);
++        r = unit_file_unmask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
+         assert_se(r >= 0);
+ 
+         dump_changes(changes, n_changes);
+@@ -141,7 +141,7 @@ int main(int argc, char* argv[]) {
+         changes = NULL;
+         n_changes = 0;
+ 
+-        r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes);
++        r = unit_file_mask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
+         assert_se(r >= 0);
+ 
+         dump_changes(changes, n_changes);
+@@ -155,10 +155,10 @@ int main(int argc, char* argv[]) {
+         changes = NULL;
+         n_changes = 0;
+ 
+-        r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes);
++        r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
+         assert_se(r >= 0);
+         log_error("disable2");
+-        r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes);
++        r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
+         assert_se(r >= 0);
+ 
+         dump_changes(changes, n_changes);
+@@ -172,7 +172,7 @@ int main(int argc, char* argv[]) {
+         changes = NULL;
+         n_changes = 0;
+ 
+-        r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes);
++        r = unit_file_unmask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
+         assert_se(r >= 0);
+ 
+         dump_changes(changes, n_changes);
+@@ -186,7 +186,7 @@ int main(int argc, char* argv[]) {
+         changes = NULL;
+         n_changes = 0;
+ 
+-        r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, false, &changes, &n_changes);
++        r = unit_file_enable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes);
+         assert_se(r >= 0);
+ 
+         dump_changes(changes, n_changes);
+@@ -200,7 +200,7 @@ int main(int argc, char* argv[]) {
+         changes = NULL;
+         n_changes = 0;
+ 
+-        r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes);
++        r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes);
+         assert_se(r >= 0);
+ 
+         dump_changes(changes, n_changes);
+@@ -213,7 +213,7 @@ int main(int argc, char* argv[]) {
+         changes = NULL;
+         n_changes = 0;
+ 
+-        r = unit_file_link(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, false, &changes, &n_changes);
++        r = unit_file_link(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes);
+         assert_se(r >= 0);
+ 
+         dump_changes(changes, n_changes);
+@@ -227,7 +227,7 @@ int main(int argc, char* argv[]) {
+         changes = NULL;
+         n_changes = 0;
+ 
+-        r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes);
++        r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes);
+         assert_se(r >= 0);
+ 
+         dump_changes(changes, n_changes);
+@@ -240,7 +240,7 @@ int main(int argc, char* argv[]) {
+         changes = NULL;
+         n_changes = 0;
+ 
+-        r = unit_file_link(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, false, &changes, &n_changes);
++        r = unit_file_link(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes);
+         assert_se(r >= 0);
+ 
+         dump_changes(changes, n_changes);
+@@ -254,7 +254,7 @@ int main(int argc, char* argv[]) {
+         changes = NULL;
+         n_changes = 0;
+ 
+-        r = unit_file_reenable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, false, &changes, &n_changes);
++        r = unit_file_reenable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes);
+         assert_se(r >= 0);
+ 
+         dump_changes(changes, n_changes);
+@@ -268,7 +268,7 @@ int main(int argc, char* argv[]) {
+         changes = NULL;
+         n_changes = 0;
+ 
+-        r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes);
++        r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes);
+         assert_se(r >= 0);
+ 
+         dump_changes(changes, n_changes);
+@@ -280,7 +280,7 @@ int main(int argc, char* argv[]) {
+         changes = NULL;
+         n_changes = 0;
+ 
+-        r = unit_file_preset(UNIT_FILE_SYSTEM, false, NULL, (char**) files, UNIT_FILE_PRESET_FULL, false, &changes, &n_changes);
++        r = unit_file_preset(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, UNIT_FILE_PRESET_FULL, &changes, &n_changes);
+         assert_se(r >= 0);
+ 
+         dump_changes(changes, n_changes);
diff --git a/SOURCES/0444-shared-systemctl-teach-is-enabled-to-show-installati.patch b/SOURCES/0444-shared-systemctl-teach-is-enabled-to-show-installati.patch
new file mode 100644
index 0000000..037d1a4
--- /dev/null
+++ b/SOURCES/0444-shared-systemctl-teach-is-enabled-to-show-installati.patch
@@ -0,0 +1,363 @@
+From fef4e6a045ae703de12ec271b0c8fd02d0bac0fc Mon Sep 17 00:00:00 2001
+From: Jan Synacek <jsynacek@redhat.com>
+Date: Thu, 20 Oct 2016 15:20:11 +0200
+Subject: [PATCH] shared, systemctl: teach is-enabled to show installation
+ targets
+
+It may be desired by users to know what targets a particular service is
+installed into. Improve user friendliness by teaching the is-enabled
+command to show such information when used with --full.
+
+This patch makes use of the newly added UnitFileFlags and adds
+UNIT_FILE_DRY_RUN flag into it. Since the API had already been modified,
+it's now easy to add the new dry-run feature for other commands as
+well. As a next step, --dry-run could be added to systemctl, which in
+turn might pave the way for a long requested dry-run feature when
+running systemctl start.
+
+(cherry picked from commit 3b3557c410c7910fae0990599dcb82711cf5fbb7)
+Resolves: #1413041
+---
+ man/systemctl.xml                      |  3 ++
+ src/core/dbus-manager.c                | 44 ++++++++++++++++++++
+ src/core/org.freedesktop.systemd1.conf |  4 ++
+ src/shared/install.c                   | 35 +++++++++-------
+ src/shared/install.h                   |  3 +-
+ src/systemctl/systemctl.c              | 73 +++++++++++++++++++++++++++++++++-
+ 6 files changed, 145 insertions(+), 17 deletions(-)
+
+diff --git a/man/systemctl.xml b/man/systemctl.xml
+index bb21f3a..4a1aff2 100644
+--- a/man/systemctl.xml
++++ b/man/systemctl.xml
+@@ -223,6 +223,8 @@
+           of <command>status</command>, <command>list-units</command>,
+           <command>list-jobs</command>, and
+           <command>list-timers</command>.</para>
++          <para>Also, show installation targets in the output of
++          <command>is-enabled</command>.</para>
+         </listitem>
+       </varlistentry>
+ 
+@@ -1054,6 +1056,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
+             exit code of 0 if at least one is enabled, non-zero
+             otherwise. Prints the current enable status (see table).
+             To suppress this output, use <option>--quiet</option>.
++            To show installation targets, use <option>--full</option>.
+             </para>
+ 
+             <table>
+diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
+index 5b40aa2..7ba1b51 100644
+--- a/src/core/dbus-manager.c
++++ b/src/core/dbus-manager.c
+@@ -1958,6 +1958,49 @@ static int method_add_dependency_unit_files(sd_bus *bus, sd_bus_message *message
+         return reply_unit_file_changes_and_free(m, bus, message, -1, changes, n_changes);
+ }
+ 
++static int method_get_unit_file_links(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
++        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
++        UnitFileChange *changes = NULL;
++        unsigned n_changes = 0, i;
++        UnitFileFlags flags;
++        const char *name;
++        char **p;
++        int runtime, r;
++
++        r = sd_bus_message_read(message, "sb", &name, &runtime);
++        if (r < 0)
++                return r;
++
++        r = sd_bus_message_new_method_return(message, &reply);
++        if (r < 0)
++                return r;
++
++        r = sd_bus_message_open_container(reply, SD_BUS_TYPE_ARRAY, "s");
++        if (r < 0)
++                return r;
++
++        p = STRV_MAKE(name);
++        flags = UNIT_FILE_DRY_RUN |
++                (runtime ? UNIT_FILE_RUNTIME : 0);
++
++        r = unit_file_disable(UNIT_FILE_SYSTEM, flags, NULL, p, &changes, &n_changes);
++        if (r < 0)
++                return log_error_errno(r, "Failed to get file links for %s: %m", name);
++
++        for (i = 0; i < n_changes; i++)
++                if (changes[i].type == UNIT_FILE_UNLINK) {
++                        r = sd_bus_message_append(reply, "s", changes[i].path);
++                        if (r < 0)
++                                return r;
++                }
++
++        r = sd_bus_message_close_container(reply);
++        if (r < 0)
++                return r;
++
++        return sd_bus_send(bus, reply, NULL);
++}
++
+ const sd_bus_vtable bus_manager_vtable[] = {
+         SD_BUS_VTABLE_START(0),
+ 
+@@ -2049,6 +2092,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
+         SD_BUS_METHOD("GetDefaultTarget", NULL, "s", method_get_default_target, SD_BUS_VTABLE_UNPRIVILEGED),
+         SD_BUS_METHOD("PresetAllUnitFiles", "sbb", "a(sss)", method_preset_all_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
+         SD_BUS_METHOD("AddDependencyUnitFiles", "asssbb", "a(sss)", method_add_dependency_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
++        SD_BUS_METHOD("GetUnitFileLinks", "sb", "as", method_get_unit_file_links, SD_BUS_VTABLE_UNPRIVILEGED),
+ 
+         SD_BUS_SIGNAL("UnitNew", "so", 0),
+         SD_BUS_SIGNAL("UnitRemoved", "so", 0),
+diff --git a/src/core/org.freedesktop.systemd1.conf b/src/core/org.freedesktop.systemd1.conf
+index 6a7a37e..3997dd0 100644
+--- a/src/core/org.freedesktop.systemd1.conf
++++ b/src/core/org.freedesktop.systemd1.conf
+@@ -78,6 +78,10 @@
+ 
+                 <allow send_destination="org.freedesktop.systemd1"
+                        send_interface="org.freedesktop.systemd1.Manager"
++                       send_member="GetUnitFileLinks"/>
++
++                <allow send_destination="org.freedesktop.systemd1"
++                       send_interface="org.freedesktop.systemd1.Manager"
+                        send_member="ListJobs"/>
+ 
+                 <allow send_destination="org.freedesktop.systemd1"
+diff --git a/src/shared/install.c b/src/shared/install.c
+index b3df6b3..bdfd7b9 100644
+--- a/src/shared/install.c
++++ b/src/shared/install.c
+@@ -340,6 +340,7 @@ static int remove_marked_symlinks_fd(
+                 int fd,
+                 const char *path,
+                 const char *config_path,
++                bool dry_run,
+                 bool *restart,
+                 UnitFileChange **changes,
+                 unsigned *n_changes) {
+@@ -400,7 +401,7 @@ static int remove_marked_symlinks_fd(
+                         }
+ 
+                         /* This will close nfd, regardless whether it succeeds or not */
+-                        q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, restart, changes, n_changes);
++                        q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, dry_run, restart, changes, n_changes);
+                         if (q < 0 && r == 0)
+                                 r = q;
+ 
+@@ -439,21 +440,23 @@ static int remove_marked_symlinks_fd(
+                         if (!found)
+                                 continue;
+ 
+-                        if (unlink(p) < 0 && errno != ENOENT) {
+-                                if (r == 0)
+-                                        r = -errno;
+-                                continue;
+-                        }
++                        if (!dry_run) {
++                                if (unlink(p) < 0 && errno != ENOENT) {
++                                        if (r == 0)
++                                                r = -errno;
++                                        continue;
++                                }
+ 
+-                        path_kill_slashes(p);
+-                        (void) rmdir_parents(p, config_path);
++                                path_kill_slashes(p);
++                                (void) rmdir_parents(p, config_path);
++                        }
+ 
+                         unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
+ 
+                         q = mark_symlink_for_removal(&remove_symlinks_to, p);
+                         if (q < 0)
+                                 return q;
+-                        if (q > 0)
++                        if (q > 0 && !dry_run)
+                                 *restart = true;
+                 }
+         }
+@@ -464,6 +467,7 @@ static int remove_marked_symlinks_fd(
+ static int remove_marked_symlinks(
+                 Set *remove_symlinks_to,
+                 const char *config_path,
++                bool dry_run,
+                 UnitFileChange **changes,
+                 unsigned *n_changes) {
+ 
+@@ -491,7 +495,7 @@ static int remove_marked_symlinks(
+                 }
+ 
+                 /* This takes possession of cfd and closes it */
+-                q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &restart, changes, n_changes);
++                q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, dry_run, &restart, changes, n_changes);
+                 if (r == 0)
+                         r = q;
+         } while (restart);
+@@ -1604,6 +1608,7 @@ int unit_file_unmask(
+         _cleanup_strv_free_ char **todo = NULL;
+         size_t n_todo = 0, n_allocated = 0;
+         char **i;
++        bool dry_run;
+         int r, q;
+ 
+         assert(scope >= 0);
+@@ -1617,6 +1622,8 @@ int unit_file_unmask(
+         if (r < 0)
+                 return r;
+ 
++        dry_run = !!(flags & UNIT_FILE_DRY_RUN);
++
+         STRV_FOREACH(i, files) {
+                 _cleanup_free_ char *path = NULL;
+ 
+@@ -1655,7 +1662,7 @@ int unit_file_unmask(
+                 if (!path)
+                         return -ENOMEM;
+ 
+-                if (unlink(path) < 0) {
++                if (!dry_run && unlink(path) < 0) {
+                         if (errno != -ENOENT && r >= 0)
+                                 r = -errno;
+                 } else {
+@@ -1667,7 +1674,7 @@ int unit_file_unmask(
+                 }
+         }
+ 
+-        q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
++        q = remove_marked_symlinks(remove_symlinks_to, config_path, dry_run, changes, n_changes);
+         if (r >= 0)
+                 r = q;
+ 
+@@ -1931,7 +1938,7 @@ int unit_file_disable(
+         if (r < 0)
+                 return r;
+ 
+-        return remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
++        return remove_marked_symlinks(remove_symlinks_to, config_path, !!(flags & UNIT_FILE_DRY_RUN), changes, n_changes);
+ }
+ 
+ int unit_file_reenable(
+@@ -2243,7 +2250,7 @@ static int execute_preset(
+                 if (r < 0)
+                         return r;
+ 
+-                r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
++                r = remove_marked_symlinks(remove_symlinks_to, config_path, false, changes, n_changes);
+         } else
+                 r = 0;
+ 
+diff --git a/src/shared/install.h b/src/shared/install.h
+index c961b53..c236dcf 100644
+--- a/src/shared/install.h
++++ b/src/shared/install.h
+@@ -68,7 +68,8 @@ typedef enum UnitFileChangeType {
+ 
+ typedef enum UnitFileFlags {
+         UNIT_FILE_RUNTIME = 1,
+-        UNIT_FILE_FORCE = 1 << 1
++        UNIT_FILE_FORCE = 1 << 1,
++        UNIT_FILE_DRY_RUN = 1 << 2
+ } UnitFileFlags;
+ 
+ static inline bool unit_file_change_is_modification(UnitFileChangeType type) {
+diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
+index e0dbf0f..ff8b4e9 100644
+--- a/src/systemctl/systemctl.c
++++ b/src/systemctl/systemctl.c
+@@ -5722,6 +5722,63 @@ finish:
+         return r;
+ }
+ 
++static int show_installation_targets_client_side(const char *name) {
++        UnitFileChange *changes = NULL;
++        unsigned n_changes = 0, i;
++        UnitFileFlags flags;
++        char **p;
++        int r;
++
++        p = STRV_MAKE(name);
++        flags = UNIT_FILE_DRY_RUN |
++                (arg_runtime ? UNIT_FILE_RUNTIME : 0);
++
++        r = unit_file_disable(UNIT_FILE_SYSTEM, flags, NULL, p, &changes, &n_changes);
++        if (r < 0)
++                return log_error_errno(r, "Failed to get file links for %s: %m", name);
++
++        for (i = 0; i < n_changes; i++)
++                if (changes[i].type == UNIT_FILE_UNLINK)
++                        printf("  %s\n", changes[i].path);
++
++        return 0;
++}
++
++static int show_installation_targets(sd_bus *bus, const char *name) {
++        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
++        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
++        const char *link;
++        int r;
++
++        r = sd_bus_call_method(
++                        bus,
++                        "org.freedesktop.systemd1",
++                        "/org/freedesktop/systemd1",
++                        "org.freedesktop.systemd1.Manager",
++                        "GetUnitFileLinks",
++                        &error,
++                        &reply,
++                        "sb", name, arg_runtime);
++        if (r < 0)
++                return log_error_errno(r, "Failed to get unit file links for %s: %s", name, bus_error_message(&error, r));
++
++        r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
++        if (r < 0)
++                return bus_log_parse_error(r);
++
++        while ((r = sd_bus_message_read(reply, "s", &link)) > 0)
++                printf("  %s\n", link);
++
++        if (r < 0)
++                return bus_log_parse_error(r);
++
++        r = sd_bus_message_exit_container(reply);
++        if (r < 0)
++                return bus_log_parse_error(r);
++
++        return 0;
++}
++
+ static int unit_is_enabled(sd_bus *bus, char **args) {
+ 
+         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+@@ -5755,8 +5812,14 @@ static int unit_is_enabled(sd_bus *bus, char **args) {
+                             state == UNIT_FILE_INDIRECT)
+                                 enabled = true;
+ 
+-                        if (!arg_quiet)
++                        if (!arg_quiet) {
+                                 puts(unit_file_state_to_string(state));
++                                if (arg_full) {
++                                        r = show_installation_targets_client_side(*name);
++                                        if (r < 0)
++                                                return r;
++                                }
++                        }
+                 }
+ 
+         } else {
+@@ -5785,8 +5848,14 @@ static int unit_is_enabled(sd_bus *bus, char **args) {
+                         if (STR_IN_SET(s, "enabled", "enabled-runtime", "static", "indirect"))
+                                 enabled = true;
+ 
+-                        if (!arg_quiet)
++                        if (!arg_quiet) {
+                                 puts(s);
++                                if (arg_full) {
++                                        r = show_installation_targets(bus, *name);
++                                        if (r < 0)
++                                                return r;
++                                }
++                        }
+                 }
+         }
+ 
diff --git a/SOURCES/0445-udev-fix-crash-with-invalid-udev.log-priority.patch b/SOURCES/0445-udev-fix-crash-with-invalid-udev.log-priority.patch
new file mode 100644
index 0000000..8595f73
--- /dev/null
+++ b/SOURCES/0445-udev-fix-crash-with-invalid-udev.log-priority.patch
@@ -0,0 +1,32 @@
+From 22423054480ed8dee70160e9e886ca372b3440f3 Mon Sep 17 00:00:00 2001
+From: Michal Schmidt <mschmidt@redhat.com>
+Date: Tue, 21 Jul 2015 18:26:09 +0200
+Subject: [PATCH] udev: fix crash with invalid udev.log-priority
+
+Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1245293
+
+Conflicts:
+	src/udev/udevd.c
+
+Cherry-picked from: e00f5bddde0daff900cbd93e1ee0530ad1ae06ce
+Resolves: #1245293
+---
+ src/udev/udevd.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/src/udev/udevd.c b/src/udev/udevd.c
+index 21e7e7f..82c7a54 100644
+--- a/src/udev/udevd.c
++++ b/src/udev/udevd.c
+@@ -990,7 +990,10 @@ static void kernel_cmdline_options(struct udev *udev) {
+                         int prio;
+ 
+                         prio = util_log_priority(value);
+-                        log_set_max_level(prio);
++                        if (prio < 0)
++                                log_warning("Invalid udev.log-priority ignored: %s", value);
++                        else
++                                log_set_max_level(prio);
+                 } else if ((value = startswith(opt, "udev.children-max="))) {
+                         r = safe_atoi(value, &arg_children_max);
+                         if (r < 0)
diff --git a/SOURCES/0446-core-make-exec-code-a-bit-more-readable.patch b/SOURCES/0446-core-make-exec-code-a-bit-more-readable.patch
new file mode 100644
index 0000000..f6483f9
--- /dev/null
+++ b/SOURCES/0446-core-make-exec-code-a-bit-more-readable.patch
@@ -0,0 +1,73 @@
+From ccf46ebc548054f876a418fc2e949a05a74a9c2a Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Wed, 13 May 2015 16:34:02 +0200
+Subject: [PATCH] core: make exec code a bit more readable
+
+Let's add a function that checks whether we need fs namespacing, to make
+things easier to read, instead of using a humungous if expression...
+
+Cherry-picked from: 8b44a3d22c1fdfc5ce5fcb77e38a90ec02ba8019
+Related: #1421181
+---
+ src/core/execute.c | 41 +++++++++++++++++++++++++++++++----------
+ 1 file changed, 31 insertions(+), 10 deletions(-)
+
+diff --git a/src/core/execute.c b/src/core/execute.c
+index e9b4359..59340ec 100644
+--- a/src/core/execute.c
++++ b/src/core/execute.c
+@@ -1256,6 +1256,36 @@ static int build_environment(
+         return 0;
+ }
+ 
++static bool exec_needs_mount_namespace(
++                const ExecContext *context,
++                const ExecParameters *params,
++                ExecRuntime *runtime) {
++
++        assert(context);
++        assert(params);
++
++        if (!strv_isempty(context->read_write_dirs) ||
++            !strv_isempty(context->read_only_dirs) ||
++            !strv_isempty(context->inaccessible_dirs))
++                return true;
++
++        if (context->mount_flags != 0)
++                return true;
++
++        if (context->private_tmp && runtime && (runtime->tmp_dir || runtime->var_tmp_dir))
++                return true;
++
++        if (params->bus_endpoint_path)
++                return true;
++
++        if (context->private_devices ||
++            context->protect_system != PROTECT_SYSTEM_NO ||
++            context->protect_home != PROTECT_HOME_NO)
++                return true;
++
++        return false;
++}
++
+ static int exec_child(
+                 ExecCommand *command,
+                 const ExecContext *context,
+@@ -1563,16 +1593,7 @@ static int exec_child(
+                 }
+         }
+ 
+-        if (!strv_isempty(context->read_write_dirs) ||
+-            !strv_isempty(context->read_only_dirs) ||
+-            !strv_isempty(context->inaccessible_dirs) ||
+-            context->mount_flags != 0 ||
+-            (context->private_tmp && runtime && (runtime->tmp_dir || runtime->var_tmp_dir)) ||
+-            params->bus_endpoint_path ||
+-            context->private_devices ||
+-            context->protect_system != PROTECT_SYSTEM_NO ||
+-            context->protect_home != PROTECT_HOME_NO) {
+-
++        if (exec_needs_mount_namespace(context, params, runtime)) {
+                 char *tmp = NULL, *var = NULL;
+ 
+                 /* The runtime struct only contains the parent
diff --git a/SOURCES/0447-core-Private-Protect-options-with-RootDirectory.patch b/SOURCES/0447-core-Private-Protect-options-with-RootDirectory.patch
new file mode 100644
index 0000000..7da95e2
--- /dev/null
+++ b/SOURCES/0447-core-Private-Protect-options-with-RootDirectory.patch
@@ -0,0 +1,295 @@
+From 2b4894764e9e92ae9004524ed466b4bdf94b2a34 Mon Sep 17 00:00:00 2001
+From: Alban Crequy <alban@endocode.com>
+Date: Mon, 18 May 2015 12:20:28 +0200
+Subject: [PATCH] core: Private*/Protect* options with RootDirectory
+
+When a service is chrooted with the option RootDirectory=/opt/..., then
+the options PrivateDevices, PrivateTmp, ProtectHome, ProtectSystem must
+mount the directories under $RootDirectory/{dev,tmp,home,usr,boot}.
+
+The test-ns tool can test setup_namespace() with and without chroot:
+ $ sudo TEST_NS_PROJECTS=/home/lennart/projects ./test-ns
+ $ sudo TEST_NS_CHROOT=/home/alban/debian-tree TEST_NS_PROJECTS=/home/alban/debian-tree/home/alban/Documents ./test-ns
+
+Cherry-picked from: ee818b89f4890b3a00e93772249fce810f60811e
+Resolves: #1421181
+---
+ src/core/execute.c   |  8 ++++--
+ src/core/namespace.c | 80 +++++++++++++++++++++++++++++++++++++++++++++-------
+ src/core/namespace.h |  3 +-
+ src/test/test-ns.c   | 24 ++++++++++++++--
+ 4 files changed, 100 insertions(+), 15 deletions(-)
+
+diff --git a/src/core/execute.c b/src/core/execute.c
+index 59340ec..863babd 100644
+--- a/src/core/execute.c
++++ b/src/core/execute.c
+@@ -1305,6 +1305,7 @@ static int exec_child(
+         uid_t uid = UID_INVALID;
+         gid_t gid = GID_INVALID;
+         int i, r;
++        bool needs_mount_namespace;
+ 
+         assert(command);
+         assert(context);
+@@ -1593,7 +1594,9 @@ static int exec_child(
+                 }
+         }
+ 
+-        if (exec_needs_mount_namespace(context, params, runtime)) {
++        needs_mount_namespace = exec_needs_mount_namespace(context, params, runtime);
++
++        if (needs_mount_namespace) {
+                 char *tmp = NULL, *var = NULL;
+ 
+                 /* The runtime struct only contains the parent
+@@ -1610,6 +1613,7 @@ static int exec_child(
+                 }
+ 
+                 r = setup_namespace(
++                                params->apply_chroot ? context->root_directory : NULL,
+                                 context->read_write_dirs,
+                                 context->read_only_dirs,
+                                 context->inaccessible_dirs,
+@@ -1635,7 +1639,7 @@ static int exec_child(
+         }
+ 
+         if (params->apply_chroot) {
+-                if (context->root_directory)
++                if (!needs_mount_namespace && context->root_directory)
+                         if (chroot(context->root_directory) < 0) {
+                                 *exit_status = EXIT_CHROOT;
+                                 return -errno;
+diff --git a/src/core/namespace.c b/src/core/namespace.c
+index 00495c1..5747462 100644
+--- a/src/core/namespace.c
++++ b/src/core/namespace.c
+@@ -44,6 +44,7 @@
+ #include "label.h"
+ #include "selinux-util.h"
+ #include "namespace.h"
++#include "mkdir.h"
+ 
+ typedef enum MountMode {
+         /* This is ordered by priority! */
+@@ -132,6 +133,22 @@ static void drop_duplicates(BindMount *m, unsigned *n) {
+         *n = t - m;
+ }
+ 
++static int mount_move_root(const char *path) {
++        if (chdir(path) < 0)
++                return -errno;
++
++        if (mount(path, "/", NULL, MS_MOVE, NULL) < 0)
++                return -errno;
++
++        if (chroot(".") < 0)
++                return -errno;
++
++        if (chdir("/") < 0)
++                return -errno;
++
++        return 0;
++}
++
+ static int mount_dev(BindMount *m) {
+         static const char devnodes[] =
+                 "/dev/null\0"
+@@ -231,7 +248,13 @@ static int mount_dev(BindMount *m) {
+ 
+         dev_setup(temporary_mount);
+ 
+-        if (mount(dev, "/dev/", NULL, MS_MOVE, NULL) < 0) {
++        /* Create the /dev directory if missing. It is more likely to be
++         * missing when the service is started with RootDirectory. This is
++         * consistent with mount units creating the mount points when missing.
++         */
++        (void) mkdir_p_label(m->path, 0755);
++
++        if (mount(dev, m->path, NULL, MS_MOVE, NULL) < 0) {
+                 r = -errno;
+                 goto fail;
+         }
+@@ -410,6 +433,7 @@ static int make_read_only(BindMount *m) {
+ }
+ 
+ int setup_namespace(
++                const char* root_directory,
+                 char** read_write_dirs,
+                 char** read_only_dirs,
+                 char** inaccessible_dirs,
+@@ -455,37 +479,56 @@ int setup_namespace(
+                         return r;
+ 
+                 if (tmp_dir) {
+-                        m->path = "/tmp";
++                        m->path = prefix_roota(root_directory, "/tmp");
+                         m->mode = PRIVATE_TMP;
+                         m++;
+                 }
+ 
+                 if (var_tmp_dir) {
+-                        m->path = "/var/tmp";
++                        m->path = prefix_roota(root_directory, "/var/tmp");
+                         m->mode = PRIVATE_VAR_TMP;
+                         m++;
+                 }
+ 
+                 if (private_dev) {
+-                        m->path = "/dev";
++                        m->path = prefix_roota(root_directory, "/dev");
+                         m->mode = PRIVATE_DEV;
+                         m++;
+                 }
+ 
+                 if (bus_endpoint_path) {
+-                        m->path = bus_endpoint_path;
++                        m->path = prefix_roota(root_directory, bus_endpoint_path);
+                         m->mode = PRIVATE_BUS_ENDPOINT;
+                         m++;
+                 }
+ 
+                 if (protect_home != PROTECT_HOME_NO) {
+-                        r = append_mounts(&m, STRV_MAKE("-/home", "-/run/user", "-/root"), protect_home == PROTECT_HOME_READ_ONLY ? READONLY : INACCESSIBLE);
++                        const char *home_dir, *run_user_dir, *root_dir;
++
++                        home_dir = prefix_roota(root_directory, "/home");
++                        home_dir = strjoina("-", home_dir);
++                        run_user_dir = prefix_roota(root_directory, "/run/user");
++                        run_user_dir = strjoina("-", run_user_dir);
++                        root_dir = prefix_roota(root_directory, "/root");
++                        root_dir = strjoina("-", root_dir);
++
++                        r = append_mounts(&m, STRV_MAKE(home_dir, run_user_dir, root_dir),
++                                protect_home == PROTECT_HOME_READ_ONLY ? READONLY : INACCESSIBLE);
+                         if (r < 0)
+                                 return r;
+                 }
+ 
+                 if (protect_system != PROTECT_SYSTEM_NO) {
+-                        r = append_mounts(&m, protect_system == PROTECT_SYSTEM_FULL ? STRV_MAKE("/usr", "-/boot", "/etc") : STRV_MAKE("/usr", "-/boot"), READONLY);
++                        const char *usr_dir, *boot_dir, *etc_dir;
++
++                        usr_dir = prefix_roota(root_directory, "/home");
++                        boot_dir = prefix_roota(root_directory, "/boot");
++                        boot_dir = strjoina("-", boot_dir);
++                        etc_dir = prefix_roota(root_directory, "/etc");
++
++                        r = append_mounts(&m, protect_system == PROTECT_SYSTEM_FULL
++                                ? STRV_MAKE(usr_dir, boot_dir, etc_dir)
++                                : STRV_MAKE(usr_dir, boot_dir), READONLY);
+                         if (r < 0)
+                                 return r;
+                 }
+@@ -496,12 +539,20 @@ int setup_namespace(
+                 drop_duplicates(mounts, &n);
+         }
+ 
+-        if (n > 0) {
++        if (n > 0 || root_directory) {
+                 /* Remount / as SLAVE so that nothing now mounted in the namespace
+                    shows up in the parent */
+                 if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0)
+                         return -errno;
++        }
++
++        if (root_directory) {
++                /* Turn directory into bind mount */
++                if (mount(root_directory, root_directory, NULL, MS_BIND|MS_REC, NULL) < 0)
++                        return -errno;
++        }
+ 
++        if (n > 0) {
+                 for (m = mounts; m < mounts + n; ++m) {
+                         r = apply_mount(m, tmp_dir, var_tmp_dir);
+                         if (r < 0)
+@@ -515,12 +566,21 @@ int setup_namespace(
+                 }
+         }
+ 
++        if (root_directory) {
++                /* MS_MOVE does not work on MS_SHARED so the remount MS_SHARED will be done later */
++                r = mount_move_root(root_directory);
++
++                /* at this point, we cannot rollback */
++                if (r < 0)
++                        return r;
++        }
++
+         /* Remount / as the desired mode. Not that this will not
+          * reestablish propagation from our side to the host, since
+          * what's disconnected is disconnected. */
+         if (mount(NULL, "/", NULL, mount_flags | MS_REC, NULL) < 0) {
+-                r = -errno;
+-                goto fail;
++                /* at this point, we cannot rollback */
++                return -errno;
+         }
+ 
+         return 0;
+diff --git a/src/core/namespace.h b/src/core/namespace.h
+index 42b92e7..00ab22b 100644
+--- a/src/core/namespace.h
++++ b/src/core/namespace.h
+@@ -41,7 +41,8 @@ typedef enum ProtectSystem {
+         _PROTECT_SYSTEM_INVALID = -1
+ } ProtectSystem;
+ 
+-int setup_namespace(char **read_write_dirs,
++int setup_namespace(const char *chroot,
++                    char **read_write_dirs,
+                     char **read_only_dirs,
+                     char **inaccessible_dirs,
+                     const char *tmp_dir,
+diff --git a/src/test/test-ns.c b/src/test/test-ns.c
+index 7cd7b77..72a0004 100644
+--- a/src/test/test-ns.c
++++ b/src/test/test-ns.c
+@@ -42,10 +42,12 @@ int main(int argc, char *argv[]) {
+                 NULL
+         };
+ 
+-        const char * const inaccessible[] = {
++        const char *inaccessible[] = {
+                 "/home/lennart/projects",
+                 NULL
+         };
++        char *root_directory;
++        char *projects_directory;
+ 
+         int r;
+         char tmp_dir[] = "/tmp/systemd-private-XXXXXX",
+@@ -54,7 +56,20 @@ int main(int argc, char *argv[]) {
+         assert_se(mkdtemp(tmp_dir));
+         assert_se(mkdtemp(var_tmp_dir));
+ 
+-        r = setup_namespace((char **) writable,
++        root_directory = getenv("TEST_NS_CHROOT");
++        projects_directory = getenv("TEST_NS_PROJECTS");
++
++        if (projects_directory)
++                inaccessible[0] = projects_directory;
++
++        log_info("Inaccessible directory: '%s'", inaccessible[0]);
++        if (root_directory)
++                log_info("Chroot: '%s'", root_directory);
++        else
++                log_info("Not chrooted");
++
++        r = setup_namespace(root_directory,
++                            (char **) writable,
+                             (char **) readonly,
+                             (char **) inaccessible,
+                             tmp_dir,
+@@ -66,6 +81,11 @@ int main(int argc, char *argv[]) {
+                             0);
+         if (r < 0) {
+                 log_error_errno(r, "Failed to setup namespace: %m");
++
++                log_info("Usage:\n"
++                         "  sudo TEST_NS_PROJECTS=/home/lennart/projects ./test-ns\n"
++                         "  sudo TEST_NS_CHROOT=/home/alban/debian-tree TEST_NS_PROJECTS=/home/alban/debian-tree/home/alban/Documents ./test-ns");
++
+                 return 1;
+         }
+ 
diff --git a/SOURCES/0448-core-if-the-start-command-vanishes-during-runtime-do.patch b/SOURCES/0448-core-if-the-start-command-vanishes-during-runtime-do.patch
new file mode 100644
index 0000000..f75e106
--- /dev/null
+++ b/SOURCES/0448-core-if-the-start-command-vanishes-during-runtime-do.patch
@@ -0,0 +1,38 @@
+From a66f97acac8b99a49aac58adf6d652cad7e4be38 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Fri, 21 Oct 2016 12:27:46 +0200
+Subject: [PATCH] core: if the start command vanishes during runtime don't hit
+ an assert
+
+This can happen when the configuration is changed and reloaded while we are
+executing a service. Let's not hit an assert in this case.
+
+Fixes: #4444
+
+Cherry-picked from: 47fffb3530af3e3ad4048570611685635fde062e
+Resolves: #1421658
+---
+ src/core/service.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/src/core/service.c b/src/core/service.c
+index 6e7baa7..84e0057 100644
+--- a/src/core/service.c
++++ b/src/core/service.c
+@@ -1563,7 +1563,15 @@ static void service_enter_start(Service *s) {
+         }
+ 
+         if (!c) {
+-                assert(s->type == SERVICE_ONESHOT);
++                if (s->type != SERVICE_ONESHOT) {
++                        /* There's no command line configured for the main command? Hmm, that is strange. This can only
++                         * happen if the configuration changes at runtime. In this case, let's enter a failure
++                         * state. */
++                        log_unit_error(UNIT(s), "There's no 'start' task anymore we could start: %m");
++                        r = -ENXIO;
++                        goto fail;
++                }
++
+                 service_enter_start_post(s);
+                 return;
+         }
diff --git a/SOURCES/0449-systemctl-make-sure-that-now-is-carried-out-5209.patch b/SOURCES/0449-systemctl-make-sure-that-now-is-carried-out-5209.patch
new file mode 100644
index 0000000..d054751
--- /dev/null
+++ b/SOURCES/0449-systemctl-make-sure-that-now-is-carried-out-5209.patch
@@ -0,0 +1,46 @@
+From 10bf9c070764d09a4b39aa65ccba8b7501918a34 Mon Sep 17 00:00:00 2001
+From: Jan Synacek <jan.synacek@gmail.com>
+Date: Wed, 8 Feb 2017 20:57:08 +0100
+Subject: [PATCH] systemctl: make sure that --now is carried out (#5209)
+
+When services are already enabled/disabled/masked, make sure
+that --now still enforces start/stop.
+(cherry picked from commit 6bc30691b109302d386007c6bdabcc27d04991bc)
+Resolves: #1417459
+---
+ src/systemctl/systemctl.c | 20 ++++++++++++--------
+ 1 file changed, 12 insertions(+), 8 deletions(-)
+
+diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
+index ff8b4e9..0333599 100644
+--- a/src/systemctl/systemctl.c
++++ b/src/systemctl/systemctl.c
+@@ -5549,16 +5549,20 @@ static int enable_unit(sd_bus *bus, char **args) {
+                             "3) A unit may be started when needed via activation (socket, path, timer,\n"
+                             "   D-Bus, udev, scripted systemctl call, ...).\n");
+ 
+-        if (arg_now && n_changes > 0 && STR_IN_SET(args[0], "enable", "disable", "mask")) {
+-                char *new_args[n_changes + 2];
+-                unsigned i;
++        if (arg_now && STR_IN_SET(args[0], "enable", "disable", "mask")) {
++                unsigned len, i;
+ 
+-                new_args[0] = streq(args[0], "enable") ? (char *)"start" : (char *)"stop";
+-                for (i = 0; i < n_changes; i++)
+-                        new_args[i + 1] = basename(changes[i].path);
+-                new_args[i + 1] = NULL;
++                len = strv_length(names);
++                {
++                        char *new_args[len + 2];
+ 
+-                r = start_unit(bus, new_args);
++                        new_args[0] = (char*) (streq(args[0], "enable") ? "start" : "stop");
++                        for (i = 0; i < len; i++)
++                                new_args[i + 1] = basename(names[i]);
++                        new_args[i + 1] = NULL;
++
++                        r = start_unit(bus, new_args);
++                }
+         }
+ 
+ finish:
diff --git a/SOURCES/0450-udev-inform-systemd-how-many-workers-we-can-potentia.patch b/SOURCES/0450-udev-inform-systemd-how-many-workers-we-can-potentia.patch
new file mode 100644
index 0000000..8535cfe
--- /dev/null
+++ b/SOURCES/0450-udev-inform-systemd-how-many-workers-we-can-potentia.patch
@@ -0,0 +1,47 @@
+From fa37e91818c1de70977462d170df08f441170db5 Mon Sep 17 00:00:00 2001
+From: Michal Sekletar <msekletar@users.noreply.github.com>
+Date: Thu, 25 Aug 2016 08:18:42 +0200
+Subject: [PATCH] udev: inform systemd how many workers we can potentially
+ spawn (#4036)
+
+(cherry picked from commit 1ef72b55ba6d38f879d7ac9f0237cf8a2b53f0e6)
+Resolves: #1361601
+---
+ src/udev/udevd.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/src/udev/udevd.c b/src/udev/udevd.c
+index 82c7a54..1d21182 100644
+--- a/src/udev/udevd.c
++++ b/src/udev/udevd.c
+@@ -697,6 +697,10 @@ static struct udev_ctrl_connection *handle_ctrl_msg(struct udev_ctrl *uctrl) {
+         if (i >= 0) {
+                 log_debug("udevd message (SET_MAX_CHILDREN) received, children_max=%i", i);
+                 arg_children_max = i;
++
++                (void) sd_notifyf(false,
++                                  "READY=1\n"
++                                  "STATUS=Processing with %u children at max", arg_children_max);
+         }
+ 
+         if (udev_ctrl_get_ping(ctrl_msg) > 0)
+@@ -1271,8 +1275,6 @@ int main(int argc, char *argv[]) {
+                 setsid();
+ 
+                 write_string_file("/proc/self/oom_score_adj", "-1000");
+-        } else {
+-                sd_notify(1, "READY=1");
+         }
+ 
+         if (arg_children_max <= 0) {
+@@ -1321,6 +1323,10 @@ int main(int argc, char *argv[]) {
+         ep_netlink.data.fd = fd_netlink;
+         ep_worker.data.fd = fd_worker;
+ 
++        (void) sd_notifyf(false,
++                          "READY=1\n"
++                          "STATUS=Processing with %u children at max", arg_children_max);
++
+         fd_ep = epoll_create1(EPOLL_CLOEXEC);
+         if (fd_ep < 0) {
+                 log_error_errno(errno, "error creating epoll fd: %m");
diff --git a/SOURCES/0451-service-log_unit-consumes-id-of-unit-not-a-unit.patch b/SOURCES/0451-service-log_unit-consumes-id-of-unit-not-a-unit.patch
new file mode 100644
index 0000000..59c16f6
--- /dev/null
+++ b/SOURCES/0451-service-log_unit-consumes-id-of-unit-not-a-unit.patch
@@ -0,0 +1,24 @@
+From 01cfafc9f1d79f751405239046db827b6eb73f1e Mon Sep 17 00:00:00 2001
+From: Lukas Nykryn <lnykryn@redhat.com>
+Date: Mon, 20 Feb 2017 12:32:42 +0100
+Subject: [PATCH] service: log_unit consumes id of unit not a unit
+
+rhel-only
+Related: #1421658
+---
+ src/core/service.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/core/service.c b/src/core/service.c
+index 84e0057..3bd6c33 100644
+--- a/src/core/service.c
++++ b/src/core/service.c
+@@ -1567,7 +1567,7 @@ static void service_enter_start(Service *s) {
+                         /* There's no command line configured for the main command? Hmm, that is strange. This can only
+                          * happen if the configuration changes at runtime. In this case, let's enter a failure
+                          * state. */
+-                        log_unit_error(UNIT(s), "There's no 'start' task anymore we could start: %m");
++                        log_unit_error(UNIT(s)->id, "There's no 'start' task anymore we could start: %m");
+                         r = -ENXIO;
+                         goto fail;
+                 }
diff --git a/SOURCES/0452-automount-add-expire-support.patch b/SOURCES/0452-automount-add-expire-support.patch
new file mode 100644
index 0000000..f904603
--- /dev/null
+++ b/SOURCES/0452-automount-add-expire-support.patch
@@ -0,0 +1,578 @@
+From c38c0e05767c5fd526368b63cebcdd5617332940 Mon Sep 17 00:00:00 2001
+From: Michael Olbrich <m.olbrich@pengutronix.de>
+Date: Tue, 14 Apr 2015 22:01:48 +0200
+Subject: [PATCH] automount: add expire support
+
+(cherry picked from commit deb0a77cf0b409141c4b116ae30becb3d878e1ad)
+Resolves: #1354410
+---
+ man/systemd.automount.xml             |   8 ++
+ man/systemd.mount.xml                 |   9 ++
+ src/core/automount.c                  | 224 ++++++++++++++++++++++++++++++++--
+ src/core/automount.h                  |   6 +-
+ src/core/dbus-automount.c             |   1 +
+ src/core/load-fragment-gperf.gperf.m4 |   1 +
+ src/core/mount.c                      |  20 +--
+ src/fstab-generator/fstab-generator.c |  28 +++++
+ 8 files changed, 269 insertions(+), 28 deletions(-)
+
+diff --git a/man/systemd.automount.xml b/man/systemd.automount.xml
+index b5b5885..9561590 100644
+--- a/man/systemd.automount.xml
++++ b/man/systemd.automount.xml
+@@ -135,6 +135,14 @@
+         creating these directories. Takes an access mode in octal
+         notation. Defaults to 0755.</para></listitem>
+       </varlistentry>
++      <varlistentry>
++        <term><varname>TimeoutIdleSec=</varname></term>
++        <listitem><para>Configures an idleness timeout. Once the mount has been
++        idle for the specified time, systemd will attempt to unmount. Takes a
++        unit-less value in seconds, or a time span value such as "5min 20s".
++        Pass 0 to disable the timeout logic. The timeout is disabled by
++        default.</para></listitem>
++      </varlistentry>
+     </variablelist>
+   </refsect1>
+ 
+diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml
+index 8e652e1..04ed1e1 100644
+--- a/man/systemd.mount.xml
++++ b/man/systemd.mount.xml
+@@ -178,6 +178,15 @@
+       </varlistentry>
+ 
+       <varlistentry>
++        <term><option>x-systemd.idle-timeout=</option></term>
++
++        <listitem><para>Configures the idleness timeout of the
++        automount unit. See <varname>TimeoutIdleSec=</varname> in
++        <citerefentry><refentrytitle>systemd.automount</refentrytitle><manvolnum>5</manvolnum></citerefentry>
++        for details.</para></listitem>
++      </varlistentry>
++
++      <varlistentry>
+         <term><option>x-systemd.device-timeout=</option></term>
+ 
+         <listitem><para>Configure how long systemd should wait for a
+diff --git a/src/core/automount.c b/src/core/automount.c
+index b391f61..4e06661 100644
+--- a/src/core/automount.c
++++ b/src/core/automount.c
+@@ -42,6 +42,7 @@
+ #include "dbus-automount.h"
+ #include "bus-util.h"
+ #include "bus-error.h"
++#include "async.h"
+ 
+ static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = {
+         [AUTOMOUNT_DEAD] = UNIT_INACTIVE,
+@@ -50,6 +51,22 @@ static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = {
+         [AUTOMOUNT_FAILED] = UNIT_FAILED
+ };
+ 
++struct expire_data {
++        int dev_autofs_fd;
++        int ioctl_fd;
++};
++
++static inline void expire_data_free(struct expire_data *data) {
++        if (!data)
++                return;
++
++        safe_close(data->dev_autofs_fd);
++        safe_close(data->ioctl_fd);
++        free(data);
++}
++
++DEFINE_TRIVIAL_CLEANUP_FUNC(struct expire_data*, expire_data_free);
++
+ static int open_dev_autofs(Manager *m);
+ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata);
+ 
+@@ -81,13 +98,16 @@ static void repeat_unmount(const char *path) {
+         }
+ }
+ 
++static int automount_send_ready(Automount *a, Set *tokens, int status);
++
+ static void unmount_autofs(Automount *a) {
+         assert(a);
+ 
+         if (a->pipe_fd < 0)
+                 return;
+ 
+-        automount_send_ready(a, -EHOSTDOWN);
++        automount_send_ready(a, a->tokens, -EHOSTDOWN);
++        automount_send_ready(a, a->expire_tokens, -EHOSTDOWN);
+ 
+         a->pipe_event_source = sd_event_source_unref(a->pipe_event_source);
+         a->pipe_fd = safe_close(a->pipe_fd);
+@@ -112,6 +132,10 @@ static void automount_done(Unit *u) {
+ 
+         set_free(a->tokens);
+         a->tokens = NULL;
++        set_free(a->expire_tokens);
++        a->expire_tokens = NULL;
++
++        a->expire_event_source = sd_event_source_unref(a->expire_event_source);
+ }
+ 
+ static int automount_add_mount_links(Automount *a) {
+@@ -265,6 +289,7 @@ static int automount_coldplug(Unit *u, Hashmap *deferred_work) {
+ }
+ 
+ static void automount_dump(Unit *u, FILE *f, const char *prefix) {
++        char time_string[FORMAT_TIMESPAN_MAX];
+         Automount *a = AUTOMOUNT(u);
+ 
+         assert(a);
+@@ -273,11 +298,13 @@ static void automount_dump(Unit *u, FILE *f, const char *prefix) {
+                 "%sAutomount State: %s\n"
+                 "%sResult: %s\n"
+                 "%sWhere: %s\n"
+-                "%sDirectoryMode: %04o\n",
++                "%sDirectoryMode: %04o\n"
++                "%sTimeoutIdleUSec: %s\n",
+                 prefix, automount_state_to_string(a->state),
+                 prefix, automount_result_to_string(a->result),
+                 prefix, a->where,
+-                prefix, a->directory_mode);
++                prefix, a->directory_mode,
++                prefix, format_timespan(time_string, FORMAT_TIMESPAN_MAX, a->timeout_idle_usec, USEC_PER_SEC));
+ }
+ 
+ static void automount_enter_dead(Automount *a, AutomountResult f) {
+@@ -367,7 +394,7 @@ static int autofs_protocol(int dev_autofs_fd, int ioctl_fd) {
+         return 0;
+ }
+ 
+-static int autofs_set_timeout(int dev_autofs_fd, int ioctl_fd, time_t sec) {
++static int autofs_set_timeout(int dev_autofs_fd, int ioctl_fd, usec_t usec) {
+         struct autofs_dev_ioctl param;
+ 
+         assert(dev_autofs_fd >= 0);
+@@ -375,7 +402,9 @@ static int autofs_set_timeout(int dev_autofs_fd, int ioctl_fd, time_t sec) {
+ 
+         init_autofs_dev_ioctl(&param);
+         param.ioctlfd = ioctl_fd;
+-        param.timeout.timeout = sec;
++
++        /* Convert to seconds, rounding up. */
++        param.timeout.timeout = (usec + USEC_PER_SEC - 1) / USEC_PER_SEC;
+ 
+         if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_TIMEOUT, &param) < 0)
+                 return -errno;
+@@ -404,7 +433,7 @@ static int autofs_send_ready(int dev_autofs_fd, int ioctl_fd, uint32_t token, in
+         return 0;
+ }
+ 
+-int automount_send_ready(Automount *a, int status) {
++static int automount_send_ready(Automount *a, Set *tokens, int status) {
+         _cleanup_close_ int ioctl_fd = -1;
+         unsigned token;
+         int r;
+@@ -412,7 +441,7 @@ int automount_send_ready(Automount *a, int status) {
+         assert(a);
+         assert(status <= 0);
+ 
+-        if (set_isempty(a->tokens))
++        if (set_isempty(tokens))
+                 return 0;
+ 
+         ioctl_fd = open_ioctl_fd(UNIT(a)->manager->dev_autofs_fd, a->where, a->dev_id);
+@@ -427,7 +456,7 @@ int automount_send_ready(Automount *a, int status) {
+         r = 0;
+ 
+         /* Autofs thankfully does not hand out 0 as a token */
+-        while ((token = PTR_TO_UINT(set_steal_first(a->tokens)))) {
++        while ((token = PTR_TO_UINT(set_steal_first(tokens)))) {
+                 int k;
+ 
+                 /* Autofs fun fact II:
+@@ -446,6 +475,55 @@ int automount_send_ready(Automount *a, int status) {
+         return r;
+ }
+ 
++int automount_update_mount(Automount *a, MountState old_state, MountState state) {
++        _cleanup_close_ int ioctl_fd = -1;
++
++        assert(a);
++
++        switch (state) {
++        case MOUNT_MOUNTED:
++        case MOUNT_REMOUNTING:
++                automount_send_ready(a, a->tokens, 0);
++                break;
++         case MOUNT_DEAD:
++         case MOUNT_UNMOUNTING:
++         case MOUNT_MOUNTING_SIGTERM:
++         case MOUNT_MOUNTING_SIGKILL:
++         case MOUNT_REMOUNTING_SIGTERM:
++         case MOUNT_REMOUNTING_SIGKILL:
++         case MOUNT_UNMOUNTING_SIGTERM:
++         case MOUNT_UNMOUNTING_SIGKILL:
++         case MOUNT_FAILED:
++                if (old_state != state)
++                        automount_send_ready(a, a->tokens, -ENODEV);
++                break;
++        default:
++                break;
++        }
++
++        switch (state) {
++        case MOUNT_DEAD:
++                automount_send_ready(a, a->expire_tokens, 0);
++                break;
++         case MOUNT_MOUNTING:
++         case MOUNT_MOUNTING_DONE:
++         case MOUNT_MOUNTING_SIGTERM:
++         case MOUNT_MOUNTING_SIGKILL:
++         case MOUNT_REMOUNTING_SIGTERM:
++         case MOUNT_REMOUNTING_SIGKILL:
++         case MOUNT_UNMOUNTING_SIGTERM:
++         case MOUNT_UNMOUNTING_SIGKILL:
++         case MOUNT_FAILED:
++                if (old_state != state)
++                        automount_send_ready(a, a->expire_tokens, -ENODEV);
++                break;
++        default:
++                break;
++        }
++
++        return 0;
++}
++
+ static void automount_enter_waiting(Automount *a) {
+         _cleanup_close_ int ioctl_fd = -1;
+         int p[2] = { -1, -1 };
+@@ -505,7 +583,7 @@ static void automount_enter_waiting(Automount *a) {
+         if (r < 0)
+                 goto fail;
+ 
+-        r = autofs_set_timeout(dev_autofs_fd, ioctl_fd, 300);
++        r = autofs_set_timeout(dev_autofs_fd, ioctl_fd, a->timeout_idle_usec);
+         if (r < 0)
+                 goto fail;
+ 
+@@ -537,6 +615,83 @@ fail:
+         automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
+ }
+ 
++static void *expire_thread(void *p) {
++        struct autofs_dev_ioctl param;
++        _cleanup_(expire_data_freep) struct expire_data *data = (struct expire_data*)p;
++        int r;
++
++        assert(data->dev_autofs_fd >= 0);
++        assert(data->ioctl_fd >= 0);
++
++        init_autofs_dev_ioctl(&param);
++        param.ioctlfd = data->ioctl_fd;
++
++        do {
++                r = ioctl(data->dev_autofs_fd, AUTOFS_DEV_IOCTL_EXPIRE, &param);
++        } while (r >= 0);
++
++        if (errno != EAGAIN)
++                log_warning_errno(errno, "Failed to expire automount, ignoring: %m");
++
++        return NULL;
++}
++
++static int automount_start_expire(Automount *a);
++
++static int automount_dispatch_expire(sd_event_source *source, usec_t usec, void *userdata) {
++        Automount *a = AUTOMOUNT(userdata);
++        _cleanup_(expire_data_freep) struct expire_data *data = NULL;
++        int r;
++
++        assert(a);
++        assert(source == a->expire_event_source);
++
++        data = new0(struct expire_data, 1);
++        if (!data)
++                return log_oom();
++
++        data->ioctl_fd = -1;
++
++        data->dev_autofs_fd = fcntl(UNIT(a)->manager->dev_autofs_fd, F_DUPFD_CLOEXEC, 3);
++        if (data->dev_autofs_fd < 0)
++                return log_unit_error_errno(UNIT(a)->id, errno, "Failed to duplicate autofs fd: %m");
++
++        data->ioctl_fd = open_ioctl_fd(UNIT(a)->manager->dev_autofs_fd, a->where, a->dev_id);
++        if (data->ioctl_fd < 0)
++                return log_unit_error_errno(UNIT(a)->id, data->ioctl_fd, "Couldn't open autofs ioctl fd: %m");
++
++        r = asynchronous_job(expire_thread, data);
++        if (r < 0)
++                return log_unit_error_errno(UNIT(a)->id, r, "Failed to start expire job: %m");
++
++        data = NULL;
++
++        return automount_start_expire(a);
++}
++
++static int automount_start_expire(Automount *a) {
++        int r;
++        usec_t timeout;
++
++        assert(a);
++
++        timeout = now(CLOCK_MONOTONIC) + MAX(a->timeout_idle_usec/10, USEC_PER_SEC);
++
++        if (a->expire_event_source) {
++                r = sd_event_source_set_time(a->expire_event_source, timeout);
++                if (r < 0)
++                        return r;
++
++                return sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_ONESHOT);
++        }
++
++        return sd_event_add_time(
++                        UNIT(a)->manager->event,
++                        &a->expire_event_source,
++                        CLOCK_MONOTONIC, timeout, 0,
++                        automount_dispatch_expire, a);
++}
++
+ static void automount_enter_runnning(Automount *a) {
+         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+         struct stat st;
+@@ -549,7 +704,8 @@ static void automount_enter_runnning(Automount *a) {
+         if (unit_stop_pending(UNIT(a))) {
+                 log_unit_debug(UNIT(a)->id,
+                                "Suppressing automount request on %s since unit stop is scheduled.", UNIT(a)->id);
+-                automount_send_ready(a, -EHOSTDOWN);
++                automount_send_ready(a, a->tokens, -EHOSTDOWN);
++                automount_send_ready(a, a->expire_tokens, -EHOSTDOWN);
+                 return;
+         }
+ 
+@@ -576,6 +732,10 @@ static void automount_enter_runnning(Automount *a) {
+                 }
+         }
+ 
++        r = automount_start_expire(a);
++        if (r < 0)
++                log_unit_warning_errno(UNIT(a)->id, r, "Failed to start expiration timer, ignoring: %m");
++
+         automount_set_state(a, AUTOMOUNT_RUNNING);
+         return;
+ 
+@@ -629,6 +789,8 @@ static int automount_serialize(Unit *u, FILE *f, FDSet *fds) {
+ 
+         SET_FOREACH(p, a->tokens, i)
+                 unit_serialize_item_format(u, f, "token", "%u", PTR_TO_UINT(p));
++        SET_FOREACH(p, a->expire_tokens, i)
++                unit_serialize_item_format(u, f, "expire-token", "%u", PTR_TO_UINT(p));
+ 
+         if (a->pipe_fd >= 0) {
+                 int copy;
+@@ -688,6 +850,22 @@ static int automount_deserialize_item(Unit *u, const char *key, const char *valu
+                         if (r < 0)
+                                 return r;
+                 }
++        } else if (streq(key, "expire-token")) {
++                unsigned token;
++
++                if (safe_atou(value, &token) < 0)
++                        log_unit_debug(u->id, "Failed to parse token value %s", value);
++                else {
++                        r = set_ensure_allocated(&a->expire_tokens, NULL);
++                        if (r < 0) {
++                                log_oom();
++                                return 0;
++                        }
++
++                        r = set_put(a->expire_tokens, UINT_TO_PTR(token));
++                        if (r < 0)
++                                log_unit_error_errno(u->id, r, "Failed to add expire token to set: %m");
++                }
+         } else if (streq(key, "pipe-fd")) {
+                 int fd;
+ 
+@@ -725,6 +903,7 @@ static bool automount_check_gc(Unit *u) {
+ }
+ 
+ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata) {
++        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+         union autofs_v5_packet_union packet;
+         Automount *a = AUTOMOUNT(userdata);
+         ssize_t l;
+@@ -777,6 +956,31 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo
+                 automount_enter_runnning(a);
+                 break;
+ 
++        case autofs_ptype_expire_direct:
++                log_unit_debug(UNIT(a)->id, "Got direct umount request on %s", a->where);
++
++                (void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF);
++
++                r = set_ensure_allocated(&a->expire_tokens, NULL);
++                if (r < 0) {
++                        log_unit_error(UNIT(a)->id, "Failed to allocate token set.");
++                        goto fail;
++                }
++
++                r = set_put(a->expire_tokens, UINT_TO_PTR(packet.v5_packet.wait_queue_token));
++                if (r < 0) {
++                        log_unit_error_errno(UNIT(a)->id, r, "Failed to remember token: %m");
++                        goto fail;
++                }
++                r = manager_add_job(UNIT(a)->manager, JOB_STOP, UNIT_TRIGGER(UNIT(a)), JOB_REPLACE, true, &error, NULL);
++                if (r < 0) {
++                        log_unit_warning(UNIT(a)->id,
++                                         "%s failed to queue umount startup job: %s",
++                                         UNIT(a)->id, bus_error_message(&error, r));
++                        goto fail;
++                }
++                break;
++
+         default:
+                 log_unit_error(UNIT(a)->id, "Received unknown automount request %i", packet.hdr.type);
+                 break;
+diff --git a/src/core/automount.h b/src/core/automount.h
+index 60f5522..2a50fef 100644
+--- a/src/core/automount.h
++++ b/src/core/automount.h
+@@ -47,6 +47,7 @@ struct Automount {
+         AutomountState state, deserialized_state;
+ 
+         char *where;
++        usec_t timeout_idle_usec;
+ 
+         int pipe_fd;
+         sd_event_source *pipe_event_source;
+@@ -54,13 +55,16 @@ struct Automount {
+         dev_t dev_id;
+ 
+         Set *tokens;
++        Set *expire_tokens;
++
++        sd_event_source *expire_event_source;
+ 
+         AutomountResult result;
+ };
+ 
+ extern const UnitVTable automount_vtable;
+ 
+-int automount_send_ready(Automount *a, int status);
++int automount_update_mount(Automount *a, MountState old_state, MountState state);
+ 
+ const char* automount_state_to_string(AutomountState i) _const_;
+ AutomountState automount_state_from_string(const char *s) _pure_;
+diff --git a/src/core/dbus-automount.c b/src/core/dbus-automount.c
+index b2a510a..c62ad82 100644
+--- a/src/core/dbus-automount.c
++++ b/src/core/dbus-automount.c
+@@ -32,5 +32,6 @@ const sd_bus_vtable bus_automount_vtable[] = {
+         SD_BUS_PROPERTY("Where", "s", NULL, offsetof(Automount, where), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Automount, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Automount, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
++        SD_BUS_PROPERTY("TimeoutIdleUSec", "t", bus_property_get_usec, offsetof(Automount, timeout_idle_usec), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_VTABLE_END
+ };
+diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
+index f3a6e13..c866a9c 100644
+--- a/src/core/load-fragment-gperf.gperf.m4
++++ b/src/core/load-fragment-gperf.gperf.m4
+@@ -318,6 +318,7 @@ KILL_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
+ m4_dnl
+ Automount.Where,                 config_parse_path,                  0,                             offsetof(Automount, where)
+ Automount.DirectoryMode,         config_parse_mode,                  0,                             offsetof(Automount, directory_mode)
++Automount.TimeoutIdleSec,        config_parse_sec,                   0,                             offsetof(Automount, timeout_idle_usec)
+ m4_dnl
+ Swap.What,                       config_parse_path,                  0,                             offsetof(Swap, parameters_fragment.what)
+ Swap.Priority,                   config_parse_int,                   0,                             offsetof(Swap, parameters_fragment.priority)
+diff --git a/src/core/mount.c b/src/core/mount.c
+index 3fbdb7d..7ca7f5a 100644
+--- a/src/core/mount.c
++++ b/src/core/mount.c
+@@ -552,7 +552,7 @@ static int mount_load(Unit *u) {
+         return mount_verify(m);
+ }
+ 
+-static int mount_notify_automount(Mount *m, int status) {
++static int mount_notify_automount(Mount *m, MountState old_state, MountState state) {
+         Unit *p;
+         int r;
+         Iterator i;
+@@ -561,7 +561,7 @@ static int mount_notify_automount(Mount *m, int status) {
+ 
+         SET_FOREACH(p, UNIT(m)->dependencies[UNIT_TRIGGERED_BY], i)
+                 if (p->type == UNIT_AUTOMOUNT) {
+-                         r = automount_send_ready(AUTOMOUNT(p), status);
++                         r = automount_update_mount(AUTOMOUNT(p), old_state, state);
+                          if (r < 0)
+                                  return r;
+                 }
+@@ -592,21 +592,7 @@ static void mount_set_state(Mount *m, MountState state) {
+                 m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
+         }
+ 
+-        if (state == MOUNT_MOUNTED ||
+-            state == MOUNT_REMOUNTING)
+-                mount_notify_automount(m, 0);
+-        else if (state == MOUNT_DEAD ||
+-                 state == MOUNT_UNMOUNTING ||
+-                 state == MOUNT_MOUNTING_SIGTERM ||
+-                 state == MOUNT_MOUNTING_SIGKILL ||
+-                 state == MOUNT_REMOUNTING_SIGTERM ||
+-                 state == MOUNT_REMOUNTING_SIGKILL ||
+-                 state == MOUNT_UNMOUNTING_SIGTERM ||
+-                 state == MOUNT_UNMOUNTING_SIGKILL ||
+-                 state == MOUNT_FAILED) {
+-                if (state != old_state)
+-                        mount_notify_automount(m, -ENODEV);
+-        }
++        mount_notify_automount(m, old_state, state);
+ 
+         if (state != old_state)
+                 log_unit_debug(UNIT(m)->id,
+diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
+index 029eb16..a943393 100644
+--- a/src/fstab-generator/fstab-generator.c
++++ b/src/fstab-generator/fstab-generator.c
+@@ -213,6 +213,30 @@ static int write_requires_mounts_for(FILE *f, const char *opts) {
+ 
+         return 0;
+ }
++
++static int write_idle_timeout(FILE *f, const char *where, const char *opts, char **filtered) {
++        _cleanup_free_ char *timeout = NULL;
++        char timespan[FORMAT_TIMESPAN_MAX];
++        usec_t u;
++        int r;
++
++        r = fstab_filter_options(opts, "x-systemd.idle-timeout\0", NULL, &timeout, filtered);
++        if (r < 0)
++                return log_warning_errno(r, "Failed to parse options: %m");
++        if (r == 0)
++                return 0;
++
++        r = parse_sec(timeout, &u);
++        if (r < 0) {
++                log_warning("Failed to parse timeout for %s, ignoring: %s", where, timeout);
++                return 0;
++        }
++
++        fprintf(f, "TimeoutIdleSec=%s\n", format_timespan(timespan, sizeof(timespan), u, 0));
++
++        return 0;
++}
++
+ static int add_mount(
+                 const char *what,
+                 const char *where,
+@@ -374,6 +398,10 @@ static int add_mount(
+                         "Where=%s\n",
+                         where);
+ 
++                r = write_idle_timeout(f, where, opts, &filtered);
++                if (r < 0)
++                        return r;
++
+                 fflush(f);
+                 if (ferror(f))
+                         return log_error_errno(errno, "Failed to write unit file %s: %m", automount_unit);
diff --git a/SOURCES/0453-fstab-generator-fix-memleak.patch b/SOURCES/0453-fstab-generator-fix-memleak.patch
new file mode 100644
index 0000000..4338eeb
--- /dev/null
+++ b/SOURCES/0453-fstab-generator-fix-memleak.patch
@@ -0,0 +1,45 @@
+From c6b00287b8847c550ab75947f52e37282632a2f3 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Sat, 2 May 2015 12:01:28 -0500
+Subject: [PATCH] fstab-generator: fix memleak
+
+filtered was used to store an allocated string twice. The first allocation was
+thus lost. The string is not needed for anything, so simply skip the allocation.
+
+Fixup for deb0a77cf0b409141c4.
+
+(cherry picked from commit 336b5c615e9c101476784b32df1b86aaeac96431)
+Related: #1354410
+---
+ src/fstab-generator/fstab-generator.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
+index a943393..32aca22 100644
+--- a/src/fstab-generator/fstab-generator.c
++++ b/src/fstab-generator/fstab-generator.c
+@@ -214,13 +214,13 @@ static int write_requires_mounts_for(FILE *f, const char *opts) {
+         return 0;
+ }
+ 
+-static int write_idle_timeout(FILE *f, const char *where, const char *opts, char **filtered) {
++static int write_idle_timeout(FILE *f, const char *where, const char *opts) {
+         _cleanup_free_ char *timeout = NULL;
+         char timespan[FORMAT_TIMESPAN_MAX];
+         usec_t u;
+         int r;
+ 
+-        r = fstab_filter_options(opts, "x-systemd.idle-timeout\0", NULL, &timeout, filtered);
++        r = fstab_filter_options(opts, "x-systemd.idle-timeout\0", NULL, &timeout, NULL);
+         if (r < 0)
+                 return log_warning_errno(r, "Failed to parse options: %m");
+         if (r == 0)
+@@ -398,7 +398,7 @@ static int add_mount(
+                         "Where=%s\n",
+                         where);
+ 
+-                r = write_idle_timeout(f, where, opts, &filtered);
++                r = write_idle_timeout(f, where, opts);
+                 if (r < 0)
+                         return r;
+ 
diff --git a/SOURCES/0454-remove-bus-proxyd.patch b/SOURCES/0454-remove-bus-proxyd.patch
new file mode 100644
index 0000000..6bcc656
--- /dev/null
+++ b/SOURCES/0454-remove-bus-proxyd.patch
@@ -0,0 +1,5066 @@
+From 1425f8f9a084e962df43dcdead04104cf1b3b83d Mon Sep 17 00:00:00 2001
+From: Daniel Mack <daniel@zonque.org>
+Date: Fri, 12 Feb 2016 15:25:27 +0100
+Subject: [PATCH] remove bus-proxyd
+
+As kdbus won't land in the anticipated way, the bus-proxy is not needed in
+its current form. It can be resurrected at any time thanks to the history,
+but for now, let's remove it from the sources. If we'll have a similar tool
+in the future, it will look quite differently anyway.
+
+Note that stdio-bridge is still available. It was restored from a version
+prior to f252ff17, and refactored to make use of the current APIs.
+
+(cherry picked from commit 798c486fbcdce3346cd862c52e1a200bb8a2cb23)
+Resolves: #1317518
+---
+ .gitignore                               |    1 -
+ Makefile-man.am                          |    2 -
+ Makefile.am                              |   80 +-
+ README                                   |    3 -
+ TODO                                     |    4 -
+ man/busctl.xml                           |    1 -
+ man/systemd-bus-proxyd.xml               |  109 ---
+ man/systemd-bus-proxyd@.service.xml      |   81 --
+ src/bus-proxyd/Makefile                  |    1 -
+ src/bus-proxyd/bus-proxyd.c              |  346 --------
+ src/bus-proxyd/bus-xml-policy.c          | 1325 ------------------------------
+ src/bus-proxyd/bus-xml-policy.h          |  151 ----
+ src/bus-proxyd/driver.c                  |  608 --------------
+ src/bus-proxyd/driver.h                  |   27 -
+ src/bus-proxyd/proxy.c                   |  864 -------------------
+ src/bus-proxyd/proxy.h                   |   53 --
+ src/bus-proxyd/stdio-bridge.c            |  263 ------
+ src/bus-proxyd/synthesize.c              |  228 -----
+ src/bus-proxyd/synthesize.h              |   34 -
+ src/bus-proxyd/test-bus-xml-policy.c     |  182 ----
+ src/stdio-bridge/stdio-bridge.c          |  303 +++++++
+ src/test/test-tables.c                   |    3 -
+ sysusers.d/systemd.conf.m4               |    3 -
+ units/.gitignore                         |    2 -
+ units/systemd-bus-proxyd.service.m4.in   |   19 -
+ units/systemd-bus-proxyd.socket          |   12 -
+ units/user/.gitignore                    |    2 -
+ units/user/systemd-bus-proxyd.service.in |   13 -
+ units/user/systemd-bus-proxyd.socket     |   12 -
+ 29 files changed, 305 insertions(+), 4427 deletions(-)
+ delete mode 100644 man/systemd-bus-proxyd.xml
+ delete mode 100644 man/systemd-bus-proxyd@.service.xml
+ delete mode 120000 src/bus-proxyd/Makefile
+ delete mode 100644 src/bus-proxyd/bus-proxyd.c
+ delete mode 100644 src/bus-proxyd/bus-xml-policy.c
+ delete mode 100644 src/bus-proxyd/bus-xml-policy.h
+ delete mode 100644 src/bus-proxyd/driver.c
+ delete mode 100644 src/bus-proxyd/driver.h
+ delete mode 100644 src/bus-proxyd/proxy.c
+ delete mode 100644 src/bus-proxyd/proxy.h
+ delete mode 100644 src/bus-proxyd/stdio-bridge.c
+ delete mode 100644 src/bus-proxyd/synthesize.c
+ delete mode 100644 src/bus-proxyd/synthesize.h
+ delete mode 100644 src/bus-proxyd/test-bus-xml-policy.c
+ create mode 100644 src/stdio-bridge/stdio-bridge.c
+ delete mode 100644 units/systemd-bus-proxyd.service.m4.in
+ delete mode 100644 units/systemd-bus-proxyd.socket
+ delete mode 100644 units/user/systemd-bus-proxyd.service.in
+ delete mode 100644 units/user/systemd-bus-proxyd.socket
+
+diff --git a/.gitignore b/.gitignore
+index 0360f7c..5ac188b 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -56,7 +56,6 @@
+ /systemd-backlight
+ /systemd-binfmt
+ /systemd-bootchart
+-/systemd-bus-proxyd
+ /systemd-cat
+ /systemd-cgls
+ /systemd-cgroups-agent
+diff --git a/Makefile-man.am b/Makefile-man.am
+index 7ec709c..734c805 100644
+--- a/Makefile-man.am
++++ b/Makefile-man.am
+@@ -1762,8 +1762,6 @@ EXTRA_DIST += \
+ 	man/systemd-backlight@.service.xml \
+ 	man/systemd-binfmt.service.xml \
+ 	man/systemd-bootchart.xml \
+-	man/systemd-bus-proxyd.xml \
+-	man/systemd-bus-proxyd@.service.xml \
+ 	man/systemd-cat.xml \
+ 	man/systemd-cgls.xml \
+ 	man/systemd-cgtop.xml \
+diff --git a/Makefile.am b/Makefile.am
+index b347aed..924b34b 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -397,7 +397,6 @@ rootlibexec_PROGRAMS = \
+ 	systemd-ac-power \
+ 	systemd-sysctl \
+ 	systemd-sleep \
+-	systemd-bus-proxyd \
+ 	systemd-socket-proxyd \
+ 	systemd-update-done
+ 
+@@ -1421,7 +1420,6 @@ tests += \
+ 	test-ratelimit \
+ 	test-condition \
+ 	test-uid-range \
+-	test-bus-policy \
+ 	test-locale-util \
+ 	test-execute \
+ 	test-copy \
+@@ -1792,14 +1790,11 @@ test_unaligned_SOURCES = \
+ test_tables_SOURCES = \
+ 	src/test/test-tables.c \
+ 	src/shared/test-tables.h \
+-	src/bus-proxyd/bus-xml-policy.c \
+-	src/bus-proxyd/bus-xml-policy.h \
+ 	src/journal/journald-server.c \
+ 	src/journal/journald-server.h
+ 
+ test_tables_CPPFLAGS = \
+-	$(AM_CPPFLAGS) \
+-	-I$(top_srcdir)/src/bus-proxyd
++	$(AM_CPPFLAGS)
+ 
+ test_tables_CFLAGS = \
+ 	$(AM_CFLAGS) \
+@@ -2041,14 +2036,6 @@ test_conf_files_SOURCES = \
+ test_conf_files_LDADD = \
+ 	libsystemd-shared.la
+ 
+-test_bus_policy_SOURCES = \
+-	src/bus-proxyd/test-bus-xml-policy.c
+-
+-test_bus_policy_LDADD = \
+-	libsystemd-proxy.la \
+-	libsystemd-internal.la \
+-	libsystemd-shared.la
+-
+ # ------------------------------------------------------------------------------
+ ## .PHONY so it always rebuilds it
+ .PHONY: coverage lcov-run lcov-report coverage-sync
+@@ -2704,75 +2691,12 @@ systemd_run_LDADD = \
+ 	libsystemd-shared.la
+ 
+ # ------------------------------------------------------------------------------
+-noinst_LTLIBRARIES += \
+-	libsystemd-proxy.la
+-
+-libsystemd_proxy_la_SOURCES = \
+-	src/bus-proxyd/bus-xml-policy.c \
+-	src/bus-proxyd/bus-xml-policy.h \
+-	src/bus-proxyd/driver.c \
+-	src/bus-proxyd/driver.h \
+-	src/bus-proxyd/proxy.c \
+-	src/bus-proxyd/proxy.h \
+-	src/bus-proxyd/synthesize.c \
+-	src/bus-proxyd/synthesize.h
+-
+-libsystemd_proxy_la_CFLAGS = \
+-	$(AM_CFLAGS) \
+-	-pthread
+-
+-libsystemd_proxy_la_LIBADD = \
+-	libsystemd-internal.la \
+-	libsystemd-shared.la
+-
+-systemd_bus_proxyd_SOURCES = \
+-	src/bus-proxyd/bus-proxyd.c
+-
+-systemd_bus_proxyd_CFLAGS = \
+-	$(AM_CFLAGS) \
+-	-pthread
+-
+-systemd_bus_proxyd_LDADD = \
+-	libsystemd-proxy.la \
+-	libsystemd-internal.la \
+-	libsystemd-shared.la
+-
+ systemd_stdio_bridge_SOURCES = \
+-	src/bus-proxyd/stdio-bridge.c
++	src/stdio-bridge/stdio-bridge.c
+ 
+ systemd_stdio_bridge_LDADD = \
+-	libsystemd-proxy.la \
+ 	libsystemd-internal.la \
+ 	libsystemd-shared.la
+-
+-if ENABLE_KDBUS
+-nodist_systemunit_DATA += \
+-	units/systemd-bus-proxyd.service
+-
+-dist_systemunit_DATA += \
+-	units/systemd-bus-proxyd.socket
+-
+-nodist_userunit_DATA += \
+-	units/user/systemd-bus-proxyd.service
+-
+-dist_userunit_DATA += \
+-	units/user/systemd-bus-proxyd.socket
+-endif
+-
+-EXTRA_DIST += \
+-	units/systemd-bus-proxyd.service.m4.in \
+-	units/user/systemd-bus-proxyd.service.in
+-
+-CLEANFILES += \
+-	units/systemd-bus-proxyd.service.m4
+-
+-if HAVE_SMACK
+-bus-proxyd-set-cap-hook:
+-	-$(SETCAP) cap_mac_admin+ei $(DESTDIR)$(rootlibexecdir)/systemd-bus-proxyd
+-
+-INSTALL_EXEC_HOOKS += bus-proxyd-set-cap-hook
+-endif
+-
+ # ------------------------------------------------------------------------------
+ systemd_tty_ask_password_agent_SOURCES = \
+ 	src/tty-ask-password-agent/tty-ask-password-agent.c
+diff --git a/README b/README
+index ffc2cf9..bf75909 100644
+--- a/README
++++ b/README
+@@ -198,9 +198,6 @@ USERS AND GROUPS:
+         Similarly, the name resolution daemon requires the
+         "systemd-resolve" system user and group to exist.
+ 
+-        Similarly, the kdbus dbus1 proxy daemon requires the
+-        "systemd-bus-proxy" system user and group to exist.
+-
+ NSS:
+         systemd ships with three NSS modules:
+ 
+diff --git a/TODO b/TODO
+index 498d82c..9947307 100644
+--- a/TODO
++++ b/TODO
+@@ -431,10 +431,6 @@ Features:
+        - path escaping
+   - update systemd.special(7) to mention that dbus.socket is only about the compatibility socket now
+   - test bloom filter generation indexes
+-  - bus-proxy: when passing messages from kdbus, make sure we properly
+-    handle the case where a large number of fds is appended that we
+-    cannot pass into sendmsg() of the AF_UNIX sokcet (which only accepts
+-    253 messages)
+   - kdbus: introduce a concept of "send-only" connections
+   - kdbus: add counter for refused unicast messages that is passed out via the RECV ioctl. SImilar to the counter for dropped multicast messages we already have.
+ 
+diff --git a/man/busctl.xml b/man/busctl.xml
+index 0635280..c68fe23 100644
+--- a/man/busctl.xml
++++ b/man/busctl.xml
+@@ -468,7 +468,6 @@ o "/org/freedesktop/systemd1/job/42684"</programlisting>
+       <ulink url="https://code.google.com/p/d-bus/">kdbus</ulink>,
+       <citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+       <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+-      <citerefentry><refentrytitle>systemd-bus-proxyd</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+       <citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+       <citerefentry project='die-net'><refentrytitle>wireshark</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+     </para>
+diff --git a/man/systemd-bus-proxyd.xml b/man/systemd-bus-proxyd.xml
+deleted file mode 100644
+index e0efe99..0000000
+--- a/man/systemd-bus-proxyd.xml
++++ /dev/null
+@@ -1,109 +0,0 @@
+-<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
+-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+-
+-<!--
+-This file is part of systemd.
+-
+-Copyright 2013 Zbigniew Jędrzejewski-Szmek
+-
+-systemd is free software; you can redistribute it and/or modify it
+-under the terms of the GNU Lesser General Public License as published by
+-the Free Software Foundation; either version 2.1 of the License, or
+-(at your option) any later version.
+-
+-systemd is distributed in the hope that it will be useful, but
+-WITHOUT ANY WARRANTY; without even the implied warranty of
+-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-Lesser General Public License for more details.
+-
+-You should have received a copy of the GNU Lesser General Public License
+-along with systemd; If not, see <http://www.gnu.org/licenses/>.
+--->
+-
+-<refentry id="systemd-bus-proxyd" conditional="ENABLE_KDBUS"
+-          xmlns:xi="http://www.w3.org/2001/XInclude">
+-
+-  <refentryinfo>
+-    <title>systemd-bus-proxyd</title>
+-    <productname>systemd</productname>
+-
+-    <authorgroup>
+-      <author>
+-        <contrib>Developer</contrib>
+-        <firstname>Lennart</firstname>
+-        <surname>Poettering</surname>
+-        <email>lennart@poettering.net</email>
+-      </author>
+-    </authorgroup>
+-  </refentryinfo>
+-
+-  <refmeta>
+-    <refentrytitle>systemd-bus-proxyd</refentrytitle>
+-    <manvolnum>8</manvolnum>
+-  </refmeta>
+-
+-  <refnamediv>
+-    <refname>systemd-bus-proxyd</refname>
+-    <refpurpose>Connect STDIO or a socket to a given bus address</refpurpose>
+-  </refnamediv>
+-
+-  <refsynopsisdiv>
+-    <cmdsynopsis>
+-      <command>/usr/lib/systemd/systemd-bus-proxyd</command>
+-      <arg choice="opt" rep="repeat">OPTIONS</arg>
+-      <arg choice="opt"><replaceable>PLACEHOLDER</replaceable></arg>
+-    </cmdsynopsis>
+-  </refsynopsisdiv>
+-
+-  <refsect1>
+-    <title>Description</title>
+-
+-    <para><command>systemd-bus-proxyd</command> will proxy D-Bus
+-    messages to and from a bus. The will be either the system bus or
+-    the bus specified with <option>--address</option> when that option
+-    is given. Messages will be proxied to/from standard input and
+-    output, or the socket received through socket activation.</para>
+-
+-    <para>This program can be used to connect a program using classic
+-    D-Bus to kdbus.</para>
+-  </refsect1>
+-
+-  <refsect1>
+-    <title>Options and Arguments</title>
+-
+-    <para>The following options are understood:</para>
+-
+-    <variablelist>
+-      <varlistentry>
+-        <term><option>--address=<replaceable>ADDRESS</replaceable><optional>:<replaceable>ADDRESS...</replaceable></optional></option></term>
+-
+-        <listitem>
+-          <para>Connect to the bus specified by
+-          <replaceable>ADDRESS</replaceable>. Multiple colon-separated
+-          addresses can be specified, in which case
+-          <command>systemd-bus-proxyd</command> will attempt to
+-          connect to them in turn.</para>
+-        </listitem>
+-      </varlistentry>
+-
+-      <xi:include href="standard-options.xml" xpointer="help" />
+-      <xi:include href="standard-options.xml" xpointer="version" />
+-    </variablelist>
+-
+-    <para><replaceable>PLACEHOLDER</replaceable>, if given, must be a string
+-    of <literal>x</literal> and will be used to display information about
+-    the process that <command>systemd-bus-proxyd</command> is forwarding
+-    messages for.</para>
+-  </refsect1>
+-
+-  <refsect1>
+-    <title>See Also</title>
+-
+-    <para>
+-      <citerefentry project='dbus'><refentrytitle>dbus-daemon</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+-      <ulink url="http://freedesktop.org/wiki/Software/dbus">D-Bus</ulink>,
+-      <ulink url="https://code.google.com/p/d-bus/">kdbus</ulink>
+-    </para>
+-  </refsect1>
+-</refentry>
+diff --git a/man/systemd-bus-proxyd@.service.xml b/man/systemd-bus-proxyd@.service.xml
+deleted file mode 100644
+index dc4f07f..0000000
+--- a/man/systemd-bus-proxyd@.service.xml
++++ /dev/null
+@@ -1,81 +0,0 @@
+-<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
+-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+-
+-<!--
+-  This file is part of systemd.
+-
+-  Copyright 2013 Zbigniew Jędrzejewski-Szmek
+-
+-  systemd is free software; you can redistribute it and/or modify it
+-  under the terms of the GNU Lesser General Public License as published by
+-  the Free Software Foundation; either version 2.1 of the License, or
+-  (at your option) any later version.
+-
+-  systemd is distributed in the hope that it will be useful, but
+-  WITHOUT ANY WARRANTY; without even the implied warranty of
+-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-  Lesser General Public License for more details.
+-
+-  You should have received a copy of the GNU Lesser General Public License
+-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+--->
+-
+-<refentry id="systemd-bus-proxyd@.service" conditional='ENABLE_KDBUS'>
+-
+-  <refentryinfo>
+-    <title>systemd-bus-proxyd@.service</title>
+-    <productname>systemd</productname>
+-
+-    <authorgroup>
+-      <author>
+-        <contrib>Developer</contrib>
+-        <firstname>Lennart</firstname>
+-        <surname>Poettering</surname>
+-        <email>lennart@poettering.net</email>
+-      </author>
+-    </authorgroup>
+-  </refentryinfo>
+-
+-  <refmeta>
+-    <refentrytitle>systemd-bus-proxyd@.service</refentrytitle>
+-    <manvolnum>8</manvolnum>
+-  </refmeta>
+-
+-  <refnamediv>
+-    <refname>systemd-bus-proxyd@.service</refname>
+-    <refname>systemd-bus-proxyd.socket</refname>
+-    <refpurpose>Proxy classic D-Bus clients to kdbus</refpurpose>
+-  </refnamediv>
+-
+-  <refsynopsisdiv>
+-    <para><filename>systemd-bus-proxyd@.service</filename></para>
+-    <para><filename>systemd-bus-proxyd.socket</filename></para>
+-  </refsynopsisdiv>
+-
+-  <refsect1>
+-    <title>Description</title>
+-
+-    <para><filename>systemd-bus-proxyd.socket</filename> will launch
+-    <filename>systemd-bus-proxyd@.service</filename> for connections
+-    to the classic D-Bus socket in
+-    <filename>/var/run/dbus/system_bus_socket</filename>.</para>
+-
+-    <para><filename>systemd-bus-proxyd@.service</filename> is launched
+-    for an existing D-Bus connection and will use
+-    <command>systemd-bus-proxyd</command> to proxy messages from this
+-    connection to the system bus (either kdbus or classic D-Bus).
+-    </para>
+-  </refsect1>
+-
+-  <refsect1>
+-    <title>See Also</title>
+-
+-    <para>
+-      <citerefentry><refentrytitle>systemd-bus-proxyd</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+-      <citerefentry project='dbus'><refentrytitle>dbus-daemon</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+-      <ulink url="http://freedesktop.org/wiki/Software/dbus">D-Bus</ulink>,
+-      <ulink url="https://code.google.com/p/d-bus/">kdbus</ulink>
+-    </para>
+-  </refsect1>
+-</refentry>
+diff --git a/src/bus-proxyd/Makefile b/src/bus-proxyd/Makefile
+deleted file mode 120000
+index d0b0e8e..0000000
+--- a/src/bus-proxyd/Makefile
++++ /dev/null
+@@ -1 +0,0 @@
+-../Makefile
+\ No newline at end of file
+diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c
+deleted file mode 100644
+index b6550ed..0000000
+--- a/src/bus-proxyd/bus-proxyd.c
++++ /dev/null
+@@ -1,346 +0,0 @@
+-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+-
+-/***
+-  This file is part of systemd.
+-
+-  Copyright 2010 Lennart Poettering
+-  Copyright 2013 Daniel Mack
+-  Copyright 2014 Kay Sievers
+-  Copyright 2015 David Herrmann
+-
+-  systemd is free software; you can redistribute it and/or modify it
+-  under the terms of the GNU Lesser General Public License as published by
+-  the Free Software Foundation; either version 2.1 of the License, or
+-  (at your option) any later version.
+-
+-  systemd is distributed in the hope that it will be useful, but
+-  WITHOUT ANY WARRANTY; without even the implied warranty of
+-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-  Lesser General Public License for more details.
+-
+-  You should have received a copy of the GNU Lesser General Public License
+-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+-***/
+-
+-#include <sys/socket.h>
+-#include <sys/un.h>
+-#include <sys/types.h>
+-#include <fcntl.h>
+-#include <unistd.h>
+-#include <string.h>
+-#include <errno.h>
+-#include <poll.h>
+-#include <sys/prctl.h>
+-#include <stddef.h>
+-#include <getopt.h>
+-#include <pthread.h>
+-
+-#include "log.h"
+-#include "util.h"
+-#include "hashmap.h"
+-#include "socket-util.h"
+-#include "sd-daemon.h"
+-#include "sd-bus.h"
+-#include "bus-internal.h"
+-#include "bus-message.h"
+-#include "bus-util.h"
+-#include "build.h"
+-#include "strv.h"
+-#include "def.h"
+-#include "capability.h"
+-#include "bus-control.h"
+-#include "smack-util.h"
+-#include "set.h"
+-#include "bus-xml-policy.h"
+-#include "driver.h"
+-#include "proxy.h"
+-#include "synthesize.h"
+-
+-static char *arg_address = NULL;
+-static char **arg_configuration = NULL;
+-
+-typedef struct {
+-        int fd;
+-        SharedPolicy *policy;
+-        uid_t bus_uid;
+-} ClientContext;
+-
+-static ClientContext *client_context_free(ClientContext *c) {
+-        if (!c)
+-                return NULL;
+-
+-        safe_close(c->fd);
+-        free(c);
+-
+-        return NULL;
+-}
+-
+-DEFINE_TRIVIAL_CLEANUP_FUNC(ClientContext*, client_context_free);
+-
+-static int client_context_new(ClientContext **out) {
+-        _cleanup_(client_context_freep) ClientContext *c = NULL;
+-
+-        c = new0(ClientContext, 1);
+-        if (!c)
+-                return -ENOMEM;
+-
+-        c->fd = -1;
+-
+-        *out = c;
+-        c = NULL;
+-        return 0;
+-}
+-
+-static void *run_client(void *userdata) {
+-        _cleanup_(client_context_freep) ClientContext *c = userdata;
+-        _cleanup_(proxy_freep) Proxy *p = NULL;
+-        char comm[16];
+-        int r;
+-
+-        r = proxy_new(&p, c->fd, c->fd, arg_address);
+-        if (r < 0)
+-                goto exit;
+-
+-        c->fd = -1;
+-
+-        /* set comm to "p$PIDu$UID" and suffix with '*' if truncated */
+-        r = snprintf(comm, sizeof(comm), "p" PID_FMT "u" UID_FMT, p->local_creds.pid, p->local_creds.uid);
+-        if (r >= (ssize_t)sizeof(comm))
+-                comm[sizeof(comm) - 2] = '*';
+-        (void) prctl(PR_SET_NAME, comm);
+-
+-        r = proxy_set_policy(p, c->policy, arg_configuration);
+-        if (r < 0)
+-                goto exit;
+-
+-        r = proxy_hello_policy(p, c->bus_uid);
+-        if (r < 0)
+-                goto exit;
+-
+-        r = proxy_run(p);
+-
+-exit:
+-        return NULL;
+-}
+-
+-static int loop_clients(int accept_fd, uid_t bus_uid) {
+-        _cleanup_(shared_policy_freep) SharedPolicy *sp = NULL;
+-        pthread_attr_t attr;
+-        int r;
+-
+-        r = pthread_attr_init(&attr);
+-        if (r < 0) {
+-                return log_error_errno(errno, "Cannot initialize pthread attributes: %m");
+-        }
+-
+-        r = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+-        if (r < 0) {
+-                r = log_error_errno(errno, "Cannot mark pthread attributes as detached: %m");
+-                goto finish;
+-        }
+-
+-        r = shared_policy_new(&sp);
+-        if (r < 0)
+-                goto finish;
+-
+-        for (;;) {
+-                ClientContext *c;
+-                pthread_t tid;
+-                int fd;
+-
+-                fd = accept4(accept_fd, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC);
+-                if (fd < 0) {
+-                        if (errno == EAGAIN || errno == EINTR)
+-                                continue;
+-
+-                        r = log_error_errno(errno, "accept4() failed: %m");
+-                        goto finish;
+-                }
+-
+-                r = client_context_new(&c);
+-                if (r < 0) {
+-                        log_oom();
+-                        close(fd);
+-                        continue;
+-                }
+-
+-                c->fd = fd;
+-                c->policy = sp;
+-                c->bus_uid = bus_uid;
+-
+-                r = pthread_create(&tid, &attr, run_client, c);
+-                if (r < 0) {
+-                        log_error("Cannot spawn thread: %m");
+-                        client_context_free(c);
+-                        continue;
+-                }
+-        }
+-
+-finish:
+-        pthread_attr_destroy(&attr);
+-        return r;
+-}
+-
+-static int help(void) {
+-
+-        printf("%s [OPTIONS...]\n\n"
+-               "DBus proxy server.\n\n"
+-               "  -h --help               Show this help\n"
+-               "     --version            Show package version\n"
+-               "     --configuration=PATH Configuration file or directory\n"
+-               "     --machine=MACHINE    Connect to specified machine\n"
+-               "     --address=ADDRESS    Connect to the bus specified by ADDRESS\n"
+-               "                          (default: " DEFAULT_SYSTEM_BUS_ADDRESS ")\n",
+-               program_invocation_short_name);
+-
+-        return 0;
+-}
+-
+-static int parse_argv(int argc, char *argv[]) {
+-
+-        enum {
+-                ARG_VERSION = 0x100,
+-                ARG_ADDRESS,
+-                ARG_CONFIGURATION,
+-                ARG_MACHINE,
+-        };
+-
+-        static const struct option options[] = {
+-                { "help",            no_argument,       NULL, 'h'                 },
+-                { "version",         no_argument,       NULL, ARG_VERSION         },
+-                { "address",         required_argument, NULL, ARG_ADDRESS         },
+-                { "configuration",   required_argument, NULL, ARG_CONFIGURATION   },
+-                { "machine",         required_argument, NULL, ARG_MACHINE         },
+-                {},
+-        };
+-
+-        int c, r;
+-
+-        assert(argc >= 0);
+-        assert(argv);
+-
+-        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
+-
+-                switch (c) {
+-
+-                case 'h':
+-                        help();
+-                        return 0;
+-
+-                case ARG_VERSION:
+-                        puts(PACKAGE_STRING);
+-                        puts(SYSTEMD_FEATURES);
+-                        return 0;
+-
+-                case ARG_ADDRESS:
+-                        r = free_and_strdup(&arg_address, optarg);
+-                        if (r < 0)
+-                                return log_oom();
+-                        break;
+-
+-                case ARG_CONFIGURATION:
+-                        r = strv_extend(&arg_configuration, optarg);
+-                        if (r < 0)
+-                                return log_oom();
+-                        break;
+-
+-                case ARG_MACHINE: {
+-                        _cleanup_free_ char *e = NULL;
+-                        char *a;
+-
+-                        e = bus_address_escape(optarg);
+-                        if (!e)
+-                                return log_oom();
+-
+-#ifdef ENABLE_KDBUS
+-                        a = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e, NULL);
+-#else
+-                        a = strjoin("x-machine-unix:machine=", e, NULL);
+-#endif
+-                        if (!a)
+-                                return log_oom();
+-
+-                        free(arg_address);
+-                        arg_address = a;
+-
+-                        break;
+-                }
+-
+-                case '?':
+-                        return -EINVAL;
+-
+-                default:
+-                        assert_not_reached("Unhandled option");
+-                }
+-
+-        if (argc > optind) {
+-                log_error("Too many arguments");
+-                return -EINVAL;
+-        }
+-
+-        if (!arg_address) {
+-                arg_address = strdup(DEFAULT_SYSTEM_BUS_ADDRESS);
+-                if (!arg_address)
+-                        return log_oom();
+-        }
+-
+-        return 1;
+-}
+-
+-int main(int argc, char *argv[]) {
+-        int r, accept_fd;
+-        uid_t uid, bus_uid;
+-        gid_t gid;
+-
+-        log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
+-        log_parse_environment();
+-        log_open();
+-
+-        bus_uid = getuid();
+-
+-        if (geteuid() == 0) {
+-                const char *user = "systemd-bus-proxy";
+-
+-                r = get_user_creds(&user, &uid, &gid, NULL, NULL);
+-                if (r < 0) {
+-                        log_error_errno(r, "Cannot resolve user name %s: %m", user);
+-                        goto finish;
+-                }
+-
+-                r = drop_privileges(uid, gid, 1ULL << CAP_IPC_OWNER);
+-                if (r < 0) {
+-                        log_error_errno(r, "Cannot drop privileges: %m");
+-                        goto finish;
+-                }
+-        }
+-
+-        r = parse_argv(argc, argv);
+-        if (r <= 0)
+-                goto finish;
+-
+-        r = sd_listen_fds(0);
+-        if (r != 1) {
+-                log_error("Illegal number of file descriptors passed");
+-                goto finish;
+-        }
+-
+-        accept_fd = SD_LISTEN_FDS_START;
+-
+-        r = fd_nonblock(accept_fd, false);
+-        if (r < 0) {
+-                log_error_errno(r, "Cannot mark accept-fd non-blocking: %m");
+-                goto finish;
+-        }
+-
+-        r = loop_clients(accept_fd, bus_uid);
+-
+-finish:
+-        sd_notify(false,
+-                  "STOPPING=1\n"
+-                  "STATUS=Shutting down.");
+-
+-        strv_free(arg_configuration);
+-        free(arg_address);
+-
+-        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+-}
+diff --git a/src/bus-proxyd/bus-xml-policy.c b/src/bus-proxyd/bus-xml-policy.c
+deleted file mode 100644
+index f6ac0c0..0000000
+--- a/src/bus-proxyd/bus-xml-policy.c
++++ /dev/null
+@@ -1,1325 +0,0 @@
+-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+-
+-/***
+-  This file is part of systemd.
+-
+-  Copyright 2013 Lennart Poettering
+-
+-  systemd is free software; you can redistribute it and/or modify it
+-  under the terms of the GNU Lesser General Public License as published by
+-  the Free Software Foundation; either version 2.1 of the License, or
+-  (at your option) any later version.
+-
+-  systemd is distributed in the hope that it will be useful, but
+-  WITHOUT ANY WARRANTY; without even the implied warranty of
+-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-  Lesser General Public License for more details.
+-
+-  You should have received a copy of the GNU Lesser General Public License
+-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+-***/
+-
+-#include "xml.h"
+-#include "fileio.h"
+-#include "strv.h"
+-#include "set.h"
+-#include "conf-files.h"
+-#include "bus-internal.h"
+-#include "bus-message.h"
+-#include "bus-xml-policy.h"
+-#include "sd-login.h"
+-
+-static void policy_item_free(PolicyItem *i) {
+-        assert(i);
+-
+-        free(i->interface);
+-        free(i->member);
+-        free(i->error);
+-        free(i->name);
+-        free(i->path);
+-        free(i);
+-}
+-
+-DEFINE_TRIVIAL_CLEANUP_FUNC(PolicyItem*, policy_item_free);
+-
+-static void item_append(PolicyItem *i, PolicyItem **list) {
+-
+-        PolicyItem *tail;
+-
+-        LIST_FIND_TAIL(items, *list, tail);
+-        LIST_INSERT_AFTER(items, *list, tail, i);
+-}
+-
+-static int file_load(Policy *p, const char *path) {
+-
+-        _cleanup_free_ char *c = NULL, *policy_user = NULL, *policy_group = NULL;
+-        _cleanup_(policy_item_freep) PolicyItem *i = NULL;
+-        void *xml_state = NULL;
+-        unsigned n_other = 0;
+-        const char *q;
+-        int r;
+-
+-        enum {
+-                STATE_OUTSIDE,
+-                STATE_BUSCONFIG,
+-                STATE_POLICY,
+-                STATE_POLICY_CONTEXT,
+-                STATE_POLICY_CONSOLE,
+-                STATE_POLICY_USER,
+-                STATE_POLICY_GROUP,
+-                STATE_POLICY_OTHER_ATTRIBUTE,
+-                STATE_ALLOW_DENY,
+-                STATE_ALLOW_DENY_INTERFACE,
+-                STATE_ALLOW_DENY_MEMBER,
+-                STATE_ALLOW_DENY_ERROR,
+-                STATE_ALLOW_DENY_PATH,
+-                STATE_ALLOW_DENY_MESSAGE_TYPE,
+-                STATE_ALLOW_DENY_NAME,
+-                STATE_ALLOW_DENY_OTHER_ATTRIBUTE,
+-                STATE_OTHER,
+-        } state = STATE_OUTSIDE;
+-
+-        enum {
+-                POLICY_CATEGORY_NONE,
+-                POLICY_CATEGORY_DEFAULT,
+-                POLICY_CATEGORY_MANDATORY,
+-                POLICY_CATEGORY_ON_CONSOLE,
+-                POLICY_CATEGORY_NO_CONSOLE,
+-                POLICY_CATEGORY_USER,
+-                POLICY_CATEGORY_GROUP
+-        } policy_category = POLICY_CATEGORY_NONE;
+-
+-        unsigned line = 0;
+-
+-        assert(p);
+-
+-        r = read_full_file(path, &c, NULL);
+-        if (r < 0) {
+-                if (r == -ENOENT)
+-                        return 0;
+-                if (r == -EISDIR)
+-                        return r;
+-
+-                return log_error_errno(r, "Failed to load %s: %m", path);
+-        }
+-
+-        q = c;
+-        for (;;) {
+-                _cleanup_free_ char *name = NULL;
+-                int t;
+-
+-                t = xml_tokenize(&q, &name, &xml_state, &line);
+-                if (t < 0)
+-                        return log_error_errno(t, "XML parse failure in %s: %m", path);
+-
+-                switch (state) {
+-
+-                case STATE_OUTSIDE:
+-
+-                        if (t == XML_TAG_OPEN) {
+-                                if (streq(name, "busconfig"))
+-                                        state = STATE_BUSCONFIG;
+-                                else {
+-                                        log_error("Unexpected tag %s at %s:%u.", name, path, line);
+-                                        return -EINVAL;
+-                                }
+-
+-                        } else if (t == XML_END)
+-                                return 0;
+-                        else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
+-                                log_error("Unexpected token (1) at %s:%u.", path, line);
+-                                return -EINVAL;
+-                        }
+-
+-                        break;
+-
+-                case STATE_BUSCONFIG:
+-
+-                        if (t == XML_TAG_OPEN) {
+-                                if (streq(name, "policy")) {
+-                                        state = STATE_POLICY;
+-                                        policy_category = POLICY_CATEGORY_NONE;
+-                                        free(policy_user);
+-                                        free(policy_group);
+-                                        policy_user = policy_group = NULL;
+-                                } else {
+-                                        state = STATE_OTHER;
+-                                        n_other = 0;
+-                                }
+-                        } else if (t == XML_TAG_CLOSE_EMPTY ||
+-                                   (t == XML_TAG_CLOSE && streq(name, "busconfig")))
+-                                state = STATE_OUTSIDE;
+-                        else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
+-                                log_error("Unexpected token (2) at %s:%u.", path, line);
+-                                return -EINVAL;
+-                        }
+-
+-                        break;
+-
+-                case STATE_POLICY:
+-
+-                        if (t == XML_ATTRIBUTE_NAME) {
+-                                if (streq(name, "context"))
+-                                        state = STATE_POLICY_CONTEXT;
+-                                else if (streq(name, "at_console"))
+-                                        state = STATE_POLICY_CONSOLE;
+-                                else if (streq(name, "user"))
+-                                        state = STATE_POLICY_USER;
+-                                else if (streq(name, "group"))
+-                                        state = STATE_POLICY_GROUP;
+-                                else {
+-                                        log_warning("Attribute %s of <policy> tag unknown at %s:%u, ignoring.", name, path, line);
+-                                        state = STATE_POLICY_OTHER_ATTRIBUTE;
+-                                }
+-                        } else if (t == XML_TAG_CLOSE_EMPTY ||
+-                                   (t == XML_TAG_CLOSE && streq(name, "policy")))
+-                                state = STATE_BUSCONFIG;
+-                        else if (t == XML_TAG_OPEN) {
+-                                PolicyItemType it;
+-
+-                                if (streq(name, "allow"))
+-                                        it = POLICY_ITEM_ALLOW;
+-                                else if (streq(name, "deny"))
+-                                        it = POLICY_ITEM_DENY;
+-                                else {
+-                                        log_warning("Unknown tag %s in <policy> %s:%u.", name, path, line);
+-                                        return -EINVAL;
+-                                }
+-
+-                                assert(!i);
+-                                i = new0(PolicyItem, 1);
+-                                if (!i)
+-                                        return log_oom();
+-
+-                                i->type = it;
+-                                state = STATE_ALLOW_DENY;
+-
+-                        } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
+-                                log_error("Unexpected token (3) at %s:%u.", path, line);
+-                                return -EINVAL;
+-                        }
+-
+-                        break;
+-
+-                case STATE_POLICY_CONTEXT:
+-
+-                        if (t == XML_ATTRIBUTE_VALUE) {
+-                                if (streq(name, "default")) {
+-                                        policy_category = POLICY_CATEGORY_DEFAULT;
+-                                        state = STATE_POLICY;
+-                                } else if (streq(name, "mandatory")) {
+-                                        policy_category = POLICY_CATEGORY_MANDATORY;
+-                                        state = STATE_POLICY;
+-                                } else {
+-                                        log_error("context= parameter %s unknown for <policy> at %s:%u.", name, path, line);
+-                                        return -EINVAL;
+-                                }
+-                        } else {
+-                                log_error("Unexpected token (4) at %s:%u.", path, line);
+-                                return -EINVAL;
+-                        }
+-
+-                        break;
+-
+-                case STATE_POLICY_CONSOLE:
+-
+-                        if (t == XML_ATTRIBUTE_VALUE) {
+-                                if (streq(name, "true")) {
+-                                        policy_category = POLICY_CATEGORY_ON_CONSOLE;
+-                                        state = STATE_POLICY;
+-                                } else if (streq(name, "false")) {
+-                                        policy_category = POLICY_CATEGORY_NO_CONSOLE;
+-                                        state = STATE_POLICY;
+-                                } else {
+-                                        log_error("at_console= parameter %s unknown for <policy> at %s:%u.", name, path, line);
+-                                        return -EINVAL;
+-                                }
+-                        } else {
+-                                log_error("Unexpected token (4.1) at %s:%u.", path, line);
+-                                return -EINVAL;
+-                        }
+-
+-                        break;
+-
+-                case STATE_POLICY_USER:
+-
+-                        if (t == XML_ATTRIBUTE_VALUE) {
+-                                free(policy_user);
+-                                policy_user = name;
+-                                name = NULL;
+-                                policy_category = POLICY_CATEGORY_USER;
+-                                state = STATE_POLICY;
+-                        } else {
+-                                log_error("Unexpected token (5) in %s:%u.", path, line);
+-                                return -EINVAL;
+-                        }
+-
+-                        break;
+-
+-                case STATE_POLICY_GROUP:
+-
+-                        if (t == XML_ATTRIBUTE_VALUE) {
+-                                free(policy_group);
+-                                policy_group = name;
+-                                name = NULL;
+-                                policy_category = POLICY_CATEGORY_GROUP;
+-                                state = STATE_POLICY;
+-                        } else {
+-                                log_error("Unexpected token (6) at %s:%u.", path, line);
+-                                return -EINVAL;
+-                        }
+-
+-                        break;
+-
+-                case STATE_POLICY_OTHER_ATTRIBUTE:
+-
+-                        if (t == XML_ATTRIBUTE_VALUE)
+-                                state = STATE_POLICY;
+-                        else {
+-                                log_error("Unexpected token (7) in %s:%u.", path, line);
+-                                return -EINVAL;
+-                        }
+-
+-                        break;
+-
+-                case STATE_ALLOW_DENY:
+-
+-                        assert(i);
+-
+-                        if (t == XML_ATTRIBUTE_NAME) {
+-                                PolicyItemClass ic;
+-
+-                                if (startswith(name, "send_"))
+-                                        ic = POLICY_ITEM_SEND;
+-                                else if (startswith(name, "receive_"))
+-                                        ic = POLICY_ITEM_RECV;
+-                                else if (streq(name, "own"))
+-                                        ic = POLICY_ITEM_OWN;
+-                                else if (streq(name, "own_prefix"))
+-                                        ic = POLICY_ITEM_OWN_PREFIX;
+-                                else if (streq(name, "user"))
+-                                        ic = POLICY_ITEM_USER;
+-                                else if (streq(name, "group"))
+-                                        ic = POLICY_ITEM_GROUP;
+-                                else if (streq(name, "eavesdrop")) {
+-                                        log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line);
+-                                        state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
+-                                        break;
+-                                } else {
+-                                        log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
+-                                        state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
+-                                        break;
+-                                }
+-
+-                                if (i->class != _POLICY_ITEM_CLASS_UNSET && ic != i->class) {
+-                                        log_error("send_, receive_/eavesdrop fields mixed on same tag at %s:%u.", path, line);
+-                                        return -EINVAL;
+-                                }
+-
+-                                i->class = ic;
+-
+-                                if (ic == POLICY_ITEM_SEND || ic == POLICY_ITEM_RECV) {
+-                                        const char *u;
+-
+-                                        u = strchr(name, '_');
+-                                        assert(u);
+-
+-                                        u++;
+-
+-                                        if (streq(u, "interface"))
+-                                                state = STATE_ALLOW_DENY_INTERFACE;
+-                                        else if (streq(u, "member"))
+-                                                state = STATE_ALLOW_DENY_MEMBER;
+-                                        else if (streq(u, "error"))
+-                                                state = STATE_ALLOW_DENY_ERROR;
+-                                        else if (streq(u, "path"))
+-                                                state = STATE_ALLOW_DENY_PATH;
+-                                        else if (streq(u, "type"))
+-                                                state = STATE_ALLOW_DENY_MESSAGE_TYPE;
+-                                        else if ((streq(u, "destination") && ic == POLICY_ITEM_SEND) ||
+-                                                 (streq(u, "sender") && ic == POLICY_ITEM_RECV))
+-                                                state = STATE_ALLOW_DENY_NAME;
+-                                        else {
+-                                                if (streq(u, "requested_reply"))
+-                                                        log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line);
+-                                                else
+-                                                        log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
+-                                                state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
+-                                                break;
+-                                        }
+-                                } else
+-                                        state = STATE_ALLOW_DENY_NAME;
+-
+-                        } else if (t == XML_TAG_CLOSE_EMPTY ||
+-                                   (t == XML_TAG_CLOSE && streq(name, i->type == POLICY_ITEM_ALLOW ? "allow" : "deny"))) {
+-
+-                                /* If the tag is fully empty so far, we consider it a recv */
+-                                if (i->class == _POLICY_ITEM_CLASS_UNSET)
+-                                        i->class = POLICY_ITEM_RECV;
+-
+-                                if (policy_category == POLICY_CATEGORY_DEFAULT)
+-                                        item_append(i, &p->default_items);
+-                                else if (policy_category == POLICY_CATEGORY_MANDATORY)
+-                                        item_append(i, &p->mandatory_items);
+-                                else if (policy_category == POLICY_CATEGORY_ON_CONSOLE)
+-                                        item_append(i, &p->on_console_items);
+-                                else if (policy_category == POLICY_CATEGORY_NO_CONSOLE)
+-                                        item_append(i, &p->no_console_items);
+-                                else if (policy_category == POLICY_CATEGORY_USER) {
+-                                        const char *u = policy_user;
+-
+-                                        assert_cc(sizeof(uid_t) == sizeof(uint32_t));
+-
+-                                        r = hashmap_ensure_allocated(&p->user_items, NULL);
+-                                        if (r < 0)
+-                                                return log_oom();
+-
+-                                        if (!u) {
+-                                                log_error("User policy without name");
+-                                                return -EINVAL;
+-                                        }
+-
+-                                        r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
+-                                        if (r < 0) {
+-                                                log_error_errno(r, "Failed to resolve user %s, ignoring policy: %m", u);
+-                                                free(i);
+-                                        } else {
+-                                                PolicyItem *first;
+-
+-                                                first = hashmap_get(p->user_items, UINT32_TO_PTR(i->uid));
+-                                                item_append(i, &first);
+-                                                i->uid_valid = true;
+-
+-                                                r = hashmap_replace(p->user_items, UINT32_TO_PTR(i->uid), first);
+-                                                if (r < 0) {
+-                                                        LIST_REMOVE(items, first, i);
+-                                                        return log_oom();
+-                                                }
+-                                        }
+-
+-                                } else if (policy_category == POLICY_CATEGORY_GROUP) {
+-                                        const char *g = policy_group;
+-
+-                                        assert_cc(sizeof(gid_t) == sizeof(uint32_t));
+-
+-                                        r = hashmap_ensure_allocated(&p->group_items, NULL);
+-                                        if (r < 0)
+-                                                return log_oom();
+-
+-                                        if (!g) {
+-                                                log_error("Group policy without name");
+-                                                return -EINVAL;
+-                                        }
+-
+-                                        r = get_group_creds(&g, &i->gid);
+-                                        if (r < 0) {
+-                                                log_error_errno(r, "Failed to resolve group %s, ignoring policy: %m", g);
+-                                                free(i);
+-                                        } else {
+-                                                PolicyItem *first;
+-
+-                                                first = hashmap_get(p->group_items, UINT32_TO_PTR(i->gid));
+-                                                item_append(i, &first);
+-                                                i->gid_valid = true;
+-
+-                                                r = hashmap_replace(p->group_items, UINT32_TO_PTR(i->gid), first);
+-                                                if (r < 0) {
+-                                                        LIST_REMOVE(items, first, i);
+-                                                        return log_oom();
+-                                                }
+-                                        }
+-                                }
+-
+-                                state = STATE_POLICY;
+-                                i = NULL;
+-
+-                        } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
+-                                log_error("Unexpected token (8) at %s:%u.", path, line);
+-                                return -EINVAL;
+-                        }
+-
+-                        break;
+-
+-                case STATE_ALLOW_DENY_INTERFACE:
+-
+-                        if (t == XML_ATTRIBUTE_VALUE) {
+-                                assert(i);
+-                                if (i->interface) {
+-                                        log_error("Duplicate interface at %s:%u.", path, line);
+-                                        return -EINVAL;
+-                                }
+-
+-                                if (!streq(name, "*")) {
+-                                        i->interface = name;
+-                                        name = NULL;
+-                                }
+-                                state = STATE_ALLOW_DENY;
+-                        } else {
+-                                log_error("Unexpected token (9) at %s:%u.", path, line);
+-                                return -EINVAL;
+-                        }
+-
+-                        break;
+-
+-                case STATE_ALLOW_DENY_MEMBER:
+-
+-                        if (t == XML_ATTRIBUTE_VALUE) {
+-                                assert(i);
+-                                if (i->member) {
+-                                        log_error("Duplicate member in %s:%u.", path, line);
+-                                        return -EINVAL;
+-                                }
+-
+-                                if (!streq(name, "*")) {
+-                                        i->member = name;
+-                                        name = NULL;
+-                                }
+-                                state = STATE_ALLOW_DENY;
+-                        } else {
+-                                log_error("Unexpected token (10) in %s:%u.", path, line);
+-                                return -EINVAL;
+-                        }
+-
+-                        break;
+-
+-                case STATE_ALLOW_DENY_ERROR:
+-
+-                        if (t == XML_ATTRIBUTE_VALUE) {
+-                                assert(i);
+-                                if (i->error) {
+-                                        log_error("Duplicate error in %s:%u.", path, line);
+-                                        return -EINVAL;
+-                                }
+-
+-                                if (!streq(name, "*")) {
+-                                        i->error = name;
+-                                        name = NULL;
+-                                }
+-                                state = STATE_ALLOW_DENY;
+-                        } else {
+-                                log_error("Unexpected token (11) in %s:%u.", path, line);
+-                                return -EINVAL;
+-                        }
+-
+-                        break;
+-
+-                case STATE_ALLOW_DENY_PATH:
+-
+-                        if (t == XML_ATTRIBUTE_VALUE) {
+-                                assert(i);
+-                                if (i->path) {
+-                                        log_error("Duplicate path in %s:%u.", path, line);
+-                                        return -EINVAL;
+-                                }
+-
+-                                if (!streq(name, "*")) {
+-                                        i->path = name;
+-                                        name = NULL;
+-                                }
+-                                state = STATE_ALLOW_DENY;
+-                        } else {
+-                                log_error("Unexpected token (12) in %s:%u.", path, line);
+-                                return -EINVAL;
+-                        }
+-
+-                        break;
+-
+-                case STATE_ALLOW_DENY_MESSAGE_TYPE:
+-
+-                        if (t == XML_ATTRIBUTE_VALUE) {
+-                                assert(i);
+-
+-                                if (i->message_type != 0) {
+-                                        log_error("Duplicate message type in %s:%u.", path, line);
+-                                        return -EINVAL;
+-                                }
+-
+-                                if (!streq(name, "*")) {
+-                                        r = bus_message_type_from_string(name, &i->message_type);
+-                                        if (r < 0) {
+-                                                log_error("Invalid message type in %s:%u.", path, line);
+-                                                return -EINVAL;
+-                                        }
+-                                }
+-
+-                                state = STATE_ALLOW_DENY;
+-                        } else {
+-                                log_error("Unexpected token (13) in %s:%u.", path, line);
+-                                return -EINVAL;
+-                        }
+-
+-                        break;
+-
+-                case STATE_ALLOW_DENY_NAME:
+-
+-                        if (t == XML_ATTRIBUTE_VALUE) {
+-                                assert(i);
+-                                if (i->name) {
+-                                        log_error("Duplicate name in %s:%u.", path, line);
+-                                        return -EINVAL;
+-                                }
+-
+-                                switch (i->class) {
+-                                case POLICY_ITEM_USER:
+-                                        if (!streq(name, "*")) {
+-                                                const char *u = name;
+-
+-                                                r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
+-                                                if (r < 0)
+-                                                        log_error_errno(r, "Failed to resolve user %s: %m", name);
+-                                                else
+-                                                        i->uid_valid = true;
+-                                        }
+-                                        break;
+-                                case POLICY_ITEM_GROUP:
+-                                        if (!streq(name, "*")) {
+-                                                const char *g = name;
+-
+-                                                r = get_group_creds(&g, &i->gid);
+-                                                if (r < 0)
+-                                                        log_error_errno(r, "Failed to resolve group %s: %m", name);
+-                                                else
+-                                                        i->gid_valid = true;
+-                                        }
+-                                        break;
+-
+-                                case POLICY_ITEM_SEND:
+-                                case POLICY_ITEM_RECV:
+-
+-                                        if (streq(name, "*")) {
+-                                                free(name);
+-                                                name = NULL;
+-                                        }
+-                                        break;
+-
+-
+-                                default:
+-                                        break;
+-                                }
+-
+-                                i->name = name;
+-                                name = NULL;
+-
+-                                state = STATE_ALLOW_DENY;
+-                        } else {
+-                                log_error("Unexpected token (14) in %s:%u.", path, line);
+-                                return -EINVAL;
+-                        }
+-
+-                        break;
+-
+-                case STATE_ALLOW_DENY_OTHER_ATTRIBUTE:
+-
+-                        if (t == XML_ATTRIBUTE_VALUE)
+-                                state = STATE_ALLOW_DENY;
+-                        else {
+-                                log_error("Unexpected token (15) in %s:%u.", path, line);
+-                                return -EINVAL;
+-                        }
+-
+-                        break;
+-
+-                case STATE_OTHER:
+-
+-                        if (t == XML_TAG_OPEN)
+-                                n_other++;
+-                        else if (t == XML_TAG_CLOSE || t == XML_TAG_CLOSE_EMPTY) {
+-
+-                                if (n_other == 0)
+-                                        state = STATE_BUSCONFIG;
+-                                else
+-                                        n_other--;
+-                        }
+-
+-                        break;
+-                }
+-        }
+-}
+-
+-enum {
+-        DENY,
+-        ALLOW,
+-        DUNNO,
+-};
+-
+-static const char *verdict_to_string(int v) {
+-        switch (v) {
+-
+-        case DENY:
+-                return "DENY";
+-        case ALLOW:
+-                return "ALLOW";
+-        case DUNNO:
+-                return "DUNNO";
+-        }
+-
+-        return NULL;
+-}
+-
+-struct policy_check_filter {
+-        PolicyItemClass class;
+-        uid_t uid;
+-        gid_t gid;
+-        int message_type;
+-        const char *name;
+-        const char *interface;
+-        const char *path;
+-        const char *member;
+-};
+-
+-static int is_permissive(PolicyItem *i) {
+-
+-        assert(i);
+-
+-        return (i->type == POLICY_ITEM_ALLOW) ? ALLOW : DENY;
+-}
+-
+-static int check_policy_item(PolicyItem *i, const struct policy_check_filter *filter) {
+-
+-        assert(i);
+-        assert(filter);
+-
+-        switch (i->class) {
+-        case POLICY_ITEM_SEND:
+-        case POLICY_ITEM_RECV:
+-
+-                if (i->name && !streq_ptr(i->name, filter->name))
+-                        break;
+-
+-                if ((i->message_type != 0) && (i->message_type != filter->message_type))
+-                        break;
+-
+-                if (i->path && !streq_ptr(i->path, filter->path))
+-                        break;
+-
+-                if (i->member && !streq_ptr(i->member, filter->member))
+-                        break;
+-
+-                if (i->interface && !streq_ptr(i->interface, filter->interface))
+-                        break;
+-
+-                return is_permissive(i);
+-
+-        case POLICY_ITEM_OWN:
+-                assert(filter->name);
+-
+-                if (streq(i->name, "*") || streq(i->name, filter->name))
+-                        return is_permissive(i);
+-                break;
+-
+-        case POLICY_ITEM_OWN_PREFIX:
+-                assert(filter->name);
+-
+-                if (streq(i->name, "*") || service_name_startswith(filter->name, i->name))
+-                        return is_permissive(i);
+-                break;
+-
+-        case POLICY_ITEM_USER:
+-                if (filter->uid != UID_INVALID)
+-                        if ((streq_ptr(i->name, "*") || (i->uid_valid && i->uid == filter->uid)))
+-                                return is_permissive(i);
+-                break;
+-
+-        case POLICY_ITEM_GROUP:
+-                if (filter->gid != GID_INVALID)
+-                        if ((streq_ptr(i->name, "*") || (i->gid_valid && i->gid == filter->gid)))
+-                                return is_permissive(i);
+-                break;
+-
+-        case POLICY_ITEM_IGNORE:
+-        default:
+-                break;
+-        }
+-
+-        return DUNNO;
+-}
+-
+-static int check_policy_items(PolicyItem *items, const struct policy_check_filter *filter) {
+-
+-        PolicyItem *i;
+-        int verdict = DUNNO;
+-
+-        assert(filter);
+-
+-        /* Check all policies in a set - a broader one might be followed by a more specific one,
+-         * and the order of rules in policy definitions matters */
+-        LIST_FOREACH(items, i, items) {
+-                int v;
+-
+-                if (i->class != filter->class &&
+-                    !(i->class == POLICY_ITEM_OWN_PREFIX && filter->class == POLICY_ITEM_OWN))
+-                        continue;
+-
+-                v = check_policy_item(i, filter);
+-                if (v != DUNNO)
+-                        verdict = v;
+-        }
+-
+-        return verdict;
+-}
+-
+-static int policy_check(Policy *p, const struct policy_check_filter *filter) {
+-
+-        PolicyItem *items;
+-        int verdict, v;
+-
+-        assert(p);
+-        assert(filter);
+-
+-        assert(IN_SET(filter->class, POLICY_ITEM_SEND, POLICY_ITEM_RECV, POLICY_ITEM_OWN, POLICY_ITEM_USER, POLICY_ITEM_GROUP));
+-
+-        /*
+-         * The policy check is implemented by the following logic:
+-         *
+-         *  1. Check default items
+-         *  2. Check group items
+-         *  3. Check user items
+-         *  4. Check on/no_console items
+-         *  5. Check mandatory items
+-         *
+-         *  Later rules override earlier rules.
+-         */
+-
+-        verdict = check_policy_items(p->default_items, filter);
+-
+-        if (filter->gid != GID_INVALID) {
+-                items = hashmap_get(p->group_items, UINT32_TO_PTR(filter->gid));
+-                if (items) {
+-                        v = check_policy_items(items, filter);
+-                        if (v != DUNNO)
+-                                verdict = v;
+-                }
+-        }
+-
+-        if (filter->uid != UID_INVALID) {
+-                items = hashmap_get(p->user_items, UINT32_TO_PTR(filter->uid));
+-                if (items) {
+-                        v = check_policy_items(items, filter);
+-                        if (v != DUNNO)
+-                                verdict = v;
+-                }
+-        }
+-
+-        if (filter->uid != UID_INVALID && sd_uid_get_seats(filter->uid, -1, NULL) > 0)
+-                v = check_policy_items(p->on_console_items, filter);
+-        else
+-                v = check_policy_items(p->no_console_items, filter);
+-        if (v != DUNNO)
+-                verdict = v;
+-
+-        v = check_policy_items(p->mandatory_items, filter);
+-        if (v != DUNNO)
+-                verdict = v;
+-
+-        return verdict;
+-}
+-
+-bool policy_check_own(Policy *p, uid_t uid, gid_t gid, const char *name) {
+-
+-        struct policy_check_filter filter = {
+-                .class = POLICY_ITEM_OWN,
+-                .uid   = uid,
+-                .gid   = gid,
+-                .name  = name,
+-        };
+-
+-        int verdict;
+-
+-        assert(p);
+-        assert(name);
+-
+-        verdict = policy_check(p, &filter);
+-
+-        log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
+-                 "Ownership permission check for uid=" UID_FMT " gid=" GID_FMT" name=%s: %s",
+-                 uid, gid, strna(name), strna(verdict_to_string(verdict)));
+-
+-        return verdict == ALLOW;
+-}
+-
+-bool policy_check_hello(Policy *p, uid_t uid, gid_t gid) {
+-
+-        struct policy_check_filter filter = {
+-                .uid = uid,
+-                .gid = gid,
+-        };
+-        int verdict;
+-
+-        assert(p);
+-
+-        filter.class = POLICY_ITEM_USER;
+-        verdict = policy_check(p, &filter);
+-
+-        if (verdict != DENY) {
+-                int v;
+-
+-                filter.class = POLICY_ITEM_GROUP;
+-                v = policy_check(p, &filter);
+-                if (v != DUNNO)
+-                        verdict = v;
+-        }
+-
+-        log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
+-                 "Hello permission check for uid=" UID_FMT " gid=" GID_FMT": %s",
+-                 uid, gid, strna(verdict_to_string(verdict)));
+-
+-        return verdict == ALLOW;
+-}
+-
+-bool policy_check_one_recv(Policy *p,
+-                           uid_t uid,
+-                           gid_t gid,
+-                           int message_type,
+-                           const char *name,
+-                           const char *path,
+-                           const char *interface,
+-                           const char *member) {
+-
+-        struct policy_check_filter filter = {
+-                .class        = POLICY_ITEM_RECV,
+-                .uid          = uid,
+-                .gid          = gid,
+-                .message_type = message_type,
+-                .name         = name,
+-                .interface    = interface,
+-                .path         = path,
+-                .member       = member,
+-        };
+-
+-        assert(p);
+-
+-        return policy_check(p, &filter) == ALLOW;
+-}
+-
+-bool policy_check_recv(Policy *p,
+-                       uid_t uid,
+-                       gid_t gid,
+-                       int message_type,
+-                       Set *names,
+-                       char **namesv,
+-                       const char *path,
+-                       const char *interface,
+-                       const char *member,
+-                       bool dbus_to_kernel) {
+-
+-        char *n, **nv, *last = NULL;
+-        bool allow = false;
+-        Iterator i;
+-
+-        assert(p);
+-
+-        if (set_isempty(names) && strv_isempty(namesv)) {
+-                allow = policy_check_one_recv(p, uid, gid, message_type, NULL, path, interface, member);
+-        } else {
+-                SET_FOREACH(n, names, i) {
+-                        last = n;
+-                        allow = policy_check_one_recv(p, uid, gid, message_type, n, path, interface, member);
+-                        if (allow)
+-                                break;
+-                }
+-                if (!allow) {
+-                        STRV_FOREACH(nv, namesv) {
+-                                last = *nv;
+-                                allow = policy_check_one_recv(p, uid, gid, message_type, *nv, path, interface, member);
+-                                if (allow)
+-                                        break;
+-                        }
+-                }
+-        }
+-
+-        log_full(LOG_AUTH | (!allow ? LOG_WARNING : LOG_DEBUG),
+-                 "Receive permission check %s for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s path=%s interface=%s member=%s: %s",
+-                 dbus_to_kernel ? "dbus-1 to kernel" : "kernel to dbus-1", uid, gid, bus_message_type_to_string(message_type), strna(last),
+-                 strna(path), strna(interface), strna(member), allow ? "ALLOW" : "DENY");
+-
+-        return allow;
+-}
+-
+-bool policy_check_one_send(Policy *p,
+-                           uid_t uid,
+-                           gid_t gid,
+-                           int message_type,
+-                           const char *name,
+-                           const char *path,
+-                           const char *interface,
+-                           const char *member) {
+-
+-        struct policy_check_filter filter = {
+-                .class        = POLICY_ITEM_SEND,
+-                .uid          = uid,
+-                .gid          = gid,
+-                .message_type = message_type,
+-                .name         = name,
+-                .interface    = interface,
+-                .path         = path,
+-                .member       = member,
+-        };
+-
+-        assert(p);
+-
+-        return policy_check(p, &filter) == ALLOW;
+-}
+-
+-bool policy_check_send(Policy *p,
+-                       uid_t uid,
+-                       gid_t gid,
+-                       int message_type,
+-                       Set *names,
+-                       char **namesv,
+-                       const char *path,
+-                       const char *interface,
+-                       const char *member,
+-                       bool dbus_to_kernel,
+-                       char **out_used_name) {
+-
+-        char *n, **nv, *last = NULL;
+-        bool allow = false;
+-        Iterator i;
+-
+-        assert(p);
+-
+-        if (set_isempty(names) && strv_isempty(namesv)) {
+-                allow = policy_check_one_send(p, uid, gid, message_type, NULL, path, interface, member);
+-        } else {
+-                SET_FOREACH(n, names, i) {
+-                        last = n;
+-                        allow = policy_check_one_send(p, uid, gid, message_type, n, path, interface, member);
+-                        if (allow)
+-                                break;
+-                }
+-                if (!allow) {
+-                        STRV_FOREACH(nv, namesv) {
+-                                last = *nv;
+-                                allow = policy_check_one_send(p, uid, gid, message_type, *nv, path, interface, member);
+-                                if (allow)
+-                                        break;
+-                        }
+-                }
+-        }
+-
+-        if (out_used_name)
+-                *out_used_name = last;
+-
+-        log_full(LOG_AUTH | (!allow ? LOG_WARNING : LOG_DEBUG),
+-                 "Send permission check %s for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s path=%s interface=%s member=%s: %s",
+-                 dbus_to_kernel ? "dbus-1 to kernel" : "kernel to dbus-1", uid, gid, bus_message_type_to_string(message_type), strna(last),
+-                 strna(path), strna(interface), strna(member), allow ? "ALLOW" : "DENY");
+-
+-        return allow;
+-}
+-
+-int policy_load(Policy *p, char **files) {
+-        char **i;
+-        int r;
+-
+-        assert(p);
+-
+-        STRV_FOREACH(i, files) {
+-
+-                r = file_load(p, *i);
+-                if (r == -EISDIR) {
+-                        _cleanup_strv_free_ char **l = NULL;
+-                        char **j;
+-
+-                        r = conf_files_list(&l, ".conf", NULL, *i, NULL);
+-                        if (r < 0)
+-                                return log_error_errno(r, "Failed to get configuration file list: %m");
+-
+-                        STRV_FOREACH(j, l)
+-                                file_load(p, *j);
+-                }
+-
+-                /* We ignore all errors but EISDIR, and just proceed. */
+-        }
+-
+-        return 0;
+-}
+-
+-void policy_free(Policy *p) {
+-        PolicyItem *i, *first;
+-
+-        if (!p)
+-                return;
+-
+-        while ((i = p->default_items)) {
+-                LIST_REMOVE(items, p->default_items, i);
+-                policy_item_free(i);
+-        }
+-
+-        while ((i = p->mandatory_items)) {
+-                LIST_REMOVE(items, p->mandatory_items, i);
+-                policy_item_free(i);
+-        }
+-
+-        while ((i = p->on_console_items)) {
+-                LIST_REMOVE(items, p->on_console_items, i);
+-                policy_item_free(i);
+-        }
+-
+-        while ((i = p->no_console_items)) {
+-                LIST_REMOVE(items, p->no_console_items, i);
+-                policy_item_free(i);
+-        }
+-
+-        while ((first = hashmap_steal_first(p->user_items))) {
+-
+-                while ((i = first)) {
+-                        LIST_REMOVE(items, first, i);
+-                        policy_item_free(i);
+-                }
+-        }
+-
+-        while ((first = hashmap_steal_first(p->group_items))) {
+-
+-                while ((i = first)) {
+-                        LIST_REMOVE(items, first, i);
+-                        policy_item_free(i);
+-                }
+-        }
+-
+-        hashmap_free(p->user_items);
+-        hashmap_free(p->group_items);
+-
+-        p->user_items = p->group_items = NULL;
+-}
+-
+-static void dump_items(PolicyItem *items, const char *prefix) {
+-
+-        PolicyItem *i;
+-
+-        if (!items)
+-                return;
+-
+-        if (!prefix)
+-                prefix = "";
+-
+-        LIST_FOREACH(items, i, items) {
+-
+-                printf("%sType: %s\n"
+-                       "%sClass: %s\n",
+-                       prefix, policy_item_type_to_string(i->type),
+-                       prefix, policy_item_class_to_string(i->class));
+-
+-                if (i->interface)
+-                        printf("%sInterface: %s\n",
+-                               prefix, i->interface);
+-
+-                if (i->member)
+-                        printf("%sMember: %s\n",
+-                               prefix, i->member);
+-
+-                if (i->error)
+-                        printf("%sError: %s\n",
+-                               prefix, i->error);
+-
+-                if (i->path)
+-                        printf("%sPath: %s\n",
+-                               prefix, i->path);
+-
+-                if (i->name)
+-                        printf("%sName: %s\n",
+-                               prefix, i->name);
+-
+-                if (i->message_type != 0)
+-                        printf("%sMessage Type: %s\n",
+-                               prefix, bus_message_type_to_string(i->message_type));
+-
+-                if (i->uid_valid) {
+-                        _cleanup_free_ char *user;
+-
+-                        user = uid_to_name(i->uid);
+-
+-                        printf("%sUser: %s ("UID_FMT")\n",
+-                               prefix, strna(user), i->uid);
+-                }
+-
+-                if (i->gid_valid) {
+-                        _cleanup_free_ char *group;
+-
+-                        group = gid_to_name(i->gid);
+-
+-                        printf("%sGroup: %s ("GID_FMT")\n",
+-                               prefix, strna(group), i->gid);
+-                }
+-                printf("%s-\n", prefix);
+-        }
+-}
+-
+-static void dump_hashmap_items(Hashmap *h) {
+-        PolicyItem *i;
+-        Iterator j;
+-        void *k;
+-
+-        HASHMAP_FOREACH_KEY(i, k, h, j) {
+-                printf("\t%s Item for %u:\n", draw_special_char(DRAW_ARROW), PTR_TO_UINT(k));
+-                dump_items(i, "\t\t");
+-        }
+-}
+-
+-void policy_dump(Policy *p) {
+-
+-        printf("%s Default Items:\n", draw_special_char(DRAW_ARROW));
+-        dump_items(p->default_items, "\t");
+-
+-        printf("%s Group Items:\n", draw_special_char(DRAW_ARROW));
+-        dump_hashmap_items(p->group_items);
+-
+-        printf("%s User Items:\n", draw_special_char(DRAW_ARROW));
+-        dump_hashmap_items(p->user_items);
+-
+-        printf("%s On-Console Items:\n", draw_special_char(DRAW_ARROW));
+-        dump_items(p->on_console_items, "\t");
+-
+-        printf("%s No-Console Items:\n", draw_special_char(DRAW_ARROW));
+-        dump_items(p->no_console_items, "\t");
+-
+-        printf("%s Mandatory Items:\n", draw_special_char(DRAW_ARROW));
+-        dump_items(p->mandatory_items, "\t");
+-
+-        fflush(stdout);
+-}
+-
+-int shared_policy_new(SharedPolicy **out) {
+-        SharedPolicy *sp;
+-        int r;
+-
+-        sp = new0(SharedPolicy, 1);
+-        if (!sp)
+-                return log_oom();
+-
+-        r = pthread_mutex_init(&sp->lock, NULL);
+-        if (r < 0) {
+-                log_error_errno(r, "Cannot initialize shared policy mutex: %m");
+-                goto exit_free;
+-        }
+-
+-        r = pthread_rwlock_init(&sp->rwlock, NULL);
+-        if (r < 0) {
+-                log_error_errno(r, "Cannot initialize shared policy rwlock: %m");
+-                goto exit_mutex;
+-        }
+-
+-        *out = sp;
+-        sp = NULL;
+-        return 0;
+-
+-        /* pthread lock destruction is not fail-safe... meh! */
+-exit_mutex:
+-        pthread_mutex_destroy(&sp->lock);
+-exit_free:
+-        free(sp);
+-        return r;
+-}
+-
+-SharedPolicy *shared_policy_free(SharedPolicy *sp) {
+-        if (!sp)
+-                return NULL;
+-
+-        policy_free(sp->policy);
+-        pthread_rwlock_destroy(&sp->rwlock);
+-        pthread_mutex_destroy(&sp->lock);
+-        strv_free(sp->configuration);
+-        free(sp);
+-
+-        return NULL;
+-}
+-
+-static int shared_policy_reload_unlocked(SharedPolicy *sp, char **configuration) {
+-        Policy old, buffer = {};
+-        bool free_old;
+-        int r;
+-
+-        assert(sp);
+-
+-        r = policy_load(&buffer, configuration);
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to load policy: %m");
+-
+-        log_debug("Reloading configuration");
+-        /* policy_dump(&buffer); */
+-
+-        pthread_rwlock_wrlock(&sp->rwlock);
+-        memcpy(&old, &sp->buffer, sizeof(old));
+-        memcpy(&sp->buffer, &buffer, sizeof(buffer));
+-        free_old = !!sp->policy;
+-        sp->policy = &sp->buffer;
+-        pthread_rwlock_unlock(&sp->rwlock);
+-
+-        if (free_old)
+-                policy_free(&old);
+-
+-        return 0;
+-}
+-
+-int shared_policy_reload(SharedPolicy *sp) {
+-        int r;
+-
+-        assert(sp);
+-
+-        pthread_mutex_lock(&sp->lock);
+-        r = shared_policy_reload_unlocked(sp, sp->configuration);
+-        pthread_mutex_unlock(&sp->lock);
+-
+-        return r;
+-}
+-
+-int shared_policy_preload(SharedPolicy *sp, char **configuration) {
+-        _cleanup_strv_free_ char **conf = NULL;
+-        int r = 0;
+-
+-        assert(sp);
+-
+-        conf = strv_copy(configuration);
+-        if (!conf)
+-                return log_oom();
+-
+-        pthread_mutex_lock(&sp->lock);
+-        if (!sp->policy) {
+-                r = shared_policy_reload_unlocked(sp, conf);
+-                if (r >= 0) {
+-                        sp->configuration = conf;
+-                        conf = NULL;
+-                }
+-        }
+-        pthread_mutex_unlock(&sp->lock);
+-
+-        return r;
+-}
+-
+-Policy *shared_policy_acquire(SharedPolicy *sp) {
+-        assert(sp);
+-
+-        pthread_rwlock_rdlock(&sp->rwlock);
+-        if (sp->policy)
+-                return sp->policy;
+-        pthread_rwlock_unlock(&sp->rwlock);
+-
+-        return NULL;
+-}
+-
+-void shared_policy_release(SharedPolicy *sp, Policy *p) {
+-        assert(sp);
+-        assert(!p || sp->policy == p);
+-
+-        if (p)
+-                pthread_rwlock_unlock(&sp->rwlock);
+-}
+-
+-static const char* const policy_item_type_table[_POLICY_ITEM_TYPE_MAX] = {
+-        [_POLICY_ITEM_TYPE_UNSET] = "unset",
+-        [POLICY_ITEM_ALLOW] = "allow",
+-        [POLICY_ITEM_DENY] = "deny",
+-};
+-DEFINE_STRING_TABLE_LOOKUP(policy_item_type, PolicyItemType);
+-
+-static const char* const policy_item_class_table[_POLICY_ITEM_CLASS_MAX] = {
+-        [_POLICY_ITEM_CLASS_UNSET] = "unset",
+-        [POLICY_ITEM_SEND] = "send",
+-        [POLICY_ITEM_RECV] = "recv",
+-        [POLICY_ITEM_OWN] = "own",
+-        [POLICY_ITEM_OWN_PREFIX] = "own-prefix",
+-        [POLICY_ITEM_USER] = "user",
+-        [POLICY_ITEM_GROUP] = "group",
+-        [POLICY_ITEM_IGNORE] = "ignore",
+-};
+-DEFINE_STRING_TABLE_LOOKUP(policy_item_class, PolicyItemClass);
+diff --git a/src/bus-proxyd/bus-xml-policy.h b/src/bus-proxyd/bus-xml-policy.h
+deleted file mode 100644
+index f2ec1bb..0000000
+--- a/src/bus-proxyd/bus-xml-policy.h
++++ /dev/null
+@@ -1,151 +0,0 @@
+-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+-
+-#pragma once
+-
+-/***
+-  This file is part of systemd.
+-
+-  Copyright 2013 Lennart Poettering
+-
+-  systemd is free software; you can redistribute it and/or modify it
+-  under the terms of the GNU Lesser General Public License as published by
+-  the Free Software Foundation; either version 2.1 of the License, or
+-  (at your option) any later version.
+-
+-  systemd is distributed in the hope that it will be useful, but
+-  WITHOUT ANY WARRANTY; without even the implied warranty of
+-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-  Lesser General Public License for more details.
+-
+-  You should have received a copy of the GNU Lesser General Public License
+-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+-***/
+-
+-#include <inttypes.h>
+-#include <pthread.h>
+-
+-#include "list.h"
+-#include "hashmap.h"
+-#include "set.h"
+-
+-typedef enum PolicyItemType {
+-        _POLICY_ITEM_TYPE_UNSET = 0,
+-        POLICY_ITEM_ALLOW,
+-        POLICY_ITEM_DENY,
+-        _POLICY_ITEM_TYPE_MAX,
+-        _POLICY_ITEM_TYPE_INVALID = -1,
+-} PolicyItemType;
+-
+-typedef enum PolicyItemClass {
+-        _POLICY_ITEM_CLASS_UNSET = 0,
+-        POLICY_ITEM_SEND,
+-        POLICY_ITEM_RECV,
+-        POLICY_ITEM_OWN,
+-        POLICY_ITEM_OWN_PREFIX,
+-        POLICY_ITEM_USER,
+-        POLICY_ITEM_GROUP,
+-        POLICY_ITEM_IGNORE,
+-        _POLICY_ITEM_CLASS_MAX,
+-        _POLICY_ITEM_CLASS_INVALID = -1,
+-} PolicyItemClass;
+-
+-typedef struct PolicyItem PolicyItem;
+-
+-struct PolicyItem {
+-        PolicyItemType type;
+-        PolicyItemClass class;
+-        char *interface;
+-        char *member;
+-        char *error;
+-        char *path;
+-        char *name;
+-        uint8_t message_type;
+-        uid_t uid;
+-        gid_t gid;
+-
+-        bool uid_valid, gid_valid;
+-
+-        LIST_FIELDS(PolicyItem, items);
+-};
+-
+-typedef struct Policy {
+-        LIST_HEAD(PolicyItem, default_items);
+-        LIST_HEAD(PolicyItem, mandatory_items);
+-        LIST_HEAD(PolicyItem, on_console_items);
+-        LIST_HEAD(PolicyItem, no_console_items);
+-        Hashmap *user_items;
+-        Hashmap *group_items;
+-} Policy;
+-
+-typedef struct SharedPolicy {
+-        char **configuration;
+-        pthread_mutex_t lock;
+-        pthread_rwlock_t rwlock;
+-        Policy buffer;
+-        Policy *policy;
+-} SharedPolicy;
+-
+-/* policy */
+-
+-int policy_load(Policy *p, char **files);
+-void policy_free(Policy *p);
+-
+-bool policy_check_own(Policy *p, uid_t uid, gid_t gid, const char *name);
+-bool policy_check_hello(Policy *p, uid_t uid, gid_t gid);
+-bool policy_check_one_recv(Policy *p,
+-                           uid_t uid,
+-                           gid_t gid,
+-                           int message_type,
+-                           const char *name,
+-                           const char *path,
+-                           const char *interface,
+-                           const char *member);
+-bool policy_check_recv(Policy *p,
+-                       uid_t uid,
+-                       gid_t gid,
+-                       int message_type,
+-                       Set *names,
+-                       char **namesv,
+-                       const char *path,
+-                       const char *interface,
+-                       const char *member,
+-                       bool dbus_to_kernel);
+-bool policy_check_one_send(Policy *p,
+-                           uid_t uid,
+-                           gid_t gid,
+-                           int message_type,
+-                           const char *name,
+-                           const char *path,
+-                           const char *interface,
+-                           const char *member);
+-bool policy_check_send(Policy *p,
+-                       uid_t uid,
+-                       gid_t gid,
+-                       int message_type,
+-                       Set *names,
+-                       char **namesv,
+-                       const char *path,
+-                       const char *interface,
+-                       const char *member,
+-                       bool dbus_to_kernel,
+-                       char **out_used_name);
+-
+-void policy_dump(Policy *p);
+-
+-const char* policy_item_type_to_string(PolicyItemType t) _const_;
+-PolicyItemType policy_item_type_from_string(const char *s) _pure_;
+-
+-const char* policy_item_class_to_string(PolicyItemClass t) _const_;
+-PolicyItemClass policy_item_class_from_string(const char *s) _pure_;
+-
+-/* shared policy */
+-
+-int shared_policy_new(SharedPolicy **out);
+-SharedPolicy *shared_policy_free(SharedPolicy *sp);
+-
+-int shared_policy_reload(SharedPolicy *sp);
+-int shared_policy_preload(SharedPolicy *sp, char **configuration);
+-Policy *shared_policy_acquire(SharedPolicy *sp);
+-void shared_policy_release(SharedPolicy *sp, Policy *p);
+-
+-DEFINE_TRIVIAL_CLEANUP_FUNC(SharedPolicy*, shared_policy_free);
+diff --git a/src/bus-proxyd/driver.c b/src/bus-proxyd/driver.c
+deleted file mode 100644
+index bc2c0c8..0000000
+--- a/src/bus-proxyd/driver.c
++++ /dev/null
+@@ -1,608 +0,0 @@
+-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+-
+-/***
+-  This file is part of systemd.
+-
+-  Copyright 2010 Lennart Poettering
+-  Copyright 2013 Daniel Mack
+-  Copyright 2014 Kay Sievers
+-
+-  systemd is free software; you can redistribute it and/or modify it
+-  under the terms of the GNU Lesser General Public License as published by
+-  the Free Software Foundation; either version 2.1 of the License, or
+-  (at your option) any later version.
+-
+-  systemd is distributed in the hope that it will be useful, but
+-  WITHOUT ANY WARRANTY; without even the implied warranty of
+-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-  Lesser General Public License for more details.
+-
+-  You should have received a copy of the GNU Lesser General Public License
+-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+-***/
+-
+-#include <sys/types.h>
+-#include <unistd.h>
+-#include <string.h>
+-#include <errno.h>
+-#include <stddef.h>
+-
+-#include "log.h"
+-#include "util.h"
+-#include "sd-bus.h"
+-#include "bus-internal.h"
+-#include "bus-message.h"
+-#include "bus-util.h"
+-#include "build.h"
+-#include "strv.h"
+-#include "def.h"
+-#include "capability.h"
+-#include "bus-control.h"
+-#include "set.h"
+-#include "driver.h"
+-#include "synthesize.h"
+-
+-static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
+-        _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
+-        int r;
+-
+-        assert(bus);
+-        assert(name);
+-        assert(_creds);
+-
+-        r = sd_bus_get_name_creds(bus, name, mask, &c);
+-        if (r == -ESRCH || r == -ENXIO)
+-                return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name);
+-        if (r < 0)
+-                return r;
+-
+-        if ((c->mask & mask) != mask)
+-                return -ENOTSUP;
+-
+-        *_creds = c;
+-        c = NULL;
+-
+-        return 0;
+-}
+-
+-static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
+-        const char *name;
+-        int r;
+-
+-        assert(bus);
+-        assert(m);
+-        assert(_creds);
+-
+-        r = sd_bus_message_read(m, "s", &name);
+-        if (r < 0)
+-                return r;
+-
+-        return get_creds_by_name(bus, name, mask, _creds, error);
+-}
+-
+-int bus_proxy_process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPolicy *sp, const struct ucred *ucred, Set *owned_names) {
+-        int r;
+-
+-        assert(a);
+-        assert(b);
+-        assert(m);
+-
+-        if (!a->is_kernel)
+-                return 0;
+-
+-        if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
+-                return 0;
+-
+-        /* The "Hello()" call is is handled in process_hello() */
+-
+-        if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
+-
+-                if (!sd_bus_message_has_signature(m, ""))
+-                        return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+-
+-                return synthetic_reply_method_return(m, "s",
+-                        "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
+-                          "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
+-                        "<node>\n"
+-                        " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
+-                        "  <method name=\"Introspect\">\n"
+-                        "   <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
+-                        "  </method>\n"
+-                        " </interface>\n"
+-                        " <interface name=\"org.freedesktop.DBus\">\n"
+-                        "  <method name=\"AddMatch\">\n"
+-                        "   <arg type=\"s\" direction=\"in\"/>\n"
+-                        "  </method>\n"
+-                        "  <method name=\"RemoveMatch\">\n"
+-                        "   <arg type=\"s\" direction=\"in\"/>\n"
+-                        "  </method>\n"
+-                        "  <method name=\"GetConnectionSELinuxSecurityContext\">\n"
+-                        "   <arg type=\"s\" direction=\"in\"/>\n"
+-                        "   <arg type=\"ay\" direction=\"out\"/>\n"
+-                        "  </method>\n"
+-                        "  <method name=\"GetConnectionUnixProcessID\">\n"
+-                        "   <arg type=\"s\" direction=\"in\"/>\n"
+-                        "   <arg type=\"u\" direction=\"out\"/>\n"
+-                        "  </method>\n"
+-                        "  <method name=\"GetConnectionUnixUser\">\n"
+-                        "   <arg type=\"s\" direction=\"in\"/>\n"
+-                        "   <arg type=\"u\" direction=\"out\"/>\n"
+-                        "  </method>\n"
+-                        "  <method name=\"GetId\">\n"
+-                        "   <arg type=\"s\" direction=\"out\"/>\n"
+-                        "  </method>\n"
+-                        "  <method name=\"GetNameOwner\">\n"
+-                        "   <arg type=\"s\" direction=\"in\"/>\n"
+-                        "   <arg type=\"s\" direction=\"out\"/>\n"
+-                        "  </method>\n"
+-                        "  <method name=\"Hello\">\n"
+-                        "   <arg type=\"s\" direction=\"out\"/>\n"
+-                        "  </method>\n"
+-                        "  <method name=\"ListActivatableNames\">\n"
+-                        "   <arg type=\"as\" direction=\"out\"/>\n"
+-                        "  </method>\n"
+-                        "  <method name=\"ListNames\">\n"
+-                        "   <arg type=\"as\" direction=\"out\"/>\n"
+-                        "  </method>\n"
+-                        "  <method name=\"ListQueuedOwners\">\n"
+-                        "   <arg type=\"s\" direction=\"in\"/>\n"
+-                        "   <arg type=\"as\" direction=\"out\"/>\n"
+-                        "  </method>\n"
+-                        "  <method name=\"NameHasOwner\">\n"
+-                        "   <arg type=\"s\" direction=\"in\"/>\n"
+-                        "   <arg type=\"b\" direction=\"out\"/>\n"
+-                        "  </method>\n"
+-                        "  <method name=\"ReleaseName\">\n"
+-                        "   <arg type=\"s\" direction=\"in\"/>\n"
+-                        "   <arg type=\"u\" direction=\"out\"/>\n"
+-                        "  </method>\n"
+-                        "  <method name=\"ReloadConfig\">\n"
+-                        "  </method>\n"
+-                        "  <method name=\"RequestName\">\n"
+-                        "   <arg type=\"s\" direction=\"in\"/>\n"
+-                        "   <arg type=\"u\" direction=\"in\"/>\n"
+-                        "   <arg type=\"u\" direction=\"out\"/>\n"
+-                        "  </method>\n"
+-                        "  <method name=\"StartServiceByName\">\n"
+-                        "   <arg type=\"s\" direction=\"in\"/>\n"
+-                        "   <arg type=\"u\" direction=\"in\"/>\n"
+-                        "   <arg type=\"u\" direction=\"out\"/>\n"
+-                        "  </method>\n"
+-                        "  <method name=\"UpdateActivationEnvironment\">\n"
+-                        "   <arg type=\"a{ss}\" direction=\"in\"/>\n"
+-                        "  </method>\n"
+-                        "  <signal name=\"NameAcquired\">\n"
+-                        "   <arg type=\"s\"/>\n"
+-                        "  </signal>\n"
+-                        "  <signal name=\"NameLost\">\n"
+-                        "   <arg type=\"s\"/>\n"
+-                        "  </signal>\n"
+-                        "  <signal name=\"NameOwnerChanged\">\n"
+-                        "   <arg type=\"s\"/>\n"
+-                        "   <arg type=\"s\"/>\n"
+-                        "   <arg type=\"s\"/>\n"
+-                        "  </signal>\n"
+-                        " </interface>\n"
+-                        "</node>\n");
+-
+-        } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) {
+-                const char *match;
+-
+-                if (!sd_bus_message_has_signature(m, "s"))
+-                        return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+-
+-                r = sd_bus_message_read(m, "s", &match);
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                r = sd_bus_add_match(a, NULL, match, NULL, NULL);
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                return synthetic_reply_method_return(m, NULL);
+-
+-        } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
+-                const char *match;
+-
+-                if (!sd_bus_message_has_signature(m, "s"))
+-                        return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+-
+-                r = sd_bus_message_read(m, "s", &match);
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                r = bus_remove_match_by_string(a, match, NULL, NULL);
+-                if (r == 0)
+-                        return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found"));
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                return synthetic_reply_method_return(m, NULL);
+-
+-        } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionSELinuxSecurityContext")) {
+-                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+-                _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+-
+-                if (!sd_bus_message_has_signature(m, "s"))
+-                        return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+-
+-                r = get_creds_by_message(a, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, &error);
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, &error);
+-
+-                return synthetic_reply_method_return(m, "y", creds->label, strlen(creds->label));
+-
+-        } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixProcessID")) {
+-                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+-                _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+-
+-                if (!sd_bus_message_has_signature(m, "s"))
+-                        return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+-
+-                r = get_creds_by_message(a, m, SD_BUS_CREDS_PID, &creds, &error);
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, &error);
+-
+-                return synthetic_reply_method_return(m, "u", (uint32_t) creds->pid);
+-
+-        } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixUser")) {
+-                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+-                _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+-
+-                if (!sd_bus_message_has_signature(m, "s"))
+-                        return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+-
+-                r = get_creds_by_message(a, m, SD_BUS_CREDS_EUID, &creds, &error);
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, &error);
+-
+-                return synthetic_reply_method_return(m, "u", (uint32_t) creds->euid);
+-
+-        } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetId")) {
+-                sd_id128_t server_id;
+-                char buf[SD_ID128_STRING_MAX];
+-
+-                if (!sd_bus_message_has_signature(m, ""))
+-                        return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+-
+-                r = sd_bus_get_bus_id(a, &server_id);
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                return synthetic_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
+-
+-        } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetNameOwner")) {
+-                const char *name;
+-                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+-                _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+-
+-                if (!sd_bus_message_has_signature(m, "s"))
+-                        return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+-
+-                r = sd_bus_message_read(m, "s", &name);
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                if (streq(name, "org.freedesktop.DBus"))
+-                        return synthetic_reply_method_return(m, "s", "org.freedesktop.DBus");
+-
+-                r = get_creds_by_name(a, name, SD_BUS_CREDS_UNIQUE_NAME, &creds, &error);
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, &error);
+-
+-                return synthetic_reply_method_return(m, "s", creds->unique_name);
+-
+-        } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListActivatableNames")) {
+-                _cleanup_strv_free_ char **names = NULL;
+-
+-                if (!sd_bus_message_has_signature(m, ""))
+-                        return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+-
+-                r = sd_bus_list_names(a, NULL, &names);
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                /* Let's sort the names list to make it stable */
+-                strv_sort(names);
+-
+-                return synthetic_reply_method_return_strv(m, names);
+-
+-        } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListNames")) {
+-                _cleanup_strv_free_ char **names = NULL;
+-
+-                if (!sd_bus_message_has_signature(m, ""))
+-                        return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+-
+-                r = sd_bus_list_names(a, &names, NULL);
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                r = strv_extend(&names, "org.freedesktop.DBus");
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                /* Let's sort the names list to make it stable */
+-                strv_sort(names);
+-
+-                return synthetic_reply_method_return_strv(m, names);
+-
+-        } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) {
+-                struct kdbus_cmd_list cmd = {
+-                        .flags = KDBUS_LIST_QUEUED,
+-                        .size = sizeof(cmd),
+-                };
+-                struct kdbus_info *name_list, *name;
+-                _cleanup_strv_free_ char **owners = NULL;
+-                _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+-                char *arg0;
+-                int err = 0;
+-
+-                if (!sd_bus_message_has_signature(m, "s"))
+-                        return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+-
+-                r = sd_bus_message_read(m, "s", &arg0);
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                r = sd_bus_get_name_creds(a, arg0, 0, NULL);
+-                if (r == -ESRCH || r == -ENXIO) {
+-                        sd_bus_error_setf(&error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Could not get owners of name '%s': no such name.", arg0);
+-                        return synthetic_reply_method_errno(m, r, &error);
+-                }
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                r = ioctl(a->input_fd, KDBUS_CMD_LIST, &cmd);
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, -errno, NULL);
+-
+-                name_list = (struct kdbus_info *) ((uint8_t *) a->kdbus_buffer + cmd.offset);
+-
+-                KDBUS_FOREACH(name, name_list, cmd.list_size) {
+-                        const char *entry_name = NULL;
+-                        struct kdbus_item *item;
+-                        char *n;
+-
+-                        KDBUS_ITEM_FOREACH(item, name, items)
+-                                if (item->type == KDBUS_ITEM_OWNED_NAME)
+-                                        entry_name = item->name.name;
+-
+-                        if (!streq_ptr(entry_name, arg0))
+-                                continue;
+-
+-                        if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0) {
+-                                err  = -ENOMEM;
+-                                break;
+-                        }
+-
+-                        r = strv_consume(&owners, n);
+-                        if (r < 0) {
+-                                err = r;
+-                                break;
+-                        }
+-                }
+-
+-                r = bus_kernel_cmd_free(a, cmd.offset);
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                if (err < 0)
+-                        return synthetic_reply_method_errno(m, err, NULL);
+-
+-                return synthetic_reply_method_return_strv(m, owners);
+-
+-        } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) {
+-                const char *name;
+-
+-                if (!sd_bus_message_has_signature(m, "s"))
+-                        return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+-
+-                r = sd_bus_message_read(m, "s", &name);
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                if (streq(name, "org.freedesktop.DBus"))
+-                        return synthetic_reply_method_return(m, "b", true);
+-
+-                r = sd_bus_get_name_creds(a, name, 0, NULL);
+-                if (r < 0 && r != -ESRCH && r != -ENXIO)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                return synthetic_reply_method_return(m, "b", r >= 0);
+-
+-        } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) {
+-                const char *name;
+-
+-                if (!sd_bus_message_has_signature(m, "s"))
+-                        return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+-
+-                r = sd_bus_message_read(m, "s", &name);
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                r = sd_bus_release_name(a, name);
+-                if (r < 0) {
+-                        if (r == -ESRCH)
+-                                return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
+-                        if (r == -EADDRINUSE)
+-                                return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
+-
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-                }
+-
+-                set_remove(owned_names, (char*) name);
+-
+-                return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED);
+-
+-        } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) {
+-                if (!sd_bus_message_has_signature(m, ""))
+-                        return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+-
+-                r = shared_policy_reload(sp);
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                return synthetic_reply_method_return(m, NULL);
+-
+-        } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
+-                const char *name;
+-                uint32_t flags, param;
+-                bool in_queue;
+-
+-                if (!sd_bus_message_has_signature(m, "su"))
+-                        return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+-
+-                r = sd_bus_message_read(m, "su", &name, &flags);
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                if (sp) {
+-                        Policy *policy;
+-                        bool denied;
+-
+-                        policy = shared_policy_acquire(sp);
+-                        denied = !policy_check_own(policy, ucred->uid, ucred->gid, name);
+-                        shared_policy_release(sp, policy);
+-                        if (denied)
+-                                return synthetic_reply_method_errno(m, -EPERM, NULL);
+-                }
+-
+-                if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0)
+-                        return synthetic_reply_method_errno(m, -EINVAL, NULL);
+-
+-                param = 0;
+-                if (flags & BUS_NAME_ALLOW_REPLACEMENT)
+-                        param |= SD_BUS_NAME_ALLOW_REPLACEMENT;
+-                if (flags & BUS_NAME_REPLACE_EXISTING)
+-                        param |= SD_BUS_NAME_REPLACE_EXISTING;
+-                if (!(flags & BUS_NAME_DO_NOT_QUEUE))
+-                        param |= SD_BUS_NAME_QUEUE;
+-
+-                r = set_put_strdup(owned_names, name);
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                r = sd_bus_request_name(a, name, param);
+-                if (r < 0) {
+-                        if (r == -EALREADY)
+-                                return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
+-
+-                        set_remove(owned_names, (char*) name);
+-
+-                        if (r == -EEXIST)
+-                                return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-                }
+-
+-                in_queue = (r == 0);
+-
+-                if (in_queue)
+-                        return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
+-
+-                return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
+-
+-        } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) {
+-                _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
+-                const char *name;
+-                uint32_t flags;
+-
+-                if (!sd_bus_message_has_signature(m, "su"))
+-                        return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+-
+-                r = sd_bus_message_read(m, "su", &name, &flags);
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                if (flags != 0)
+-                        return synthetic_reply_method_errno(m, -EINVAL, NULL);
+-
+-                r = sd_bus_get_name_creds(a, name, 0, NULL);
+-                if (r >= 0 || streq(name, "org.freedesktop.DBus"))
+-                        return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
+-                if (r != -ESRCH)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                r = sd_bus_message_new_method_call(
+-                                a,
+-                                &msg,
+-                                name,
+-                                "/",
+-                                "org.freedesktop.DBus.Peer",
+-                                "Ping");
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                r = sd_bus_send(a, msg, NULL);
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
+-
+-        } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) {
+-                _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
+-                _cleanup_strv_free_ char **args = NULL;
+-
+-                if (!sd_bus_message_has_signature(m, "a{ss}"))
+-                        return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+-
+-                r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) {
+-                        _cleanup_free_ char *s = NULL;
+-                        const char *key;
+-                        const char *value;
+-
+-                        r = sd_bus_message_read(m, "ss", &key, &value);
+-                        if (r < 0)
+-                                return synthetic_reply_method_errno(m, r, NULL);
+-
+-                        s = strjoin(key, "=", value, NULL);
+-                        if (!s)
+-                                return synthetic_reply_method_errno(m, -ENOMEM, NULL);
+-
+-                        r  = strv_extend(&args, s);
+-                        if (r < 0)
+-                                return synthetic_reply_method_errno(m, r, NULL);
+-
+-                        r = sd_bus_message_exit_container(m);
+-                        if (r < 0)
+-                                return synthetic_reply_method_errno(m, r, NULL);
+-                }
+-
+-                r = sd_bus_message_exit_container(m);
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                if (!args)
+-                        return synthetic_reply_method_errno(m, -EINVAL, NULL);
+-
+-                r = sd_bus_message_new_method_call(
+-                                a,
+-                                &msg,
+-                                "org.freedesktop.systemd1",
+-                                "/org/freedesktop/systemd1",
+-                                "org.freedesktop.systemd1.Manager",
+-                                "SetEnvironment");
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                r = sd_bus_message_append_strv(msg, args);
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                r = sd_bus_call(a, msg, 0, NULL, NULL);
+-                if (r < 0)
+-                        return synthetic_reply_method_errno(m, r, NULL);
+-
+-                return synthetic_reply_method_return(m, NULL);
+-
+-        } else {
+-                _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+-
+-                r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member);
+-
+-                return synthetic_reply_method_errno(m, r, &error);
+-        }
+-}
+diff --git a/src/bus-proxyd/driver.h b/src/bus-proxyd/driver.h
+deleted file mode 100644
+index b8cedf5..0000000
+--- a/src/bus-proxyd/driver.h
++++ /dev/null
+@@ -1,27 +0,0 @@
+-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+-
+-#pragma once
+-
+-/***
+-  This file is part of systemd.
+-
+-  Copyright 2014 Lennart Poettering
+-
+-  systemd is free software; you can redistribute it and/or modify it
+-  under the terms of the GNU Lesser General Public License as published by
+-  the Free Software Foundation; either version 2.1 of the License, or
+-  (at your option) any later version.
+-
+-  systemd is distributed in the hope that it will be useful, but
+-  WITHOUT ANY WARRANTY; without even the implied warranty of
+-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-  Lesser General Public License for more details.
+-
+-  You should have received a copy of the GNU Lesser General Public License
+-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+-***/
+-
+-#include "sd-bus.h"
+-#include "bus-xml-policy.h"
+-
+-int bus_proxy_process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPolicy *sp, const struct ucred *ucred, Set *owned_names);
+diff --git a/src/bus-proxyd/proxy.c b/src/bus-proxyd/proxy.c
+deleted file mode 100644
+index e13cf5e..0000000
+--- a/src/bus-proxyd/proxy.c
++++ /dev/null
+@@ -1,864 +0,0 @@
+-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+-
+-/***
+-  This file is part of systemd.
+-
+-  Copyright 2010 Lennart Poettering
+-  Copyright 2013 Daniel Mack
+-  Copyright 2014 Kay Sievers
+-  Copyright 2014 David Herrmann
+-
+-  systemd is free software; you can redistribute it and/or modify it
+-  under the terms of the GNU Lesser General Public License as published by
+-  the Free Software Foundation; either version 2.1 of the License, or
+-  (at your option) any later version.
+-
+-  systemd is distributed in the hope that it will be useful, but
+-  WITHOUT ANY WARRANTY; without even the implied warranty of
+-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-  Lesser General Public License for more details.
+-
+-  You should have received a copy of the GNU Lesser General Public License
+-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+-***/
+-
+-#include <sys/socket.h>
+-#include <sys/un.h>
+-#include <sys/types.h>
+-#include <fcntl.h>
+-#include <unistd.h>
+-#include <string.h>
+-#include <errno.h>
+-#include <poll.h>
+-#include <stddef.h>
+-#include <getopt.h>
+-
+-#include "log.h"
+-#include "util.h"
+-#include "socket-util.h"
+-#include "sd-daemon.h"
+-#include "sd-bus.h"
+-#include "bus-internal.h"
+-#include "bus-message.h"
+-#include "bus-util.h"
+-#include "build.h"
+-#include "strv.h"
+-#include "def.h"
+-#include "capability.h"
+-#include "bus-control.h"
+-#include "smack-util.h"
+-#include "set.h"
+-#include "bus-xml-policy.h"
+-#include "driver.h"
+-#include "proxy.h"
+-#include "synthesize.h"
+-
+-static int proxy_create_destination(Proxy *p, const char *destination, const char *local_sec, bool negotiate_fds) {
+-        _cleanup_bus_close_unref_ sd_bus *b = NULL;
+-        int r;
+-
+-        r = sd_bus_new(&b);
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to allocate bus: %m");
+-
+-        r = sd_bus_set_description(b, "sd-proxy");
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to set bus name: %m");
+-
+-        r = sd_bus_set_address(b, destination);
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to set address to connect to: %m");
+-
+-        r = sd_bus_negotiate_fds(b, negotiate_fds);
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to set FD negotiation: %m");
+-
+-        r = sd_bus_negotiate_creds(b, true, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SELINUX_CONTEXT);
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to set credential negotiation: %m");
+-
+-        if (p->local_creds.pid > 0) {
+-                b->fake_pids.pid = p->local_creds.pid;
+-                b->fake_pids_valid = true;
+-
+-                b->fake_creds.uid = UID_INVALID;
+-                b->fake_creds.euid = p->local_creds.uid;
+-                b->fake_creds.suid = UID_INVALID;
+-                b->fake_creds.fsuid = UID_INVALID;
+-                b->fake_creds.gid = GID_INVALID;
+-                b->fake_creds.egid = p->local_creds.gid;
+-                b->fake_creds.sgid = GID_INVALID;
+-                b->fake_creds.fsgid = GID_INVALID;
+-                b->fake_creds_valid = true;
+-        }
+-
+-        if (local_sec) {
+-                b->fake_label = strdup(local_sec);
+-                if (!b->fake_label)
+-                        return log_oom();
+-        }
+-
+-        b->manual_peer_interface = true;
+-
+-        r = sd_bus_start(b);
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to start bus client: %m");
+-
+-        p->destination_bus = b;
+-        b = NULL;
+-        return 0;
+-}
+-
+-static int proxy_create_local(Proxy *p, int in_fd, int out_fd, bool negotiate_fds) {
+-        _cleanup_bus_close_unref_ sd_bus *b = NULL;
+-        sd_id128_t server_id;
+-        int r;
+-
+-        r = sd_bus_new(&b);
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to allocate bus: %m");
+-
+-        r = sd_bus_set_fd(b, in_fd, out_fd);
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to set fds: %m");
+-
+-        r = sd_bus_get_bus_id(p->destination_bus, &server_id);
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to get server ID: %m");
+-
+-        r = sd_bus_set_server(b, 1, server_id);
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to set server mode: %m");
+-
+-        r = sd_bus_negotiate_fds(b, negotiate_fds);
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to set FD negotiation: %m");
+-
+-        r = sd_bus_negotiate_creds(b, true, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SELINUX_CONTEXT);
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to set credential negotiation: %m");
+-
+-        r = sd_bus_set_anonymous(b, true);
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to set anonymous authentication: %m");
+-
+-        b->manual_peer_interface = true;
+-
+-        r = sd_bus_start(b);
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to start bus client: %m");
+-
+-        p->local_bus = b;
+-        b = NULL;
+-        return 0;
+-}
+-
+-static int proxy_prepare_matches(Proxy *p) {
+-        _cleanup_free_ char *match = NULL;
+-        const char *unique;
+-        int r;
+-
+-        if (!p->destination_bus->is_kernel)
+-                return 0;
+-
+-        r = sd_bus_get_unique_name(p->destination_bus, &unique);
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to get unique name: %m");
+-
+-        match = strjoin("type='signal',"
+-                        "sender='org.freedesktop.DBus',"
+-                        "path='/org/freedesktop/DBus',"
+-                        "interface='org.freedesktop.DBus',"
+-                        "member='NameOwnerChanged',"
+-                        "arg1='",
+-                        unique,
+-                        "'",
+-                        NULL);
+-        if (!match)
+-                return log_oom();
+-
+-        r = sd_bus_add_match(p->destination_bus, NULL, match, NULL, NULL);
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to add match for NameLost: %m");
+-
+-        free(match);
+-        match = strjoin("type='signal',"
+-                        "sender='org.freedesktop.DBus',"
+-                        "path='/org/freedesktop/DBus',"
+-                        "interface='org.freedesktop.DBus',"
+-                        "member='NameOwnerChanged',"
+-                        "arg2='",
+-                        unique,
+-                        "'",
+-                        NULL);
+-        if (!match)
+-                return log_oom();
+-
+-        r = sd_bus_add_match(p->destination_bus, NULL, match, NULL, NULL);
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to add match for NameAcquired: %m");
+-
+-        return 0;
+-}
+-
+-int proxy_new(Proxy **out, int in_fd, int out_fd, const char *destination) {
+-        _cleanup_(proxy_freep) Proxy *p = NULL;
+-        _cleanup_free_ char *local_sec = NULL;
+-        bool is_unix;
+-        int r;
+-
+-        p = new0(Proxy, 1);
+-        if (!p)
+-                return log_oom();
+-
+-        p->local_in = in_fd;
+-        p->local_out = out_fd;
+-
+-        p->owned_names = set_new(&string_hash_ops);
+-        if (!p->owned_names)
+-                return log_oom();
+-
+-        is_unix = sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
+-                  sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
+-
+-        if (is_unix) {
+-                (void) getpeercred(in_fd, &p->local_creds);
+-                (void) getpeersec(in_fd, &local_sec);
+-        }
+-
+-        r = proxy_create_destination(p, destination, local_sec, is_unix);
+-        if (r < 0)
+-                return r;
+-
+-        r = proxy_create_local(p, in_fd, out_fd, is_unix);
+-        if (r < 0)
+-                return r;
+-
+-        r = proxy_prepare_matches(p);
+-        if (r < 0)
+-                return r;
+-
+-        *out = p;
+-        p = NULL;
+-        return 0;
+-}
+-
+-Proxy *proxy_free(Proxy *p) {
+-        if (!p)
+-                return NULL;
+-
+-        sd_bus_close_unrefp(&p->local_bus);
+-        sd_bus_close_unrefp(&p->destination_bus);
+-        set_free_free(p->owned_names);
+-        free(p);
+-
+-        return NULL;
+-}
+-
+-int proxy_set_policy(Proxy *p, SharedPolicy *sp, char **configuration) {
+-        _cleanup_strv_free_ char **strv = NULL;
+-        Policy *policy;
+-        int r;
+-
+-        assert(p);
+-        assert(sp);
+-
+-        /* no need to load legacy policy if destination is not kdbus */
+-        if (!p->destination_bus->is_kernel)
+-                return 0;
+-
+-        p->policy = sp;
+-
+-        policy = shared_policy_acquire(sp);
+-        if (policy) {
+-                /* policy already pre-loaded */
+-                shared_policy_release(sp, policy);
+-                return 0;
+-        }
+-
+-        if (!configuration) {
+-                const char *scope;
+-
+-                r = sd_bus_get_scope(p->destination_bus, &scope);
+-                if (r < 0)
+-                        return log_error_errno(r, "Couldn't determine bus scope: %m");
+-
+-                if (streq(scope, "system"))
+-                        strv = strv_new("/etc/dbus-1/system.conf",
+-                                        "/etc/dbus-1/system.d/",
+-                                        "/etc/dbus-1/system-local.conf",
+-                                        NULL);
+-                else if (streq(scope, "user"))
+-                        strv = strv_new("/etc/dbus-1/session.conf",
+-                                        "/etc/dbus-1/session.d/",
+-                                        "/etc/dbus-1/session-local.conf",
+-                                        NULL);
+-                else
+-                        return log_error("Unknown scope %s, don't know which policy to load. Refusing.", scope);
+-
+-                if (!strv)
+-                        return log_oom();
+-
+-                configuration = strv;
+-        }
+-
+-        return shared_policy_preload(sp, configuration);
+-}
+-
+-int proxy_hello_policy(Proxy *p, uid_t original_uid) {
+-        Policy *policy;
+-        int r = 0;
+-
+-        assert(p);
+-
+-        if (!p->policy)
+-                return 0;
+-
+-        policy = shared_policy_acquire(p->policy);
+-
+-        if (p->local_creds.uid == original_uid)
+-                log_debug("Permitting access, since bus owner matches bus client.");
+-        else if (policy_check_hello(policy, p->local_creds.uid, p->local_creds.gid))
+-                log_debug("Permitting access due to XML policy.");
+-        else
+-                r = log_error_errno(EPERM, "Policy denied connection.");
+-
+-        shared_policy_release(p->policy, policy);
+-
+-        return r;
+-}
+-
+-static int proxy_wait(Proxy *p) {
+-        uint64_t timeout_destination, timeout_local, t;
+-        int events_destination, events_local, fd;
+-        struct timespec _ts, *ts;
+-        struct pollfd *pollfd;
+-        int r;
+-
+-        assert(p);
+-
+-        fd = sd_bus_get_fd(p->destination_bus);
+-        if (fd < 0)
+-                return log_error_errno(fd, "Failed to get fd: %m");
+-
+-        events_destination = sd_bus_get_events(p->destination_bus);
+-        if (events_destination < 0)
+-                return log_error_errno(events_destination, "Failed to get events mask: %m");
+-
+-        r = sd_bus_get_timeout(p->destination_bus, &timeout_destination);
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to get timeout: %m");
+-
+-        events_local = sd_bus_get_events(p->local_bus);
+-        if (events_local < 0)
+-                return log_error_errno(events_local, "Failed to get events mask: %m");
+-
+-        r = sd_bus_get_timeout(p->local_bus, &timeout_local);
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to get timeout: %m");
+-
+-        t = timeout_destination;
+-        if (t == (uint64_t) -1 || (timeout_local != (uint64_t) -1 && timeout_local < timeout_destination))
+-                t = timeout_local;
+-
+-        if (t == (uint64_t) -1)
+-                ts = NULL;
+-        else {
+-                usec_t nw;
+-
+-                nw = now(CLOCK_MONOTONIC);
+-                if (t > nw)
+-                        t -= nw;
+-                else
+-                        t = 0;
+-
+-                ts = timespec_store(&_ts, t);
+-        }
+-
+-        pollfd = (struct pollfd[3]) {
+-                { .fd = fd,           .events = events_destination,     },
+-                { .fd = p->local_in,  .events = events_local & POLLIN,  },
+-                { .fd = p->local_out, .events = events_local & POLLOUT, },
+-        };
+-
+-        r = ppoll(pollfd, 3, ts, NULL);
+-        if (r < 0)
+-                return log_error_errno(errno, "ppoll() failed: %m");
+-
+-        return 0;
+-}
+-
+-static int handle_policy_error(sd_bus_message *m, int r) {
+-        if (r == -ESRCH || r == -ENXIO)
+-                return synthetic_reply_method_errorf(m, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", m->destination);
+-
+-        return r;
+-}
+-
+-static int process_policy_unlocked(sd_bus *from, sd_bus *to, sd_bus_message *m, Policy *policy, const struct ucred *our_ucred, Set *owned_names) {
+-        int r;
+-
+-        assert(from);
+-        assert(to);
+-        assert(m);
+-
+-        if (!policy)
+-                return 0;
+-
+-        /*
+-         * dbus-1 distinguishes expected and non-expected replies by tracking
+-         * method-calls and timeouts. By default, DENY rules are *NEVER* applied
+-         * on expected replies, unless explicitly specified. But we dont track
+-         * method-calls, thus, we cannot know whether a reply is expected.
+-         * Fortunately, the kdbus forbids non-expected replies, so we can safely
+-         * ignore any policy on those and let the kernel deal with it.
+-         *
+-         * TODO: To be correct, we should only ignore policy-tags that are
+-         * applied on non-expected replies. However, so far we don't parse those
+-         * tags so we let everything pass. I haven't seen a DENY policy tag on
+-         * expected-replies, ever, so don't bother..
+-         */
+-        if (m->reply_cookie > 0)
+-                return 0;
+-
+-        if (from->is_kernel) {
+-                uid_t sender_uid = UID_INVALID;
+-                gid_t sender_gid = GID_INVALID;
+-                char **sender_names = NULL;
+-
+-                /* Driver messages are always OK */
+-                if (streq_ptr(m->sender, "org.freedesktop.DBus"))
+-                        return 0;
+-
+-                /* The message came from the kernel, and is sent to our legacy client. */
+-                (void) sd_bus_creds_get_well_known_names(&m->creds, &sender_names);
+-
+-                (void) sd_bus_creds_get_euid(&m->creds, &sender_uid);
+-                (void) sd_bus_creds_get_egid(&m->creds, &sender_gid);
+-
+-                if (sender_uid == UID_INVALID || sender_gid == GID_INVALID) {
+-                        _cleanup_bus_creds_unref_ sd_bus_creds *sender_creds = NULL;
+-
+-                        /* If the message came from another legacy
+-                         * client, then the message creds will be
+-                         * missing, simply because on legacy clients
+-                         * per-message creds were unknown. In this
+-                         * case, query the creds of the peer
+-                         * instead. */
+-
+-                        r = bus_get_name_creds_kdbus(from, m->sender, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID, true, &sender_creds);
+-                        if (r < 0)
+-                                return handle_policy_error(m, r);
+-
+-                        (void) sd_bus_creds_get_euid(sender_creds, &sender_uid);
+-                        (void) sd_bus_creds_get_egid(sender_creds, &sender_gid);
+-                }
+-
+-                /* First check whether the sender can send the message to our name */
+-                if (policy_check_send(policy, sender_uid, sender_gid, m->header->type, owned_names, NULL, m->path, m->interface, m->member, false, NULL) &&
+-                    policy_check_recv(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, sender_names, m->path, m->interface, m->member, false))
+-                        return 0;
+-
+-                /* Return an error back to the caller */
+-                if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
+-                        return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML receiver policy.");
+-
+-                /* Return 1, indicating that the message shall not be processed any further */
+-                return 1;
+-        }
+-
+-        if (to->is_kernel) {
+-                _cleanup_bus_creds_unref_ sd_bus_creds *destination_creds = NULL;
+-                uid_t destination_uid = UID_INVALID;
+-                gid_t destination_gid = GID_INVALID;
+-                const char *destination_unique = NULL;
+-                char **destination_names = NULL;
+-                char *n;
+-
+-                /* Driver messages are always OK */
+-                if (streq_ptr(m->destination, "org.freedesktop.DBus"))
+-                        return 0;
+-
+-                /* The message came from the legacy client, and is sent to kdbus. */
+-                if (m->destination) {
+-                        r = bus_get_name_creds_kdbus(to, m->destination,
+-                                                     SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME|
+-                                                     SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID,
+-                                                     true, &destination_creds);
+-                        if (r < 0)
+-                                return handle_policy_error(m, r);
+-
+-                        r = sd_bus_creds_get_unique_name(destination_creds, &destination_unique);
+-                        if (r < 0)
+-                                return handle_policy_error(m, r);
+-
+-                        (void) sd_bus_creds_get_well_known_names(destination_creds, &destination_names);
+-
+-                        (void) sd_bus_creds_get_euid(destination_creds, &destination_uid);
+-                        (void) sd_bus_creds_get_egid(destination_creds, &destination_gid);
+-                }
+-
+-                /* First check if we (the sender) can send to this name */
+-                if (policy_check_send(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, destination_names, m->path, m->interface, m->member, true, &n)) {
+-                        if (n) {
+-                                /* If we made a receiver decision, then remember which
+-                                 * name's policy we used, and to which unique ID it
+-                                 * mapped when we made the decision. Then, let's pass
+-                                 * this to the kernel when sending the message, so that
+-                                 * it refuses the operation should the name and unique
+-                                 * ID not map to each other anymore. */
+-
+-                                r = free_and_strdup(&m->destination_ptr, n);
+-                                if (r < 0)
+-                                        return r;
+-
+-                                r = bus_kernel_parse_unique_name(destination_unique, &m->verify_destination_id);
+-                                if (r < 0)
+-                                        return r;
+-                        }
+-
+-                        if (sd_bus_message_is_signal(m, NULL, NULL)) {
+-                                /* If we forward a signal from dbus-1 to kdbus,
+-                                 * we have no idea who the recipient is.
+-                                 * Therefore, we cannot apply any dbus-1
+-                                 * receiver policies that match on receiver
+-                                 * credentials. We know sd-bus always sets
+-                                 * KDBUS_MSG_SIGNAL, so the kernel applies
+-                                 * receiver policies to the message. Therefore,
+-                                 * skip policy checks in this case. */
+-                                return 0;
+-                        } else if (policy_check_recv(policy, destination_uid, destination_gid, m->header->type, owned_names, NULL, m->path, m->interface, m->member, true)) {
+-                                return 0;
+-                        }
+-                }
+-
+-                /* Return an error back to the caller */
+-                if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
+-                        return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML sender policy.");
+-
+-                /* Return 1, indicating that the message shall not be processed any further */
+-                return 1;
+-        }
+-
+-        return 0;
+-}
+-
+-static int process_policy(sd_bus *from, sd_bus *to, sd_bus_message *m, SharedPolicy *sp, const struct ucred *our_ucred, Set *owned_names) {
+-        Policy *policy;
+-        int r;
+-
+-        assert(sp);
+-
+-        policy = shared_policy_acquire(sp);
+-        r = process_policy_unlocked(from, to, m, policy, our_ucred, owned_names);
+-        shared_policy_release(sp, policy);
+-
+-        return r;
+-}
+-
+-static int process_hello(Proxy *p, sd_bus_message *m) {
+-        _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
+-        bool is_hello;
+-        int r;
+-
+-        assert(p);
+-        assert(m);
+-
+-        /* As reaction to hello we need to respond with two messages:
+-         * the callback reply and the NameAcquired for the unique
+-         * name, since hello is otherwise obsolete on kdbus. */
+-
+-        is_hello =
+-                sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
+-                streq_ptr(m->destination, "org.freedesktop.DBus");
+-
+-        if (!is_hello) {
+-                if (p->got_hello)
+-                        return 0;
+-
+-                return log_error_errno(EIO, "First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
+-        }
+-
+-        if (p->got_hello)
+-                return log_error_errno(EIO, "Got duplicate hello, aborting.");
+-
+-        p->got_hello = true;
+-
+-        if (!p->destination_bus->is_kernel)
+-                return 0;
+-
+-        r = sd_bus_message_new_method_return(m, &n);
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to generate HELLO reply: %m");
+-
+-        r = sd_bus_message_append(n, "s", p->destination_bus->unique_name);
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to append unique name to HELLO reply: %m");
+-
+-        r = bus_message_append_sender(n, "org.freedesktop.DBus");
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to append sender to HELLO reply: %m");
+-
+-        r = bus_seal_synthetic_message(p->local_bus, n);
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to seal HELLO reply: %m");
+-
+-        r = sd_bus_send(p->local_bus, n, NULL);
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to send HELLO reply: %m");
+-
+-        n = sd_bus_message_unref(n);
+-        r = sd_bus_message_new_signal(
+-                        p->local_bus,
+-                        &n,
+-                        "/org/freedesktop/DBus",
+-                        "org.freedesktop.DBus",
+-                        "NameAcquired");
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to allocate initial NameAcquired message: %m");
+-
+-        r = sd_bus_message_append(n, "s", p->destination_bus->unique_name);
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to append unique name to NameAcquired message: %m");
+-
+-        r = bus_message_append_sender(n, "org.freedesktop.DBus");
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to append sender to NameAcquired message: %m");
+-
+-        r = bus_seal_synthetic_message(p->local_bus, n);
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to seal NameAcquired message: %m");
+-
+-        r = sd_bus_send(p->local_bus, n, NULL);
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to send NameAcquired message: %m");
+-
+-        return 1;
+-}
+-
+-static int patch_sender(sd_bus *a, sd_bus_message *m) {
+-        char **well_known = NULL;
+-        sd_bus_creds *c;
+-        int r;
+-
+-        assert(a);
+-        assert(m);
+-
+-        if (!a->is_kernel)
+-                return 0;
+-
+-        /* We will change the sender of messages from the bus driver
+-         * so that they originate from the bus driver. This is a
+-         * speciality originating from dbus1, where the bus driver did
+-         * not have a unique id, but only the well-known name. */
+-
+-        c = sd_bus_message_get_creds(m);
+-        if (!c)
+-                return 0;
+-
+-        r = sd_bus_creds_get_well_known_names(c, &well_known);
+-        if (r < 0)
+-                return r;
+-
+-        if (strv_contains(well_known, "org.freedesktop.DBus"))
+-                m->sender = "org.freedesktop.DBus";
+-
+-        return 0;
+-}
+-
+-static int proxy_process_destination_to_local(Proxy *p) {
+-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+-        int r;
+-
+-        assert(p);
+-
+-        r = sd_bus_process(p->destination_bus, &m);
+-        if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */
+-                return r;
+-        if (r < 0) {
+-                log_error_errno(r, "Failed to process destination bus: %m");
+-                return r;
+-        }
+-        if (r == 0)
+-                return 0;
+-        if (!m)
+-                return 1;
+-
+-        /* We officially got EOF, let's quit */
+-        if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected"))
+-                return -ECONNRESET;
+-
+-        r = synthesize_name_acquired(p->destination_bus, p->local_bus, m);
+-        if (r == -ECONNRESET || r == -ENOTCONN)
+-                return r;
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to synthesize message: %m");
+-
+-        patch_sender(p->destination_bus, m);
+-
+-        if (p->policy) {
+-                r = process_policy(p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names);
+-                if (r == -ECONNRESET || r == -ENOTCONN)
+-                        return r;
+-                if (r < 0)
+-                        return log_error_errno(r, "Failed to process policy: %m");
+-                if (r > 0)
+-                        return 1;
+-        }
+-
+-        r = sd_bus_send(p->local_bus, m, NULL);
+-        if (r < 0) {
+-                if (r == -ECONNRESET || r == -ENOTCONN)
+-                        return r;
+-
+-                /* If the peer tries to send a reply and it is
+-                 * rejected with EPERM by the kernel, we ignore the
+-                 * error. This catches cases where the original
+-                 * method-call didn't had EXPECT_REPLY set, but the
+-                 * proxy-peer still sends a reply. This is allowed in
+-                 * dbus1, but not in kdbus. We don't want to track
+-                 * reply-windows in the proxy, so we simply ignore
+-                 * EPERM for all replies. The only downside is, that
+-                 * callers are no longer notified if their replies are
+-                 * dropped. However, this is equivalent to the
+-                 * caller's timeout to expire, so this should be
+-                 * acceptable. Nobody sane sends replies without a
+-                 * matching method-call, so nobody should care. */
+-                if (r == -EPERM && m->reply_cookie > 0)
+-                        return 1;
+-
+-                /* Return the error to the client, if we can */
+-                synthetic_reply_method_errnof(m, r, "Failed to forward message we got from destination: %m");
+-                if (r == -ENOBUFS) {
+-                        /* if local dbus1 peer does not dispatch its queue, warn only once */
+-                        if (!p->queue_overflow)
+-                                log_error("Dropped messages due to queue overflow of local peer (pid: "PID_FMT" uid: "UID_FMT")", p->local_creds.pid, p->local_creds.uid);
+-                        p->queue_overflow = true;
+-                } else
+-                        log_error_errno(r,
+-                                 "Failed to forward message we got from destination: uid=" UID_FMT " gid=" GID_FMT" message=%s destination=%s path=%s interface=%s member=%s: %m",
+-                                 p->local_creds.uid, p->local_creds.gid, bus_message_type_to_string(m->header->type),
+-                                 strna(m->destination), strna(m->path), strna(m->interface), strna(m->member));
+-
+-                return 1;
+-        }
+-
+-        p->queue_overflow = false;
+-        return 1;
+-}
+-
+-static int proxy_process_local_to_destination(Proxy *p) {
+-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+-        int r;
+-
+-        assert(p);
+-
+-        r = sd_bus_process(p->local_bus, &m);
+-        if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */
+-                return r;
+-        if (r < 0) {
+-                log_error_errno(r, "Failed to process local bus: %m");
+-                return r;
+-        }
+-        if (r == 0)
+-                return 0;
+-        if (!m)
+-                return 1;
+-
+-        /* We officially got EOF, let's quit */
+-        if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected"))
+-                return -ECONNRESET;
+-
+-        r = process_hello(p, m);
+-        if (r == -ECONNRESET || r == -ENOTCONN)
+-                return r;
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to process HELLO: %m");
+-        if (r > 0)
+-                return 1;
+-
+-        r = bus_proxy_process_driver(p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names);
+-        if (r == -ECONNRESET || r == -ENOTCONN)
+-                return r;
+-        if (r < 0)
+-                return log_error_errno(r, "Failed to process driver calls: %m");
+-        if (r > 0)
+-                return 1;
+-
+-        for (;;) {
+-                if (p->policy) {
+-                        r = process_policy(p->local_bus, p->destination_bus, m, p->policy, &p->local_creds, p->owned_names);
+-                        if (r == -ECONNRESET || r == -ENOTCONN)
+-                                return r;
+-                        if (r < 0)
+-                                return log_error_errno(r, "Failed to process policy: %m");
+-                        if (r > 0)
+-                                return 1;
+-                }
+-
+-                r = sd_bus_send(p->destination_bus, m, NULL);
+-                if (r < 0) {
+-                        if (r == -ECONNRESET || r == -ENOTCONN)
+-                                return r;
+-
+-                        /* The name database changed since the policy check, hence let's check again */
+-                        if (r == -EREMCHG)
+-                                continue;
+-
+-                        /* see above why EPERM is ignored for replies */
+-                        if (r == -EPERM && m->reply_cookie > 0)
+-                                return 1;
+-
+-                        synthetic_reply_method_errnof(m, r, "Failed to forward message we got from local: %m");
+-                        log_error_errno(r,
+-                                 "Failed to forward message we got from local: uid=" UID_FMT " gid=" GID_FMT" message=%s destination=%s path=%s interface=%s member=%s: %m",
+-                                 p->local_creds.uid, p->local_creds.gid, bus_message_type_to_string(m->header->type),
+-                                 strna(m->destination), strna(m->path), strna(m->interface), strna(m->member));
+-                        return 1;
+-                }
+-
+-                break;
+-        }
+-
+-        return 1;
+-}
+-
+-int proxy_run(Proxy *p) {
+-        int r;
+-
+-        assert(p);
+-
+-        for (;;) {
+-                bool busy = false;
+-
+-                if (p->got_hello) {
+-                        /* Read messages from bus, to pass them on to our client */
+-                        r = proxy_process_destination_to_local(p);
+-                        if (r == -ECONNRESET || r == -ENOTCONN)
+-                                return 0;
+-                        if (r < 0)
+-                                return r;
+-                        if (r > 0)
+-                                busy = true;
+-                }
+-
+-                /* Read messages from our client, to pass them on to the bus */
+-                r = proxy_process_local_to_destination(p);
+-                if (r == -ECONNRESET || r == -ENOTCONN)
+-                        return 0;
+-                if (r < 0)
+-                        return r;
+-                if (r > 0)
+-                        busy = true;
+-
+-                if (!busy) {
+-                        r = proxy_wait(p);
+-                        if (r == -ECONNRESET || r == -ENOTCONN)
+-                                return 0;
+-                        if (r < 0)
+-                                return r;
+-                }
+-        }
+-
+-        return 0;
+-}
+diff --git a/src/bus-proxyd/proxy.h b/src/bus-proxyd/proxy.h
+deleted file mode 100644
+index 782c4e6..0000000
+--- a/src/bus-proxyd/proxy.h
++++ /dev/null
+@@ -1,53 +0,0 @@
+-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+-
+-#pragma once
+-
+-/***
+-  This file is part of systemd.
+-
+-  Copyright 2014 David Herrmann
+-
+-  systemd is free software; you can redistribute it and/or modify it
+-  under the terms of the GNU Lesser General Public License as published by
+-  the Free Software Foundation; either version 2.1 of the License, or
+-  (at your option) any later version.
+-
+-  systemd is distributed in the hope that it will be useful, but
+-  WITHOUT ANY WARRANTY; without even the implied warranty of
+-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-  Lesser General Public License for more details.
+-
+-  You should have received a copy of the GNU Lesser General Public License
+-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+-***/
+-
+-#include <stdlib.h>
+-#include "sd-bus.h"
+-#include "bus-xml-policy.h"
+-#include "util.h"
+-
+-typedef struct Proxy Proxy;
+-
+-struct Proxy {
+-        sd_bus *local_bus;
+-        struct ucred local_creds;
+-        int local_in;
+-        int local_out;
+-
+-        sd_bus *destination_bus;
+-
+-        Set *owned_names;
+-        SharedPolicy *policy;
+-
+-        bool got_hello : 1;
+-        bool queue_overflow : 1;
+-};
+-
+-int proxy_new(Proxy **out, int in_fd, int out_fd, const char *dest);
+-Proxy *proxy_free(Proxy *p);
+-
+-int proxy_set_policy(Proxy *p, SharedPolicy *policy, char **configuration);
+-int proxy_hello_policy(Proxy *p, uid_t original_uid);
+-int proxy_run(Proxy *p);
+-
+-DEFINE_TRIVIAL_CLEANUP_FUNC(Proxy*, proxy_free);
+diff --git a/src/bus-proxyd/stdio-bridge.c b/src/bus-proxyd/stdio-bridge.c
+deleted file mode 100644
+index 9fb3e9f..0000000
+--- a/src/bus-proxyd/stdio-bridge.c
++++ /dev/null
+@@ -1,263 +0,0 @@
+-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+-
+-/***
+-  This file is part of systemd.
+-
+-  Copyright 2010 Lennart Poettering
+-  Copyright 2013 Daniel Mack
+-  Copyright 2014 Kay Sievers
+-
+-  systemd is free software; you can redistribute it and/or modify it
+-  under the terms of the GNU Lesser General Public License as published by
+-  the Free Software Foundation; either version 2.1 of the License, or
+-  (at your option) any later version.
+-
+-  systemd is distributed in the hope that it will be useful, but
+-  WITHOUT ANY WARRANTY; without even the implied warranty of
+-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-  Lesser General Public License for more details.
+-
+-  You should have received a copy of the GNU Lesser General Public License
+-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+-***/
+-
+-#include <sys/socket.h>
+-#include <sys/un.h>
+-#include <sys/types.h>
+-#include <fcntl.h>
+-#include <unistd.h>
+-#include <string.h>
+-#include <errno.h>
+-#include <poll.h>
+-#include <stddef.h>
+-#include <getopt.h>
+-
+-#include "log.h"
+-#include "util.h"
+-#include "socket-util.h"
+-#include "sd-daemon.h"
+-#include "sd-bus.h"
+-#include "bus-internal.h"
+-#include "bus-message.h"
+-#include "bus-util.h"
+-#include "build.h"
+-#include "strv.h"
+-#include "def.h"
+-#include "capability.h"
+-#include "bus-control.h"
+-#include "smack-util.h"
+-#include "set.h"
+-#include "bus-xml-policy.h"
+-#include "driver.h"
+-#include "proxy.h"
+-#include "synthesize.h"
+-
+-static char *arg_address = NULL;
+-static char *arg_command_line_buffer = NULL;
+-
+-static int help(void) {
+-
+-        printf("%s [OPTIONS...]\n\n"
+-               "Connect STDIO to a given bus address.\n\n"
+-               "  -h --help               Show this help\n"
+-               "     --version            Show package version\n"
+-               "     --machine=MACHINE    Connect to specified machine\n"
+-               "     --address=ADDRESS    Connect to the bus specified by ADDRESS\n"
+-               "                          (default: " DEFAULT_SYSTEM_BUS_ADDRESS ")\n",
+-               program_invocation_short_name);
+-
+-        return 0;
+-}
+-
+-static int parse_argv(int argc, char *argv[]) {
+-
+-        enum {
+-                ARG_VERSION = 0x100,
+-                ARG_ADDRESS,
+-                ARG_MACHINE,
+-        };
+-
+-        static const struct option options[] = {
+-                { "help",            no_argument,       NULL, 'h'                 },
+-                { "version",         no_argument,       NULL, ARG_VERSION         },
+-                { "address",         required_argument, NULL, ARG_ADDRESS         },
+-                { "machine",         required_argument, NULL, ARG_MACHINE         },
+-                {},
+-        };
+-
+-        int c;
+-
+-        assert(argc >= 0);
+-        assert(argv);
+-
+-        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
+-
+-                switch (c) {
+-
+-                case 'h':
+-                        help();
+-                        return 0;
+-
+-                case ARG_VERSION:
+-                        puts(PACKAGE_STRING);
+-                        puts(SYSTEMD_FEATURES);
+-                        return 0;
+-
+-                case ARG_ADDRESS: {
+-                        char *a;
+-
+-                        a = strdup(optarg);
+-                        if (!a)
+-                                return log_oom();
+-
+-                        free(arg_address);
+-                        arg_address = a;
+-                        break;
+-                }
+-
+-                case ARG_MACHINE: {
+-                        _cleanup_free_ char *e = NULL;
+-                        char *a;
+-
+-                        e = bus_address_escape(optarg);
+-                        if (!e)
+-                                return log_oom();
+-
+-#ifdef ENABLE_KDBUS
+-                        a = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e, NULL);
+-#else
+-                        a = strjoin("x-machine-unix:machine=", e, NULL);
+-#endif
+-                        if (!a)
+-                                return log_oom();
+-
+-                        free(arg_address);
+-                        arg_address = a;
+-
+-                        break;
+-                }
+-
+-                case '?':
+-                        return -EINVAL;
+-
+-                default:
+-                        assert_not_reached("Unhandled option");
+-                }
+-
+-        /* If the first command line argument is only "x" characters
+-         * we'll write who we are talking to into it, so that "ps" is
+-         * explanatory */
+-        arg_command_line_buffer = argv[optind];
+-        if (argc > optind + 1 || (arg_command_line_buffer && !in_charset(arg_command_line_buffer, "x"))) {
+-                log_error("Too many arguments");
+-                return -EINVAL;
+-        }
+-
+-        if (!arg_address) {
+-                arg_address = strdup(DEFAULT_SYSTEM_BUS_ADDRESS);
+-                if (!arg_address)
+-                        return log_oom();
+-        }
+-
+-        return 1;
+-}
+-
+-static int rename_service(sd_bus *a, sd_bus *b) {
+-        _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+-        _cleanup_free_ char *p = NULL, *name = NULL;
+-        const char *comm;
+-        char **cmdline;
+-        uid_t uid;
+-        pid_t pid;
+-        int r;
+-
+-        assert(a);
+-        assert(b);
+-
+-        r = sd_bus_get_owner_creds(b, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_AUGMENT, &creds);
+-        if (r < 0)
+-                return r;
+-
+-        r = sd_bus_creds_get_euid(creds, &uid);
+-        if (r < 0)
+-                return r;
+-
+-        r = sd_bus_creds_get_pid(creds, &pid);
+-        if (r < 0)
+-                return r;
+-
+-        r = sd_bus_creds_get_cmdline(creds, &cmdline);
+-        if (r < 0)
+-                return r;
+-
+-        r = sd_bus_creds_get_comm(creds, &comm);
+-        if (r < 0)
+-                return r;
+-
+-        name = uid_to_name(uid);
+-        if (!name)
+-                return -ENOMEM;
+-
+-        p = strv_join(cmdline, " ");
+-        if (!p)
+-                return -ENOMEM;
+-
+-        /* The status string gets the full command line ... */
+-        sd_notifyf(false,
+-                   "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)",
+-                   pid, p,
+-                   uid, name);
+-
+-        /* ... and the argv line only the short comm */
+-        if (arg_command_line_buffer) {
+-                size_t m, w;
+-
+-                m = strlen(arg_command_line_buffer);
+-                w = snprintf(arg_command_line_buffer, m,
+-                             "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]",
+-                             pid, comm,
+-                             uid, name);
+-
+-                if (m > w)
+-                        memzero(arg_command_line_buffer + w, m - w);
+-        }
+-
+-        log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s",
+-                  pid, p,
+-                  uid, name,
+-                  a->unique_name);
+-
+-        return 0;
+-}
+-
+-int main(int argc, char *argv[]) {
+-        _cleanup_(proxy_freep) Proxy *p = NULL;
+-        int r;
+-
+-        log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
+-        log_parse_environment();
+-        log_open();
+-
+-        r = parse_argv(argc, argv);
+-        if (r <= 0)
+-                goto finish;
+-
+-        r = proxy_new(&p, STDIN_FILENO, STDOUT_FILENO, arg_address);
+-        if (r < 0)
+-                goto finish;
+-
+-        r = rename_service(p->destination_bus, p->local_bus);
+-        if (r < 0)
+-                log_debug_errno(r, "Failed to rename process: %m");
+-
+-        r = proxy_run(p);
+-
+-finish:
+-        sd_notify(false,
+-                  "STOPPING=1\n"
+-                  "STATUS=Shutting down.");
+-
+-        free(arg_address);
+-
+-        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+-}
+diff --git a/src/bus-proxyd/synthesize.c b/src/bus-proxyd/synthesize.c
+deleted file mode 100644
+index e1b0fd3..0000000
+--- a/src/bus-proxyd/synthesize.c
++++ /dev/null
+@@ -1,228 +0,0 @@
+-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+-
+-/***
+-  This file is part of systemd.
+-
+-  Copyright 2010 Lennart Poettering
+-  Copyright 2013 Daniel Mack
+-  Copyright 2014 Kay Sievers
+-
+-  systemd is free software; you can redistribute it and/or modify it
+-  under the terms of the GNU Lesser General Public License as published by
+-  the Free Software Foundation; either version 2.1 of the License, or
+-  (at your option) any later version.
+-
+-  systemd is distributed in the hope that it will be useful, but
+-  WITHOUT ANY WARRANTY; without even the implied warranty of
+-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-  Lesser General Public License for more details.
+-
+-  You should have received a copy of the GNU Lesser General Public License
+-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+-***/
+-
+-#include <sys/types.h>
+-#include <unistd.h>
+-#include <string.h>
+-#include <errno.h>
+-#include <stddef.h>
+-
+-#include "log.h"
+-#include "util.h"
+-#include "sd-bus.h"
+-#include "bus-internal.h"
+-#include "bus-message.h"
+-#include "bus-util.h"
+-#include "strv.h"
+-#include "def.h"
+-#include "bus-control.h"
+-#include "synthesize.h"
+-
+-static int synthetic_driver_send(sd_bus *b, sd_bus_message *m) {
+-        int r;
+-
+-        assert(b);
+-        assert(m);
+-
+-        r = bus_message_append_sender(m, "org.freedesktop.DBus");
+-        if (r < 0)
+-                return r;
+-
+-        r = bus_seal_synthetic_message(b, m);
+-        if (r < 0)
+-                return r;
+-
+-        return sd_bus_send(b, m, NULL);
+-}
+-
+-int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e) {
+-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+-        int r;
+-
+-        assert(call);
+-
+-        if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
+-                return 0;
+-
+-        r = sd_bus_message_new_method_error(call, &m, e);
+-        if (r < 0)
+-                return r;
+-
+-        return synthetic_driver_send(call->bus, m);
+-}
+-
+-int synthetic_reply_method_errorf(sd_bus_message *call, const char *name, const char *format, ...) {
+-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+-        va_list ap;
+-
+-        va_start(ap, format);
+-        bus_error_setfv(&error, name, format, ap);
+-        va_end(ap);
+-
+-        return synthetic_reply_method_error(call, &error);
+-}
+-
+-int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p) {
+-        _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
+-
+-        assert(call);
+-
+-        if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
+-                return 0;
+-
+-        if (sd_bus_error_is_set(p))
+-                return synthetic_reply_method_error(call, p);
+-
+-        sd_bus_error_set_errno(&berror, error);
+-
+-        return synthetic_reply_method_error(call, &berror);
+-}
+-
+-int synthetic_reply_method_errnof(sd_bus_message *call, int error, const char *format, ...) {
+-        _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
+-        va_list ap;
+-
+-        assert(call);
+-
+-        if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
+-                return 0;
+-
+-        va_start(ap, format);
+-        sd_bus_error_set_errnofv(&berror, error, format, ap);
+-        va_end(ap);
+-
+-        return synthetic_reply_method_error(call, &berror);
+-}
+-
+-int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...) {
+-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+-        int r;
+-
+-        assert(call);
+-
+-        if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
+-                return 0;
+-
+-        r = sd_bus_message_new_method_return(call, &m);
+-        if (r < 0)
+-                return r;
+-
+-        if (!isempty(types)) {
+-                va_list ap;
+-
+-                va_start(ap, types);
+-                r = bus_message_append_ap(m, types, ap);
+-                va_end(ap);
+-                if (r < 0)
+-                        return r;
+-        }
+-
+-        return synthetic_driver_send(call->bus, m);
+-}
+-
+-int synthetic_reply_method_return_strv(sd_bus_message *call, char **l) {
+-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+-        int r;
+-
+-        assert(call);
+-
+-        if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
+-                return 0;
+-
+-        r = sd_bus_message_new_method_return(call, &m);
+-        if (r < 0)
+-                return synthetic_reply_method_errno(call, r, NULL);
+-
+-        r = sd_bus_message_append_strv(m, l);
+-        if (r < 0)
+-                return synthetic_reply_method_errno(call, r, NULL);
+-
+-        return synthetic_driver_send(call->bus, m);
+-}
+-
+-int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m) {
+-        _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
+-        const char *name, *old_owner, *new_owner;
+-        int r;
+-
+-        assert(a);
+-        assert(b);
+-        assert(m);
+-
+-        /* If we get NameOwnerChanged for our own name, we need to
+-         * synthesize NameLost/NameAcquired, since socket clients need
+-         * that, even though it is obsoleted on kdbus */
+-
+-        if (!a->is_kernel)
+-                return 0;
+-
+-        if (!sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged") ||
+-            !streq_ptr(m->path, "/org/freedesktop/DBus") ||
+-            !streq_ptr(m->sender, "org.freedesktop.DBus"))
+-                return 0;
+-
+-        r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner);
+-        if (r < 0)
+-                return r;
+-
+-        r = sd_bus_message_rewind(m, true);
+-        if (r < 0)
+-                return r;
+-
+-        if (streq(old_owner, a->unique_name)) {
+-
+-                r = sd_bus_message_new_signal(
+-                                b,
+-                                &n,
+-                                "/org/freedesktop/DBus",
+-                                "org.freedesktop.DBus",
+-                                "NameLost");
+-
+-        } else if (streq(new_owner, a->unique_name)) {
+-
+-                r = sd_bus_message_new_signal(
+-                                b,
+-                                &n,
+-                                "/org/freedesktop/DBus",
+-                                "org.freedesktop.DBus",
+-                                "NameAcquired");
+-        } else
+-                return 0;
+-
+-        if (r < 0)
+-                return r;
+-
+-        r = sd_bus_message_append(n, "s", name);
+-        if (r < 0)
+-                return r;
+-
+-        r = bus_message_append_sender(n, "org.freedesktop.DBus");
+-        if (r < 0)
+-                return r;
+-
+-        r = bus_seal_synthetic_message(b, n);
+-        if (r < 0)
+-                return r;
+-
+-        return sd_bus_send(b, n, NULL);
+-}
+diff --git a/src/bus-proxyd/synthesize.h b/src/bus-proxyd/synthesize.h
+deleted file mode 100644
+index a55f171..0000000
+--- a/src/bus-proxyd/synthesize.h
++++ /dev/null
+@@ -1,34 +0,0 @@
+-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+-
+-#pragma once
+-
+-/***
+-  This file is part of systemd.
+-
+-  Copyright 2014 Lennart Poettering
+-
+-  systemd is free software; you can redistribute it and/or modify it
+-  under the terms of the GNU Lesser General Public License as published by
+-  the Free Software Foundation; either version 2.1 of the License, or
+-  (at your option) any later version.
+-
+-  systemd is distributed in the hope that it will be useful, but
+-  WITHOUT ANY WARRANTY; without even the implied warranty of
+-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-  Lesser General Public License for more details.
+-
+-  You should have received a copy of the GNU Lesser General Public License
+-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+-***/
+-
+-#include "sd-bus.h"
+-
+-int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...);
+-int synthetic_reply_method_return_strv(sd_bus_message *call, char **l);
+-
+-int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e);
+-int synthetic_reply_method_errorf(sd_bus_message *call, const char *name, const char *format, ...) _sd_printf_(3, 4);
+-int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p);
+-int synthetic_reply_method_errnof(sd_bus_message *call, int error, const char *format, ...) _sd_printf_(3, 4);
+-
+-int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m);
+diff --git a/src/bus-proxyd/test-bus-xml-policy.c b/src/bus-proxyd/test-bus-xml-policy.c
+deleted file mode 100644
+index 421487e..0000000
+--- a/src/bus-proxyd/test-bus-xml-policy.c
++++ /dev/null
+@@ -1,182 +0,0 @@
+-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+-
+-/***
+-  This file is part of systemd.
+-
+-  Copyright 2014 Daniel Mack
+-
+-  systemd is free software; you can redistribute it and/or modify it
+-  under the terms of the GNU Lesser General Public License as published by
+-  the Free Software Foundation; either version 2.1 of the License, or
+-  (at your option) any later version.
+-
+-  systemd is distributed in the hope that it will be useful, but
+-  WITHOUT ANY WARRANTY; without even the implied warranty of
+-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-  Lesser General Public License for more details.
+-
+-  You should have received a copy of the GNU Lesser General Public License
+-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+-***/
+-
+-#include <sys/socket.h>
+-#include <sys/un.h>
+-#include <sys/types.h>
+-#include <fcntl.h>
+-#include <unistd.h>
+-#include <string.h>
+-#include <errno.h>
+-#include <poll.h>
+-#include <stddef.h>
+-#include <getopt.h>
+-
+-#include "log.h"
+-#include "util.h"
+-#include "sd-bus.h"
+-#include "bus-internal.h"
+-#include "bus-message.h"
+-#include "bus-util.h"
+-#include "build.h"
+-#include "strv.h"
+-#include "def.h"
+-#include "capability.h"
+-#include "bus-xml-policy.h"
+-
+-static int test_policy_load(Policy *p, const char *name) {
+-        _cleanup_free_ char *path = NULL;
+-        int r = 0;
+-
+-        path = strjoin(TEST_DIR, "/bus-policy/", name, NULL);
+-        assert_se(path);
+-
+-        if (access(path, R_OK) == 0)
+-                r = policy_load(p, STRV_MAKE(path));
+-        else
+-                r = -ENOENT;
+-
+-        return r;
+-}
+-
+-static int show_policy(const char *fn) {
+-        Policy p = {};
+-        int r;
+-
+-        r = policy_load(&p, STRV_MAKE(fn));
+-        if (r < 0) {
+-                log_error_errno(r, "Failed to load policy %s: %m", fn);
+-                return r;
+-        }
+-
+-        policy_dump(&p);
+-        policy_free(&p);
+-
+-        return 0;
+-}
+-
+-int main(int argc, char *argv[]) {
+-
+-        Policy p = {};
+-
+-        printf("Showing session policy BEGIN\n");
+-        show_policy("/etc/dbus-1/session.conf");
+-        printf("Showing session policy END\n");
+-
+-        printf("Showing system policy BEGIN\n");
+-        show_policy("/etc/dbus-1/system.conf");
+-        printf("Showing system policy END\n");
+-
+-        /* Ownership tests */
+-        assert_se(test_policy_load(&p, "ownerships.conf") == 0);
+-
+-        assert_se(policy_check_own(&p, 0, 0, "org.test.test1") == true);
+-        assert_se(policy_check_own(&p, 1, 0, "org.test.test1") == true);
+-
+-        assert_se(policy_check_own(&p, 0, 0, "org.test.test2") == true);
+-        assert_se(policy_check_own(&p, 1, 0, "org.test.test2") == false);
+-
+-        assert_se(policy_check_own(&p, 0, 0, "org.test.test3") == false);
+-        assert_se(policy_check_own(&p, 1, 0, "org.test.test3") == false);
+-
+-        assert_se(policy_check_own(&p, 0, 0, "org.test.test4") == false);
+-        assert_se(policy_check_own(&p, 1, 0, "org.test.test4") == true);
+-
+-        policy_free(&p);
+-
+-        /* Signaltest */
+-        assert_se(test_policy_load(&p, "signals.conf") == 0);
+-
+-        assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_SIGNAL, "bli.bla.blubb", NULL, "/an/object/path", NULL) == true);
+-        assert_se(policy_check_one_send(&p, 1, 0, SD_BUS_MESSAGE_SIGNAL, "bli.bla.blubb", NULL, "/an/object/path", NULL) == false);
+-
+-        policy_free(&p);
+-
+-        /* Method calls */
+-        assert_se(test_policy_load(&p, "methods.conf") == 0);
+-        policy_dump(&p);
+-
+-        assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "bli.bla.blubb", "Member") == false);
+-        assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "bli.bla.blubb", "Member") == false);
+-        assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int1", "Member") == true);
+-        assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int2", "Member") == true);
+-
+-        assert_se(policy_check_one_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test3", "/an/object/path", "org.test.int3", "Member111") == true);
+-
+-        policy_free(&p);
+-
+-        /* User and groups */
+-        assert_se(test_policy_load(&p, "hello.conf") == 0);
+-        policy_dump(&p);
+-
+-        assert_se(policy_check_hello(&p, 0, 0) == true);
+-        assert_se(policy_check_hello(&p, 1, 0) == false);
+-        assert_se(policy_check_hello(&p, 0, 1) == false);
+-
+-        policy_free(&p);
+-
+-        /* dbus1 test file: ownership */
+-
+-        assert_se(test_policy_load(&p, "check-own-rules.conf") >= 0);
+-        policy_dump(&p);
+-
+-        assert_se(policy_check_own(&p, 0, 0, "org.freedesktop") == false);
+-        assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystem") == false);
+-        assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems") == true);
+-        assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems.foo") == true);
+-        assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems.foo.bar") == true);
+-        assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems2") == false);
+-        assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems2.foo") == false);
+-        assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems2.foo.bar") == false);
+-
+-        policy_free(&p);
+-
+-        /* dbus1 test file: many rules */
+-
+-        assert_se(test_policy_load(&p, "many-rules.conf") >= 0);
+-        policy_dump(&p);
+-        policy_free(&p);
+-
+-        /* dbus1 test file: generic test */
+-
+-        assert_se(test_policy_load(&p, "test.conf") >= 0);
+-        policy_dump(&p);
+-
+-        assert_se(policy_check_own(&p, 0, 0, "org.foo.FooService") == true);
+-        assert_se(policy_check_own(&p, 0, 0, "org.foo.FooService2") == false);
+-        assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int2", "Member") == false);
+-        assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == true);
+-        assert_se(policy_check_one_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == true);
+-        assert_se(policy_check_one_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface2", "Member") == false);
+-        assert_se(policy_check_one_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService2", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == false);
+-
+-        assert_se(policy_check_own(&p, 100, 0, "org.foo.FooService") == false);
+-        assert_se(policy_check_own(&p, 100, 0, "org.foo.FooService2") == false);
+-        assert_se(policy_check_one_send(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int2", "Member") == false);
+-        assert_se(policy_check_one_send(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == false);
+-        assert_se(policy_check_one_recv(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == true);
+-        assert_se(policy_check_one_recv(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface2", "Member") == false);
+-        assert_se(policy_check_one_recv(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService2", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == false);
+-
+-        policy_free(&p);
+-
+-        return EXIT_SUCCESS;
+-}
+diff --git a/src/stdio-bridge/stdio-bridge.c b/src/stdio-bridge/stdio-bridge.c
+new file mode 100644
+index 0000000..791e545
+--- /dev/null
++++ b/src/stdio-bridge/stdio-bridge.c
+@@ -0,0 +1,303 @@
++/***
++  This file is part of systemd.
++
++  Copyright 2010 Lennart Poettering
++
++  systemd is free software; you can redistribute it and/or modify it
++  under the terms of the GNU Lesser General Public License as published by
++  the Free Software Foundation; either version 2.1 of the License, or
++  (at your option) any later version.
++
++  systemd is distributed in the hope that it will be useful, but
++  WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public License
++  along with systemd; If not, see <http://www.gnu.org/licenses/>.
++***/
++
++#include <errno.h>
++#include <getopt.h>
++#include <poll.h>
++#include <stddef.h>
++#include <string.h>
++#include <unistd.h>
++
++#include "sd-bus.h"
++#include "sd-daemon.h"
++
++#include "bus-internal.h"
++#include "bus-util.h"
++#include "build.h"
++#include "log.h"
++#include "util.h"
++
++#define DEFAULT_BUS_PATH "unix:path=/run/dbus/system_bus_socket"
++
++const char *arg_bus_path = DEFAULT_BUS_PATH;
++
++static int help(void) {
++
++        printf("%s [OPTIONS...]\n\n"
++               "STDIO or socket-activatable proxy to a given DBus endpoint.\n\n"
++               "  -h --help              Show this help\n"
++               "     --version           Show package version\n"
++               "     --bus-path=PATH     Path to the kernel bus (default: %s)\n",
++               program_invocation_short_name, DEFAULT_BUS_PATH);
++
++        return 0;
++}
++
++static int parse_argv(int argc, char *argv[]) {
++
++        enum {
++                ARG_VERSION = 0x100,
++        };
++
++        static const struct option options[] = {
++                { "help",            no_argument,       NULL, 'h'     },
++                { "bus-path",        required_argument, NULL, 'p'     },
++                { NULL,              0,                 NULL, 0       }
++        };
++
++        int c;
++
++        assert(argc >= 0);
++        assert(argv);
++
++        while ((c = getopt_long(argc, argv, "hsup:", options, NULL)) >= 0) {
++
++                switch (c) {
++
++                case 'h':
++                        help();
++                        return 0;
++
++                case ARG_VERSION:
++                        puts(PACKAGE_STRING);
++                        puts(SYSTEMD_FEATURES);
++                        return 0;
++
++                case '?':
++                        return -EINVAL;
++
++                case 'p':
++                        arg_bus_path = optarg;
++                        break;
++
++                default:
++                        log_error("Unknown option code %c", c);
++                        return -EINVAL;
++                }
++        }
++
++        return 1;
++}
++
++int main(int argc, char *argv[]) {
++        _cleanup_(sd_bus_unrefp) sd_bus *a = NULL, *b = NULL;
++        sd_id128_t server_id;
++        bool is_unix;
++        int r, in_fd, out_fd;
++
++        log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
++        log_parse_environment();
++        log_open();
++
++        r = parse_argv(argc, argv);
++        if (r <= 0)
++                goto finish;
++
++        r = sd_listen_fds(0);
++        if (r == 0) {
++                in_fd = STDIN_FILENO;
++                out_fd = STDOUT_FILENO;
++        } else if (r == 1) {
++                in_fd = SD_LISTEN_FDS_START;
++                out_fd = SD_LISTEN_FDS_START;
++        } else {
++                log_error("Illegal number of file descriptors passed\n");
++                goto finish;
++        }
++
++        is_unix =
++                sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
++                sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
++
++        r = sd_bus_new(&a);
++        if (r < 0) {
++                log_error_errno(r, "Failed to allocate bus: %m");
++                goto finish;
++        }
++
++        r = sd_bus_set_address(a, arg_bus_path);
++        if (r < 0) {
++                log_error_errno(r, "Failed to set address to connect to: %m");
++                goto finish;
++        }
++
++        r = sd_bus_negotiate_fds(a, is_unix);
++        if (r < 0) {
++                log_error_errno(r, "Failed to set FD negotiation: %m");
++                goto finish;
++        }
++
++        r = sd_bus_start(a);
++        if (r < 0) {
++                log_error_errno(r, "Failed to start bus client: %m");
++                goto finish;
++        }
++
++        r = sd_bus_get_bus_id(a, &server_id);
++        if (r < 0) {
++                log_error_errno(r, "Failed to get server ID: %m");
++                goto finish;
++        }
++
++        r = sd_bus_new(&b);
++        if (r < 0) {
++                log_error_errno(r, "Failed to allocate bus: %m");
++                goto finish;
++        }
++
++        r = sd_bus_set_fd(b, in_fd, out_fd);
++        if (r < 0) {
++                log_error_errno(r, "Failed to set fds: %m");
++                goto finish;
++        }
++
++        r = sd_bus_set_server(b, 1, server_id);
++        if (r < 0) {
++                log_error_errno(r, "Failed to set server mode: %m");
++                goto finish;
++        }
++
++        r = sd_bus_negotiate_fds(b, is_unix);
++        if (r < 0) {
++                log_error_errno(r, "Failed to set FD negotiation: %m");
++                goto finish;
++        }
++
++        r = sd_bus_set_anonymous(b, true);
++        if (r < 0) {
++                log_error_errno(r, "Failed to set anonymous authentication: %m");
++                goto finish;
++        }
++
++        r = sd_bus_start(b);
++        if (r < 0) {
++                log_error_errno(r, "Failed to start bus client: %m");
++                goto finish;
++        }
++
++        for (;;) {
++                 _cleanup_(sd_bus_message_unrefp)sd_bus_message *m = NULL;
++                int events_a, events_b, fd;
++                uint64_t timeout_a, timeout_b, t;
++                struct timespec _ts, *ts;
++
++                r = sd_bus_process(a, &m);
++                if (r < 0) {
++                        log_error_errno(r, "Failed to process bus a: %m");
++                        goto finish;
++                }
++
++                if (m) {
++                        r = sd_bus_send(b, m, NULL);
++                        if (r < 0) {
++                                log_error_errno(r, "Failed to send message: %m");
++                                goto finish;
++                        }
++                }
++
++                if (r > 0)
++                        continue;
++
++                r = sd_bus_process(b, &m);
++                if (r < 0) {
++                        /* treat 'connection reset by peer' as clean exit condition */
++                        if (r == -ECONNRESET)
++                                r = 0;
++
++                        goto finish;
++                }
++
++                if (m) {
++                        r = sd_bus_send(a, m, NULL);
++                        if (r < 0) {
++                                log_error_errno(r, "Failed to send message: %m");
++                                goto finish;
++                        }
++                }
++
++                if (r > 0)
++                        continue;
++
++                fd = sd_bus_get_fd(a);
++                if (fd < 0) {
++                        log_error_errno(r, "Failed to get fd: %m");
++                        goto finish;
++                }
++
++                events_a = sd_bus_get_events(a);
++                if (events_a < 0) {
++                        log_error_errno(r, "Failed to get events mask: %m");
++                        goto finish;
++                }
++
++                r = sd_bus_get_timeout(a, &timeout_a);
++                if (r < 0) {
++                        log_error_errno(r, "Failed to get timeout: %m");
++                        goto finish;
++                }
++
++                events_b = sd_bus_get_events(b);
++                if (events_b < 0) {
++                        log_error_errno(r, "Failed to get events mask: %m");
++                        goto finish;
++                }
++
++                r = sd_bus_get_timeout(b, &timeout_b);
++                if (r < 0) {
++                        log_error_errno(r, "Failed to get timeout: %m");
++                        goto finish;
++                }
++
++                t = timeout_a;
++                if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
++                        t = timeout_b;
++
++                if (t == (uint64_t) -1)
++                        ts = NULL;
++                else {
++                        usec_t nw;
++
++                        nw = now(CLOCK_MONOTONIC);
++                        if (t > nw)
++                                t -= nw;
++                        else
++                                t = 0;
++
++                        ts = timespec_store(&_ts, t);
++                }
++
++                {
++                        struct pollfd p[3] = {
++                                {.fd = fd,            .events = events_a, },
++                                {.fd = STDIN_FILENO,  .events = events_b & POLLIN, },
++                                {.fd = STDOUT_FILENO, .events = events_b & POLLOUT, }};
++
++                        r = ppoll(p, ELEMENTSOF(p), ts, NULL);
++                }
++                if (r < 0) {
++                        log_error("ppoll() failed: %m");
++                        goto finish;
++                }
++        }
++
++        r = 0;
++
++finish:
++        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
++}
+diff --git a/src/test/test-tables.c b/src/test/test-tables.c
+index e409790..afd4ab7 100644
+--- a/src/test/test-tables.c
++++ b/src/test/test-tables.c
+@@ -46,7 +46,6 @@
+ #include "util.h"
+ #include "architecture.h"
+ #include "link-config.h"
+-#include "bus-xml-policy.h"
+ #include "busname.h"
+ #include "journald-server.h"
+ #include "locale-util.h"
+@@ -86,8 +85,6 @@ int main(int argc, char **argv) {
+         test_table(path_result, PATH_RESULT);
+         test_table(path_state, PATH_STATE);
+         test_table(path_type, PATH_TYPE);
+-        test_table(policy_item_class, POLICY_ITEM_CLASS);
+-        test_table(policy_item_type, POLICY_ITEM_TYPE);
+         test_table(protect_home, PROTECT_HOME);
+         test_table(protect_system, PROTECT_SYSTEM);
+         test_table(rlimit, RLIMIT);
+diff --git a/sysusers.d/systemd.conf.m4 b/sysusers.d/systemd.conf.m4
+index 23175de..3d3e237 100644
+--- a/sysusers.d/systemd.conf.m4
++++ b/sysusers.d/systemd.conf.m4
+@@ -6,9 +6,6 @@
+ #  (at your option) any later version.
+ 
+ g systemd-journal   - -
+-m4_ifdef(`ENABLE_KDBUS',
+-u systemd-bus-proxy - "systemd Bus Proxy"
+-)m4_dnl
+ m4_ifdef(`ENABLE_NETWORKD',
+ u systemd-network   - "systemd Network Management"
+ )m4_dnl
+diff --git a/units/.gitignore b/units/.gitignore
+index 7f3e0d0..48c8f72 100644
+--- a/units/.gitignore
++++ b/units/.gitignore
+@@ -1,4 +1,3 @@
+-/systemd-bus-proxyd.service.m4
+ /user@.service.m4
+ /console-getty.service
+ /console-getty.service.m4
+@@ -24,7 +23,6 @@
+ /systemd-backlight@.service
+ /systemd-binfmt.service
+ /systemd-bootchart.service
+-/systemd-bus-proxyd.service
+ /systemd-firstboot.service
+ /systemd-fsck-root.service
+ /systemd-fsck@.service
+diff --git a/units/systemd-bus-proxyd.service.m4.in b/units/systemd-bus-proxyd.service.m4.in
+deleted file mode 100644
+index ffaf0bd..0000000
+--- a/units/systemd-bus-proxyd.service.m4.in
++++ /dev/null
+@@ -1,19 +0,0 @@
+-#  This file is part of systemd.
+-#
+-#  systemd is free software; you can redistribute it and/or modify it
+-#  under the terms of the GNU Lesser General Public License as published by
+-#  the Free Software Foundation; either version 2.1 of the License, or
+-#  (at your option) any later version.
+-
+-[Unit]
+-Description=Legacy D-Bus Protocol Compatibility Daemon
+-
+-[Service]
+-ExecStart=@rootlibexecdir@/systemd-bus-proxyd --address=kernel:path=/sys/fs/kdbus/0-system/bus
+-NotifyAccess=main
+-CapabilityBoundingSet=CAP_IPC_OWNER CAP_SETUID CAP_SETGID CAP_SETPCAP m4_ifdef(`HAVE_SMACK', CAP_MAC_ADMIN )
+-PrivateTmp=yes
+-PrivateDevices=yes
+-PrivateNetwork=yes
+-ProtectSystem=full
+-ProtectHome=yes
+diff --git a/units/systemd-bus-proxyd.socket b/units/systemd-bus-proxyd.socket
+deleted file mode 100644
+index 3f80a1d..0000000
+--- a/units/systemd-bus-proxyd.socket
++++ /dev/null
+@@ -1,12 +0,0 @@
+-#  This file is part of systemd.
+-#
+-#  systemd is free software; you can redistribute it and/or modify it
+-#  under the terms of the GNU Lesser General Public License as published by
+-#  the Free Software Foundation; either version 2.1 of the License, or
+-#  (at your option) any later version.
+-
+-[Unit]
+-Description=Legacy D-Bus Protocol Compatibility Socket
+-
+-[Socket]
+-ListenStream=/var/run/dbus/system_bus_socket
+diff --git a/units/user/.gitignore b/units/user/.gitignore
+index 6111b10..41a74f5 100644
+--- a/units/user/.gitignore
++++ b/units/user/.gitignore
+@@ -1,3 +1 @@
+ /systemd-exit.service
+-/systemd-bus-proxyd.service
+-/systemd-consoled.service
+diff --git a/units/user/systemd-bus-proxyd.service.in b/units/user/systemd-bus-proxyd.service.in
+deleted file mode 100644
+index e1e399d..0000000
+--- a/units/user/systemd-bus-proxyd.service.in
++++ /dev/null
+@@ -1,13 +0,0 @@
+-#  This file is part of systemd.
+-#
+-#  systemd is free software; you can redistribute it and/or modify it
+-#  under the terms of the GNU Lesser General Public License as published by
+-#  the Free Software Foundation; either version 2.1 of the License, or
+-#  (at your option) any later version.
+-
+-[Unit]
+-Description=Legacy D-Bus Protocol Compatibility Daemon
+-
+-[Service]
+-ExecStart=@rootlibexecdir@/systemd-bus-proxyd --address=kernel:path=/sys/fs/kdbus/%U-user/bus
+-NotifyAccess=main
+diff --git a/units/user/systemd-bus-proxyd.socket b/units/user/systemd-bus-proxyd.socket
+deleted file mode 100644
+index b9efc0e..0000000
+--- a/units/user/systemd-bus-proxyd.socket
++++ /dev/null
+@@ -1,12 +0,0 @@
+-#  This file is part of systemd.
+-#
+-#  systemd is free software; you can redistribute it and/or modify it
+-#  under the terms of the GNU Lesser General Public License as published by
+-#  the Free Software Foundation; either version 2.1 of the License, or
+-#  (at your option) any later version.
+-
+-[Unit]
+-Description=Legacy D-Bus Protocol Compatibility Socket
+-
+-[Socket]
+-ListenStream=%t/bus
diff --git a/SOURCES/0455-execute-Add-new-PassEnvironment-directive.patch b/SOURCES/0455-execute-Add-new-PassEnvironment-directive.patch
new file mode 100644
index 0000000..f03f615
--- /dev/null
+++ b/SOURCES/0455-execute-Add-new-PassEnvironment-directive.patch
@@ -0,0 +1,391 @@
+From 88d2ec272d3e503412e477d9abaebfe2ca199e78 Mon Sep 17 00:00:00 2001
+From: Filipe Brandenburger <filbranden@google.com>
+Date: Sun, 6 Sep 2015 23:06:53 -0700
+Subject: [PATCH] execute: Add new PassEnvironment= directive
+
+This directive allows passing environment variables from the system
+manager to spawned services. Variables in the system manager can be set
+inside a container by passing `--set-env=...` options to systemd-spawn.
+
+Tested with an on-disk test.service unit. Tested using multiple variable
+names on a single line, with an empty setting to clear the current list
+of variables, with non-existing variables.
+
+Tested using `systemd-run -p PassEnvironment=VARNAME` to confirm it
+works with transient units.
+
+Confirmed that `systemctl show` will display the PassEnvironment
+settings.
+
+Checked that man pages are generated correctly.
+
+No regressions in `make check`.
+
+(cherry picked from commit b4c14404b3e8753c41bac0b1d49369230a15c544)
+
+Resolves: #1426214
+---
+ man/systemd.exec.xml                  | 27 +++++++++++++++
+ shell-completion/bash/systemd-run     |  2 +-
+ src/core/dbus-execute.c               | 34 ++++++++++++++++++
+ src/core/execute.c                    | 44 ++++++++++++++++++++++--
+ src/core/execute.h                    |  1 +
+ src/core/load-fragment-gperf.gperf.m4 |  1 +
+ src/core/load-fragment.c              | 65 +++++++++++++++++++++++++++++++++++
+ src/core/load-fragment.h              |  1 +
+ src/libsystemd/sd-bus/bus-util.c      |  2 +-
+ src/shared/env-util.c                 | 15 ++++++++
+ src/shared/env-util.h                 |  1 +
+ 11 files changed, 189 insertions(+), 4 deletions(-)
+
+diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
+index c5199d3..aa5831c 100644
+--- a/man/systemd.exec.xml
++++ b/man/systemd.exec.xml
+@@ -294,6 +294,33 @@
+       </varlistentry>
+ 
+       <varlistentry>
++        <term><varname>PassEnvironment=</varname></term>
++
++        <listitem><para>Pass environment variables from the systemd system
++        manager to executed processes. Takes a space-separated list of variable
++        names. This option may be specified more than once, in which case all
++        listed variables will be set. If the empty string is assigned to this
++        option, the list of environment variables is reset, all prior
++        assignments have no effect. Variables that are not set in the system
++        manager will not be passed and will be silently ignored.</para>
++
++        <para>Variables passed from this setting are overridden by those passed
++        from <varname>Environment=</varname> or
++        <varname>EnvironmentFile=</varname>.</para>
++
++        <para>Example:
++        <programlisting>PassEnvironment=VAR1 VAR2 VAR3</programlisting>
++        passes three variables <literal>VAR1</literal>,
++        <literal>VAR2</literal>, <literal>VAR3</literal>
++        with the values set for those variables in PID1.</para>
++
++        <para>
++        See
++        <citerefentry project='man-pages'><refentrytitle>environ</refentrytitle><manvolnum>7</manvolnum></citerefentry>
++        for details about environment variables.</para></listitem>
++      </varlistentry>
++
++      <varlistentry>
+         <term><varname>StandardInput=</varname></term>
+         <listitem><para>Controls where file descriptor 0 (STDIN) of
+         the executed processes is connected to. Takes one of
+diff --git a/shell-completion/bash/systemd-run b/shell-completion/bash/systemd-run
+index 5145cd3..36ffa46 100644
+--- a/shell-completion/bash/systemd-run
++++ b/shell-completion/bash/systemd-run
+@@ -73,7 +73,7 @@ _systemd_run() {
+                          KillSignal= LimitCPU= LimitFSIZE= LimitDATA= LimitSTACK=
+                          LimitCORE= LimitRSS= LimitNOFILE= LimitAS= LimitNPROC=
+                          LimitMEMLOCK= LimitLOCKS= LimitSIGPENDING= LimitMSGQUEUE=
+-                         LimitNICE= LimitRTPRIO= LimitRTTIME='
++                         LimitNICE= LimitRTPRIO= LimitRTTIME= PassEnvironment='
+ 
+             COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
+             return 0
+diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
+index a9f7971..da8b10d 100644
+--- a/src/core/dbus-execute.c
++++ b/src/core/dbus-execute.c
+@@ -597,6 +597,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
+         SD_BUS_VTABLE_START(0),
+         SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("EnvironmentFiles", "a(sb)", property_get_environment_files, 0, SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("PassEnvironment", "as", NULL, offsetof(ExecContext, pass_environment), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("UMask", "u", bus_property_get_mode, offsetof(ExecContext, umask), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("LimitCPU", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("LimitFSIZE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
+@@ -963,6 +964,39 @@ int bus_exec_context_set_transient_property(
+ 
+                 return 1;
+ 
++        } else if (streq(name, "PassEnvironment")) {
++
++                _cleanup_strv_free_ char **l = NULL;
++
++                r = sd_bus_message_read_strv(message, &l);
++                if (r < 0)
++                        return r;
++
++                if (!strv_env_name_is_valid(l))
++                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid PassEnvironment block.");
++
++                if (mode != UNIT_CHECK) {
++                        if (strv_isempty(l)) {
++                                strv_free(c->pass_environment);
++                                c->pass_environment = NULL;
++                                unit_write_drop_in_private_format(u, mode, name, "PassEnvironment=\n");
++                        } else {
++                                _cleanup_free_ char *joined = NULL;
++
++                                r = strv_extend_strv(&c->pass_environment, l);
++                                if (r < 0)
++                                        return r;
++
++                                joined = strv_join_quoted(c->pass_environment);
++                                if (!joined)
++                                        return -ENOMEM;
++
++                                unit_write_drop_in_private_format(u, mode, name, "PassEnvironment=%s\n", joined);
++                        }
++                }
++
++                return 1;
++
+         } else if (rlimit_from_string(name) >= 0) {
+                 uint64_t rl;
+                 rlim_t x;
+diff --git a/src/core/execute.c b/src/core/execute.c
+index 863babd..f72b209 100644
+--- a/src/core/execute.c
++++ b/src/core/execute.c
+@@ -1256,6 +1256,34 @@ static int build_environment(
+         return 0;
+ }
+ 
++static int build_pass_environment(const ExecContext *c, char ***ret) {
++        _cleanup_strv_free_ char **pass_env = NULL;
++        size_t n_env = 0, n_bufsize = 0;
++        char **i;
++
++        STRV_FOREACH(i, c->pass_environment) {
++                _cleanup_free_ char *x = NULL;
++                char *v;
++
++                v = getenv(*i);
++                if (!v)
++                        continue;
++                x = strjoin(*i, "=", v, NULL);
++                if (!x)
++                        return -ENOMEM;
++                if (!GREEDY_REALLOC(pass_env, n_bufsize, n_env + 2))
++                        return -ENOMEM;
++                pass_env[n_env++] = x;
++                pass_env[n_env] = NULL;
++                x = NULL;
++        }
++
++        *ret = pass_env;
++        pass_env = NULL;
++
++        return 0;
++}
++
+ static bool exec_needs_mount_namespace(
+                 const ExecContext *context,
+                 const ExecParameters *params,
+@@ -1297,7 +1325,7 @@ static int exec_child(
+                 char **files_env,
+                 int *exit_status) {
+ 
+-        _cleanup_strv_free_ char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL;
++        _cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL;
+         _cleanup_free_ char *mac_selinux_context_net = NULL;
+         const char *username = NULL, *home = NULL, *shell = NULL;
+         unsigned n_dont_close = 0;
+@@ -1805,9 +1833,16 @@ static int exec_child(
+                 return r;
+         }
+ 
+-        final_env = strv_env_merge(5,
++        r = build_pass_environment(context, &pass_env);
++        if (r < 0) {
++                *exit_status = EXIT_MEMORY;
++                return r;
++        }
++
++        final_env = strv_env_merge(6,
+                                    params->environment,
+                                    our_env,
++                                   pass_env,
+                                    context->environment,
+                                    files_env,
+                                    pam_env,
+@@ -1965,6 +2000,8 @@ void exec_context_done(ExecContext *c) {
+ 
+         strv_free(c->environment_files);
+         c->environment_files = NULL;
++        strv_free(c->pass_environment);
++        c->pass_environment = NULL;
+ 
+         for (l = 0; l < ELEMENTSOF(c->rlimit); l++) {
+                 free(c->rlimit[l]);
+@@ -2267,6 +2304,9 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
+         STRV_FOREACH(e, c->environment_files)
+                 fprintf(f, "%sEnvironmentFile: %s\n", prefix, *e);
+ 
++        STRV_FOREACH(e, c->pass_environment)
++                fprintf(f, "%sPassEnvironment: %s\n", prefix, *e);
++
+         if (c->nice_set)
+                 fprintf(f,
+                         "%sNice: %i\n",
+diff --git a/src/core/execute.h b/src/core/execute.h
+index 6e0c9fa..cadd0e6 100644
+--- a/src/core/execute.h
++++ b/src/core/execute.h
+@@ -96,6 +96,7 @@ struct ExecRuntime {
+ struct ExecContext {
+         char **environment;
+         char **environment_files;
++        char **pass_environment;
+ 
+         struct rlimit *rlimit[_RLIMIT_MAX];
+         char *working_directory, *root_directory;
+diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
+index c866a9c..b50fe45 100644
+--- a/src/core/load-fragment-gperf.gperf.m4
++++ b/src/core/load-fragment-gperf.gperf.m4
+@@ -33,6 +33,7 @@ $1.CPUAffinity,                  config_parse_exec_cpu_affinity,     0,
+ $1.UMask,                        config_parse_mode,                  0,                             offsetof($1, exec_context.umask)
+ $1.Environment,                  config_parse_environ,               0,                             offsetof($1, exec_context.environment)
+ $1.EnvironmentFile,              config_parse_unit_env_file,         0,                             offsetof($1, exec_context.environment_files)
++$1.PassEnvironment,              config_parse_pass_environ,          0,                             offsetof($1, exec_context.pass_environment)
+ $1.StandardInput,                config_parse_input,                 0,                             offsetof($1, exec_context.std_input)
+ $1.StandardOutput,               config_parse_output,                0,                             offsetof($1, exec_context.std_output)
+ $1.StandardError,                config_parse_output,                0,                             offsetof($1, exec_context.std_error)
+diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
+index 3a3c456..c450fe2 100644
+--- a/src/core/load-fragment.c
++++ b/src/core/load-fragment.c
+@@ -2265,6 +2265,71 @@ int config_parse_environ(const char *unit,
+         return 0;
+ }
+ 
++int config_parse_pass_environ(const char *unit,
++                              const char *filename,
++                              unsigned line,
++                              const char *section,
++                              unsigned section_line,
++                              const char *lvalue,
++                              int ltype,
++                              const char *rvalue,
++                              void *data,
++                              void *userdata) {
++
++        const char *whole_rvalue = rvalue;
++        char*** passenv = data;
++        _cleanup_strv_free_ char **n = NULL;
++        size_t nlen = 0, nbufsize = 0;
++        int r;
++
++        assert(filename);
++        assert(lvalue);
++        assert(rvalue);
++        assert(data);
++
++        if (isempty(rvalue)) {
++                /* Empty assignment resets the list */
++                strv_free(*passenv);
++                *passenv = NULL;
++                return 0;
++        }
++
++        for (;;) {
++                _cleanup_free_ char *word = NULL;
++
++                r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES);
++                if (r == 0)
++                        break;
++                if (r == -ENOMEM)
++                        return log_oom();
++                if (r < 0) {
++                        log_syntax(unit, LOG_ERR, filename, line, r,
++                                   "Trailing garbage in %s, ignoring: %s", lvalue, whole_rvalue);
++                        break;
++                }
++
++                if (!env_name_is_valid(word)) {
++                        log_syntax(unit, LOG_ERR, filename, line, EINVAL,
++                                   "Invalid environment name for %s, ignoring: %s", lvalue, word);
++                        continue;
++                }
++
++                if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
++                        return log_oom();
++                n[nlen++] = word;
++                n[nlen] = NULL;
++                word = NULL;
++        }
++
++        if (n) {
++                r = strv_extend_strv(passenv, n);
++                if (r < 0)
++                        return r;
++        }
++
++        return 0;
++}
++
+ int config_parse_ip_tos(const char *unit,
+                         const char *filename,
+                         unsigned line,
+diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
+index 7c69e53..9dd7d1b 100644
+--- a/src/core/load-fragment.h
++++ b/src/core/load-fragment.h
+@@ -85,6 +85,7 @@ int config_parse_syscall_filter(const char *unit, const char *filename, unsigned
+ int config_parse_syscall_archs(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+ int config_parse_syscall_errno(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+ int config_parse_environ(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
++int config_parse_pass_environ(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+ int config_parse_unit_slice(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+ int config_parse_cpu_shares(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+ int config_parse_memory_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c
+index d357760..ed0849b 100644
+--- a/src/libsystemd/sd-bus/bus-util.c
++++ b/src/libsystemd/sd-bus/bus-util.c
+@@ -1535,7 +1535,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
+ 
+                 r = sd_bus_message_append(m, "v", "i", i);
+ 
+-        } else if (streq(field, "Environment")) {
++        } else if (STR_IN_SET(field, "Environment", "PassEnvironment")) {
+ 
+                 r = sd_bus_message_append(m, "v", "as", 1, eq);
+ 
+diff --git a/src/shared/env-util.c b/src/shared/env-util.c
+index e8da4c9..581d84a 100644
+--- a/src/shared/env-util.c
++++ b/src/shared/env-util.c
+@@ -136,6 +136,21 @@ bool strv_env_is_valid(char **e) {
+         return true;
+ }
+ 
++bool strv_env_name_is_valid(char **l) {
++        char **p, **q;
++
++        STRV_FOREACH(p, l) {
++                if (!env_name_is_valid(*p))
++                        return false;
++
++                STRV_FOREACH(q, p + 1)
++                        if (streq(*p, *q))
++                                return false;
++        }
++
++        return true;
++}
++
+ bool strv_env_name_or_assignment_is_valid(char **l) {
+         char **p, **q;
+ 
+diff --git a/src/shared/env-util.h b/src/shared/env-util.h
+index 252d87b..b8c2d81 100644
+--- a/src/shared/env-util.h
++++ b/src/shared/env-util.h
+@@ -34,6 +34,7 @@ bool strv_env_is_valid(char **e);
+ #define strv_env_clean(l) strv_env_clean_with_callback(l, NULL, NULL)
+ char **strv_env_clean_with_callback(char **l, void (*invalid_callback)(const char *p, void *userdata), void *userdata);
+ 
++bool strv_env_name_is_valid(char **l);
+ bool strv_env_name_or_assignment_is_valid(char **l);
+ 
+ char **strv_env_merge(unsigned n_lists, ...);
diff --git a/SOURCES/0456-test-execute-Add-tests-for-new-PassEnvironment-direc.patch b/SOURCES/0456-test-execute-Add-tests-for-new-PassEnvironment-direc.patch
new file mode 100644
index 0000000..54789b0
--- /dev/null
+++ b/SOURCES/0456-test-execute-Add-tests-for-new-PassEnvironment-direc.patch
@@ -0,0 +1,130 @@
+From f35b737bdd6e508cf73f43a1beb3f5cb8c1ebb07 Mon Sep 17 00:00:00 2001
+From: Filipe Brandenburger <filbranden@google.com>
+Date: Sun, 8 Nov 2015 10:37:05 -0800
+Subject: [PATCH] test-execute: Add tests for new PassEnvironment= directive
+
+Check the base case, plus erasing the list, listing the same variable
+name more than once and when variables are absent from the manager
+execution environment.
+
+Confirmed that `sudo ./test-execute` passes and that modifying the test
+cases (or the values of the set variables in test-execute.c) is enough
+to make the test cases fail.
+
+(cherry picked from commit 4c80d201ace0377312c27143afab04e9c9f1ee64)
+
+Related: #1426214
+---
+ Makefile.am                                |  4 ++++
+ src/test/test-execute.c                    | 14 ++++++++++++++
+ test/exec-passenvironment-absent.service   |  7 +++++++
+ test/exec-passenvironment-empty.service    |  8 ++++++++
+ test/exec-passenvironment-repeated.service |  8 ++++++++
+ test/exec-passenvironment.service          |  7 +++++++
+ 6 files changed, 48 insertions(+)
+ create mode 100644 test/exec-passenvironment-absent.service
+ create mode 100644 test/exec-passenvironment-empty.service
+ create mode 100644 test/exec-passenvironment-repeated.service
+ create mode 100644 test/exec-passenvironment.service
+
+diff --git a/Makefile.am b/Makefile.am
+index 924b34b..e9ceac9 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -1477,6 +1477,10 @@ EXTRA_DIST += \
+ 	test/exec-environment-empty.service \
+ 	test/exec-environment-multiple.service \
+ 	test/exec-environment.service \
++	test/exec-passenvironment-absent.service \
++	test/exec-passenvironment-empty.service \
++	test/exec-passenvironment-repeated.service \
++	test/exec-passenvironment.service \
+ 	test/exec-group.service \
+ 	test/exec-ignoresigpipe-no.service \
+ 	test/exec-ignoresigpipe-yes.service \
+diff --git a/src/test/test-execute.c b/src/test/test-execute.c
+index 5a02960..8def194 100644
+--- a/src/test/test-execute.c
++++ b/src/test/test-execute.c
+@@ -142,6 +142,19 @@ static void test_exec_environment(Manager *m) {
+         test(m, "exec-environment-empty.service", 0, CLD_EXITED);
+ }
+ 
++static void test_exec_passenvironment(Manager *m) {
++        assert_se(setenv("VAR1", "word1 word2", 1) == 0);
++        assert_se(setenv("VAR2", "word3", 1) == 0);
++        assert_se(setenv("VAR3", "$word 5 6", 1) == 0);
++        test(m, "exec-passenvironment.service", 0, CLD_EXITED);
++        test(m, "exec-passenvironment-repeated.service", 0, CLD_EXITED);
++        test(m, "exec-passenvironment-empty.service", 0, CLD_EXITED);
++        assert_se(unsetenv("VAR1") == 0);
++        assert_se(unsetenv("VAR2") == 0);
++        assert_se(unsetenv("VAR3") == 0);
++        test(m, "exec-passenvironment-absent.service", 0, CLD_EXITED);
++}
++
+ static void test_exec_umask(Manager *m) {
+         test(m, "exec-umask-default.service", 0, CLD_EXITED);
+         test(m, "exec-umask-0177.service", 0, CLD_EXITED);
+@@ -165,6 +178,7 @@ int main(int argc, char *argv[]) {
+                 test_exec_user,
+                 test_exec_group,
+                 test_exec_environment,
++                test_exec_passenvironment,
+                 test_exec_umask,
+                 test_exec_runtimedirectory,
+                 NULL,
+diff --git a/test/exec-passenvironment-absent.service b/test/exec-passenvironment-absent.service
+new file mode 100644
+index 0000000..7d5e32a
+--- /dev/null
++++ b/test/exec-passenvironment-absent.service
+@@ -0,0 +1,7 @@
++[Unit]
++Description=Test for PassEnvironment with variables absent from the execution environment
++
++[Service]
++ExecStart=/bin/sh -x -c 'test "$${VAR1-unset}" = "unset" && test "$${VAR2-unset}" = "unset" && test "$${VAR3-unset}" = "unset"'
++Type=oneshot
++PassEnvironment=VAR1 VAR2 VAR3
+diff --git a/test/exec-passenvironment-empty.service b/test/exec-passenvironment-empty.service
+new file mode 100644
+index 0000000..c93c197
+--- /dev/null
++++ b/test/exec-passenvironment-empty.service
+@@ -0,0 +1,8 @@
++[Unit]
++Description=Test for PassEnvironment and erasing the variable list
++
++[Service]
++ExecStart=/bin/sh -x -c 'test "$${VAR1-unset}" = "unset" && test "$${VAR2-unset}" = "unset" && test "$${VAR3-unset}" = "unset"'
++Type=oneshot
++PassEnvironment=VAR1 VAR2 VAR3
++PassEnvironment=
+diff --git a/test/exec-passenvironment-repeated.service b/test/exec-passenvironment-repeated.service
+new file mode 100644
+index 0000000..5e8c56f
+--- /dev/null
++++ b/test/exec-passenvironment-repeated.service
+@@ -0,0 +1,8 @@
++[Unit]
++Description=Test for PassEnvironment with a variable name repeated
++
++[Service]
++ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6"'
++Type=oneshot
++PassEnvironment=VAR1 VAR2
++PassEnvironment=VAR1 VAR3
+diff --git a/test/exec-passenvironment.service b/test/exec-passenvironment.service
+new file mode 100644
+index 0000000..b4a9909
+--- /dev/null
++++ b/test/exec-passenvironment.service
+@@ -0,0 +1,7 @@
++[Unit]
++Description=Test for PassEnvironment
++
++[Service]
++ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6"'
++Type=oneshot
++PassEnvironment=VAR1 VAR2 VAR3
diff --git a/SOURCES/0457-test-execute-Clarify-interaction-of-PassEnvironment-.patch b/SOURCES/0457-test-execute-Clarify-interaction-of-PassEnvironment-.patch
new file mode 100644
index 0000000..a2a4d47
--- /dev/null
+++ b/SOURCES/0457-test-execute-Clarify-interaction-of-PassEnvironment-.patch
@@ -0,0 +1,69 @@
+From ddad59f50e67a5e36cd9c40e774d28240a6a7c0c Mon Sep 17 00:00:00 2001
+From: Filipe Brandenburger <filbranden@google.com>
+Date: Wed, 11 Nov 2015 09:24:34 -0800
+Subject: [PATCH] test-execute: Clarify interaction of PassEnvironment= and
+ MANAGER_USER
+
+@evverx brought up that test-execute runs under MANAGER_USER which
+forwards all its environment variables to the services. It turns out it
+only forwards those that were in the environment at the time of manager
+creation, so this test was still working.
+
+It was still possible to attack it by running something like:
+  $ sudo VAR1=a VAR2=b VAR3=c ./test-execute
+
+Prevent that attack by unsetting the three variables explicitly before
+creating the manager for the test case.
+
+Also add comments explaining the interactions with MANAGER_USER and,
+while it has some caveats, this tests are still valid in that context.
+
+Tested by checking that the test running with the variables set from the
+external environment will still pass.
+
+(cherry picked from commit e1abca2ee42e5938ee1f2542c3eba9e70edb0be2)
+
+Related: #1426214
+---
+ src/test/test-execute.c | 21 +++++++++++++++++++++
+ 1 file changed, 21 insertions(+)
+
+diff --git a/src/test/test-execute.c b/src/test/test-execute.c
+index 8def194..6e5567c 100644
+--- a/src/test/test-execute.c
++++ b/src/test/test-execute.c
+@@ -143,6 +143,17 @@ static void test_exec_environment(Manager *m) {
+ }
+ 
+ static void test_exec_passenvironment(Manager *m) {
++        /* test-execute runs under MANAGER_USER which, by default, forwards all
++         * variables present in the environment, but only those that are
++         * present _at the time it is created_!
++         *
++         * So these PassEnvironment checks are still expected to work, since we
++         * are ensuring the variables are not present at manager creation (they
++         * are unset explicitly in main) and are only set here.
++         *
++         * This is still a good approximation of how a test for MANAGER_SYSTEM
++         * would work.
++         */
+         assert_se(setenv("VAR1", "word1 word2", 1) == 0);
+         assert_se(setenv("VAR2", "word3", 1) == 0);
+         assert_se(setenv("VAR3", "$word 5 6", 1) == 0);
+@@ -199,6 +210,16 @@ int main(int argc, char *argv[]) {
+         assert_se(setenv("XDG_RUNTIME_DIR", "/tmp/", 1) == 0);
+         assert_se(set_unit_path(TEST_DIR ":") >= 0);
+ 
++        /* Unset VAR1, VAR2 and VAR3 which are used in the PassEnvironment test
++         * cases, otherwise (and if they are present in the environment),
++         * `manager_default_environment` will copy them into the default
++         * environment which is passed to each created job, which will make the
++         * tests that expect those not to be present to fail.
++         */
++        assert_se(unsetenv("VAR1") == 0);
++        assert_se(unsetenv("VAR2") == 0);
++        assert_se(unsetenv("VAR3") == 0);
++
+         r = manager_new(SYSTEMD_USER, true, &m);
+         if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT)) {
+                 printf("Skipping test: manager_new: %s", strerror(-r));
diff --git a/SOURCES/0458-load-fragment-resolve-specifiers-in-RuntimeDirectory.patch b/SOURCES/0458-load-fragment-resolve-specifiers-in-RuntimeDirectory.patch
new file mode 100644
index 0000000..1107f2b
--- /dev/null
+++ b/SOURCES/0458-load-fragment-resolve-specifiers-in-RuntimeDirectory.patch
@@ -0,0 +1,46 @@
+From 2520d152da83096b42fe7d27cf0bf97a62b50fac Mon Sep 17 00:00:00 2001
+From: Michael Gebetsroither <michael@mgeb.org>
+Date: Thu, 17 Sep 2015 22:54:13 +0200
+Subject: [PATCH] load-fragment: resolve specifiers in RuntimeDirectory
+
+Cherry-picked from: 9b5864d
+Resolves: #1428110
+---
+ src/core/load-fragment.c | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
+index c450fe2..6fc4d74 100644
+--- a/src/core/load-fragment.c
++++ b/src/core/load-fragment.c
+@@ -3384,6 +3384,7 @@ int config_parse_runtime_directory(
+                 void *userdata) {
+ 
+         char***rt = data;
++        Unit *u = userdata;
+         const char *word, *state;
+         size_t l;
+         int r;
+@@ -3401,12 +3402,19 @@ int config_parse_runtime_directory(
+         }
+ 
+         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
+-                _cleanup_free_ char *n;
++                _cleanup_free_ char *t = NULL, *n = NULL;
+ 
+-                n = strndup(word, l);
+-                if (!n)
++                t = strndup(word, l);
++                if (!t)
+                         return log_oom();
+ 
++                r = unit_name_printf(u, t, &n);
++                if (r < 0) {
++                        log_syntax(unit, LOG_ERR, filename, line, -r,
++                                   "Failed to resolve specifiers, ignoring: %s", strerror(-r));
++                        continue;
++                }
++
+                 if (!filename_is_valid(n)) {
+                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                                    "Runtime directory is not valid, ignoring assignment: %s", rvalue);
diff --git a/SOURCES/0459-Add-microphone-mute-keymap-for-Dell-Precision.patch b/SOURCES/0459-Add-microphone-mute-keymap-for-Dell-Precision.patch
new file mode 100644
index 0000000..35371ba
--- /dev/null
+++ b/SOURCES/0459-Add-microphone-mute-keymap-for-Dell-Precision.patch
@@ -0,0 +1,25 @@
+From 80d1022b06ca59190fab4bff0bb9c0acc57e9435 Mon Sep 17 00:00:00 2001
+From: "Chen-Han Hsiao (Stanley)" <stanley.hsiao@canonical.com>
+Date: Thu, 10 Sep 2015 11:20:50 +0800
+Subject: [PATCH] Add microphone mute keymap for Dell Precision
+
+(cherry picked from commit 6e675e278c04bd5662914888a2b3cf856d743659)
+
+Resolves: #1413477
+---
+ hwdb/60-keyboard.hwdb | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/hwdb/60-keyboard.hwdb b/hwdb/60-keyboard.hwdb
+index 8890665..a7ae2f8 100644
+--- a/hwdb/60-keyboard.hwdb
++++ b/hwdb/60-keyboard.hwdb
+@@ -263,6 +263,8 @@ keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnXPS12-9Q33*:pvr*
+ 
+ # Dell Latitude microphone mute
+ keyboard:name:Dell WMI hotkeys:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*
++# Dell Precision microphone mute
++keyboard:name:Dell WMI hotkeys:dmi:bvn*:bvr*:bd*:svnDell*:pnPrecision*
+  KEYBOARD_KEY_150=f20                                   # Mic mute toggle, should be micmute
+ 
+ ###########################################################
diff --git a/SOURCES/0460-hwdb-update-micmute-YCODE-on-device-node-at-DELL-LAT.patch b/SOURCES/0460-hwdb-update-micmute-YCODE-on-device-node-at-DELL-LAT.patch
new file mode 100644
index 0000000..54d6f0c
--- /dev/null
+++ b/SOURCES/0460-hwdb-update-micmute-YCODE-on-device-node-at-DELL-LAT.patch
@@ -0,0 +1,26 @@
+From 96d51b2f972c0de259c4d52471894cfac5d85872 Mon Sep 17 00:00:00 2001
+From: nikolaof <fikasnikolaos@gmail.com>
+Date: Wed, 11 Jan 2017 15:35:20 +0200
+Subject: [PATCH] hwdb: update micmute YCODE on device node at DELL LATITUDE
+ laptops for mic mute button. (#5012)
+
+(cherry picked from commit fc6e082622c73eb9a22ce16a278d8c4dd7594cbb)
+
+Related: #1413477
+---
+ hwdb/60-keyboard.hwdb | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/hwdb/60-keyboard.hwdb b/hwdb/60-keyboard.hwdb
+index a7ae2f8..a9cd73b 100644
+--- a/hwdb/60-keyboard.hwdb
++++ b/hwdb/60-keyboard.hwdb
+@@ -265,7 +265,7 @@ keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnXPS12-9Q33*:pvr*
+ keyboard:name:Dell WMI hotkeys:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*
+ # Dell Precision microphone mute
+ keyboard:name:Dell WMI hotkeys:dmi:bvn*:bvr*:bd*:svnDell*:pnPrecision*
+- KEYBOARD_KEY_150=f20                                   # Mic mute toggle, should be micmute
++ KEYBOARD_KEY_100150=f20                                # Mic mute toggle, should be micmute
+ 
+ ###########################################################
+ # Everex
diff --git a/SOURCES/0461-udev-path_id-improve-and-enhance-bus-detection-for-L.patch b/SOURCES/0461-udev-path_id-improve-and-enhance-bus-detection-for-L.patch
new file mode 100644
index 0000000..e825b29
--- /dev/null
+++ b/SOURCES/0461-udev-path_id-improve-and-enhance-bus-detection-for-L.patch
@@ -0,0 +1,163 @@
+From b9146e4dab45e2f76ceca3772564c0f01e227a9f Mon Sep 17 00:00:00 2001
+From: Liu Yuan Yuan <bjyyliu@linux.vnet.ibm.com>
+Date: Fri, 13 Nov 2015 11:50:42 +0100
+Subject: [PATCH] udev/path_id: improve and enhance bus detection for Linux on
+ z Systems
+
+Improve and enhance the path_id udev builtin to correctly handle bus'
+available on Linux on z Systems (s390).
+
+Previously, the CCW bus and, in particular, any FCP devices on it, have
+been treated separately.  This commit integrates the CCW bus into the
+device chain loop.  FCP devices and their associated SCSI disks are now
+handled through the common SCSI handling functions in path_id.
+
+This implies also a change in the naming of the symbolic links created
+by udev.  So any backports of this commit to existing Linux distribution
+must be done with care.  If a backport is required, a udev rule must be
+created to also create the "old-style" symbolic links.
+
+Apart from the CCW bus, this commit adds bus support for the:
+
+- ccwgroup bus which manages network devices, and
+- ap bus which manages cryptographic adapters
+- iucv bus which manages IUCV devices on z/VM
+
+Cherry-picked from: e7eb5a8d88367a755944fdda3023a308e5272953
+Resolves: #1274401
+---
+ rules/40-redhat.rules           | 25 ++++++++++++++++
+ src/udev/udev-builtin-path_id.c | 63 +++++++++++++++++++++++------------------
+ 2 files changed, 60 insertions(+), 28 deletions(-)
+
+diff --git a/rules/40-redhat.rules b/rules/40-redhat.rules
+index 0164dc9..c928d41 100644
+--- a/rules/40-redhat.rules
++++ b/rules/40-redhat.rules
+@@ -15,3 +15,28 @@ SUBSYSTEM=="scsi", ENV{DEVTYPE}=="scsi_target", TEST!="[module/sg]", RUN+="/sbin
+ 
+ # Rule for prandom character device node permissions
+ KERNEL=="prandom", MODE="0644"
++
++
++# Rules for creating the ID_PATH for SCSI devices based on the CCW bus
++# using the form: ccw-<BUS_ID>-zfcp-<WWPN>:<LUN>
++#
++ACTION=="remove", GOTO="zfcp_scsi_device_end"
++
++#
++# Set environment variable "ID_ZFCP_BUS" to "1" if the devices
++# (both disk and partition) are SCSI devices based on FCP devices
++#
++KERNEL=="sd*", SUBSYSTEMS=="ccw", DRIVERS=="zfcp", ENV{.ID_ZFCP_BUS}="1"
++
++# For SCSI disks
++KERNEL=="sd*[!0-9]", SUBSYSTEMS=="scsi",
++        ENV{.ID_ZFCP_BUS}=="1", ENV{DEVTYPE}=="disk",
++        SYMLINK+="disk/by-path/ccw-$attr{hba_id}-zfcp-$attr{wwpn}:$attr{fcp_lun}"
++
++
++# For partitions on a SCSI disk
++KERNEL=="sd*[0-9]", SUBSYSTEMS=="scsi",
++        ENV{.ID_ZFCP_BUS}=="1", ENV{DEVTYPE}=="partition",
++        SYMLINK+="disk/by-path/ccw-$attr{hba_id}-zfcp-$attr{wwpn}:$attr{fcp_lun}-part%n"
++
++LABEL="zfcp_scsi_device_end"
+diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c
+index 88a812f..1944720 100644
+--- a/src/udev/udev-builtin-path_id.c
++++ b/src/udev/udev-builtin-path_id.c
+@@ -615,27 +615,23 @@ static struct udev_device *handle_bcma(struct udev_device *parent, char **path)
+         return parent;
+ }
+ 
+-static struct udev_device *handle_ccw(struct udev_device *parent, struct udev_device *dev, char **path) {
+-        struct udev_device *scsi_dev;
+-
+-        scsi_dev = udev_device_get_parent_with_subsystem_devtype(dev, "scsi", "scsi_device");
+-        if (scsi_dev != NULL) {
+-                const char *wwpn;
+-                const char *lun;
+-                const char *hba_id;
+-
+-                hba_id = udev_device_get_sysattr_value(scsi_dev, "hba_id");
+-                wwpn = udev_device_get_sysattr_value(scsi_dev, "wwpn");
+-                lun = udev_device_get_sysattr_value(scsi_dev, "fcp_lun");
+-                if (hba_id != NULL && lun != NULL && wwpn != NULL) {
+-                        path_prepend(path, "ccw-%s-zfcp-%s:%s", hba_id, wwpn, lun);
+-                        goto out;
+-                }
+-        }
++/* Handle devices of AP bus in System z platform. */
++static struct udev_device *handle_ap(struct udev_device *parent, char **path) {
++        const char *type, *func;
++
++        assert(parent);
++        assert(path);
++
++        type = udev_device_get_sysattr_value(parent, "type");
++        func = udev_device_get_sysattr_value(parent, "ap_functions");
+ 
+-        path_prepend(path, "ccw-%s", udev_device_get_sysname(parent));
++        if (type != NULL && func != NULL) {
++                path_prepend(path, "ap-%s-%s", type, func);
++                goto out;
++        }
++        path_prepend(path, "ap-%s", udev_device_get_sysname(parent));
+ out:
+-        parent = skip_subsystem(parent, "ccw");
++        parent = skip_subsystem(parent, "ap");
+         return parent;
+ }
+ 
+@@ -647,15 +643,8 @@ static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool
+         bool new_sas_path = false;
+         bool enable_new_sas_path = true;
+ 
+-        /* S390 ccw bus */
+-        parent = udev_device_get_parent_with_subsystem_devtype(dev, "ccw", NULL);
+-        if (parent != NULL) {
+-                handle_ccw(parent, dev, &path);
+-                goto out;
+-        }
+-
+ restart:
+-        ;
++
+         /* walk up the chain of devices and compose path */
+         parent = dev;
+         while (parent != NULL) {
+@@ -718,6 +707,25 @@ restart:
+                                 supported_parent = true;
+                                 supported_transport = true;
+                         }
++                } else if (streq(subsys, "ccw")) {
++                        path_prepend(&path, "ccw-%s", udev_device_get_sysname(parent));
++                        parent = skip_subsystem(parent, "ccw");
++                        supported_transport = true;
++                        supported_parent = true;
++                } else if (streq(subsys, "ccwgroup")) {
++                        path_prepend(&path, "ccwgroup-%s", udev_device_get_sysname(parent));
++                        parent = skip_subsystem(parent, "ccwgroup");
++                        supported_transport = true;
++                        supported_parent = true;
++                } else if (streq(subsys, "ap")) {
++                        parent = handle_ap(parent, &path);
++                        supported_transport = true;
++                        supported_parent = true;
++                } else if (streq(subsys, "iucv")) {
++                        path_prepend(&path, "iucv-%s", udev_device_get_sysname(parent));
++                        parent = skip_subsystem(parent, "iucv");
++                        supported_transport = true;
++                        supported_parent = true;
+                 }
+ 
+                 parent = udev_device_get_parent(parent);
+@@ -743,7 +751,6 @@ restart:
+                 path = NULL;
+         }
+ 
+-out:
+         if (path != NULL) {
+                 char tag[UTIL_NAME_SIZE];
+                 size_t i;
diff --git a/SOURCES/0462-core-port-config_parse_bounding_set-to-extract_first.patch b/SOURCES/0462-core-port-config_parse_bounding_set-to-extract_first.patch
new file mode 100644
index 0000000..987940f
--- /dev/null
+++ b/SOURCES/0462-core-port-config_parse_bounding_set-to-extract_first.patch
@@ -0,0 +1,70 @@
+From f1801ded8014054752356123849f86b6746f2a49 Mon Sep 17 00:00:00 2001
+From: Evgeny Vereshchagin <evvers@ya.ru>
+Date: Fri, 30 Oct 2015 09:25:12 +0300
+Subject: [PATCH] core: port config_parse_bounding_set to extract_first_word
+
+Cherry-picked from: 9ef57298cc57b105c62e2f1dab9ef5837d910604
+Resolves: #1387398
+---
+ src/core/load-fragment.c | 29 ++++++++++++++++++-----------
+ 1 file changed, 18 insertions(+), 11 deletions(-)
+
+diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
+index 6fc4d74..4830d7a 100644
+--- a/src/core/load-fragment.c
++++ b/src/core/load-fragment.c
+@@ -1028,10 +1028,10 @@ int config_parse_bounding_set(const char *unit,
+ 
+         uint64_t *capability_bounding_set_drop = data;
+         uint64_t capability_bounding_set;
+-        const char *word, *state;
+-        size_t l;
+         bool invert = false;
+         uint64_t sum = 0;
++        const char *prev;
++        const char *cur;
+ 
+         assert(filename);
+         assert(lvalue);
+@@ -1048,25 +1048,32 @@ int config_parse_bounding_set(const char *unit,
+          * non-inverted everywhere to have a fully normalized
+          * interface. */
+ 
+-        FOREACH_WORD_QUOTED(word, l, rvalue, state) {
+-                _cleanup_free_ char *t = NULL;
++        prev = cur = rvalue;
++        for (;;) {
++                _cleanup_free_ char *word = NULL;
+                 int cap;
++                int r;
+ 
+-                t = strndup(word, l);
+-                if (!t)
++                r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES);
++                if (r == 0)
++                        break;
++                if (r == -ENOMEM)
+                         return log_oom();
++                if (r < 0) {
++                        log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage in bounding set, ignoring: %s", prev);
++                        break;
++                }
+ 
+-                cap = capability_from_name(t);
++                cap = capability_from_name(word);
+                 if (cap < 0) {
+-                        log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse capability in bounding set, ignoring: %s", t);
++                        log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding set, ignoring: %s", word);
++                        prev = cur;
+                         continue;
+                 }
+ 
+                 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
++                prev = cur;
+         }
+-        if (!isempty(state))
+-                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+-                           "Trailing garbage, ignoring.");
+ 
+         capability_bounding_set = invert ? ~sum : sum;
+         if (*capability_bounding_set_drop && capability_bounding_set)
diff --git a/SOURCES/0463-core-simplify-parsing-of-capability-bounding-set-set.patch b/SOURCES/0463-core-simplify-parsing-of-capability-bounding-set-set.patch
new file mode 100644
index 0000000..e1aaac1
--- /dev/null
+++ b/SOURCES/0463-core-simplify-parsing-of-capability-bounding-set-set.patch
@@ -0,0 +1,100 @@
+From 044455df76969ad26dfdcfa186e5ce81beb5b527 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Tue, 10 Nov 2015 16:08:03 +0100
+Subject: [PATCH] core: simplify parsing of capability bounding set settings
+
+Let's generate a simple error, and that's it. Let's not try to be smart
+and record the last word that failed.
+
+Also, let's make sure we don't compare numeric values with 0 by relying
+on C's downgrade-to-bool feature, as suggested in CODING_STYLE.
+
+Cherry-picked from: 65dce26488030eff078c498673d5d93e3c87b6a1
+Resolves: #1387398
+---
+ src/core/load-fragment.c | 42 +++++++++++++++++++-----------------------
+ 1 file changed, 19 insertions(+), 23 deletions(-)
+
+diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
+index 4830d7a..ab3b0c2 100644
+--- a/src/core/load-fragment.c
++++ b/src/core/load-fragment.c
+@@ -1015,23 +1015,22 @@ int config_parse_exec_secure_bits(const char *unit,
+         return 0;
+ }
+ 
+-int config_parse_bounding_set(const char *unit,
+-                              const char *filename,
+-                              unsigned line,
+-                              const char *section,
+-                              unsigned section_line,
+-                              const char *lvalue,
+-                              int ltype,
+-                              const char *rvalue,
+-                              void *data,
+-                              void *userdata) {
++int config_parse_bounding_set(
++                const char *unit,
++                const char *filename,
++                unsigned line,
++                const char *section,
++                unsigned section_line,
++                const char *lvalue,
++                int ltype,
++                const char *rvalue,
++                void *data,
++                void *userdata) {
+ 
+         uint64_t *capability_bounding_set_drop = data;
+-        uint64_t capability_bounding_set;
++        uint64_t capability_bounding_set, sum = 0;
+         bool invert = false;
+-        uint64_t sum = 0;
+-        const char *prev;
+-        const char *cur;
++        const char *p;
+ 
+         assert(filename);
+         assert(lvalue);
+@@ -1048,35 +1047,32 @@ int config_parse_bounding_set(const char *unit,
+          * non-inverted everywhere to have a fully normalized
+          * interface. */
+ 
+-        prev = cur = rvalue;
++        p = rvalue;
+         for (;;) {
+                 _cleanup_free_ char *word = NULL;
+-                int cap;
+-                int r;
++                int cap, r;
+ 
+-                r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES);
++                r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
+                 if (r == 0)
+                         break;
+                 if (r == -ENOMEM)
+                         return log_oom();
+                 if (r < 0) {
+-                        log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage in bounding set, ignoring: %s", prev);
++                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse word, ignoring: %s", rvalue);
+                         break;
+                 }
+ 
+                 cap = capability_from_name(word);
+                 if (cap < 0) {
+                         log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding set, ignoring: %s", word);
+-                        prev = cur;
+                         continue;
+                 }
+ 
+-                sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
+-                prev = cur;
++                sum |= ((uint64_t) UINT64_C(1)) << (uint64_t) cap;
+         }
+ 
+         capability_bounding_set = invert ? ~sum : sum;
+-        if (*capability_bounding_set_drop && capability_bounding_set)
++        if (*capability_bounding_set_drop != 0 && capability_bounding_set != 0)
+                 *capability_bounding_set_drop = ~(~*capability_bounding_set_drop | capability_bounding_set);
+         else
+                 *capability_bounding_set_drop = ~capability_bounding_set;
diff --git a/SOURCES/0464-test-add-test-for-capability-bounding-set-parsing.patch b/SOURCES/0464-test-add-test-for-capability-bounding-set-parsing.patch
new file mode 100644
index 0000000..b149dd6
--- /dev/null
+++ b/SOURCES/0464-test-add-test-for-capability-bounding-set-parsing.patch
@@ -0,0 +1,88 @@
+From cac429e0a75667c021782210045c8e365f5cc8b0 Mon Sep 17 00:00:00 2001
+From: Evgeny Vereshchagin <evvers@ya.ru>
+Date: Thu, 29 Oct 2015 14:12:22 +0300
+Subject: [PATCH] test: add test for capability bounding set parsing
+
+Cherry-picked from: a8107a54
+Resolves: #1387398
+---
+ src/test/test-unit-file.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 45 insertions(+)
+
+diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c
+index 0384305..0f00a8f 100644
+--- a/src/test/test-unit-file.c
++++ b/src/test/test-unit-file.c
+@@ -24,6 +24,7 @@
+ #include <stdio.h>
+ #include <stddef.h>
+ #include <string.h>
++#include <sys/capability.h>
+ #include <unistd.h>
+ #include <fcntl.h>
+ 
+@@ -545,6 +546,9 @@ static void test_install_printf(void) {
+         expect(i4, "%U", "0");
+ }
+ 
++static uint64_t make_cap(int cap) {
++        return ((uint64_t) 1ULL << (uint64_t) cap);
++}
+ 
+ static void test_config_parse_rlimit(void) {
+         struct rlimit * rl[_RLIMIT_MAX] = {};
+@@ -661,6 +665,46 @@ static void test_config_parse_rlimit(void) {
+         free(rl[RLIMIT_RTTIME]);
+ }
+ 
++static void test_config_parse_bounding_set(void) {
++        /* int config_parse_bounding_set(
++                 const char *unit,
++                 const char *filename,
++                 unsigned line,
++                 const char *section,
++                 unsigned section_line,
++                 const char *lvalue,
++                 int ltype,
++                 const char *rvalue,
++                 void *data,
++                 void *userdata) */
++        int r;
++        uint64_t capability_bounding_set_drop = 0;
++
++        r = config_parse_bounding_set(NULL, "fake", 1, "section", 1,
++                              "CapabilityBoundingSet", 0, "CAP_NET_RAW",
++                              &capability_bounding_set_drop, NULL);
++        assert_se(r >= 0);
++        assert_se(capability_bounding_set_drop == ~make_cap(CAP_NET_RAW));
++
++        r = config_parse_bounding_set(NULL, "fake", 1, "section", 1,
++                              "CapabilityBoundingSet", 0, "CAP_NET_ADMIN",
++                              &capability_bounding_set_drop, NULL);
++        assert_se(r >= 0);
++        assert_se(capability_bounding_set_drop == ~(make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN)));
++
++        r = config_parse_bounding_set(NULL, "fake", 1, "section", 1,
++                              "CapabilityBoundingSet", 0, "",
++                              &capability_bounding_set_drop, NULL);
++        assert_se(r >= 0);
++        assert_se(capability_bounding_set_drop == ~((uint64_t) 0ULL));
++
++        r = config_parse_bounding_set(NULL, "fake", 1, "section", 1,
++                              "CapabilityBoundingSet", 0, "~",
++                              &capability_bounding_set_drop, NULL);
++        assert_se(r >= 0);
++        assert_se(capability_bounding_set_drop == (uint64_t) 0ULL);
++}
++
+ int main(int argc, char *argv[]) {
+         int r;
+ 
+@@ -670,6 +714,7 @@ int main(int argc, char *argv[]) {
+         r = test_unit_file_get_set();
+         test_config_parse_exec();
+         test_config_parse_rlimit();
++        test_config_parse_bounding_set();
+         test_load_env_file_1();
+         test_load_env_file_2();
+         test_load_env_file_3();
diff --git a/SOURCES/0465-capabilities-keep-bounding-set-in-non-inverted-forma.patch b/SOURCES/0465-capabilities-keep-bounding-set-in-non-inverted-forma.patch
new file mode 100644
index 0000000..73904e0
--- /dev/null
+++ b/SOURCES/0465-capabilities-keep-bounding-set-in-non-inverted-forma.patch
@@ -0,0 +1,473 @@
+From 201006fa521199ebf109016c9dd22812c435dfe9 Mon Sep 17 00:00:00 2001
+From: Ismo Puustinen <ismo.puustinen@intel.com>
+Date: Fri, 8 Jan 2016 00:00:04 +0200
+Subject: [PATCH] capabilities: keep bounding set in non-inverted format.
+
+Change the capability bounding set parser and logic so that the bounding
+set is kept as a positive set internally. This means that the set
+reflects those capabilities that we want to keep instead of drop.
+
+Resolves: #1387398
+---
+ src/core/dbus-execute.c               |  4 +-
+ src/core/execute.c                    |  9 ++--
+ src/core/execute.h                    |  2 +-
+ src/core/load-fragment-gperf.gperf.m4 |  2 +-
+ src/core/load-fragment.c              | 25 +++++-----
+ src/core/load-fragment.h              |  2 +-
+ src/core/main.c                       | 10 ++--
+ src/core/unit.c                       |  2 +-
+ src/import/import-common.c            |  2 +-
+ src/nspawn/nspawn.c                   |  2 +-
+ src/shared/capability.c               | 16 +++----
+ src/shared/capability.h               | 12 ++++-
+ src/test/test-unit-file.c             | 89 +++++++++++++++++++----------------
+ 13 files changed, 96 insertions(+), 81 deletions(-)
+
+diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
+index da8b10d..a564c53 100644
+--- a/src/core/dbus-execute.c
++++ b/src/core/dbus-execute.c
+@@ -324,9 +324,7 @@ static int property_get_capability_bounding_set(
+         assert(reply);
+         assert(c);
+ 
+-        /* We store this negated internally, to match the kernel, but
+-         * we expose it normalized. */
+-        return sd_bus_message_append(reply, "t", ~c->capability_bounding_set_drop);
++        return sd_bus_message_append(reply, "t", c->capability_bounding_set);
+ }
+ 
+ static int property_get_capabilities(
+diff --git a/src/core/execute.c b/src/core/execute.c
+index f72b209..40db11e 100644
+--- a/src/core/execute.c
++++ b/src/core/execute.c
+@@ -1733,8 +1733,8 @@ static int exec_child(
+                         }
+                 }
+ 
+-                if (context->capability_bounding_set_drop) {
+-                        r = capability_bounding_set_drop(context->capability_bounding_set_drop, false);
++                if (!cap_test_all(context->capability_bounding_set)) {
++                        r = capability_bounding_set_drop(context->capability_bounding_set, false);
+                         if (r < 0) {
+                                 *exit_status = EXIT_CAPABILITIES;
+                                 return r;
+@@ -1988,6 +1988,7 @@ void exec_context_init(ExecContext *c) {
+         c->timer_slack_nsec = NSEC_INFINITY;
+         c->personality = 0xffffffffUL;
+         c->runtime_directory_mode = 0755;
++        c->capability_bounding_set = CAP_ALL;
+ }
+ 
+ void exec_context_done(ExecContext *c) {
+@@ -2419,12 +2420,12 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
+                         (c->secure_bits & 1<<SECURE_NOROOT) ? " noroot" : "",
+                         (c->secure_bits & 1<<SECURE_NOROOT_LOCKED) ? "noroot-locked" : "");
+ 
+-        if (c->capability_bounding_set_drop) {
++        if (c->capability_bounding_set != CAP_ALL) {
+                 unsigned long l;
+                 fprintf(f, "%sCapabilityBoundingSet:", prefix);
+ 
+                 for (l = 0; l <= cap_last_cap(); l++)
+-                        if (!(c->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) l)))
++                        if (c->capability_bounding_set & (UINT64_C(1) << l))
+                                 fprintf(f, " %s", strna(capability_to_name(l)));
+ 
+                 fputs("\n", f);
+diff --git a/src/core/execute.h b/src/core/execute.h
+index cadd0e6..40f7b79 100644
+--- a/src/core/execute.h
++++ b/src/core/execute.h
+@@ -150,7 +150,7 @@ struct ExecContext {
+         char **read_write_dirs, **read_only_dirs, **inaccessible_dirs;
+         unsigned long mount_flags;
+ 
+-        uint64_t capability_bounding_set_drop;
++        uint64_t capability_bounding_set;
+ 
+         cap_t capabilities;
+         int secure_bits;
+diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
+index b50fe45..e4ce292 100644
+--- a/src/core/load-fragment-gperf.gperf.m4
++++ b/src/core/load-fragment-gperf.gperf.m4
+@@ -47,7 +47,7 @@ $1.SyslogLevel,                  config_parse_log_level,             0,
+ $1.SyslogLevelPrefix,            config_parse_bool,                  0,                             offsetof($1, exec_context.syslog_level_prefix)
+ $1.Capabilities,                 config_parse_exec_capabilities,     0,                             offsetof($1, exec_context)
+ $1.SecureBits,                   config_parse_exec_secure_bits,      0,                             offsetof($1, exec_context)
+-$1.CapabilityBoundingSet,        config_parse_bounding_set,          0,                             offsetof($1, exec_context.capability_bounding_set_drop)
++$1.CapabilityBoundingSet,        config_parse_capability_set,        0,                             offsetof($1, exec_context.capability_bounding_set)
+ $1.TimerSlackNSec,               config_parse_nsec,                  0,                             offsetof($1, exec_context.timer_slack_nsec)
+ $1.NoNewPrivileges,              config_parse_no_new_privileges,     0,                             offsetof($1, exec_context)
+ m4_ifdef(`HAVE_SECCOMP',
+diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
+index ab3b0c2..dbaaf2f 100644
+--- a/src/core/load-fragment.c
++++ b/src/core/load-fragment.c
+@@ -1015,7 +1015,7 @@ int config_parse_exec_secure_bits(const char *unit,
+         return 0;
+ }
+ 
+-int config_parse_bounding_set(
++int config_parse_capability_set(
+                 const char *unit,
+                 const char *filename,
+                 unsigned line,
+@@ -1027,8 +1027,8 @@ int config_parse_bounding_set(
+                 void *data,
+                 void *userdata) {
+ 
+-        uint64_t *capability_bounding_set_drop = data;
+-        uint64_t capability_bounding_set, sum = 0;
++        uint64_t *capability_set = data;
++        uint64_t sum = 0, initial = 0;
+         bool invert = false;
+         const char *p;
+ 
+@@ -1042,10 +1042,8 @@ int config_parse_bounding_set(
+                 rvalue++;
+         }
+ 
+-        /* Note that we store this inverted internally, since the
+-         * kernel wants it like this. But we actually expose it
+-         * non-inverted everywhere to have a fully normalized
+-         * interface. */
++        if (strcmp(lvalue, "CapabilityBoundingSet") == 0)
++                initial = CAP_ALL; /* initialized to all bits on */
+ 
+         p = rvalue;
+         for (;;) {
+@@ -1071,11 +1069,14 @@ int config_parse_bounding_set(
+                 sum |= ((uint64_t) UINT64_C(1)) << (uint64_t) cap;
+         }
+ 
+-        capability_bounding_set = invert ? ~sum : sum;
+-        if (*capability_bounding_set_drop != 0 && capability_bounding_set != 0)
+-                *capability_bounding_set_drop = ~(~*capability_bounding_set_drop | capability_bounding_set);
++        sum = invert ? ~sum : sum;
++
++        if (sum == 0 || *capability_set == initial)
++                /* "" or uninitialized data -> replace */
++                *capability_set = sum;
+         else
+-                *capability_bounding_set_drop = ~capability_bounding_set;
++                /* previous data -> merge */
++                *capability_set |= sum;
+ 
+         return 0;
+ }
+@@ -4050,7 +4051,7 @@ void unit_dump_config_items(FILE *f) {
+                 { config_parse_log_level,             "LEVEL" },
+                 { config_parse_exec_capabilities,     "CAPABILITIES" },
+                 { config_parse_exec_secure_bits,      "SECUREBITS" },
+-                { config_parse_bounding_set,          "BOUNDINGSET" },
++                { config_parse_capability_set,        "BOUNDINGSET" },
+                 { config_parse_limit,                 "LIMIT" },
+                 { config_parse_unit_deps,             "UNIT [...]" },
+                 { config_parse_exec,                  "PATH [ARGUMENT [...]]" },
+diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
+index 9dd7d1b..2059353 100644
+--- a/src/core/load-fragment.h
++++ b/src/core/load-fragment.h
+@@ -54,7 +54,7 @@ int config_parse_exec_cpu_sched_prio(const char *unit, const char *filename, uns
+ int config_parse_exec_cpu_affinity(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+ int config_parse_exec_capabilities(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+ int config_parse_exec_secure_bits(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+-int config_parse_bounding_set(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
++int config_parse_capability_set(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+ int config_parse_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+ int config_parse_bytes_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+ int config_parse_sec_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+diff --git a/src/core/main.c b/src/core/main.c
+index a0df1e5..cba992c 100644
+--- a/src/core/main.c
++++ b/src/core/main.c
+@@ -108,7 +108,7 @@ static usec_t arg_runtime_watchdog = 0;
+ static usec_t arg_shutdown_watchdog = 10 * USEC_PER_MINUTE;
+ static char **arg_default_environment = NULL;
+ static struct rlimit *arg_default_rlimit[_RLIMIT_MAX] = {};
+-static uint64_t arg_capability_bounding_set_drop = 0;
++static uint64_t arg_capability_bounding_set = CAP_ALL;
+ static nsec_t arg_timer_slack_nsec = NSEC_INFINITY;
+ static usec_t arg_default_timer_accuracy_usec = 1 * USEC_PER_MINUTE;
+ static Set* arg_syscall_archs = NULL;
+@@ -642,7 +642,7 @@ static int parse_config_file(void) {
+                 { "Manager", "JoinControllers",           config_parse_join_controllers, 0, &arg_join_controllers                  },
+                 { "Manager", "RuntimeWatchdogSec",        config_parse_sec,              0, &arg_runtime_watchdog                  },
+                 { "Manager", "ShutdownWatchdogSec",       config_parse_sec,              0, &arg_shutdown_watchdog                 },
+-                { "Manager", "CapabilityBoundingSet",     config_parse_bounding_set,     0, &arg_capability_bounding_set_drop      },
++                { "Manager", "CapabilityBoundingSet",     config_parse_capability_set,   0, &arg_capability_bounding_set           },
+ #ifdef HAVE_SECCOMP
+                 { "Manager", "SystemCallArchitectures",   config_parse_syscall_archs,    0, &arg_syscall_archs                     },
+ #endif
+@@ -1622,14 +1622,14 @@ int main(int argc, char *argv[]) {
+                 if (prctl(PR_SET_TIMERSLACK, arg_timer_slack_nsec) < 0)
+                         log_error_errno(errno, "Failed to adjust timer slack: %m");
+ 
+-        if (arg_capability_bounding_set_drop) {
+-                r = capability_bounding_set_drop_usermode(arg_capability_bounding_set_drop);
++        if (!cap_test_all(arg_capability_bounding_set)) {
++                r = capability_bounding_set_drop_usermode(arg_capability_bounding_set);
+                 if (r < 0) {
+                         log_emergency_errno(r, "Failed to drop capability bounding set of usermode helpers: %m");
+                         error_message = "Failed to drop capability bounding set of usermode helpers";
+                         goto finish;
+                 }
+-                r = capability_bounding_set_drop(arg_capability_bounding_set_drop, true);
++                r = capability_bounding_set_drop(arg_capability_bounding_set, true);
+                 if (r < 0) {
+                         log_emergency_errno(r, "Failed to drop capability bounding set: %m");
+                         error_message = "Failed to drop capability bounding set";
+diff --git a/src/core/unit.c b/src/core/unit.c
+index 4eb0d78..103f920 100644
+--- a/src/core/unit.c
++++ b/src/core/unit.c
+@@ -3213,7 +3213,7 @@ int unit_patch_contexts(Unit *u) {
+                         ec->no_new_privileges = true;
+ 
+                 if (ec->private_devices)
+-                        ec->capability_bounding_set_drop |= (uint64_t) 1ULL << (uint64_t) CAP_MKNOD;
++                        ec->capability_bounding_set &= ~(UINT64_C(1) << CAP_MKNOD);
+         }
+ 
+         cc = unit_get_cgroup_context(u);
+diff --git a/src/import/import-common.c b/src/import/import-common.c
+index f10a453..243e657 100644
+--- a/src/import/import-common.c
++++ b/src/import/import-common.c
+@@ -526,7 +526,7 @@ int import_fork_tar(const char *path, pid_t *ret) {
+                 if (unshare(CLONE_NEWNET) < 0)
+                         log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
+ 
+-                r = capability_bounding_set_drop(~retain, true);
++                r = capability_bounding_set_drop(retain, true);
+                 if (r < 0)
+                         log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
+ 
+diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
+index a37b640..d0003d3 100644
+--- a/src/nspawn/nspawn.c
++++ b/src/nspawn/nspawn.c
+@@ -1863,7 +1863,7 @@ static int setup_journal(const char *directory) {
+ }
+ 
+ static int drop_capabilities(void) {
+-        return capability_bounding_set_drop(~arg_retain, false);
++        return capability_bounding_set_drop(arg_retain, false);
+ }
+ 
+ static int register_machine(pid_t pid, int local_ifindex) {
+diff --git a/src/shared/capability.c b/src/shared/capability.c
+index 2b963fd..3ed31df 100644
+--- a/src/shared/capability.c
++++ b/src/shared/capability.c
+@@ -98,7 +98,7 @@ unsigned long cap_last_cap(void) {
+         return p;
+ }
+ 
+-int capability_bounding_set_drop(uint64_t drop, bool right_now) {
++int capability_bounding_set_drop(uint64_t keep, bool right_now) {
+         _cleanup_cap_free_ cap_t after_cap = NULL;
+         cap_flag_value_t fv;
+         unsigned long i;
+@@ -139,7 +139,7 @@ int capability_bounding_set_drop(uint64_t drop, bool right_now) {
+ 
+         for (i = 0; i <= cap_last_cap(); i++) {
+ 
+-                if (drop & ((uint64_t) 1ULL << (uint64_t) i)) {
++                if (!(keep & (UINT64_C(1) << i))) {
+                         cap_value_t v;
+ 
+                         /* Drop it from the bounding set */
+@@ -178,7 +178,7 @@ finish:
+         return r;
+ }
+ 
+-static int drop_from_file(const char *fn, uint64_t drop) {
++static int drop_from_file(const char *fn, uint64_t keep) {
+         int r, k;
+         uint32_t hi, lo;
+         uint64_t current, after;
+@@ -198,7 +198,7 @@ static int drop_from_file(const char *fn, uint64_t drop) {
+                 return -EIO;
+ 
+         current = (uint64_t) lo | ((uint64_t) hi << 32ULL);
+-        after = current & ~drop;
++        after = current & keep;
+ 
+         if (current == after)
+                 return 0;
+@@ -215,14 +215,14 @@ static int drop_from_file(const char *fn, uint64_t drop) {
+         return r;
+ }
+ 
+-int capability_bounding_set_drop_usermode(uint64_t drop) {
++int capability_bounding_set_drop_usermode(uint64_t keep) {
+         int r;
+ 
+-        r = drop_from_file("/proc/sys/kernel/usermodehelper/inheritable", drop);
++        r = drop_from_file("/proc/sys/kernel/usermodehelper/inheritable", keep);
+         if (r < 0)
+                 return r;
+ 
+-        r = drop_from_file("/proc/sys/kernel/usermodehelper/bset", drop);
++        r = drop_from_file("/proc/sys/kernel/usermodehelper/bset", keep);
+         if (r < 0)
+                 return r;
+ 
+@@ -259,7 +259,7 @@ int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities) {
+                 return log_error_errno(errno, "Failed to disable keep capabilities flag: %m");
+ 
+         /* Drop all caps from the bounding set, except the ones we want */
+-        r = capability_bounding_set_drop(~keep_capabilities, true);
++        r = capability_bounding_set_drop(keep_capabilities, true);
+         if (r < 0)
+                 return log_error_errno(r, "Failed to drop capabilities: %m");
+ 
+diff --git a/src/shared/capability.h b/src/shared/capability.h
+index 6f2f6f9..04cd6e5 100644
+--- a/src/shared/capability.h
++++ b/src/shared/capability.h
+@@ -27,10 +27,12 @@
+ 
+ #include "util.h"
+ 
++#define CAP_ALL (uint64_t) -1
++
+ unsigned long cap_last_cap(void);
+ int have_effective_cap(int value);
+-int capability_bounding_set_drop(uint64_t drop, bool right_now);
+-int capability_bounding_set_drop_usermode(uint64_t drop);
++int capability_bounding_set_drop(uint64_t keep, bool right_now);
++int capability_bounding_set_drop_usermode(uint64_t keep);
+ 
+ int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilites);
+ 
+@@ -44,3 +46,9 @@ static inline void cap_free_charpp(char **p) {
+                 cap_free(*p);
+ }
+ #define _cleanup_cap_free_charp_ _cleanup_(cap_free_charpp)
++
++static inline bool cap_test_all(uint64_t caps) {
++        uint64_t m;
++        m = (UINT64_C(1) << (cap_last_cap() + 1)) - 1;
++        return (caps & m) == m;
++}
+diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c
+index 0f00a8f..38ecfe9 100644
+--- a/src/test/test-unit-file.c
++++ b/src/test/test-unit-file.c
+@@ -550,6 +550,53 @@ static uint64_t make_cap(int cap) {
+         return ((uint64_t) 1ULL << (uint64_t) cap);
+ }
+ 
++static void test_config_parse_capability_set(void) {
++        /* int config_parse_capability_set(
++                 const char *unit,
++                 const char *filename,
++                 unsigned line,
++                 const char *section,
++                 unsigned section_line,
++                 const char *lvalue,
++                 int ltype,
++                 const char *rvalue,
++                 void *data,
++                 void *userdata) */
++        int r;
++        uint64_t capability_bounding_set = 0;
++
++        r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
++                              "CapabilityBoundingSet", 0, "CAP_NET_RAW",
++                              &capability_bounding_set, NULL);
++        assert_se(r >= 0);
++        assert_se(capability_bounding_set == make_cap(CAP_NET_RAW));
++
++        r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
++                              "CapabilityBoundingSet", 0, "CAP_NET_ADMIN",
++                              &capability_bounding_set, NULL);
++        assert_se(r >= 0);
++        assert_se(capability_bounding_set == (make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN)));
++
++        r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
++                              "CapabilityBoundingSet", 0, "",
++                              &capability_bounding_set, NULL);
++        assert_se(r >= 0);
++        assert_se(capability_bounding_set == UINT64_C(0));
++
++        r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
++                              "CapabilityBoundingSet", 0, "~",
++                              &capability_bounding_set, NULL);
++        assert_se(r >= 0);
++        assert_se(cap_test_all(capability_bounding_set));
++
++        capability_bounding_set = 0;
++        r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
++                              "CapabilityBoundingSet", 0, "  'CAP_NET_RAW' WAT_CAP??? CAP_NET_ADMIN CAP'_trailing_garbage",
++                              &capability_bounding_set, NULL);
++        assert_se(r >= 0);
++        assert_se(capability_bounding_set == (make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN)));
++}
++
+ static void test_config_parse_rlimit(void) {
+         struct rlimit * rl[_RLIMIT_MAX] = {};
+ 
+@@ -665,46 +712,6 @@ static void test_config_parse_rlimit(void) {
+         free(rl[RLIMIT_RTTIME]);
+ }
+ 
+-static void test_config_parse_bounding_set(void) {
+-        /* int config_parse_bounding_set(
+-                 const char *unit,
+-                 const char *filename,
+-                 unsigned line,
+-                 const char *section,
+-                 unsigned section_line,
+-                 const char *lvalue,
+-                 int ltype,
+-                 const char *rvalue,
+-                 void *data,
+-                 void *userdata) */
+-        int r;
+-        uint64_t capability_bounding_set_drop = 0;
+-
+-        r = config_parse_bounding_set(NULL, "fake", 1, "section", 1,
+-                              "CapabilityBoundingSet", 0, "CAP_NET_RAW",
+-                              &capability_bounding_set_drop, NULL);
+-        assert_se(r >= 0);
+-        assert_se(capability_bounding_set_drop == ~make_cap(CAP_NET_RAW));
+-
+-        r = config_parse_bounding_set(NULL, "fake", 1, "section", 1,
+-                              "CapabilityBoundingSet", 0, "CAP_NET_ADMIN",
+-                              &capability_bounding_set_drop, NULL);
+-        assert_se(r >= 0);
+-        assert_se(capability_bounding_set_drop == ~(make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN)));
+-
+-        r = config_parse_bounding_set(NULL, "fake", 1, "section", 1,
+-                              "CapabilityBoundingSet", 0, "",
+-                              &capability_bounding_set_drop, NULL);
+-        assert_se(r >= 0);
+-        assert_se(capability_bounding_set_drop == ~((uint64_t) 0ULL));
+-
+-        r = config_parse_bounding_set(NULL, "fake", 1, "section", 1,
+-                              "CapabilityBoundingSet", 0, "~",
+-                              &capability_bounding_set_drop, NULL);
+-        assert_se(r >= 0);
+-        assert_se(capability_bounding_set_drop == (uint64_t) 0ULL);
+-}
+-
+ int main(int argc, char *argv[]) {
+         int r;
+ 
+@@ -713,8 +720,8 @@ int main(int argc, char *argv[]) {
+ 
+         r = test_unit_file_get_set();
+         test_config_parse_exec();
++        test_config_parse_capability_set();
+         test_config_parse_rlimit();
+-        test_config_parse_bounding_set();
+         test_load_env_file_1();
+         test_load_env_file_2();
+         test_load_env_file_3();
diff --git a/SOURCES/0466-capabilities-added-support-for-ambient-capabilities.patch b/SOURCES/0466-capabilities-added-support-for-ambient-capabilities.patch
new file mode 100644
index 0000000..148916f
--- /dev/null
+++ b/SOURCES/0466-capabilities-added-support-for-ambient-capabilities.patch
@@ -0,0 +1,397 @@
+From ab2c6236a959fe53109cc36f3642b3a7a2051746 Mon Sep 17 00:00:00 2001
+From: Ismo Puustinen <ismo.puustinen@intel.com>
+Date: Thu, 31 Dec 2015 14:54:44 +0200
+Subject: [PATCH] capabilities: added support for ambient capabilities.
+
+This patch adds support for ambient capabilities in service files. The
+idea with ambient capabilities is that the execed processes can run with
+non-root user and get some inherited capabilities, without having any
+need to add the capabilities to the executable file.
+
+You need at least Linux 4.3 to use ambient capabilities. SecureBit
+keep-caps is automatically added when you use ambient capabilities and
+wish to change the user.
+
+An example system service file might look like this:
+
+[Unit]
+Description=Service for testing caps
+
+[Service]
+ExecStart=/usr/bin/sleep 10000
+User=nobody
+AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW
+
+After starting the service it has these capabilities:
+
+CapInh: 0000000000003000
+CapPrm: 0000000000003000
+CapEff: 0000000000003000
+CapBnd: 0000003fffffffff
+CapAmb: 0000000000003000
+
+Cherry-picked from: 755d4b6
+Resolves: #1387398
+---
+ src/core/dbus-execute.c               | 19 ++++++++
+ src/core/execute.c                    | 90 ++++++++++++++++++++++++++++-------
+ src/core/execute.h                    |  2 +
+ src/core/load-fragment-gperf.gperf.m4 |  1 +
+ src/core/load-fragment.c              |  4 +-
+ src/shared/capability.c               | 55 +++++++++++++++++++++
+ src/shared/capability.h               |  3 ++
+ src/shared/missing.h                  | 16 +++++++
+ src/test/test-unit-file.c             |  1 +
+ 9 files changed, 174 insertions(+), 17 deletions(-)
+
+diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
+index a564c53..817ef80 100644
+--- a/src/core/dbus-execute.c
++++ b/src/core/dbus-execute.c
+@@ -327,6 +327,24 @@ static int property_get_capability_bounding_set(
+         return sd_bus_message_append(reply, "t", c->capability_bounding_set);
+ }
+ 
++static int property_get_ambient_capabilities(
++                sd_bus *bus,
++                const char *path,
++                const char *interface,
++                const char *property,
++                sd_bus_message *reply,
++                void *userdata,
++                sd_bus_error *error) {
++
++        ExecContext *c = userdata;
++
++        assert(bus);
++        assert(reply);
++        assert(c);
++
++        return sd_bus_message_append(reply, "t", c->capability_ambient_set);
++}
++
+ static int property_get_capabilities(
+                 sd_bus *bus,
+                 const char *path,
+@@ -637,6 +655,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
+         SD_BUS_PROPERTY("Capabilities", "s", property_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("CapabilityBoundingSet", "t", property_get_capability_bounding_set, 0, SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("AmbientCapabilities", "t", property_get_ambient_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("User", "s", NULL, offsetof(ExecContext, user), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("Group", "s", NULL, offsetof(ExecContext, group), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("SupplementaryGroups", "as", NULL, offsetof(ExecContext, supplementary_groups), SD_BUS_VTABLE_PROPERTY_CONST),
+diff --git a/src/core/execute.c b/src/core/execute.c
+index 40db11e..4265b9c 100644
+--- a/src/core/execute.c
++++ b/src/core/execute.c
+@@ -696,12 +696,7 @@ static int enforce_user(const ExecContext *context, uid_t uid) {
+         /* Sets (but doesn't lookup) the uid and make sure we keep the
+          * capabilities while doing so. */
+ 
+-        if (context->capabilities) {
+-                _cleanup_cap_free_ cap_t d = NULL;
+-                static const cap_value_t bits[] = {
+-                        CAP_SETUID,   /* Necessary so that we can run setresuid() below */
+-                        CAP_SETPCAP   /* Necessary so that we can set PR_SET_SECUREBITS later on */
+-                };
++        if (context->capabilities || context->capability_ambient_set != 0) {
+ 
+                 /* First step: If we need to keep capabilities but
+                  * drop privileges we need to make sure we keep our
+@@ -717,16 +712,24 @@ static int enforce_user(const ExecContext *context, uid_t uid) {
+                 /* Second step: set the capabilities. This will reduce
+                  * the capabilities to the minimum we need. */
+ 
+-                d = cap_dup(context->capabilities);
+-                if (!d)
+-                        return -errno;
++                if (context->capabilities) {
++                        _cleanup_cap_free_ cap_t d = NULL;
++                        static const cap_value_t bits[] = {
++                                CAP_SETUID,   /* Necessary so that we can run setresuid() below */
++                                CAP_SETPCAP   /* Necessary so that we can set PR_SET_SECUREBITS later on */
++                        };
+ 
+-                if (cap_set_flag(d, CAP_EFFECTIVE, ELEMENTSOF(bits), bits, CAP_SET) < 0 ||
+-                    cap_set_flag(d, CAP_PERMITTED, ELEMENTSOF(bits), bits, CAP_SET) < 0)
+-                        return -errno;
++                        d = cap_dup(context->capabilities);
++                        if (!d)
++                                return -errno;
+ 
+-                if (cap_set_proc(d) < 0)
+-                        return -errno;
++                        if (cap_set_flag(d, CAP_EFFECTIVE, ELEMENTSOF(bits), bits, CAP_SET) < 0 ||
++                            cap_set_flag(d, CAP_PERMITTED, ELEMENTSOF(bits), bits, CAP_SET) < 0)
++                                return -errno;
++
++                        if (cap_set_proc(d) < 0)
++                                return -errno;
++                }
+         }
+ 
+         /* Third step: actually set the uids */
+@@ -1723,6 +1726,8 @@ static int exec_child(
+ 
+         if (params->apply_permissions) {
+ 
++                int secure_bits = context->secure_bits;
++
+                 for (i = 0; i < _RLIMIT_MAX; i++) {
+                         if (!context->rlimit[i])
+                                 continue;
+@@ -1750,6 +1755,30 @@ static int exec_child(
+                         }
+                 }
+ #endif
++                /* This is done before enforce_user, but ambient set
++                 * does not survive over setresuid() if keep_caps is not set. */
++                if (context->capability_ambient_set != 0) {
++                        r = capability_ambient_set_apply(context->capability_ambient_set, true);
++                        if (r < 0) {
++                                *exit_status = EXIT_CAPABILITIES;
++                                return r;
++                        }
++
++                        if (context->capabilities) {
++
++                                /* The capabilities in ambient set need to be also in the inherited
++                                 * set. If they aren't, trying to get them will fail. Add the ambient
++                                 * set inherited capabilities to the capability set in the context.
++                                 * This is needed because if capabilities are set (using "Capabilities="
++                                 * keyword), they will override whatever we set now. */
++
++                                r = capability_update_inherited_set(context->capabilities, context->capability_ambient_set);
++                                if (r < 0) {
++                                        *exit_status = EXIT_CAPABILITIES;
++                                        return r;
++                                }
++                        }
++                }
+ 
+                 if (context->user) {
+                         r = enforce_user(context, uid);
+@@ -1757,14 +1786,32 @@ static int exec_child(
+                                 *exit_status = EXIT_USER;
+                                 return r;
+                         }
++                        if (context->capability_ambient_set != 0) {
++
++                                /* Fix the ambient capabilities after user change. */
++                                r = capability_ambient_set_apply(context->capability_ambient_set, false);
++                                if (r < 0) {
++                                        *exit_status = EXIT_CAPABILITIES;
++                                        return r;
++                                }
++
++                                /* If we were asked to change user and ambient capabilities
++                                 * were requested, we had to add keep-caps to the securebits
++                                 * so that we would maintain the inherited capability set
++                                 * through the setresuid(). Make sure that the bit is added
++                                 * also to the context secure_bits so that we don't try to
++                                 * drop the bit away next. */
++
++                                 secure_bits |= 1<<SECURE_KEEP_CAPS;
++                        }
+                 }
+ 
+                 /* PR_GET_SECUREBITS is not privileged, while
+                  * PR_SET_SECUREBITS is. So to suppress
+                  * potential EPERMs we'll try not to call
+                  * PR_SET_SECUREBITS unless necessary. */
+-                if (prctl(PR_GET_SECUREBITS) != context->secure_bits)
+-                        if (prctl(PR_SET_SECUREBITS, context->secure_bits) < 0) {
++                if (prctl(PR_GET_SECUREBITS) != secure_bits)
++                        if (prctl(PR_SET_SECUREBITS, secure_bits) < 0) {
+                                 *exit_status = EXIT_SECUREBITS;
+                                 return -errno;
+                         }
+@@ -2431,6 +2478,17 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
+                 fputs("\n", f);
+         }
+ 
++        if (c->capability_ambient_set != 0) {
++                unsigned long l;
++                fprintf(f, "%sAmbientCapabilities:", prefix);
++
++                for (l = 0; l <= cap_last_cap(); l++)
++                        if (c->capability_ambient_set & (UINT64_C(1) << l))
++                                fprintf(f, " %s", strna(capability_to_name(l)));
++
++                fputs("\n", f);
++        }
++
+         if (c->user)
+                 fprintf(f, "%sUser: %s\n", prefix, c->user);
+         if (c->group)
+diff --git a/src/core/execute.h b/src/core/execute.h
+index 40f7b79..00bf99c 100644
+--- a/src/core/execute.h
++++ b/src/core/execute.h
+@@ -152,6 +152,8 @@ struct ExecContext {
+ 
+         uint64_t capability_bounding_set;
+ 
++        uint64_t capability_ambient_set;
++
+         cap_t capabilities;
+         int secure_bits;
+ 
+diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
+index e4ce292..f996032 100644
+--- a/src/core/load-fragment-gperf.gperf.m4
++++ b/src/core/load-fragment-gperf.gperf.m4
+@@ -48,6 +48,7 @@ $1.SyslogLevelPrefix,            config_parse_bool,                  0,
+ $1.Capabilities,                 config_parse_exec_capabilities,     0,                             offsetof($1, exec_context)
+ $1.SecureBits,                   config_parse_exec_secure_bits,      0,                             offsetof($1, exec_context)
+ $1.CapabilityBoundingSet,        config_parse_capability_set,        0,                             offsetof($1, exec_context.capability_bounding_set)
++$1.AmbientCapabilities,          config_parse_capability_set,        0,                             offsetof($1, exec_context.capability_ambient_set)
+ $1.TimerSlackNSec,               config_parse_nsec,                  0,                             offsetof($1, exec_context.timer_slack_nsec)
+ $1.NoNewPrivileges,              config_parse_no_new_privileges,     0,                             offsetof($1, exec_context)
+ m4_ifdef(`HAVE_SECCOMP',
+diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
+index dbaaf2f..7d1ac6c 100644
+--- a/src/core/load-fragment.c
++++ b/src/core/load-fragment.c
+@@ -61,6 +61,7 @@
+ #include "af-list.h"
+ #include "cap-list.h"
+ #include "bus-internal.h"
++#include "capability.h"
+ 
+ #ifdef HAVE_SECCOMP
+ #include "seccomp-util.h"
+@@ -1044,6 +1045,7 @@ int config_parse_capability_set(
+ 
+         if (strcmp(lvalue, "CapabilityBoundingSet") == 0)
+                 initial = CAP_ALL; /* initialized to all bits on */
++        /* else "AmbientCapabilities" initialized to all bits off */
+ 
+         p = rvalue;
+         for (;;) {
+@@ -1062,7 +1064,7 @@ int config_parse_capability_set(
+ 
+                 cap = capability_from_name(word);
+                 if (cap < 0) {
+-                        log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding set, ignoring: %s", word);
++                        log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding/ambient set, ignoring: %s", word);
+                         continue;
+                 }
+ 
+diff --git a/src/shared/capability.c b/src/shared/capability.c
+index 3ed31df..6e3d7d2 100644
+--- a/src/shared/capability.c
++++ b/src/shared/capability.c
+@@ -98,6 +98,61 @@ unsigned long cap_last_cap(void) {
+         return p;
+ }
+ 
++int capability_update_inherited_set(cap_t caps, uint64_t set) {
++        unsigned long i;
++
++        /* Add capabilities in the set to the inherited caps. Do not apply
++         * them yet. */
++
++        for (i = 0; i < cap_last_cap(); i++) {
++
++                if (set & (UINT64_C(1) << i)) {
++                        cap_value_t v;
++
++                        v = (cap_value_t) i;
++
++                        /* Make the capability inheritable. */
++                        if (cap_set_flag(caps, CAP_INHERITABLE, 1, &v, CAP_SET) < 0)
++                                return -errno;
++                }
++        }
++
++        return 0;
++}
++
++int capability_ambient_set_apply(uint64_t set, bool also_inherit) {
++        unsigned long i;
++        _cleanup_cap_free_ cap_t caps = NULL;
++
++        /* Add the capabilities to the ambient set. */
++
++        if (also_inherit) {
++                int r;
++                caps = cap_get_proc();
++                if (!caps)
++                        return -errno;
++
++                r = capability_update_inherited_set(caps, set);
++                if (r < 0)
++                        return -errno;
++
++                if (cap_set_proc(caps) < 0)
++                        return -errno;
++        }
++
++        for (i = 0; i < cap_last_cap(); i++) {
++
++                if (set & (UINT64_C(1) << i)) {
++
++                        /* Add the capability to the ambient set. */
++                        if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0) < 0)
++                                return -errno;
++                }
++        }
++
++        return 0;
++}
++
+ int capability_bounding_set_drop(uint64_t keep, bool right_now) {
+         _cleanup_cap_free_ cap_t after_cap = NULL;
+         cap_flag_value_t fv;
+diff --git a/src/shared/capability.h b/src/shared/capability.h
+index 04cd6e5..76a7568 100644
+--- a/src/shared/capability.h
++++ b/src/shared/capability.h
+@@ -36,6 +36,9 @@ int capability_bounding_set_drop_usermode(uint64_t keep);
+ 
+ int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilites);
+ 
++int capability_ambient_set_apply(uint64_t set, bool also_inherit);
++int capability_update_inherited_set(cap_t caps, uint64_t ambient_set);
++
+ int drop_capability(cap_value_t cv);
+ 
+ DEFINE_TRIVIAL_CLEANUP_FUNC(cap_t, cap_free);
+diff --git a/src/shared/missing.h b/src/shared/missing.h
+index 4b36a9c..a7771bc 100644
+--- a/src/shared/missing.h
++++ b/src/shared/missing.h
+@@ -1004,3 +1004,19 @@ static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, uns
+ #ifndef KCMP_FILE
+ #define KCMP_FILE 0
+ #endif
++
++#ifndef PR_CAP_AMBIENT
++#define PR_CAP_AMBIENT 47
++#endif
++
++#ifndef PR_CAP_AMBIENT_IS_SET
++#define PR_CAP_AMBIENT_IS_SET 1
++#endif
++
++#ifndef PR_CAP_AMBIENT_RAISE
++#define PR_CAP_AMBIENT_RAISE 2
++#endif
++
++#ifndef PR_CAP_AMBIENT_CLEAR_ALL
++#define PR_CAP_AMBIENT_CLEAR_ALL 4
++#endif
+diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c
+index 38ecfe9..cfa3d23 100644
+--- a/src/test/test-unit-file.c
++++ b/src/test/test-unit-file.c
+@@ -38,6 +38,7 @@
+ #include "strv.h"
+ #include "fileio.h"
+ #include "test-helper.h"
++#include "capability.h"
+ 
+ static int test_unit_file_get_set(void) {
+         int r;
diff --git a/SOURCES/0467-man-add-AmbientCapabilities-entry.patch b/SOURCES/0467-man-add-AmbientCapabilities-entry.patch
new file mode 100644
index 0000000..bcd8f1c
--- /dev/null
+++ b/SOURCES/0467-man-add-AmbientCapabilities-entry.patch
@@ -0,0 +1,51 @@
+From 734c3a184c3b196412e15e4db1b7419f13b901b4 Mon Sep 17 00:00:00 2001
+From: Ismo Puustinen <ismo.puustinen@intel.com>
+Date: Mon, 11 Jan 2016 09:36:14 +0200
+Subject: [PATCH] man: add AmbientCapabilities entry.
+
+Cherry-picked from: ece8797
+Resolves: #1387398
+---
+ man/systemd.exec.xml | 29 +++++++++++++++++++++++++++++
+ 1 file changed, 29 insertions(+)
+
+diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
+index aa5831c..1b14ced 100644
+--- a/man/systemd.exec.xml
++++ b/man/systemd.exec.xml
+@@ -767,6 +767,35 @@
+       </varlistentry>
+ 
+       <varlistentry>
++        <term><varname>AmbientCapabilities=</varname></term>
++
++        <listitem><para>Controls which capabilities to include in the
++        ambient capability set for the executed process. Takes a
++        whitespace-separated list of capability names as read by
++        <citerefentry project='mankier'><refentrytitle>cap_from_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
++        e.g. <constant>CAP_SYS_ADMIN</constant>,
++        <constant>CAP_DAC_OVERRIDE</constant>,
++        <constant>CAP_SYS_PTRACE</constant>. This option may appear more than
++        once in which case the ambient capability sets are merged.
++        If the list of capabilities is prefixed with <literal>~</literal>, all
++        but the listed capabilities will be included, the effect of the
++        assignment inverted. If the empty string is
++        assigned to this option, the ambient capability set is reset to
++        the empty capability set, and all prior settings have no effect.
++        If set to <literal>~</literal> (without any further argument), the
++        ambient capability set is reset to the full set of available
++        capabilities, also undoing any previous settings. Note that adding
++        capabilities to ambient capability set adds them to the process's
++        inherited capability set.
++        </para><para>
++        Ambient capability sets are useful if you want to execute a process
++        as a non-privileged user but still want to give it some capabilities.
++        Note that in this case option <constant>keep-caps</constant> is
++        automatically added to <varname>SecureBits=</varname> to retain the
++        capabilities over the user change.</para></listitem>
++      </varlistentry>
++
++      <varlistentry>
+         <term><varname>SecureBits=</varname></term>
+         <listitem><para>Controls the secure bits set for the executed
+         process. Takes a space-separated combination of options from
diff --git a/SOURCES/0468-test-capability-rebase-to-upstream-version.patch b/SOURCES/0468-test-capability-rebase-to-upstream-version.patch
new file mode 100644
index 0000000..f450918
--- /dev/null
+++ b/SOURCES/0468-test-capability-rebase-to-upstream-version.patch
@@ -0,0 +1,353 @@
+From 900251c41dab192ff863024e07864c09462e86d2 Mon Sep 17 00:00:00 2001
+From: Lukas Nykryn <lnykryn@redhat.com>
+Date: Mon, 20 Mar 2017 12:24:09 +0100
+Subject: [PATCH] test-capability: rebase to upstream version
+
+Related: #1387398
+---
+ src/test/test-capability.c                         | 80 +++++++++++++++++++---
+ src/test/test-execute.c                            | 43 ++++++++++++
+ ...ec-capabilityambientset-merge-nfsnobody.service |  9 +++
+ test/exec-capabilityambientset-merge.service       |  9 +++
+ test/exec-capabilityambientset-nfsnobody.service   |  8 +++
+ test/exec-capabilityambientset.service             |  8 +++
+ test/exec-capabilityboundingset-invert.service     |  7 ++
+ test/exec-capabilityboundingset-merge.service      |  8 +++
+ test/exec-capabilityboundingset-reset.service      |  8 +++
+ test/exec-capabilityboundingset-simple.service     |  7 ++
+ 10 files changed, 179 insertions(+), 8 deletions(-)
+ create mode 100644 test/exec-capabilityambientset-merge-nfsnobody.service
+ create mode 100644 test/exec-capabilityambientset-merge.service
+ create mode 100644 test/exec-capabilityambientset-nfsnobody.service
+ create mode 100644 test/exec-capabilityambientset.service
+ create mode 100644 test/exec-capabilityboundingset-invert.service
+ create mode 100644 test/exec-capabilityboundingset-merge.service
+ create mode 100644 test/exec-capabilityboundingset-reset.service
+ create mode 100644 test/exec-capabilityboundingset-simple.service
+
+diff --git a/src/test/test-capability.c b/src/test/test-capability.c
+index 4376992..67a9ec2 100644
+--- a/src/test/test-capability.c
++++ b/src/test/test-capability.c
+@@ -17,21 +17,22 @@
+   along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ ***/
+ 
+-#include <sys/types.h>
+-#include <sys/wait.h>
+-#include <sys/capability.h>
+-#include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <pwd.h>
++#include <sys/capability.h>
++#include <sys/prctl.h>
++#include <sys/socket.h>
++#include <sys/wait.h>
+ #include <unistd.h>
+ 
+ #include "capability.h"
+-#include "util.h"
+ #include "macro.h"
++#include "util.h"
+ 
+ static uid_t test_uid = -1;
+ static gid_t test_gid = -1;
+-// We keep CAP_DAC_OVERRIDE to avoid errors with gcov when doing test coverage
++
++/* We keep CAP_DAC_OVERRIDE to avoid errors with gcov when doing test coverage */
+ static uint64_t test_flags = 1ULL << CAP_DAC_OVERRIDE;
+ 
+ static void fork_test(void (*test_func)(void)) {
+@@ -65,8 +66,9 @@ static void show_capabilities(void) {
+         cap_free(text);
+ }
+ 
+-static int setup_tests(void) {
++static int setup_tests(bool *run_ambient) {
+         struct passwd *nobody;
++        int r;
+ 
+         nobody = getpwnam("nobody");
+         if (!nobody) {
+@@ -76,6 +78,18 @@ static int setup_tests(void) {
+         test_uid = nobody->pw_uid;
+         test_gid = nobody->pw_gid;
+ 
++        *run_ambient = false;
++
++        r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
++
++        /* There's support for PR_CAP_AMBIENT if the prctl() call
++         * succeeded or error code was something else than EINVAL. The
++         * EINVAL check should be good enough to rule out false
++         * positives. */
++
++        if (r >= 0 || errno != EINVAL)
++                *run_ambient = true;
++
+         return 0;
+ }
+ 
+@@ -139,8 +153,53 @@ static void test_have_effective_cap(void) {
+         assert_se(!have_effective_cap(CAP_CHOWN));
+ }
+ 
++static void test_update_inherited_set(void) {
++        cap_t caps;
++        uint64_t set = 0;
++        cap_flag_value_t fv;
++
++        caps = cap_get_proc();
++        assert_se(caps);
++        assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv));
++        assert(fv == CAP_CLEAR);
++
++        set = (UINT64_C(1) << CAP_CHOWN);
++
++        assert_se(!capability_update_inherited_set(caps, set));
++        assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv));
++        assert(fv == CAP_SET);
++
++        cap_free(caps);
++}
++
++static void test_set_ambient_caps(void) {
++        cap_t caps;
++        uint64_t set = 0;
++        cap_flag_value_t fv;
++
++        caps = cap_get_proc();
++        assert_se(caps);
++        assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv));
++        assert(fv == CAP_CLEAR);
++        cap_free(caps);
++
++        assert_se(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0) == 0);
++
++        set = (UINT64_C(1) << CAP_CHOWN);
++
++        assert_se(!capability_ambient_set_apply(set, true));
++
++        caps = cap_get_proc();
++        assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv));
++        assert(fv == CAP_SET);
++        cap_free(caps);
++
++        assert_se(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0) == 1);
++}
++
+ int main(int argc, char *argv[]) {
+         int r;
++        bool run_ambient;
+ 
+         log_parse_environment();
+         log_open();
+@@ -148,14 +207,19 @@ int main(int argc, char *argv[]) {
+         if (getuid() != 0)
+                 return EXIT_TEST_SKIP;
+ 
+-        r = setup_tests();
++        r = setup_tests(&run_ambient);
+         if (r < 0)
+                 return -r;
+ 
+         show_capabilities();
+ 
+         test_drop_privileges();
++        test_update_inherited_set();
++
+         fork_test(test_have_effective_cap);
+ 
++        if (run_ambient)
++                fork_test(test_set_ambient_caps);
++
+         return 0;
+ }
+diff --git a/src/test/test-execute.c b/src/test/test-execute.c
+index 6e5567c..8e70702 100644
+--- a/src/test/test-execute.c
++++ b/src/test/test-execute.c
+@@ -17,7 +17,11 @@
+   along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ ***/
+ 
++#include <grp.h>
++#include <pwd.h>
+ #include <stdio.h>
++#include <sys/prctl.h>
++#include <sys/types.h>
+ 
+ #include "unit.h"
+ #include "manager.h"
+@@ -25,6 +29,7 @@
+ #include "macro.h"
+ #include "strv.h"
+ #include "mkdir.h"
++#include "path-util.h"
+ 
+ typedef void (*test_function_t)(Manager *m);
+ 
+@@ -177,6 +182,42 @@ static void test_exec_runtimedirectory(Manager *m) {
+         test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED);
+ }
+ 
++static void test_exec_capabilityboundingset(Manager *m) {
++        int r;
++
++        r = find_binary("capsh", true, NULL);
++        if (r < 0) {
++                log_error_errno(r, "Skipping %s, could not find capsh binary: %m", __func__);
++                return;
++        }
++
++        test(m, "exec-capabilityboundingset-simple.service", 0, CLD_EXITED);
++        test(m, "exec-capabilityboundingset-reset.service", 0, CLD_EXITED);
++        test(m, "exec-capabilityboundingset-merge.service", 0, CLD_EXITED);
++        test(m, "exec-capabilityboundingset-invert.service", 0, CLD_EXITED);
++}
++
++static void test_exec_capabilityambientset(Manager *m) {
++        int r;
++
++        /* Check if the kernel has support for ambient capabilities. Run
++         * the tests only if that's the case. Clearing all ambient
++         * capabilities is fine, since we are expecting them to be unset
++         * in the first place for the tests. */
++        r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
++        if (r >= 0 || errno != EINVAL) {
++                if (getpwnam("nobody")) {
++                        test(m, "exec-capabilityambientset.service", 0, CLD_EXITED);
++                        test(m, "exec-capabilityambientset-merge.service", 0, CLD_EXITED);
++                } else if (getpwnam("nfsnobody")) {
++                        test(m, "exec-capabilityambientset-nfsnobody.service", 0, CLD_EXITED);
++                        test(m, "exec-capabilityambientset-merge-nfsnobody.service", 0, CLD_EXITED);
++                } else
++                        log_error_errno(errno, "Skipping %s, could not find nobody/nfsnobody user: %m", __func__);
++        } else
++                log_error_errno(errno, "Skipping %s, the kernel does not support ambient capabilities: %m", __func__);
++}
++
+ int main(int argc, char *argv[]) {
+         test_function_t tests[] = {
+                 test_exec_workingdirectory,
+@@ -192,6 +233,8 @@ int main(int argc, char *argv[]) {
+                 test_exec_passenvironment,
+                 test_exec_umask,
+                 test_exec_runtimedirectory,
++                test_exec_capabilityboundingset,
++                test_exec_capabilityambientset,
+                 NULL,
+         };
+         test_function_t *test = NULL;
+diff --git a/test/exec-capabilityambientset-merge-nfsnobody.service b/test/exec-capabilityambientset-merge-nfsnobody.service
+new file mode 100644
+index 0000000..00bec58
+--- /dev/null
++++ b/test/exec-capabilityambientset-merge-nfsnobody.service
+@@ -0,0 +1,9 @@
++[Unit]
++Description=Test for AmbientCapabilities
++
++[Service]
++ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb:	0000000000003000"'
++Type=oneshot
++User=nfsnobody
++AmbientCapabilities=CAP_NET_ADMIN
++AmbientCapabilities=CAP_NET_RAW
+diff --git a/test/exec-capabilityambientset-merge.service b/test/exec-capabilityambientset-merge.service
+new file mode 100644
+index 0000000..6496438
+--- /dev/null
++++ b/test/exec-capabilityambientset-merge.service
+@@ -0,0 +1,9 @@
++[Unit]
++Description=Test for AmbientCapabilities
++
++[Service]
++ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb:	0000000000003000"'
++Type=oneshot
++User=nobody
++AmbientCapabilities=CAP_NET_ADMIN
++AmbientCapabilities=CAP_NET_RAW
+diff --git a/test/exec-capabilityambientset-nfsnobody.service b/test/exec-capabilityambientset-nfsnobody.service
+new file mode 100644
+index 0000000..614cfdd
+--- /dev/null
++++ b/test/exec-capabilityambientset-nfsnobody.service
+@@ -0,0 +1,8 @@
++[Unit]
++Description=Test for AmbientCapabilities
++
++[Service]
++ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb:	0000000000003000"'
++Type=oneshot
++User=nfsnobody
++AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW
+diff --git a/test/exec-capabilityambientset.service b/test/exec-capabilityambientset.service
+new file mode 100644
+index 0000000..d63f884
+--- /dev/null
++++ b/test/exec-capabilityambientset.service
+@@ -0,0 +1,8 @@
++[Unit]
++Description=Test for AmbientCapabilities
++
++[Service]
++ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb:	0000000000003000"'
++Type=oneshot
++User=nobody
++AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW
+diff --git a/test/exec-capabilityboundingset-invert.service b/test/exec-capabilityboundingset-invert.service
+new file mode 100644
+index 0000000..fd5d248
+--- /dev/null
++++ b/test/exec-capabilityboundingset-invert.service
+@@ -0,0 +1,7 @@
++[Unit]
++Description=Test for CapabilityBoundingSet
++
++[Service]
++ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "^Bounding set .*cap_chown"); test -z "$$c"'
++Type=oneshot
++CapabilityBoundingSet=~CAP_CHOWN
+diff --git a/test/exec-capabilityboundingset-merge.service b/test/exec-capabilityboundingset-merge.service
+new file mode 100644
+index 0000000..5c7fcaf
+--- /dev/null
++++ b/test/exec-capabilityboundingset-merge.service
+@@ -0,0 +1,8 @@
++[Unit]
++Description=Test for CapabilityBoundingSet
++
++[Service]
++ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "Bounding set "); test "$$c" = "Bounding set =cap_chown,cap_fowner,cap_kill"'
++Type=oneshot
++CapabilityBoundingSet=CAP_FOWNER
++CapabilityBoundingSet=CAP_KILL CAP_CHOWN
+diff --git a/test/exec-capabilityboundingset-reset.service b/test/exec-capabilityboundingset-reset.service
+new file mode 100644
+index 0000000..d7d3320
+--- /dev/null
++++ b/test/exec-capabilityboundingset-reset.service
+@@ -0,0 +1,8 @@
++[Unit]
++Description=Test for CapabilityBoundingSet
++
++[Service]
++ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "Bounding set "); test "$$c" = "Bounding set ="'
++Type=oneshot
++CapabilityBoundingSet=CAP_FOWNER CAP_KILL
++CapabilityBoundingSet=
+diff --git a/test/exec-capabilityboundingset-simple.service b/test/exec-capabilityboundingset-simple.service
+new file mode 100644
+index 0000000..bf1a7f5
+--- /dev/null
++++ b/test/exec-capabilityboundingset-simple.service
+@@ -0,0 +1,7 @@
++[Unit]
++Description=Test for CapabilityBoundingSet
++
++[Service]
++ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "Bounding set "); test "$$c" = "Bounding set =cap_fowner,cap_kill"'
++Type=oneshot
++CapabilityBoundingSet=CAP_FOWNER CAP_KILL
diff --git a/SOURCES/0469-namespace-don-t-fail-on-masked-mounts.patch b/SOURCES/0469-namespace-don-t-fail-on-masked-mounts.patch
new file mode 100644
index 0000000..f3dad25
--- /dev/null
+++ b/SOURCES/0469-namespace-don-t-fail-on-masked-mounts.patch
@@ -0,0 +1,54 @@
+From 8d166597076d87aae9d5f98144103386c79d6446 Mon Sep 17 00:00:00 2001
+From: Jan Synacek <jsynacek@redhat.com>
+Date: Fri, 31 Mar 2017 09:47:46 +0200
+Subject: [PATCH] namespace: don't fail on masked mounts
+
+Before this patch, a service file with ReadWriteDirectories=/file...
+could fail if the file exists but is not a mountpoint, despite being
+listed in /proc/self/mountinfo. It could happen with masked mounts.
+
+(cherry picked from commit 98df8089bea1b2407c46495b6c2eb76dda46c658)
+
+Resolves: #1433687
+---
+ src/shared/util.c | 23 +++++++++++------------
+ 1 file changed, 11 insertions(+), 12 deletions(-)
+
+diff --git a/src/shared/util.c b/src/shared/util.c
+index 1070e32..3e13cc1 100644
+--- a/src/shared/util.c
++++ b/src/shared/util.c
+@@ -7332,22 +7332,21 @@ int bind_remount_recursive(const char *prefix, bool ro) {
+                         if (r < 0)
+                                 return r;
+ 
+-                        /* Try to reuse the original flag set, but
+-                         * don't care for errors, in case of
+-                         * obstructed mounts */
++                        /* Deal with mount points that are obstructed by a
++                         * later mount */
++                        r = path_is_mount_point(x, 0);
++                        if (r == -ENOENT || r == 0)
++                                continue;
++                        if (r < 0)
++                                return r;
++
++                        /* Try to reuse the original flag set */
+                         orig_flags = 0;
+                         (void) get_mount_flags(x, &orig_flags);
+                         orig_flags &= ~MS_RDONLY;
+ 
+-                        if (mount(NULL, x, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) {
+-
+-                                /* Deal with mount points that are
+-                                 * obstructed by a later mount */
+-
+-                                if (errno != ENOENT)
+-                                        return -errno;
+-                        }
+-
++                        if (mount(NULL, x, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0)
++                                return -errno;
+                 }
+         }
+ }
diff --git a/SOURCES/0470-sysv-generator-Provides-network-should-also-pull-net.patch b/SOURCES/0470-sysv-generator-Provides-network-should-also-pull-net.patch
new file mode 100644
index 0000000..45c4a35
--- /dev/null
+++ b/SOURCES/0470-sysv-generator-Provides-network-should-also-pull-net.patch
@@ -0,0 +1,30 @@
+From 1649dac4656e8056e5fe5fa99e5753257efe1a42 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Nykr=C3=BDn?= <lnykryn@redhat.com>
+Date: Thu, 30 Mar 2017 11:12:50 +0200
+Subject: [PATCH] sysv-generator: Provides: $network should also pull
+ network.target to transaction (#5652)
+
+network.target should be pulled in to the transaction
+by the unit that provides network services, but currently
+for initscripts it only pulls in network-online.target.
+
+Cherry-picked from: bd9ad4ff5bf2252f46ccf0cb91b3ed16def1c1a4
+Resolves: #1438749
+---
+ src/sysv-generator/sysv-generator.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c
+index 7e0e7fc..fe6fae1 100644
+--- a/src/sysv-generator/sysv-generator.c
++++ b/src/sysv-generator/sysv-generator.c
+@@ -500,6 +500,9 @@ static int load_sysv(SysvStub *s) {
+                                                         r = strv_extend(&s->before, SPECIAL_NETWORK_TARGET);
+                                                         if (r < 0)
+                                                                 return log_oom();
++                                                        r = strv_extend(&s->wants, SPECIAL_NETWORK_TARGET);
++                                                        if (r < 0)
++                                                                return log_oom();
+                                                 }
+                                         }
+ 
diff --git a/SOURCES/0471-Install-correctly-report-symlink-creations.patch b/SOURCES/0471-Install-correctly-report-symlink-creations.patch
new file mode 100644
index 0000000..20790be
--- /dev/null
+++ b/SOURCES/0471-Install-correctly-report-symlink-creations.patch
@@ -0,0 +1,45 @@
+From b5eddaf0dea35bda7b68a401119c5f9f9104fb99 Mon Sep 17 00:00:00 2001
+From: Martin Pitt <martin.pitt@ubuntu.com>
+Date: Mon, 11 Apr 2016 21:03:29 +0200
+Subject: [PATCH] Install: correctly report symlink creations
+
+All callers of create_symlink(), such as install_info_symlink_wants(), expect
+that to return > 0 if it actually did something, and then return that number.
+unit_file_enable() uses that to determine if any action was done
+(carries_install_info != 0) and if not, show a "The unit files have no
+[Install] section" warning.
+
+Return 1 instead of 0 in the two code paths of create_symlink() when the link
+was created or replaced with a new value.
+
+This fixes getting a bogus "No [Install] section" warning when enabling a unit
+with full path, like "systemctl enable /some/path/myunit.service".
+
+(cherry picked from commit 3de1521427dee61000c1c124a521182b301a50de)
+Resolves: #1435098
+---
+ src/shared/install.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/shared/install.c b/src/shared/install.c
+index bdfd7b9..e73f0c9 100644
+--- a/src/shared/install.c
++++ b/src/shared/install.c
+@@ -283,7 +283,7 @@ static int create_symlink(
+ 
+         if (symlink(old_path, new_path) >= 0) {
+                 unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
+-                return 0;
++                return 1;
+         }
+ 
+         if (errno != EEXIST)
+@@ -306,7 +306,7 @@ static int create_symlink(
+         unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
+         unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
+ 
+-        return 0;
++        return 1;
+ }
+ 
+ static int mark_symlink_for_removal(
diff --git a/SOURCES/0472-rules-40-redhat.rules-rules-should-be-on-one-line.patch b/SOURCES/0472-rules-40-redhat.rules-rules-should-be-on-one-line.patch
new file mode 100644
index 0000000..22b204f
--- /dev/null
+++ b/SOURCES/0472-rules-40-redhat.rules-rules-should-be-on-one-line.patch
@@ -0,0 +1,32 @@
+From 33d6abe2452c8222b926f917171d65ed934d0136 Mon Sep 17 00:00:00 2001
+From: Lukas Nykryn <lnykryn@redhat.com>
+Date: Tue, 11 Apr 2017 15:15:00 +0200
+Subject: [PATCH] rules/40-redhat.rules: rules should be on one line
+
+rhel-only
+Related: #1274401
+---
+ rules/40-redhat.rules | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+diff --git a/rules/40-redhat.rules b/rules/40-redhat.rules
+index c928d41..34a1df9 100644
+--- a/rules/40-redhat.rules
++++ b/rules/40-redhat.rules
+@@ -29,14 +29,10 @@ ACTION=="remove", GOTO="zfcp_scsi_device_end"
+ KERNEL=="sd*", SUBSYSTEMS=="ccw", DRIVERS=="zfcp", ENV{.ID_ZFCP_BUS}="1"
+ 
+ # For SCSI disks
+-KERNEL=="sd*[!0-9]", SUBSYSTEMS=="scsi",
+-        ENV{.ID_ZFCP_BUS}=="1", ENV{DEVTYPE}=="disk",
+-        SYMLINK+="disk/by-path/ccw-$attr{hba_id}-zfcp-$attr{wwpn}:$attr{fcp_lun}"
++KERNEL=="sd*[!0-9]", SUBSYSTEMS=="scsi", ENV{.ID_ZFCP_BUS}=="1", ENV{DEVTYPE}=="disk", SYMLINK+="disk/by-path/ccw-$attr{hba_id}-zfcp-$attr{wwpn}:$attr{fcp_lun}"
+ 
+ 
+ # For partitions on a SCSI disk
+-KERNEL=="sd*[0-9]", SUBSYSTEMS=="scsi",
+-        ENV{.ID_ZFCP_BUS}=="1", ENV{DEVTYPE}=="partition",
+-        SYMLINK+="disk/by-path/ccw-$attr{hba_id}-zfcp-$attr{wwpn}:$attr{fcp_lun}-part%n"
++KERNEL=="sd*[0-9]", SUBSYSTEMS=="scsi", ENV{.ID_ZFCP_BUS}=="1", ENV{DEVTYPE}=="partition", SYMLINK+="disk/by-path/ccw-$attr{hba_id}-zfcp-$attr{wwpn}:$attr{fcp_lun}-part%n"
+ 
+ LABEL="zfcp_scsi_device_end"
diff --git a/SOURCES/0473-tmpfiles-add-new-e-action-which-cleans-up-a-dir-with.patch b/SOURCES/0473-tmpfiles-add-new-e-action-which-cleans-up-a-dir-with.patch
new file mode 100644
index 0000000..1aa1649
--- /dev/null
+++ b/SOURCES/0473-tmpfiles-add-new-e-action-which-cleans-up-a-dir-with.patch
@@ -0,0 +1,173 @@
+From f2d7881cf56b2d1448b9e09c46c076a14a05011d Mon Sep 17 00:00:00 2001
+From: Jan Synacek <jsynacek@redhat.com>
+Date: Tue, 11 Apr 2017 11:20:36 +0200
+Subject: [PATCH] tmpfiles: add new 'e' action which cleans up a dir without
+ creating it
+
+I wanted to add a config line that would empty a directory
+without creating it if doesn't exist. Existing actions don't allow
+this.
+
+v2: properly add 'e' to needs_glob() and takes_ownership()
+
+(cherry picked from commit df8dee85da5fa41e95dd7f536e67fcc6940a6488)
+Resolves: #1225739
+---
+ man/tmpfiles.d.xml      |  9 ++++++++-
+ src/tmpfiles/tmpfiles.c | 51 +++++++++++++++----------------------------------
+ 2 files changed, 23 insertions(+), 37 deletions(-)
+
+diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml
+index fc1fe13..fc9db62 100644
+--- a/man/tmpfiles.d.xml
++++ b/man/tmpfiles.d.xml
+@@ -162,6 +162,13 @@
+         </varlistentry>
+ 
+         <varlistentry>
++          <term><varname>e</varname></term>
++          <listitem><para>Clean directory contents based on the age argument.
++          Lines of this type accept shell-style globs in
++          place of normal path names.</para></listitem>
++        </varlistentry>
++
++        <varlistentry>
+           <term><varname>v</varname></term>
+           <listitem><para>Create a subvolume if the path does not
+           exist yet and the file system supports this
+@@ -467,7 +474,7 @@
+ 
+       <para>The age field only applies to lines
+       starting with <varname>d</varname>,
+-      <varname>D</varname>, and
++      <varname>D</varname>, <varname>e</varname> and
+       <varname>x</varname>. If omitted or set to
+       <literal>-</literal>, no automatic clean-up is
+       done.</para>
+diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
+index bda89df..df7676b 100644
+--- a/src/tmpfiles/tmpfiles.c
++++ b/src/tmpfiles/tmpfiles.c
+@@ -79,6 +79,7 @@ typedef enum ItemType {
+ 
+         /* These ones take globs */
+         WRITE_FILE = 'w',
++        EMPTY_DIRECTORY = 'e',
+         SET_XATTR = 't',
+         RECURSIVE_SET_XATTR = 'T',
+         SET_ACL = 'a',
+@@ -150,6 +151,7 @@ static bool needs_glob(ItemType t) {
+                       IGNORE_PATH,
+                       IGNORE_DIRECTORY_PATH,
+                       REMOVE_PATH,
++                      EMPTY_DIRECTORY,
+                       RECURSIVE_REMOVE_PATH,
+                       ADJUST_MODE,
+                       RELABEL_PATH,
+@@ -165,6 +167,7 @@ static bool takes_ownership(ItemType t) {
+                       CREATE_FILE,
+                       TRUNCATE_FILE,
+                       CREATE_DIRECTORY,
++                      EMPTY_DIRECTORY,
+                       TRUNCATE_DIRECTORY,
+                       CREATE_SUBVOLUME,
+                       CREATE_FIFO,
+@@ -1059,6 +1062,9 @@ static int create_item(Item *i) {
+ 
+                 log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation), i->path);
+ 
++                /* fall through */
++
++        case EMPTY_DIRECTORY:
+                 r = path_set_perms(i, i->path);
+                 if (r < 0)
+                         return r;
+@@ -1285,43 +1291,19 @@ static int remove_item_instance(Item *i, const char *instance) {
+ }
+ 
+ static int remove_item(Item *i) {
+-        int r = 0;
+-
+         assert(i);
+ 
+         log_debug("Running remove action for entry %c %s", (char) i->type, i->path);
+ 
+         switch (i->type) {
+-
+-        case CREATE_FILE:
+-        case TRUNCATE_FILE:
+-        case CREATE_DIRECTORY:
+-        case CREATE_SUBVOLUME:
+-        case CREATE_FIFO:
+-        case CREATE_SYMLINK:
+-        case CREATE_CHAR_DEVICE:
+-        case CREATE_BLOCK_DEVICE:
+-        case IGNORE_PATH:
+-        case IGNORE_DIRECTORY_PATH:
+-        case ADJUST_MODE:
+-        case RELABEL_PATH:
+-        case RECURSIVE_RELABEL_PATH:
+-        case WRITE_FILE:
+-        case COPY_FILES:
+-        case SET_XATTR:
+-        case RECURSIVE_SET_XATTR:
+-        case SET_ACL:
+-        case RECURSIVE_SET_ACL:
+-                break;
+-
+         case REMOVE_PATH:
+         case TRUNCATE_DIRECTORY:
+         case RECURSIVE_REMOVE_PATH:
+-                r = glob_item(i, remove_item_instance, false);
+-                break;
+-        }
++                return glob_item(i, remove_item_instance, false);
+ 
+-        return r;
++        default:
++                return 0;
++        }
+ }
+ 
+ static int clean_item_instance(Item *i, const char* instance) {
+@@ -1377,8 +1359,6 @@ static int clean_item_instance(Item *i, const char* instance) {
+ }
+ 
+ static int clean_item(Item *i) {
+-        int r = 0;
+-
+         assert(i);
+ 
+         log_debug("Running clean action for entry %c %s", (char) i->type, i->path);
+@@ -1386,19 +1366,17 @@ static int clean_item(Item *i) {
+         switch (i->type) {
+         case CREATE_DIRECTORY:
+         case CREATE_SUBVOLUME:
++        case EMPTY_DIRECTORY:
+         case TRUNCATE_DIRECTORY:
+         case IGNORE_PATH:
+         case COPY_FILES:
+                 clean_item_instance(i, i->path);
+-                break;
++                return 0;
+         case IGNORE_DIRECTORY_PATH:
+-                r = glob_item(i, clean_item_instance, false);
+-                break;
++                return glob_item(i, clean_item_instance, false);
+         default:
+-                break;
++                return 0;
+         }
+-
+-        return r;
+ }
+ 
+ static int process_item_array(ItemArray *array);
+@@ -1642,6 +1620,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
+         case TRUNCATE_FILE:
+         case CREATE_DIRECTORY:
+         case CREATE_SUBVOLUME:
++        case EMPTY_DIRECTORY:
+         case TRUNCATE_DIRECTORY:
+         case CREATE_FIFO:
+         case IGNORE_PATH:
diff --git a/SOURCES/0474-util-bind_remount_recursive-handle-return-0-of-set_c.patch b/SOURCES/0474-util-bind_remount_recursive-handle-return-0-of-set_c.patch
new file mode 100644
index 0000000..cdaaf2b
--- /dev/null
+++ b/SOURCES/0474-util-bind_remount_recursive-handle-return-0-of-set_c.patch
@@ -0,0 +1,28 @@
+From 32efad544d53f7c1745eb36eef0df95ef96d1c15 Mon Sep 17 00:00:00 2001
+From: Harald Hoyer <harald@redhat.com>
+Date: Tue, 9 Jun 2015 10:32:28 +0200
+Subject: [PATCH] util:bind_remount_recursive(): handle return 0 of
+ set_consume()
+
+set_consume() does not return -EEXIST, but 0, in case the key is already
+in the Set.
+
+Cherry-picked from: 85d834ae8e7d9e2c28ef8c1388e2913ed8fd0e3b
+Resolves: #1433687
+---
+ src/shared/util.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/shared/util.c b/src/shared/util.c
+index 3e13cc1..cadadde 100644
+--- a/src/shared/util.c
++++ b/src/shared/util.c
+@@ -7327,7 +7327,7 @@ int bind_remount_recursive(const char *prefix, bool ro) {
+                 while ((x = set_steal_first(todo))) {
+ 
+                         r = set_consume(done, x);
+-                        if (r == -EEXIST)
++                        if (r == -EEXIST || r == 0)
+                                 continue;
+                         if (r < 0)
+                                 return r;
diff --git a/SOURCES/0475-core-add-support-for-the-pids-cgroup-controller.patch b/SOURCES/0475-core-add-support-for-the-pids-cgroup-controller.patch
new file mode 100644
index 0000000..e4a5b78
--- /dev/null
+++ b/SOURCES/0475-core-add-support-for-the-pids-cgroup-controller.patch
@@ -0,0 +1,622 @@
+From 7d44d0d43465892d4753ff50592588f49d56cf95 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Thu, 10 Sep 2015 12:32:16 +0200
+Subject: [PATCH] core: add support for the "pids" cgroup controller
+
+This adds support for the new "pids" cgroup controller of 4.3 kernels.
+It allows accounting the number of tasks in a cgroup and enforcing
+limits on it.
+
+This adds two new setting TasksAccounting= and TasksMax= to each unit,
+as well as a gloabl option DefaultTasksAccounting=.
+
+This also updated "cgtop" to optionally make use of the new
+kernel-provided accounting.
+
+systemctl has been updated to show the number of tasks for each service
+if it is available.
+
+This patch also adds correct support for undoing memory limits for units
+using a MemoryLimit=infinity syntax. We do the same for TasksMax= now
+and hence keep things in sync here.
+
+Cherry-picked from: 03a7b521e3ffb7f5d153d90480ba5d4bc29d1e8f
+Resolves: #1337244
+---
+ man/systemd-system.conf.xml           | 22 ++++++------
+ man/systemd.resource-control.xml      | 63 ++++++++++++++++++++++++++++-------
+ src/core/cgroup.c                     | 44 ++++++++++++++++++++++++
+ src/core/cgroup.h                     |  5 +++
+ src/core/dbus-cgroup.c                | 41 ++++++++++++++++++++++-
+ src/core/dbus-unit.c                  | 25 ++++++++++++++
+ src/core/load-fragment-gperf.gperf.m4 |  2 ++
+ src/core/load-fragment.c              | 37 +++++++++++++++++---
+ src/core/load-fragment.h              |  1 +
+ src/core/main.c                       |  3 ++
+ src/core/manager.h                    |  1 +
+ src/core/unit.c                       |  1 +
+ src/shared/cgroup-util.h              |  1 +
+ src/systemctl/systemctl.c             | 17 ++++++++++
+ 14 files changed, 236 insertions(+), 27 deletions(-)
+
+diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml
+index 57b3b90..d367ccd 100644
+--- a/man/systemd-system.conf.xml
++++ b/man/systemd-system.conf.xml
+@@ -51,14 +51,14 @@
+   </refnamediv>
+ 
+   <refsynopsisdiv>
+-    <para><filename>/etc/systemd/system.conf</filename></para>
+-    <para><filename>/etc/systemd/system.conf.d/*.conf</filename></para>
+-    <para><filename>/run/systemd/system.conf.d/*.conf</filename></para>
+-    <para><filename>/usr/lib/systemd/system.conf.d/*.conf</filename></para>
+-    <para><filename>/etc/systemd/user.conf</filename></para>
+-    <para><filename>/etc/systemd/user.conf.d/*.conf</filename></para>
+-    <para><filename>/run/systemd/user.conf.d/*.conf</filename></para>
+-    <para><filename>/usr/lib/systemd/user.conf.d/*.conf</filename></para>
++    <para><filename>/etc/systemd/system.conf</filename>,
++    <filename>/etc/systemd/system.conf.d/*.conf</filename>,
++    <filename>/run/systemd/system.conf.d/*.conf</filename>,
++    <filename>/usr/lib/systemd/system.conf.d/*.conf</filename></para>
++    <para><filename>/etc/systemd/user.conf</filename>,
++    <filename>/etc/systemd/user.conf.d/*.conf</filename>,
++    <filename>/run/systemd/user.conf.d/*.conf</filename>,
++    <filename>/usr/lib/systemd/user.conf.d/*.conf</filename></para>
+   </refsynopsisdiv>
+ 
+   <refsect1>
+@@ -307,12 +307,14 @@
+         <term><varname>DefaultCPUAccounting=</varname></term>
+         <term><varname>DefaultBlockIOAccounting=</varname></term>
+         <term><varname>DefaultMemoryAccounting=</varname></term>
++        <term><varname>DefaultTasksAccounting=</varname></term>
+ 
+         <listitem><para>Configure the default resource accounting
+         settings, as configured per-unit by
+         <varname>CPUAccounting=</varname>,
+-        <varname>BlockIOAccounting=</varname> and
+-        <varname>MemoryAccounting=</varname>. See
++        <varname>BlockIOAccounting=</varname>,
++        <varname>MemoryAccounting=</varname> and
++        <varname>TasksAccounting=</varname>. See
+         <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+         for details on the per-unit settings.</para></listitem>
+       </varlistentry>
+diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml
+index 8f4e7a3..6b9329b 100644
+--- a/man/systemd.resource-control.xml
++++ b/man/systemd.resource-control.xml
+@@ -103,10 +103,10 @@
+         <listitem>
+           <para>Turn on CPU usage accounting for this unit. Takes a
+           boolean argument. Note that turning on CPU accounting for
+-          one unit might also implicitly turn it on for all units
++          one unit will also implicitly turn it on for all units
+           contained in the same slice and for all its parent slices
+           and the units contained therein. The system default for this
+-          setting maybe controlled with
++          setting may be controlled with
+           <varname>DefaultCPUAccounting=</varname> in
+           <citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+         </listitem>
+@@ -134,7 +134,7 @@
+           prioritizing specific services at boot-up differently than
+           during normal runtime.</para>
+ 
+-          <para>Those options imply
++          <para>These options imply
+           <literal>CPUAccounting=true</literal>.</para>
+         </listitem>
+       </varlistentry>
+@@ -168,9 +168,10 @@
+         <listitem>
+           <para>Turn on process and kernel memory accounting for this
+           unit. Takes a boolean argument. Note that turning on memory
+-          accounting for one unit might also implicitly turn it on for
+-          all its parent slices. The system default for this setting
+-          maybe controlled with
++          accounting for one unit will also implicitly turn it on for
++          all units contained in the same slice and for all its parent
++          slices and the units contained therein. The system default
++          for this setting may be controlled with
+           <varname>DefaultMemoryAccounting=</varname> in
+           <citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+         </listitem>
+@@ -186,10 +187,11 @@
+           memory size in bytes. If the value is suffixed with K, M, G
+           or T, the specified memory size is parsed as Kilobytes,
+           Megabytes, Gigabytes, or Terabytes (with the base 1024),
+-          respectively. This controls the
+-          <literal>memory.limit_in_bytes</literal> control group
+-          attribute. For details about this control group attribute,
+-          see <ulink
++          respectively. If assigned the special value
++          <literal>infinity</literal> no memory limit is applied. This
++          controls the <literal>memory.limit_in_bytes</literal>
++          control group attribute. For details about this control
++          group attribute, see <ulink
+           url="https://www.kernel.org/doc/Documentation/cgroups/memory.txt">memory.txt</ulink>.</para>
+ 
+           <para>Implies <literal>MemoryAccounting=true</literal>.</para>
+@@ -197,15 +199,52 @@
+       </varlistentry>
+ 
+       <varlistentry>
++        <term><varname>TasksAccounting=</varname></term>
++
++        <listitem>
++          <para>Turn on task accounting for this unit. Takes a
++          boolean argument. If enabled, the system manager will keep
++          track of the number of tasks in the unit. The number of
++          tasks accounted this way includes both kernel threads and
++          userspace processes, with each thread counting
++          individually. Note that turning on tasks accounting for one
++          unit will also implicitly turn it on for all units contained
++          in the same slice and for all its parent slices and the
++          units contained therein. The system default for this setting
++          may be controlled with
++          <varname>DefaultTasksAccounting=</varname> in
++          <citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>TasksMax=<replaceable>N</replaceable></varname></term>
++
++        <listitem>
++          <para>Specify the maximum number of tasks that may be
++          created in the unit. This ensures that the number of tasks
++          accounted for the unit (see above) stays below a specific
++          limit. If assigned the special value
++          <literal>infinity</literal> no tasks limit is applied. This
++          controls the <literal>pids.max</literal> control group
++          attribute. For details about this control group attribute,
++          see <ulink
++          url="https://www.kernel.org/doc/Documentation/cgroups/pids.txt">pids.txt</ulink>.</para>
++
++          <para>Implies <literal>TasksAccounting=true</literal>.</para>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
+         <term><varname>BlockIOAccounting=</varname></term>
+ 
+         <listitem>
+           <para>Turn on Block IO accounting for this unit. Takes a
+           boolean argument. Note that turning on block IO accounting
+-          for one unit might also implicitly turn it on for all units
++          for one unit will also implicitly turn it on for all units
+           contained in the same slice and all for its parent slices
+           and the units contained therein. The system default for this
+-          setting maybe controlled with
++          setting may be controlled with
+           <varname>DefaultBlockIOAccounting=</varname> in
+           <citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+         </listitem>
+diff --git a/src/core/cgroup.c b/src/core/cgroup.c
+index b7f08fb..d4a8f9c 100644
+--- a/src/core/cgroup.c
++++ b/src/core/cgroup.c
+@@ -40,6 +40,7 @@ void cgroup_context_init(CGroupContext *c) {
+         c->memory_limit = (uint64_t) -1;
+         c->blockio_weight = (unsigned long) -1;
+         c->startup_blockio_weight = (unsigned long) -1;
++        c->tasks_max = (uint64_t) -1;
+ 
+         c->cpu_quota_per_sec_usec = USEC_INFINITY;
+ }
+@@ -105,6 +106,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
+                 "%sBlockIOWeight=%lu\n"
+                 "%sStartupBlockIOWeight=%lu\n"
+                 "%sMemoryLimit=%" PRIu64 "\n"
++                "%sTasksMax=%" PRIu64 "\n"
+                 "%sDevicePolicy=%s\n"
+                 "%sDelegate=%s\n",
+                 prefix, yes_no(c->cpu_accounting),
+@@ -116,6 +118,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
+                 prefix, c->blockio_weight,
+                 prefix, c->startup_blockio_weight,
+                 prefix, c->memory_limit,
++                prefix, c->tasks_max,
+                 prefix, cgroup_device_policy_to_string(c->device_policy),
+                 prefix, yes_no(c->delegate));
+ 
+@@ -456,6 +459,21 @@ void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const cha
+                                 log_debug("Ignoring device %s while writing cgroup attribute.", a->path);
+                 }
+         }
++
++        if ((mask & CGROUP_PIDS) && !is_root) {
++
++                if (c->tasks_max != (uint64_t) -1) {
++                        char buf[DECIMAL_STR_MAX(uint64_t) + 2];
++
++                        sprintf(buf, "%" PRIu64 "\n", c->tasks_max);
++                        r = cg_set_attribute("pids", path, "pids.max", buf);
++                } else
++                        r = cg_set_attribute("pids", path, "pids.max", "max");
++
++                if (r < 0)
++                        log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
++                                       "Failed to set pids.max on %s: %m", path);
++        }
+ }
+ 
+ CGroupControllerMask cgroup_context_get_mask(CGroupContext *c) {
+@@ -484,6 +502,10 @@ CGroupControllerMask cgroup_context_get_mask(CGroupContext *c) {
+             c->device_policy != CGROUP_AUTO)
+                 mask |= CGROUP_DEVICE;
+ 
++        if (c->tasks_accounting ||
++            c->tasks_max != (uint64_t) -1)
++                mask |= CGROUP_PIDS;
++
+         return mask;
+ }
+ 
+@@ -1044,6 +1066,28 @@ int manager_notify_cgroup_empty(Manager *m, const char *cgroup) {
+         return 0;
+ }
+ 
++int unit_get_tasks_current(Unit *u, uint64_t *ret) {
++        _cleanup_free_ char *v = NULL;
++        int r;
++
++        assert(u);
++       assert(ret);
++
++        if (!u->cgroup_path)
++                return -ENODATA;
++
++        if ((u->cgroup_realized_mask & CGROUP_PIDS) == 0)
++                return -ENODATA;
++
++        r = cg_get_attribute("pids", u->cgroup_path, "pids.current", &v);
++        if (r == -ENOENT)
++                return -ENODATA;
++        if (r < 0)
++                return r;
++
++        return safe_atou64(v, ret);
++}
++
+ static const char* const cgroup_device_policy_table[_CGROUP_DEVICE_POLICY_MAX] = {
+         [CGROUP_AUTO] = "auto",
+         [CGROUP_CLOSED] = "closed",
+diff --git a/src/core/cgroup.h b/src/core/cgroup.h
+index 8fa851d..8af3eaa 100644
+--- a/src/core/cgroup.h
++++ b/src/core/cgroup.h
+@@ -72,6 +72,7 @@ struct CGroupContext {
+         bool cpu_accounting;
+         bool blockio_accounting;
+         bool memory_accounting;
++        bool tasks_accounting;
+ 
+         unsigned long cpu_shares;
+         unsigned long startup_cpu_shares;
+@@ -88,6 +89,8 @@ struct CGroupContext {
+         LIST_HEAD(CGroupDeviceAllow, device_allow);
+ 
+         bool delegate;
++
++        uint64_t tasks_max;
+ };
+ 
+ #include "unit.h"
+@@ -127,5 +130,7 @@ pid_t unit_search_main_pid(Unit *u);
+ 
+ int manager_notify_cgroup_empty(Manager *m, const char *group);
+ 
++int unit_get_tasks_current(Unit *u, uint64_t *ret);
++
+ const char* cgroup_device_policy_to_string(CGroupDevicePolicy i) _const_;
+ CGroupDevicePolicy cgroup_device_policy_from_string(const char *s) _pure_;
+diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
+index 4a9df06..a4465dc 100644
+--- a/src/core/dbus-cgroup.c
++++ b/src/core/dbus-cgroup.c
+@@ -168,6 +168,8 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
+         SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0),
+         SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0),
+         SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0),
++        SD_BUS_PROPERTY("TasksAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, tasks_accounting), 0),
++        SD_BUS_PROPERTY("TasksMax", "t", NULL, offsetof(CGroupContext, tasks_max), 0),
+         SD_BUS_VTABLE_END
+ };
+ 
+@@ -551,7 +553,11 @@ int bus_cgroup_set_property(
+                 if (mode != UNIT_CHECK) {
+                         c->memory_limit = limit;
+                         u->cgroup_realized_mask &= ~CGROUP_MEMORY;
+-                        unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, limit);
++
++                        if (limit == (uint64_t) -1)
++                                unit_write_drop_in_private(u, mode, name, "MemoryLimit=infinity");
++                        else
++                                unit_write_drop_in_private_format(u, mode, name, "MemoryLimit=%" PRIu64, limit);
+                 }
+ 
+                 return 1;
+@@ -667,6 +673,39 @@ int bus_cgroup_set_property(
+ 
+                 return 1;
+ 
++        } else if (streq(name, "TasksAccounting")) {
++                int b;
++
++                r = sd_bus_message_read(message, "b", &b);
++                if (r < 0)
++                        return r;
++
++                if (mode != UNIT_CHECK) {
++                        c->tasks_accounting = b;
++                        u->cgroup_realized_mask &= ~CGROUP_PIDS;
++                        unit_write_drop_in_private(u, mode, name, b ? "TasksAccounting=yes" : "TasksAccounting=no");
++                }
++
++                return 1;
++
++        } else if (streq(name, "TasksMax")) {
++                uint64_t limit;
++
++                r = sd_bus_message_read(message, "t", &limit);
++                if (r < 0)
++                        return r;
++
++                if (mode != UNIT_CHECK) {
++                        c->tasks_max = limit;
++                        u->cgroup_realized_mask &= ~CGROUP_PIDS;
++
++                        if (limit == (uint64_t) -1)
++                                unit_write_drop_in_private(u, mode, name, "TasksMax=infinity");
++                        else
++                                unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu64, limit);
++                }
++
++                return 1;
+         }
+ 
+         if (u->transient && u->load_state == UNIT_STUB) {
+diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
+index 056a17a..1d0d6f6 100644
+--- a/src/core/dbus-unit.c
++++ b/src/core/dbus-unit.c
+@@ -673,11 +673,36 @@ static int property_get_current_memory(
+         return sd_bus_message_append(reply, "t", sz);
+ }
+ 
++static int property_get_current_tasks(
++                sd_bus *bus,
++                const char *path,
++                const char *interface,
++                const char *property,
++                sd_bus_message *reply,
++                void *userdata,
++                sd_bus_error *error) {
++
++        uint64_t cn = (uint64_t) -1;
++        Unit *u = userdata;
++        int r;
++
++        assert(bus);
++        assert(reply);
++        assert(u);
++
++        r = unit_get_tasks_current(u, &cn);
++        if (r < 0 && r != -ENODATA)
++                log_unit_warning_errno(u->id, r, "Failed to get pids.current attribute: %m");
++
++        return sd_bus_message_append(reply, "t", cn);
++}
++
+ const sd_bus_vtable bus_unit_cgroup_vtable[] = {
+         SD_BUS_VTABLE_START(0),
+         SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
+         SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Unit, cgroup_path), 0),
+         SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0),
++        SD_BUS_PROPERTY("TasksCurrent", "t", property_get_current_tasks, 0, 0),
+         SD_BUS_VTABLE_END
+ };
+ 
+diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
+index f996032..26e4c61 100644
+--- a/src/core/load-fragment-gperf.gperf.m4
++++ b/src/core/load-fragment-gperf.gperf.m4
+@@ -125,6 +125,8 @@ $1.StartupBlockIOWeight,         config_parse_blockio_weight,        0,
+ $1.BlockIODeviceWeight,          config_parse_blockio_device_weight, 0,                             offsetof($1, cgroup_context)
+ $1.BlockIOReadBandwidth,         config_parse_blockio_bandwidth,     0,                             offsetof($1, cgroup_context)
+ $1.BlockIOWriteBandwidth,        config_parse_blockio_bandwidth,     0,                             offsetof($1, cgroup_context)
++$1.TasksAccounting,              config_parse_bool,                  0,                             offsetof($1, cgroup_context.tasks_accounting)
++$1.TasksMax,                     config_parse_tasks_max,             0,                             offsetof($1, cgroup_context)
+ $1.Delegate,                     config_parse_bool,                  0,                             offsetof($1, cgroup_context.delegate)'
+ )m4_dnl
+ Unit.Description,                config_parse_unit_string_printf,    0,                             offsetof(Unit, description)
+diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
+index 7d1ac6c..7d2e737 100644
+--- a/src/core/load-fragment.c
++++ b/src/core/load-fragment.c
+@@ -3052,7 +3052,7 @@ int config_parse_memory_limit(
+         off_t bytes;
+         int r;
+ 
+-        if (isempty(rvalue)) {
++        if (isempty(rvalue) || streq(rvalue, "infinity")) {
+                 c->memory_limit = (uint64_t) -1;
+                 return 0;
+         }
+@@ -3060,9 +3060,8 @@ int config_parse_memory_limit(
+         assert_cc(sizeof(uint64_t) == sizeof(off_t));
+ 
+         r = parse_size(rvalue, 1024, &bytes);
+-        if (r < 0) {
+-                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+-                           "Memory limit '%s' invalid. Ignoring.", rvalue);
++        if (r < 0 || bytes < 1) {
++                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Memory limit '%s' invalid. Ignoring.", rvalue);
+                 return 0;
+         }
+ 
+@@ -3070,6 +3069,36 @@ int config_parse_memory_limit(
+         return 0;
+ }
+ 
++int config_parse_tasks_max(
++                const char *unit,
++                const char *filename,
++                unsigned line,
++                const char *section,
++                unsigned section_line,
++                const char *lvalue,
++                int ltype,
++                const char *rvalue,
++                void *data,
++                void *userdata) {
++
++        CGroupContext *c = data;
++        uint64_t u;
++        int r;
++
++        if (isempty(rvalue) || streq(rvalue, "infinity")) {
++                c->tasks_max = (uint64_t) -1;
++                return 0;
++        }
++
++        r = safe_atou64(rvalue, &u);
++        if (r < 0 || u < 1) {
++                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Maximum tasks value '%s' invalid. Ignoring.", rvalue);
++                return 0;
++        }
++
++        return 0;
++}
++
+ int config_parse_device_allow(
+                 const char *unit,
+                 const char *filename,
+diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
+index 2059353..8d334f2 100644
+--- a/src/core/load-fragment.h
++++ b/src/core/load-fragment.h
+@@ -89,6 +89,7 @@ int config_parse_pass_environ(const char *unit, const char *filename, unsigned l
+ int config_parse_unit_slice(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+ int config_parse_cpu_shares(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+ int config_parse_memory_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
++int config_parse_tasks_max(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+ int config_parse_device_policy(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+ int config_parse_device_allow(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+ int config_parse_blockio_weight(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+diff --git a/src/core/main.c b/src/core/main.c
+index cba992c..aca05a5 100644
+--- a/src/core/main.c
++++ b/src/core/main.c
+@@ -117,6 +117,7 @@ static bool arg_default_cpu_accounting = false;
+ static bool arg_default_blockio_accounting = false;
+ static bool arg_default_memory_accounting = false;
+ static EmergencyAction arg_cad_burst_action = EMERGENCY_ACTION_REBOOT_FORCE;
++static bool arg_default_tasks_accounting = false;
+ 
+ static void nop_handler(int sig) {}
+ 
+@@ -676,6 +677,7 @@ static int parse_config_file(void) {
+                 { "Manager", "DefaultBlockIOAccounting",  config_parse_bool,             0, &arg_default_blockio_accounting        },
+                 { "Manager", "DefaultMemoryAccounting",   config_parse_bool,             0, &arg_default_memory_accounting         },
+                 { "Manager", "CtrlAltDelBurstAction",     config_parse_emergency_action, 0, &arg_cad_burst_action                  },
++                { "Manager", "DefaultTasksAccounting",    config_parse_bool,             0, &arg_default_tasks_accounting          },
+                 {}
+         };
+ 
+@@ -1685,6 +1687,7 @@ int main(int argc, char *argv[]) {
+         m->default_cpu_accounting = arg_default_cpu_accounting;
+         m->default_blockio_accounting = arg_default_blockio_accounting;
+         m->default_memory_accounting = arg_default_memory_accounting;
++        m->default_tasks_accounting = arg_default_tasks_accounting;
+         m->runtime_watchdog = arg_runtime_watchdog;
+         m->shutdown_watchdog = arg_shutdown_watchdog;
+ 
+diff --git a/src/core/manager.h b/src/core/manager.h
+index 231c076..96dcd83 100644
+--- a/src/core/manager.h
++++ b/src/core/manager.h
+@@ -261,6 +261,7 @@ struct Manager {
+         bool default_cpu_accounting;
+         bool default_memory_accounting;
+         bool default_blockio_accounting;
++        bool default_tasks_accounting;
+ 
+         usec_t default_timer_accuracy_usec;
+ 
+diff --git a/src/core/unit.c b/src/core/unit.c
+index 103f920..2fcb4fb 100644
+--- a/src/core/unit.c
++++ b/src/core/unit.c
+@@ -126,6 +126,7 @@ static void unit_init(Unit *u) {
+                 cc->cpu_accounting = u->manager->default_cpu_accounting;
+                 cc->blockio_accounting = u->manager->default_blockio_accounting;
+                 cc->memory_accounting = u->manager->default_memory_accounting;
++                cc->tasks_accounting = u->manager->default_tasks_accounting;
+         }
+ 
+         ec = unit_get_exec_context(u);
+diff --git a/src/shared/cgroup-util.h b/src/shared/cgroup-util.h
+index 96a3d3b..31bd8d3 100644
+--- a/src/shared/cgroup-util.h
++++ b/src/shared/cgroup-util.h
+@@ -35,6 +35,7 @@ typedef enum CGroupControllerMask {
+         CGROUP_BLKIO = 4,
+         CGROUP_MEMORY = 8,
+         CGROUP_DEVICE = 16,
++        CGROUP_PIDS = 32,
+         _CGROUP_CONTROLLER_MASK_ALL = 31
+ } CGroupControllerMask;
+ 
+diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
+index 0333599..b1862b5 100644
+--- a/src/systemctl/systemctl.c
++++ b/src/systemctl/systemctl.c
+@@ -3280,6 +3280,8 @@ typedef struct UnitStatusInfo {
+         /* CGroup */
+         uint64_t memory_current;
+         uint64_t memory_limit;
++        uint64_t tasks_current;
++        uint64_t tasks_max;
+ 
+         LIST_HEAD(ExecStatusInfo, exec);
+ } UnitStatusInfo;
+@@ -3539,6 +3541,15 @@ static void print_status_info(
+         if (i->status_errno > 0)
+                 printf("    Error: %i (%s)\n", i->status_errno, strerror(i->status_errno));
+ 
++        if (i->tasks_current != (uint64_t) -1) {
++                printf("    Tasks: %" PRIu64, i->tasks_current);
++
++                if (i->tasks_max != (uint64_t) -1)
++                        printf(" (limit: %" PRIi64 ")\n", i->tasks_max);
++                else
++                        printf("\n");
++        }
++
+         if (i->memory_current != (uint64_t) -1) {
+                 char buf[FORMAT_BYTES_MAX];
+ 
+@@ -3768,6 +3779,10 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *
+                         i->memory_current = u;
+                 else if (streq(name, "MemoryLimit"))
+                         i->memory_limit = u;
++                else if (streq(name, "TasksCurrent"))
++                        i->tasks_current = u;
++                else if (streq(name, "TasksMax"))
++                        i->tasks_max = u;
+ 
+                 break;
+         }
+@@ -4248,6 +4263,8 @@ static int show_one(
+         UnitStatusInfo info = {
+                 .memory_current = (uint64_t) -1,
+                 .memory_limit = (uint64_t) -1,
++                .tasks_current = (uint64_t) -1,
++                .tasks_max = (uint64_t) -1,
+         };
+         ExecStatusInfo *p;
+         int r;
diff --git a/SOURCES/0476-core-add-new-DefaultTasksMax-setting-for-system.conf.patch b/SOURCES/0476-core-add-new-DefaultTasksMax-setting-for-system.conf.patch
new file mode 100644
index 0000000..fdcf952
--- /dev/null
+++ b/SOURCES/0476-core-add-new-DefaultTasksMax-setting-for-system.conf.patch
@@ -0,0 +1,201 @@
+From fc7fdb72096d2baeec3238a0ef324569a05da4ae Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Fri, 13 Nov 2015 17:13:55 +0100
+Subject: [PATCH] core: add new DefaultTasksMax= setting for system.conf
+
+This allows initializing the TasksMax= setting of all units by default
+to some fixed value, instead of leaving it at infinity as before.
+
+Cherry-picked from: 0af20ea2ee2af2bcf2258e7a8e1a13181a6a75d6
+Related: #1337244
+---
+ man/systemd-system.conf.xml           | 13 ++++++++++++-
+ man/systemd.resource-control.xml      |  5 ++++-
+ src/core/dbus-manager.c               |  1 +
+ src/core/load-fragment-gperf.gperf.m4 |  2 +-
+ src/core/load-fragment.c              |  7 ++++---
+ src/core/main.c                       |  3 +++
+ src/core/manager.h                    |  1 +
+ src/core/system.conf                  |  2 ++
+ src/core/unit.c                       |  3 +++
+ src/shared/cgroup-util.c              |  3 ++-
+ 10 files changed, 33 insertions(+), 7 deletions(-)
+
+diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml
+index d367ccd..53e8ff6 100644
+--- a/man/systemd-system.conf.xml
++++ b/man/systemd-system.conf.xml
+@@ -1,4 +1,4 @@
+-<?xml version='1.0'?> <!--*-nxml-*-->
++<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
+ <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ 
+@@ -320,6 +320,17 @@
+       </varlistentry>
+ 
+       <varlistentry>
++        <term><varname>DefaultTasksMax=</varname></term>
++
++        <listitem><para>Configure the default value for the per-unit
++        <varname>TasksMax=</varname> setting. See
++        <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
++        for details. This setting applies to all unit types that
++        support resource control settings, with the exception of slice
++        units.</para></listitem>
++      </varlistentry>
++
++      <varlistentry>
+         <term><varname>DefaultLimitCPU=</varname></term>
+         <term><varname>DefaultLimitFSIZE=</varname></term>
+         <term><varname>DefaultLimitDATA=</varname></term>
+diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml
+index 6b9329b..217105e 100644
+--- a/man/systemd.resource-control.xml
++++ b/man/systemd.resource-control.xml
+@@ -231,7 +231,10 @@
+           see <ulink
+           url="https://www.kernel.org/doc/Documentation/cgroups/pids.txt">pids.txt</ulink>.</para>
+ 
+-          <para>Implies <literal>TasksAccounting=true</literal>.</para>
++          <para>Implies <literal>TasksAccounting=true</literal>. The
++          system default for this setting may be controlled with
++          <varname>DefaultTasksMax=</varname> in
++          <citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+         </listitem>
+       </varlistentry>
+ 
+diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
+index 7ba1b51..c92f8c6 100644
+--- a/src/core/dbus-manager.c
++++ b/src/core/dbus-manager.c
+@@ -2039,6 +2039,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
+         SD_BUS_WRITABLE_PROPERTY("ShutdownWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, shutdown_watchdog), 0),
+         SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Manager, cgroup_root), 0),
+         SD_BUS_PROPERTY("SystemState", "s", property_get_system_state, 0, 0),
++        SD_BUS_PROPERTY("DefaultTasksMax", "t", NULL, offsetof(Manager, default_tasks_max), SD_BUS_VTABLE_PROPERTY_CONST),
+ 
+         SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, SD_BUS_VTABLE_UNPRIVILEGED),
+         SD_BUS_METHOD("GetUnitByPID", "u", "o", method_get_unit_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
+diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
+index 26e4c61..b2fe627 100644
+--- a/src/core/load-fragment-gperf.gperf.m4
++++ b/src/core/load-fragment-gperf.gperf.m4
+@@ -126,7 +126,7 @@ $1.BlockIODeviceWeight,          config_parse_blockio_device_weight, 0,
+ $1.BlockIOReadBandwidth,         config_parse_blockio_bandwidth,     0,                             offsetof($1, cgroup_context)
+ $1.BlockIOWriteBandwidth,        config_parse_blockio_bandwidth,     0,                             offsetof($1, cgroup_context)
+ $1.TasksAccounting,              config_parse_bool,                  0,                             offsetof($1, cgroup_context.tasks_accounting)
+-$1.TasksMax,                     config_parse_tasks_max,             0,                             offsetof($1, cgroup_context)
++$1.TasksMax,                     config_parse_tasks_max,             0,                             offsetof($1, cgroup_context.tasks_max)
+ $1.Delegate,                     config_parse_bool,                  0,                             offsetof($1, cgroup_context.delegate)'
+ )m4_dnl
+ Unit.Description,                config_parse_unit_string_printf,    0,                             offsetof(Unit, description)
+diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
+index 7d2e737..c1ffee2 100644
+--- a/src/core/load-fragment.c
++++ b/src/core/load-fragment.c
+@@ -3081,12 +3081,11 @@ int config_parse_tasks_max(
+                 void *data,
+                 void *userdata) {
+ 
+-        CGroupContext *c = data;
+-        uint64_t u;
++        uint64_t *tasks_max = data, u;
+         int r;
+ 
+         if (isempty(rvalue) || streq(rvalue, "infinity")) {
+-                c->tasks_max = (uint64_t) -1;
++                *tasks_max = (uint64_t) -1;
+                 return 0;
+         }
+ 
+@@ -3096,6 +3095,8 @@ int config_parse_tasks_max(
+                 return 0;
+         }
+ 
++        *tasks_max = u;
++
+         return 0;
+ }
+ 
+diff --git a/src/core/main.c b/src/core/main.c
+index aca05a5..50c9714 100644
+--- a/src/core/main.c
++++ b/src/core/main.c
+@@ -118,6 +118,7 @@ static bool arg_default_blockio_accounting = false;
+ static bool arg_default_memory_accounting = false;
+ static EmergencyAction arg_cad_burst_action = EMERGENCY_ACTION_REBOOT_FORCE;
+ static bool arg_default_tasks_accounting = false;
++static uint64_t arg_default_tasks_max = (uint64_t) -1;
+ 
+ static void nop_handler(int sig) {}
+ 
+@@ -678,6 +679,7 @@ static int parse_config_file(void) {
+                 { "Manager", "DefaultMemoryAccounting",   config_parse_bool,             0, &arg_default_memory_accounting         },
+                 { "Manager", "CtrlAltDelBurstAction",     config_parse_emergency_action, 0, &arg_cad_burst_action                  },
+                 { "Manager", "DefaultTasksAccounting",    config_parse_bool,             0, &arg_default_tasks_accounting          },
++                { "Manager", "DefaultTasksMax",           config_parse_tasks_max,        0, &arg_default_tasks_max                 },
+                 {}
+         };
+ 
+@@ -1688,6 +1690,7 @@ int main(int argc, char *argv[]) {
+         m->default_blockio_accounting = arg_default_blockio_accounting;
+         m->default_memory_accounting = arg_default_memory_accounting;
+         m->default_tasks_accounting = arg_default_tasks_accounting;
++        m->default_tasks_max = arg_default_tasks_max;
+         m->runtime_watchdog = arg_runtime_watchdog;
+         m->shutdown_watchdog = arg_shutdown_watchdog;
+ 
+diff --git a/src/core/manager.h b/src/core/manager.h
+index 96dcd83..e91e7bd 100644
+--- a/src/core/manager.h
++++ b/src/core/manager.h
+@@ -263,6 +263,7 @@ struct Manager {
+         bool default_blockio_accounting;
+         bool default_tasks_accounting;
+ 
++        uint64_t default_tasks_max;
+         usec_t default_timer_accuracy_usec;
+ 
+         struct rlimit *rlimit[_RLIMIT_MAX];
+diff --git a/src/core/system.conf b/src/core/system.conf
+index a11f599..91ef01c 100644
+--- a/src/core/system.conf
++++ b/src/core/system.conf
+@@ -40,6 +40,8 @@
+ #DefaultCPUAccounting=no
+ #DefaultBlockIOAccounting=no
+ #DefaultMemoryAccounting=no
++#DefaultTasksAccounting=no
++#DefaultTasksMax=
+ #DefaultLimitCPU=
+ #DefaultLimitFSIZE=
+ #DefaultLimitDATA=
+diff --git a/src/core/unit.c b/src/core/unit.c
+index 2fcb4fb..6a2ad6e 100644
+--- a/src/core/unit.c
++++ b/src/core/unit.c
+@@ -127,6 +127,9 @@ static void unit_init(Unit *u) {
+                 cc->blockio_accounting = u->manager->default_blockio_accounting;
+                 cc->memory_accounting = u->manager->default_memory_accounting;
+                 cc->tasks_accounting = u->manager->default_tasks_accounting;
++
++                if (u->type != UNIT_SLICE)
++                        cc->tasks_max = u->manager->default_tasks_max;
+         }
+ 
+         ec = unit_get_exec_context(u);
+diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c
+index cf757d2..c5d9e4b 100644
+--- a/src/shared/cgroup-util.c
++++ b/src/shared/cgroup-util.c
+@@ -1606,7 +1606,8 @@ static const char mask_names[] =
+         "cpuacct\0"
+         "blkio\0"
+         "memory\0"
+-        "devices\0";
++        "devices\0"
++        "pids\0";
+ 
+ int cg_create_everywhere(CGroupControllerMask supported, CGroupControllerMask mask, const char *path) {
+         CGroupControllerMask bit = 1;
diff --git a/SOURCES/0477-logind-add-a-new-UserTasksMax-setting-to-logind.conf.patch b/SOURCES/0477-logind-add-a-new-UserTasksMax-setting-to-logind.conf.patch
new file mode 100644
index 0000000..1425404
--- /dev/null
+++ b/SOURCES/0477-logind-add-a-new-UserTasksMax-setting-to-logind.conf.patch
@@ -0,0 +1,373 @@
+From ff5349960f1cf7af5404b0f765c57eb386c91216 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Fri, 13 Nov 2015 18:25:02 +0100
+Subject: [PATCH] logind: add a new UserTasksMax= setting to logind.conf
+
+This new setting configures the TasksMax= field for the slice objects we
+create for each user.
+
+This alters logind to create the slice unit as transient unit explicitly
+instead of relying on implicit generation of slice units by simply
+starting them. This also enables us to set a friendly description for
+slice units that way.
+
+Cherry-picked from: 90558f315844ec35e3fd4f1a19ac38c8721c9354
+Conflicts:
+	src/login/logind-dbus.c
+	src/login/logind-user.c
+	src/login/logind.conf
+	src/login/logind.h
+
+Resolves: #1337244
+---
+ man/logind.conf.xml          | 15 ++++++-
+ src/login/logind-dbus.c      | 94 +++++++++++++++++++++++++++++++++++++++++++-
+ src/login/logind-gperf.gperf |  1 +
+ src/login/logind-session.c   | 25 +++++++-----
+ src/login/logind-session.h   |  3 +-
+ src/login/logind-user.c      | 41 +++++++++++++------
+ src/login/logind.c           |  1 +
+ src/login/logind.conf        |  1 +
+ src/login/logind.h           |  4 +-
+ 9 files changed, 160 insertions(+), 25 deletions(-)
+
+diff --git a/man/logind.conf.xml b/man/logind.conf.xml
+index 54651f0..bcc8ee9 100644
+--- a/man/logind.conf.xml
++++ b/man/logind.conf.xml
+@@ -1,4 +1,4 @@
+-<?xml version='1.0'?> <!--*-nxml-*-->
++<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
+ <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ 
+@@ -262,7 +262,18 @@
+         limit relative to the amount of physical RAM. Defaults to 10%.
+         Note that this size is a safety limit only. As each runtime
+         directory is a tmpfs file system, it will only consume as much
+-        memory as is needed. </para></listitem>
++        memory as is needed.</para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>UserTasksMax=</varname></term>
++
++        <listitem><para>Sets the maximum number of OS tasks each user
++        may run concurrently. This controls the
++        <varname>TasksMax=</varname> setting of the per-user slice
++        unit, see
++        <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
++        for details.</para></listitem>
+       </varlistentry>
+ 
+       <varlistentry>
+diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
+index fb84e92..63b9a0d 100644
+--- a/src/login/logind-dbus.c
++++ b/src/login/logind-dbus.c
+@@ -2325,13 +2325,101 @@ int manager_dispatch_delayed(Manager *manager) {
+         return 1;
+ }
+ 
++int manager_start_slice(
++                Manager *manager,
++                const char *slice,
++                const char *description,
++                const char *after,
++                const char *after2,
++                uint64_t tasks_max,
++                sd_bus_error *error,
++                char **job) {
++
++        _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
++        int r;
++
++        assert(manager);
++        assert(slice);
++
++        r = sd_bus_message_new_method_call(
++                        manager->bus,
++                        &m,
++                        "org.freedesktop.systemd1",
++                        "/org/freedesktop/systemd1",
++                        "org.freedesktop.systemd1.Manager",
++                        "StartTransientUnit");
++        if (r < 0)
++                return r;
++
++        r = sd_bus_message_append(m, "ss", strempty(slice), "fail");
++        if (r < 0)
++                return r;
++
++        r = sd_bus_message_open_container(m, 'a', "(sv)");
++        if (r < 0)
++                return r;
++
++        if (!isempty(description)) {
++                r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
++                if (r < 0)
++                        return r;
++        }
++
++        if (!isempty(after)) {
++                r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after);
++                if (r < 0)
++                        return r;
++        }
++
++        if (!isempty(after2)) {
++                r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after2);
++                if (r < 0)
++                        return r;
++        }
++
++        r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", tasks_max);
++        if (r < 0)
++                return r;
++
++        r = sd_bus_message_close_container(m);
++        if (r < 0)
++                return r;
++
++        r = sd_bus_message_append(m, "a(sa(sv))", 0);
++        if (r < 0)
++                return r;
++
++        r = sd_bus_call(manager->bus, m, 0, error, &reply);
++        if (r < 0)
++                return r;
++
++        if (job) {
++                const char *j;
++                char *copy;
++
++                r = sd_bus_message_read(reply, "o", &j);
++                if (r < 0)
++                        return r;
++
++                copy = strdup(j);
++                if (!copy)
++                        return -ENOMEM;
++
++                *job = copy;
++        }
++
++        return 1;
++}
++
+ int manager_start_scope(
+                 Manager *manager,
+                 const char *scope,
+                 pid_t pid,
+                 const char *slice,
+                 const char *description,
+-                const char *after, const char *after2,
++                const char *after,
++                const char *after2,
++                uint64_t tasks_max,
+                 sd_bus_error *error,
+                 char **job) {
+ 
+@@ -2399,6 +2487,10 @@ int manager_start_scope(
+         if (r < 0)
+                 return r;
+ 
++        r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", tasks_max);
++        if (r < 0)
++                return r;
++
+         r = sd_bus_message_close_container(m);
+         if (r < 0)
+                 return r;
+diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf
+index 6246067..8a064e2 100644
+--- a/src/login/logind-gperf.gperf
++++ b/src/login/logind-gperf.gperf
+@@ -33,3 +33,4 @@ Login.IdleAction,                  config_parse_handle_action, 0, offsetof(Manag
+ Login.IdleActionSec,               config_parse_sec,           0, offsetof(Manager, idle_action_usec)
+ Login.RuntimeDirectorySize,        config_parse_tmpfs_size,    0, offsetof(Manager, runtime_dir_size)
+ Login.RemoveIPC,                   config_parse_bool,          0, offsetof(Manager, remove_ipc)
++Login.UserTasksMax,                config_parse_uint64,        0, offsetof(Manager, user_tasks_max)
+diff --git a/src/login/logind-session.c b/src/login/logind-session.c
+index 746e50a..4575a02 100644
+--- a/src/login/logind-session.c
++++ b/src/login/logind-session.c
+@@ -510,21 +510,28 @@ static int session_start_scope(Session *s) {
+ 
+         if (!s->scope) {
+                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+-                _cleanup_free_ char *description = NULL;
+                 char *scope, *job = NULL;
+-
+-                description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
+-                if (!description)
+-                        return log_oom();
++                const char *description;
+ 
+                 scope = strjoin("session-", s->id, ".scope", NULL);
+                 if (!scope)
+                         return log_oom();
+ 
+-                r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-logind.service", "systemd-user-sessions.service", &error, &job);
++                description = strjoina("Session ", s->id, " of user ", s->user->name, NULL);
++
++                r = manager_start_scope(
++                                s->manager,
++                                scope,
++                                s->leader,
++                                s->user->slice,
++                                description,
++                                "systemd-logind.service",
++                                "systemd-user-sessions.service",
++                                (uint64_t) -1, /* disable TasksMax= for the scope, rely on the slice setting for it */
++                                &error,
++                                &job);
+                 if (r < 0) {
+-                        log_error("Failed to start session scope %s: %s %s",
+-                                  scope, bus_error_message(&error, r), error.name);
++                        log_error_errno(r, "Failed to start session scope %s: %s", scope, bus_error_message(&error, r));
+                         free(scope);
+                         return r;
+                 } else {
+@@ -536,7 +543,7 @@ static int session_start_scope(Session *s) {
+         }
+ 
+         if (s->scope)
+-                hashmap_put(s->manager->session_units, s->scope, s);
++                (void) hashmap_put(s->manager->session_units, s->scope, s);
+ 
+         return 0;
+ }
+diff --git a/src/login/logind-session.h b/src/login/logind-session.h
+index 5002b68..d662082 100644
+--- a/src/login/logind-session.h
++++ b/src/login/logind-session.h
+@@ -115,7 +115,8 @@ struct Session {
+ 
+         bool in_gc_queue:1;
+         bool started:1;
+-        bool stopping:1;
++
++        bool stopping;
+ 
+         sd_bus_message *create_message;
+ 
+diff --git a/src/login/logind-user.c b/src/login/logind-user.c
+index 97eb4fe..4298704 100644
+--- a/src/login/logind-user.c
++++ b/src/login/logind-user.c
+@@ -33,6 +33,7 @@
+ #include "special.h"
+ #include "unit-name.h"
+ #include "bus-util.h"
++#include "bus-common-errors.h"
+ #include "bus-error.h"
+ #include "conf-parser.h"
+ #include "clean-ipc.h"
+@@ -367,34 +368,52 @@ fail:
+ }
+ 
+ static int user_start_slice(User *u) {
+-        char *job;
+         int r;
+ 
+         assert(u);
+ 
+         if (!u->slice) {
+                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+-                char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice;
+-                sprintf(lu, UID_FMT, u->uid);
++                char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice, *job;
++                const char *description;
++
++                free(u->slice_job);
++                u->slice_job = NULL;
+ 
++                xsprintf(lu, UID_FMT, u->uid);
+                 r = build_subslice(SPECIAL_USER_SLICE, lu, &slice);
+                 if (r < 0)
+-                        return r;
+-
+-                r = manager_start_unit(u->manager, slice, &error, &job);
++                        return log_error_errno(r, "Failed to build slice name: %m");
++
++                description = strjoina("User Slice of ", u->name);
++
++                r = manager_start_slice(
++                                u->manager,
++                                slice,
++                                description,
++                                "systemd-logind.service",
++                                "systemd-user-sessions.service",
++                                u->manager->user_tasks_max,
++                                &error,
++                                &job);
+                 if (r < 0) {
+-                        log_error("Failed to start user slice: %s", bus_error_message(&error, r));
+-                        free(slice);
++
++                        if (sd_bus_error_has_name(&error, BUS_ERROR_UNIT_EXISTS))
++                                /* The slice already exists? If so, that's fine, let's just reuse it */
++                                u->slice = slice;
++                        else {
++                                log_error_errno(r, "Failed to start user slice %s, ignoring: %s (%s)", slice, bus_error_message(&error, r), error.name);
++                                free(slice);
++                                /* we don't fail due to this, let's try to continue */
++                        }
+                 } else {
+                         u->slice = slice;
+-
+-                        free(u->slice_job);
+                         u->slice_job = job;
+                 }
+         }
+ 
+         if (u->slice)
+-                hashmap_put(u->manager->user_units, u->slice, u);
++                (void) hashmap_put(u->manager->user_units, u->slice, u);
+ 
+         return 0;
+ }
+diff --git a/src/login/logind.c b/src/login/logind.c
+index e8d0669..16c931c 100644
+--- a/src/login/logind.c
++++ b/src/login/logind.c
+@@ -63,6 +63,7 @@ Manager *manager_new(void) {
+         m->idle_action_not_before_usec = now(CLOCK_MONOTONIC);
+ 
+         m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */
++        m->user_tasks_max = (uint64_t) -1;
+ 
+         m->devices = hashmap_new(&string_hash_ops);
+         m->seats = hashmap_new(&string_hash_ops);
+diff --git a/src/login/logind.conf b/src/login/logind.conf
+index be8d7df..d33e0b3 100644
+--- a/src/login/logind.conf
++++ b/src/login/logind.conf
+@@ -31,3 +31,4 @@
+ #IdleActionSec=30min
+ #RuntimeDirectorySize=10%
+ #RemoveIPC=no
++#UserTasksMax=
+diff --git a/src/login/logind.h b/src/login/logind.h
+index e0cb7d0..8503eb2 100644
+--- a/src/login/logind.h
++++ b/src/login/logind.h
+@@ -128,6 +128,7 @@ struct Manager {
+         sd_event_source *lid_switch_ignore_event_source;
+ 
+         size_t runtime_dir_size;
++        uint64_t user_tasks_max;
+ };
+ 
+ Manager *manager_new(void);
+@@ -176,7 +177,8 @@ int manager_send_changed(Manager *manager, const char *property, ...) _sentinel_
+ 
+ int manager_dispatch_delayed(Manager *manager);
+ 
+-int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, const char *after2, sd_bus_error *error, char **job);
++int manager_start_slice(Manager *manager, const char *slice, const char *description, const char *after, const char *after2, uint64_t tasks_max, sd_bus_error *error, char **job);
++int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, const char *after2, uint64_t tasks_max, sd_bus_error *error, char **job);
+ int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job);
+ int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job);
+ int manager_abandon_scope(Manager *manager, const char *scope, sd_bus_error *error);
diff --git a/SOURCES/0478-core-support-percentage-specifications-on-TasksMax.patch b/SOURCES/0478-core-support-percentage-specifications-on-TasksMax.patch
new file mode 100644
index 0000000..c234520
--- /dev/null
+++ b/SOURCES/0478-core-support-percentage-specifications-on-TasksMax.patch
@@ -0,0 +1,313 @@
+From 7ec6e537898e139cc33017e03465ef40a86dd433 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Tue, 19 Jul 2016 15:58:49 +0200
+Subject: [PATCH] core: support percentage specifications on TasksMax=
+
+This adds support for a TasksMax=40% syntax for specifying values relative to
+the system's configured maximum number of processes. This is useful in order to
+neatly subdivide the available room for tasks within containers.
+
+Cherry-picked from: 83f8e80857090f63cf6a02c54d381dad3c0fad55
+Related: #1337244
+---
+ man/systemd.resource-control.xml | 15 +++----
+ src/core/dbus-cgroup.c           | 22 +++++++++++
+ src/core/load-fragment.c         | 15 +++++--
+ src/libsystemd/sd-bus/bus-util.c | 19 +++++++++
+ src/shared/util.c                | 84 ++++++++++++++++++++++++++++++++++++++++
+ src/shared/util.h                |  5 +++
+ src/test/test-util.c             | 39 +++++++++++++++++++
+ 7 files changed, 187 insertions(+), 12 deletions(-)
+
+diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml
+index 217105e..f507c67 100644
+--- a/man/systemd.resource-control.xml
++++ b/man/systemd.resource-control.xml
+@@ -221,15 +221,12 @@
+         <term><varname>TasksMax=<replaceable>N</replaceable></varname></term>
+ 
+         <listitem>
+-          <para>Specify the maximum number of tasks that may be
+-          created in the unit. This ensures that the number of tasks
+-          accounted for the unit (see above) stays below a specific
+-          limit. If assigned the special value
+-          <literal>infinity</literal> no tasks limit is applied. This
+-          controls the <literal>pids.max</literal> control group
+-          attribute. For details about this control group attribute,
+-          see <ulink
+-          url="https://www.kernel.org/doc/Documentation/cgroups/pids.txt">pids.txt</ulink>.</para>
++          <para>Specify the maximum number of tasks that may be created in the unit. This ensures that the number of
++          tasks accounted for the unit (see above) stays below a specific limit. This either takes an absolute number
++          of tasks or a percentage value that is taken relative to the configured maximum number of tasks on the
++          system.  If assigned the special value <literal>infinity</literal>, no tasks limit is applied. This controls
++          the <literal>pids.max</literal> control group attribute. For details about this control group attribute, see
++          <ulink url="https://www.kernel.org/doc/Documentation/cgroup-v1/pids.txt">pids.txt</ulink>.</para>
+ 
+           <para>Implies <literal>TasksAccounting=true</literal>. The
+           system default for this setting may be controlled with
+diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
+index a4465dc..fa76c60 100644
+--- a/src/core/dbus-cgroup.c
++++ b/src/core/dbus-cgroup.c
+@@ -694,6 +694,8 @@ int bus_cgroup_set_property(
+                 r = sd_bus_message_read(message, "t", &limit);
+                 if (r < 0)
+                         return r;
++                if (limit <= 0)
++                        return sd_bus_error_set_errnof(error, EINVAL, "%s= is too small", name);
+ 
+                 if (mode != UNIT_CHECK) {
+                         c->tasks_max = limit;
+@@ -706,6 +708,26 @@ int bus_cgroup_set_property(
+                 }
+ 
+                 return 1;
++        } else if (streq(name, "TasksMaxScale")) {
++                uint64_t limit;
++                uint32_t raw;
++
++                r = sd_bus_message_read(message, "u", &raw);
++                if (r < 0)
++                        return r;
++
++                limit = system_tasks_max_scale(raw, UINT32_MAX);
++                if (limit <= 0 || limit >= UINT64_MAX)
++                        return sd_bus_error_set_errnof(error, EINVAL, "%s= is out of range", name);
++
++                if (mode != UNIT_CHECK) {
++                        c->tasks_max = limit;
++                        u->cgroup_realized_mask &= ~CGROUP_PIDS;
++                        unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu32 "%%",
++                                                          (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX)));
++                }
++
++                return 1;
+         }
+ 
+         if (u->transient && u->load_state == UNIT_STUB) {
+diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
+index c1ffee2..4114750 100644
+--- a/src/core/load-fragment.c
++++ b/src/core/load-fragment.c
+@@ -3089,9 +3089,18 @@ int config_parse_tasks_max(
+                 return 0;
+         }
+ 
+-        r = safe_atou64(rvalue, &u);
+-        if (r < 0 || u < 1) {
+-                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Maximum tasks value '%s' invalid. Ignoring.", rvalue);
++        r = parse_percent(rvalue);
++        if (r < 0) {
++                r = safe_atou64(rvalue, &u);
++                if (r < 0) {
++                        log_syntax(unit, LOG_ERR, filename, line, r, "Maximum tasks value '%s' invalid. Ignoring.", rvalue);
++                        return 0;
++                }
++        } else
++                u = system_tasks_max_scale(r, 100U);
++
++        if (u <= 0 || u >= UINT64_MAX) {
++                log_syntax(unit, LOG_ERR, filename, line, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue);
+                 return 0;
+         }
+ 
+diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c
+index ed0849b..f46fa2b 100644
+--- a/src/libsystemd/sd-bus/bus-util.c
++++ b/src/libsystemd/sd-bus/bus-util.c
+@@ -1409,7 +1409,26 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
+                 }
+ 
+                 r = sd_bus_message_append(m, "v", "t", (uint64_t) bytes);
++        } else if (streq(field, "TasksMax")) {
++                uint64_t t;
++
++                if (isempty(eq) || streq(eq, "infinity"))
++                        t = (uint64_t) -1;
++                else {
++                        r = parse_percent(eq);
++                        if (r >= 0) {
++                                r = sd_bus_message_append(m, "sv", "TasksMaxScale", "u", (uint32_t) (((uint64_t) UINT32_MAX * r) / 100U));
++                                if (r < 0)
++                                        return bus_log_create_error(r);
++                        } else {
++                                r = safe_atou64(eq, &t);
++                                if (r < 0)
++                                        return log_error_errno(r, "Failed to parse maximum tasks specification %s", assignment);
++                        }
++
++                }
+ 
++                r = sd_bus_message_append(m, "sv", "TasksMax", "t", t);
+         } else if (STR_IN_SET(field, "CPUShares", "BlockIOWeight")) {
+                 uint64_t u;
+ 
+diff --git a/src/shared/util.c b/src/shared/util.c
+index cadadde..bbb4577 100644
+--- a/src/shared/util.c
++++ b/src/shared/util.c
+@@ -94,6 +94,7 @@
+ #include "def.h"
+ #include "sparse-endian.h"
+ #include "conf-parser.h"
++#include "cgroup-util.h"
+ 
+ int saved_argc = 0;
+ char **saved_argv = NULL;
+@@ -8707,3 +8708,86 @@ int extract_many_words(const char **p, const char *separators, ExtractFlags flag
+ 
+         return c;
+ }
++
++int parse_percent_unbounded(const char *p) {
++        const char *pc, *n;
++        unsigned v;
++        int r;
++
++        pc = endswith(p, "%");
++        if (!pc)
++                return -EINVAL;
++
++        n = strndupa(p, pc - p);
++        r = safe_atou(n, &v);
++        if (r < 0)
++                return r;
++
++        return (int) v;
++}
++
++int parse_percent(const char *p) {
++        int v;
++
++        v = parse_percent_unbounded(p);
++        if (v > 100)
++                return -ERANGE;
++
++        return v;
++}
++
++uint64_t system_tasks_max(void) {
++
++#if SIZEOF_PID_T == 4
++#define TASKS_MAX ((uint64_t) (INT32_MAX-1))
++#elif SIZEOF_PID_T == 2
++#define TASKS_MAX ((uint64_t) (INT16_MAX-1))
++#else
++#error "Unknown pid_t size"
++#endif
++
++        _cleanup_free_ char *value = NULL, *root = NULL;
++        uint64_t a = TASKS_MAX, b = TASKS_MAX;
++
++        /* Determine the maximum number of tasks that may run on this system. We check three sources to determine this
++         * limit:
++         *
++         * a) the maximum value for the pid_t type
++         * b) the cgroups pids_max attribute for the system
++         * c) the kernel's configure maximum PID value
++         *
++         * And then pick the smallest of the three */
++
++        if (read_one_line_file("/proc/sys/kernel/pid_max", &value) >= 0)
++                (void) safe_atou64(value, &a);
++
++        if (cg_get_root_path(&root) >= 0) {
++                free(value);
++                value = NULL;
++
++                if (cg_get_attribute("pids", root, "pids.max", &value) >= 0)
++                        (void) safe_atou64(value, &b);
++        }
++
++        return MIN3(TASKS_MAX,
++                    a <= 0 ? TASKS_MAX : a,
++                    b <= 0 ? TASKS_MAX : b);
++}
++
++uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) {
++        uint64_t t, m;
++
++        assert(max > 0);
++
++        /* Multiply the system's task value by the fraction v/max. Hence, if max==100 this calculates percentages
++         * relative to the system's maximum number of tasks. Returns UINT64_MAX on overflow. */
++
++        t = system_tasks_max();
++        assert(t > 0);
++
++        m = t * v;
++        if (m / t != v) /* overflow? */
++                return UINT64_MAX;
++
++        return m / max;
++}
+diff --git a/src/shared/util.h b/src/shared/util.h
+index 12afcc3..f1b6c34 100644
+--- a/src/shared/util.h
++++ b/src/shared/util.h
+@@ -1098,3 +1098,8 @@ typedef enum ExtractFlags {
+ int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags);
+ int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue);
+ int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) _sentinel_;
++int parse_percent_unbounded(const char *p);
++int parse_percent(const char *p);
++
++uint64_t system_tasks_max(void);
++uint64_t system_tasks_max_scale(uint64_t v, uint64_t max);
+diff --git a/src/test/test-util.c b/src/test/test-util.c
+index 9ae347b..971f97d 100644
+--- a/src/test/test-util.c
++++ b/src/test/test-util.c
+@@ -1530,6 +1530,43 @@ static void test_shell_maybe_quote(void) {
+         test_shell_maybe_quote_one("foo$bar", "\"foo\\$bar\"");
+ }
+ 
++static void test_system_tasks_max(void) {
++        uint64_t t;
++
++        t = system_tasks_max();
++        assert_se(t > 0);
++        assert_se(t < UINT64_MAX);
++
++        log_info("Max tasks: %" PRIu64, t);
++}
++
++static void test_system_tasks_max_scale(void) {
++        uint64_t t;
++
++        t = system_tasks_max();
++
++        assert_se(system_tasks_max_scale(0, 100) == 0);
++        assert_se(system_tasks_max_scale(100, 100) == t);
++
++        assert_se(system_tasks_max_scale(0, 1) == 0);
++        assert_se(system_tasks_max_scale(1, 1) == t);
++        assert_se(system_tasks_max_scale(2, 1) == 2*t);
++
++        assert_se(system_tasks_max_scale(0, 2) == 0);
++        assert_se(system_tasks_max_scale(1, 2) == t/2);
++        assert_se(system_tasks_max_scale(2, 2) == t);
++        assert_se(system_tasks_max_scale(3, 2) == (3*t)/2);
++        assert_se(system_tasks_max_scale(4, 2) == t*2);
++
++        assert_se(system_tasks_max_scale(0, UINT32_MAX) == 0);
++        assert_se(system_tasks_max_scale((UINT32_MAX-1)/2, UINT32_MAX-1) == t/2);
++        assert_se(system_tasks_max_scale(UINT32_MAX, UINT32_MAX) == t);
++
++        /* overflow */
++
++        assert_se(system_tasks_max_scale(UINT64_MAX/4, UINT64_MAX) == UINT64_MAX);
++}
++
+ int main(int argc, char *argv[]) {
+         log_parse_environment();
+         log_open();
+@@ -1608,6 +1645,8 @@ int main(int argc, char *argv[]) {
+         test_uid_ptr();
+         test_sparse_write();
+         test_shell_maybe_quote();
++        test_system_tasks_max();
++        test_system_tasks_max_scale();
+ 
+         return 0;
+ }
diff --git a/SOURCES/0479-core-reinstate-propagation-of-stop-restart-jobs-via-.patch b/SOURCES/0479-core-reinstate-propagation-of-stop-restart-jobs-via-.patch
new file mode 100644
index 0000000..a90101f
--- /dev/null
+++ b/SOURCES/0479-core-reinstate-propagation-of-stop-restart-jobs-via-.patch
@@ -0,0 +1,84 @@
+From 7f72b471bbfd449f4261d12cc7b062f6e7034283 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Tue, 19 May 2015 17:40:50 +0200
+Subject: [PATCH] core: reinstate propagation of stop/restart jobs via
+ RequsiteOf dependencies
+
+This reverts the primary effect of be7d9ff730cb88d7c6a869dd5c47754c78ceaef2.
+
+After all Requisite= should be close to Requires=, without the one
+exception that it doesn't pull in dependencies on start. However,
+reverse deps on stop/restart should be treated the same way as for
+Restart=, and this is already documented in the man page, hence stick to
+it.
+
+http://lists.freedesktop.org/archives/systemd-devel/2015-May/032049.html
+(cherry picked from commit ce74e76920dca603a12ef4bf605567965e9e7e45)
+
+[msekleta: we didn't backport be7d9ff730cb88d7c6a869dd5c47754c78ceaef2
+and hence we don't have UNIT_REQUISITE_OF. Note that this patch was
+backported because it makes backports of followup patches easier]
+
+Related: #1436021
+---
+ src/core/transaction.c | 41 +++++++++++++----------------------------
+ 1 file changed, 13 insertions(+), 28 deletions(-)
+
+diff --git a/src/core/transaction.c b/src/core/transaction.c
+index 57e9cb3..428b767 100644
+--- a/src/core/transaction.c
++++ b/src/core/transaction.c
+@@ -1008,40 +1008,25 @@ int transaction_add_job_and_dependencies(
+                 }
+ 
+                 if (type == JOB_STOP || type == JOB_RESTART) {
++                        static const UnitDependency propagate_deps[] = {
++                                UNIT_REQUIRED_BY,
++                                UNIT_BOUND_BY,
++                                UNIT_CONSISTS_OF,
++                        };
+ 
+-                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRED_BY], i) {
+-                                r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
+-                                if (r < 0) {
+-                                        if (r != -EBADR)
+-                                                goto fail;
+-
+-                                        if (e)
+-                                                sd_bus_error_free(e);
+-                                }
+-                        }
+-
+-                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_BOUND_BY], i) {
+-                                r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
+-                                if (r < 0) {
+-                                        if (r != -EBADR)
+-                                                goto fail;
++                        unsigned j;
+ 
+-                                        if (e)
+-                                                sd_bus_error_free(e);
+-                                }
+-                        }
++                        for (j = 0; j < ELEMENTSOF(propagate_deps); j++)
++                                SET_FOREACH(dep, ret->unit->dependencies[propagate_deps[j]], i) {
+ 
+-                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONSISTS_OF], i) {
+-                                r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
+-                                if (r < 0) {
+-                                        if (r != -EBADR)
+-                                                goto fail;
++                                        r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
++                                        if (r < 0) {
++                                                if (r != -EBADR)
++                                                        goto fail;
+ 
+-                                        if (e)
+                                                 sd_bus_error_free(e);
++                                        }
+                                 }
+-                        }
+-
+                 }
+ 
+                 if (type == JOB_RELOAD) {
diff --git a/SOURCES/0480-core-when-propagating-restart-requests-due-to-deps-d.patch b/SOURCES/0480-core-when-propagating-restart-requests-due-to-deps-d.patch
new file mode 100644
index 0000000..65266bb
--- /dev/null
+++ b/SOURCES/0480-core-when-propagating-restart-requests-due-to-deps-d.patch
@@ -0,0 +1,142 @@
+From 77f4e582d0f381391594e6f8a7b6767d572d96f7 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Tue, 19 May 2015 18:13:22 +0200
+Subject: [PATCH] core: when propagating restart requests due to deps,
+ downgrade restart to try-restart
+
+Previously, if a service A depended on a service B via Requires=, and A
+was not running and B restarted this would trigger a start of A as well,
+since the restart was propagated as restart independently of the state
+of A.
+
+This patch ensures that a restart of B would be propagated as a
+try-restart to A, thus not changing its state if it isn't up.
+
+http://lists.freedesktop.org/archives/systemd-devel/2015-May/032061.html
+(cherry picked from commit c6497ccb7153af9a1252c48918e380b5134314de)
+
+Resolves: #1436021
+---
+ src/core/job.c         | 28 ++++++++++++++--------------
+ src/core/job.h         |  2 +-
+ src/core/manager.c     |  2 +-
+ src/core/transaction.c | 11 ++++++++---
+ 4 files changed, 24 insertions(+), 19 deletions(-)
+
+diff --git a/src/core/job.c b/src/core/job.c
+index 7032864..1617e24 100644
+--- a/src/core/job.c
++++ b/src/core/job.c
+@@ -392,38 +392,38 @@ bool job_type_is_redundant(JobType a, UnitActiveState b) {
+         }
+ }
+ 
+-void job_type_collapse(JobType *t, Unit *u) {
++JobType job_type_collapse(JobType t, Unit *u) {
+         UnitActiveState s;
+ 
+-        switch (*t) {
++        switch (t) {
+ 
+         case JOB_TRY_RESTART:
+                 s = unit_active_state(u);
+                 if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
+-                        *t = JOB_NOP;
+-                else
+-                        *t = JOB_RESTART;
+-                break;
++                        return JOB_NOP;
++
++                return JOB_RESTART;
+ 
+         case JOB_RELOAD_OR_START:
+                 s = unit_active_state(u);
+                 if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
+-                        *t = JOB_START;
+-                else
+-                        *t = JOB_RELOAD;
+-                break;
++                        return JOB_START;
++
++                return JOB_RELOAD;
+ 
+         default:
+-                ;
++                return t;
+         }
+ }
+ 
+ int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u) {
+-        JobType t = job_type_lookup_merge(*a, b);
++        JobType t;
++
++        t = job_type_lookup_merge(*a, b);
+         if (t < 0)
+                 return -EEXIST;
+-        *a = t;
+-        job_type_collapse(a, u);
++
++        *a = job_type_collapse(t, u);
+         return 0;
+ }
+ 
+diff --git a/src/core/job.h b/src/core/job.h
+index e4191ee..ce81607 100644
+--- a/src/core/job.h
++++ b/src/core/job.h
+@@ -210,7 +210,7 @@ bool job_type_is_redundant(JobType a, UnitActiveState b) _pure_;
+ 
+ /* Collapses a state-dependent job type into a simpler type by observing
+  * the state of the unit which it is going to be applied to. */
+-void job_type_collapse(JobType *t, Unit *u);
++JobType job_type_collapse(JobType t, Unit *u);
+ 
+ int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u);
+ 
+diff --git a/src/core/manager.c b/src/core/manager.c
+index 8bd80e6..287cf6a 100644
+--- a/src/core/manager.c
++++ b/src/core/manager.c
+@@ -1303,7 +1303,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove
+                        "Trying to enqueue job %s/%s/%s", unit->id,
+                        job_type_to_string(type), job_mode_to_string(mode));
+ 
+-        job_type_collapse(&type, unit);
++        type = job_type_collapse(type, unit);
+ 
+         tr = transaction_new(mode == JOB_REPLACE_IRREVERSIBLY);
+         if (!tr)
+diff --git a/src/core/transaction.c b/src/core/transaction.c
+index 428b767..34df157 100644
+--- a/src/core/transaction.c
++++ b/src/core/transaction.c
+@@ -855,8 +855,7 @@ int transaction_add_job_and_dependencies(
+         /*           by ? job_type_to_string(by->type) : "NA"); */
+ 
+         if (!IN_SET(unit->load_state, UNIT_LOADED, UNIT_ERROR, UNIT_NOT_FOUND, UNIT_MASKED))
+-                return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
+-                                         "Unit %s is not loaded properly.", unit->id);
++                return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id);
+ 
+         if (type != JOB_STOP) {
+                 r = bus_unit_check_load_state(unit, e);
+@@ -1014,12 +1013,18 @@ int transaction_add_job_and_dependencies(
+                                 UNIT_CONSISTS_OF,
+                         };
+ 
++                        JobType ptype;
+                         unsigned j;
+ 
++                        /* We propagate STOP as STOP, but RESTART only
++                         * as TRY_RESTART, in order not to start
++                         * dependencies that are not around. */
++                        ptype = type == JOB_RESTART ? JOB_TRY_RESTART : type;
++
+                         for (j = 0; j < ELEMENTSOF(propagate_deps); j++)
+                                 SET_FOREACH(dep, ret->unit->dependencies[propagate_deps[j]], i) {
+ 
+-                                        r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
++                                        r = transaction_add_job_and_dependencies(tr, job_type_collapse(ptype, dep), dep, ret, true, override, false, false, ignore_order, e);
+                                         if (r < 0) {
+                                                 if (r != -EBADR)
+                                                         goto fail;
diff --git a/SOURCES/0481-core-properly-handle-jobs-that-are-suppressed-to-JOB.patch b/SOURCES/0481-core-properly-handle-jobs-that-are-suppressed-to-JOB.patch
new file mode 100644
index 0000000..a31278f
--- /dev/null
+++ b/SOURCES/0481-core-properly-handle-jobs-that-are-suppressed-to-JOB.patch
@@ -0,0 +1,31 @@
+From b5ed9900d9a02abd78bfb151932748725b7c0bdb Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Thu, 21 May 2015 20:39:23 +0200
+Subject: [PATCH] core: properly handle jobs that are suppressed to JOB_NOPs
+ when propagating restarts
+
+Cherry-picked from: 48894cd0
+Resolves: #1436021
+---
+ src/core/transaction.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/src/core/transaction.c b/src/core/transaction.c
+index 34df157..66bbb60 100644
+--- a/src/core/transaction.c
++++ b/src/core/transaction.c
+@@ -1023,8 +1023,13 @@ int transaction_add_job_and_dependencies(
+ 
+                         for (j = 0; j < ELEMENTSOF(propagate_deps); j++)
+                                 SET_FOREACH(dep, ret->unit->dependencies[propagate_deps[j]], i) {
++                                        JobType nt;
+ 
+-                                        r = transaction_add_job_and_dependencies(tr, job_type_collapse(ptype, dep), dep, ret, true, override, false, false, ignore_order, e);
++                                        nt = job_type_collapse(ptype, dep);
++                                        if (nt == JOB_NOP)
++                                                continue;
++
++                                        r = transaction_add_job_and_dependencies(tr, nt, dep, ret, true, override, false, false, ignore_order, e);
+                                         if (r < 0) {
+                                                 if (r != -EBADR)
+                                                         goto fail;
diff --git a/SOURCES/0482-tests-set-tasks_max-to-infinity.patch b/SOURCES/0482-tests-set-tasks_max-to-infinity.patch
new file mode 100644
index 0000000..74692de
--- /dev/null
+++ b/SOURCES/0482-tests-set-tasks_max-to-infinity.patch
@@ -0,0 +1,52 @@
+From a1c4eecf9a334e5841744cabdc18bdfdc108a636 Mon Sep 17 00:00:00 2001
+From: Lukas Nykryn <lnykryn@redhat.com>
+Date: Fri, 21 Apr 2017 15:44:25 +0200
+Subject: [PATCH] tests: set tasks_max to infinity
+
+rhel-only
+(upstream does the same but the code there is quite different)
+
+Related: #1337244
+---
+ src/test/test-cgroup-mask.c | 11 +++++++++++
+ src/test/test-execute.c     |  5 +++++
+ 2 files changed, 16 insertions(+)
+
+diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c
+index 9e9de23..471adb2 100644
+--- a/src/test/test-cgroup-mask.c
++++ b/src/test/test-cgroup-mask.c
+@@ -46,6 +46,17 @@ static int test_cgroup_mask(void) {
+                 return EXIT_TEST_SKIP;
+         }
+         assert_se(r >= 0);
++
++        /* Turn off all kinds of default accouning, so that we can
++         * verify the masks resulting of our configuration and nothing
++         * else. */
++        m->default_cpu_accounting =
++                m->default_memory_accounting =
++                m->default_blockio_accounting =
++                m->default_tasks_accounting = false;
++        m->default_tasks_max = (uint64_t) -1;
++
++        assert_se(r >= 0);
+         assert_se(manager_startup(m, serial, fdset) >= 0);
+ 
+         /* Load units and verify hierarchy. */
+diff --git a/src/test/test-execute.c b/src/test/test-execute.c
+index 8e70702..627097f 100644
+--- a/src/test/test-execute.c
++++ b/src/test/test-execute.c
+@@ -270,6 +270,11 @@ int main(int argc, char *argv[]) {
+         }
+         assert_se(r >= 0);
+         assert_se(manager_startup(m, NULL, NULL) >= 0);
++        m->default_cpu_accounting =
++                m->default_memory_accounting =
++                m->default_blockio_accounting =
++                m->default_tasks_accounting = false;
++        m->default_tasks_max = (uint64_t) -1;
+ 
+         for (test = tests; test && *test; test++)
+                 (*test)(m);
diff --git a/SOURCES/0483-Avoid-forever-loop-for-journalctl-list-boots-command.patch b/SOURCES/0483-Avoid-forever-loop-for-journalctl-list-boots-command.patch
new file mode 100644
index 0000000..1dc39f2
--- /dev/null
+++ b/SOURCES/0483-Avoid-forever-loop-for-journalctl-list-boots-command.patch
@@ -0,0 +1,49 @@
+From 9576fa3ecf91fd4703e2180ac080fd975292730f Mon Sep 17 00:00:00 2001
+From: hese10 <heikki.kemppainen@nokia.com>
+Date: Wed, 12 Oct 2016 19:40:28 +0300
+Subject: [PATCH] Avoid forever loop for journalctl --list-boots command
+ (#4278)
+
+When date is changed in system to future and normal user logs to new
+journal file, and then date is changed back to present time, the
+"journalctl --list-boot" command goes to forever loop. This commit tries
+to fix this problem by checking first the boot id list if the found boot
+id was already in that list. If it is found, then stopping the boot id
+find loop.
+
+(cherry picked from commit ec02a6c90a5d8b234db534ce3f8f1901f8532057)
+
+Conflicts:
+	src/journal/journalctl.c
+Related: #1294516
+---
+ src/journal/journalctl.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
+index 723854a..c771cff 100644
+--- a/src/journal/journalctl.c
++++ b/src/journal/journalctl.c
+@@ -1039,7 +1039,7 @@ static int get_boots(
+ 
+         bool skip_once;
+         int r, count = 0;
+-        BootId *head = NULL, *tail = NULL;
++        BootId *head = NULL, *tail = NULL, *id;
+         const bool advance_older = query_ref_boot && ref_boot_offset <= 0;
+         sd_id128_t previous_boot_id;
+ 
+@@ -1121,6 +1121,13 @@ static int get_boots(
+                                 break;
+                         }
+                 } else {
++                        LIST_FOREACH(boot_list, id, head) {
++                                if (sd_id128_equal(id->id, current->id)) {
++                                        /* boot id already stored, something wrong with the journal files */
++                                        /* exiting as otherwise this problem would cause forever loop */
++                                        goto finish;
++                                }
++                        }
+                         LIST_INSERT_AFTER(boot_list, head, tail, current);
+                         tail = current;
+                         current = NULL;
diff --git a/SOURCES/0484-sd-journal-return-SD_JOURNAL_INVALIDATE-only-if-jour.patch b/SOURCES/0484-sd-journal-return-SD_JOURNAL_INVALIDATE-only-if-jour.patch
new file mode 100644
index 0000000..82b87c5
--- /dev/null
+++ b/SOURCES/0484-sd-journal-return-SD_JOURNAL_INVALIDATE-only-if-jour.patch
@@ -0,0 +1,40 @@
+From ca55fb67bc81313edf0aa6523b6f9ffce50ecdda Mon Sep 17 00:00:00 2001
+From: Michal Sekletar <msekletar@users.noreply.github.com>
+Date: Mon, 24 Apr 2017 18:33:12 +0200
+Subject: [PATCH] sd-journal: return SD_JOURNAL_INVALIDATE only if journal
+ files were actually deleted/moved (#5580)
+
+When caller invokes sd_journal_open() we usually open at least one
+directory with journal files. add_root_directory() function increments
+current_invalidate_counter. After sd_journal_open() returns
+current_invalidate_counter != last_invalidate_counter.
+
+After caller waits for journal events (e.g. waits for new messages in
+journal) then it usually calls sd_journal_process(). However, on first
+call to sd_journal_process(), function determine_change() returns
+SD_JOURNAL_INVALIDATE even though no journal files were
+deleted/moved. This is because current_invalidate_counter !=
+last_invalidate_counter.
+
+After the fix we make sure counters has the same value before we begin
+processing inotify events.
+
+(cherry picked from commit f934644424daa6c86fd2284fe8f33ea233ece874)
+
+Resolves: #1446140
+---
+ src/journal/sd-journal.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
+index 20456c3..72f312b 100644
+--- a/src/journal/sd-journal.c
++++ b/src/journal/sd-journal.c
+@@ -2190,6 +2190,7 @@ _public_ int sd_journal_process(sd_journal *j) {
+         assert_return(!journal_pid_changed(j), -ECHILD);
+ 
+         j->last_process_usec = now(CLOCK_MONOTONIC);
++        j->last_invalidate_counter = j->current_invalidate_counter;
+ 
+         for (;;) {
+                 union inotify_event_buffer buffer;
diff --git a/SOURCES/0485-load-fragment-don-t-print-error-about-incorrect-synt.patch b/SOURCES/0485-load-fragment-don-t-print-error-about-incorrect-synt.patch
new file mode 100644
index 0000000..72d7243
--- /dev/null
+++ b/SOURCES/0485-load-fragment-don-t-print-error-about-incorrect-synt.patch
@@ -0,0 +1,29 @@
+From c6774e13acf7b3d8783bc5ab31b2ea72b2fc9aaf Mon Sep 17 00:00:00 2001
+From: Michal Sekletar <msekleta@redhat.com>
+Date: Tue, 25 Apr 2017 14:53:47 +0200
+Subject: [PATCH] load-fragment: don't print error about incorrect syntax when
+ IPv6 is disabled
+
+(cherry-picked from commit f847b8b7df1de5686f8cbe5a4944a85dfb303595)
+
+Resolves: #1377055
+---
+ src/core/load-fragment.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
+index 4114750..58e44b8 100644
+--- a/src/core/load-fragment.c
++++ b/src/core/load-fragment.c
+@@ -367,8 +367,9 @@ int config_parse_socket_listen(const char *unit,
+ 
+                 r = socket_address_parse(&p->address, k ? k : rvalue);
+                 if (r < 0) {
+-                        log_syntax(unit, LOG_ERR, filename, line, -r,
+-                                   "Failed to parse address value, ignoring: %s", rvalue);
++                        if (r != -EAFNOSUPPORT)
++                                log_syntax(unit, LOG_ERR, filename, line, -r,
++                                           "Failed to parse address value, ignoring: %s", rvalue);
+                         return 0;
+                 }
+ 
diff --git a/SOURCES/0486-core-manager-add-some-missing-dbus-properties.patch b/SOURCES/0486-core-manager-add-some-missing-dbus-properties.patch
new file mode 100644
index 0000000..3b2886d
--- /dev/null
+++ b/SOURCES/0486-core-manager-add-some-missing-dbus-properties.patch
@@ -0,0 +1,36 @@
+From 285085cc7df8dd01fd372ce484ac9b3fb2d23de3 Mon Sep 17 00:00:00 2001
+From: Evgeny Vereshchagin <evvers@ya.ru>
+Date: Thu, 8 Oct 2015 07:35:36 +0300
+Subject: [PATCH] core: manager: add some missing dbus properties
+
+(cherry picked from commit 670a3efe31e729f9396fbf615aede47f10b4462e)
+
+Conflicts:
+	src/core/dbus-manager.c
+
+Resolves: #1427927
+---
+ src/core/dbus-manager.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
+index c92f8c6..9d4f633 100644
+--- a/src/core/dbus-manager.c
++++ b/src/core/dbus-manager.c
+@@ -2039,6 +2039,16 @@ const sd_bus_vtable bus_manager_vtable[] = {
+         SD_BUS_WRITABLE_PROPERTY("ShutdownWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, shutdown_watchdog), 0),
+         SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Manager, cgroup_root), 0),
+         SD_BUS_PROPERTY("SystemState", "s", property_get_system_state, 0, 0),
++        SD_BUS_PROPERTY("DefaultTimerAccuracyUSec", "t", bus_property_get_usec, offsetof(Manager, default_timer_accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("DefaultTimeoutStartUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("DefaultTimeoutStopUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("DefaultRestartUSec", "t", bus_property_get_usec, offsetof(Manager, default_restart_usec), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("DefaultStartLimitInterval", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("DefaultStartLimitBurst", "u", bus_property_get_unsigned, offsetof(Manager, default_start_limit_burst), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("DefaultCPUAccounting", "b", bus_property_get_bool, offsetof(Manager, default_cpu_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("DefaultBlockIOAccounting", "b", bus_property_get_bool, offsetof(Manager, default_blockio_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("DefaultMemoryAccounting", "b", bus_property_get_bool, offsetof(Manager, default_memory_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("DefaultTasksAccounting", "b", bus_property_get_bool, offsetof(Manager, default_tasks_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("DefaultTasksMax", "t", NULL, offsetof(Manager, default_tasks_max), SD_BUS_VTABLE_PROPERTY_CONST),
+ 
+         SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, SD_BUS_VTABLE_UNPRIVILEGED),
diff --git a/SOURCES/0487-core-manager-expose-DefaultLimit-as-properties-on-db.patch b/SOURCES/0487-core-manager-expose-DefaultLimit-as-properties-on-db.patch
new file mode 100644
index 0000000..534ee6a
--- /dev/null
+++ b/SOURCES/0487-core-manager-expose-DefaultLimit-as-properties-on-db.patch
@@ -0,0 +1,100 @@
+From 86669b5615683a5292ca048c362a000d471329d9 Mon Sep 17 00:00:00 2001
+From: Evgeny Vereshchagin <evvers@ya.ru>
+Date: Mon, 12 Oct 2015 06:39:00 +0000
+Subject: [PATCH] core: manager: expose DefaultLimit* as properties on dbus
+
+(cherry picked from commit 97eb42315785821dae3349978a1adf7d49aa5fc1)
+
+Conflicts:
+	src/core/dbus-manager.c
+
+Resolves: #1427927
+---
+ src/core/dbus-manager.c          | 16 ++++++++++++++++
+ src/libsystemd/sd-bus/bus-util.c | 39 +++++++++++++++++++++++++++++++++++++++
+ src/libsystemd/sd-bus/bus-util.h |  1 +
+ 3 files changed, 56 insertions(+)
+
+diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
+index 9d4f633..d34ed04 100644
+--- a/src/core/dbus-manager.c
++++ b/src/core/dbus-manager.c
+@@ -2049,6 +2049,22 @@ const sd_bus_vtable bus_manager_vtable[] = {
+         SD_BUS_PROPERTY("DefaultBlockIOAccounting", "b", bus_property_get_bool, offsetof(Manager, default_blockio_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("DefaultMemoryAccounting", "b", bus_property_get_bool, offsetof(Manager, default_memory_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("DefaultTasksAccounting", "b", bus_property_get_bool, offsetof(Manager, default_tasks_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("DefaultLimitCPU", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("DefaultLimitFSIZE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("DefaultLimitDATA", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("DefaultLimitSTACK", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("DefaultLimitCORE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("DefaultLimitRSS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("DefaultLimitNOFILE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("DefaultLimitAS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("DefaultLimitNPROC", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("DefaultLimitMEMLOCK", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("DefaultLimitLOCKS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("DefaultLimitSIGPENDING", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("DefaultLimitMSGQUEUE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("DefaultLimitNICE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("DefaultLimitRTPRIO", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
++        SD_BUS_PROPERTY("DefaultLimitRTTIME", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_PROPERTY("DefaultTasksMax", "t", NULL, offsetof(Manager, default_tasks_max), SD_BUS_VTABLE_PROPERTY_CONST),
+ 
+         SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, SD_BUS_VTABLE_UNPRIVILEGED),
+diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c
+index f46fa2b..2634574 100644
+--- a/src/libsystemd/sd-bus/bus-util.c
++++ b/src/libsystemd/sd-bus/bus-util.c
+@@ -1937,3 +1937,42 @@ int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, Un
+ 
+         return 0;
+ }
++
++int bus_property_get_rlimit(
++                sd_bus *bus,
++                const char *path,
++                const char *interface,
++                const char *property,
++                sd_bus_message *reply,
++                void *userdata,
++                sd_bus_error *error) {
++
++        struct rlimit *rl;
++        uint64_t u;
++        rlim_t x;
++
++        assert(bus);
++        assert(reply);
++        assert(userdata);
++
++        rl = *(struct rlimit**) userdata;
++        if (rl)
++                x = rl->rlim_max;
++        else {
++                struct rlimit buf = {};
++                int z;
++
++                z = rlimit_from_string(startswith(property, "Default") ? property + 7 : property);
++                assert(z >= 0);
++
++                getrlimit(z, &buf);
++                x = buf.rlim_max;
++        }
++
++        /* rlim_t might have different sizes, let's map
++         * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
++         * all archs */
++        u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x;
++
++        return sd_bus_message_append(reply, "t", u);
++}
+diff --git a/src/libsystemd/sd-bus/bus-util.h b/src/libsystemd/sd-bus/bus-util.h
+index 8c8846c..d5f4e97 100644
+--- a/src/libsystemd/sd-bus/bus-util.h
++++ b/src/libsystemd/sd-bus/bus-util.h
+@@ -214,3 +214,4 @@ int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet);
+ DEFINE_TRIVIAL_CLEANUP_FUNC(BusWaitForJobs*, bus_wait_for_jobs_free);
+ 
+ int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes);
++int bus_property_get_rlimit(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
diff --git a/SOURCES/0488-fstab-generator-remove-bogus-condition.patch b/SOURCES/0488-fstab-generator-remove-bogus-condition.patch
new file mode 100644
index 0000000..32a1d56
--- /dev/null
+++ b/SOURCES/0488-fstab-generator-remove-bogus-condition.patch
@@ -0,0 +1,30 @@
+From 38815fb30199a76684d4153a0a2dcd6abd3a2dda Mon Sep 17 00:00:00 2001
+From: nmartensen <nis.martensen@web.de>
+Date: Fri, 15 Jan 2016 07:55:25 +0100
+Subject: [PATCH] fstab-generator: remove bogus condition
+
+The sysroot mount is already taken care of by the add_sysroot_mount function. With this condition left in, we can get something like this:
+
+initrd-root-fs.target.requires
+`-- usr.mount -> /run/systemd/generator/usr.mount
+
+in the main system (i.e., not in the initramfs). In the initramfs, the previous condition already kicks in.
+Cherry-picked from: ce3f6d82b003f365f718f24e48f55b8a0372b924
+Resolves: #1446171
+---
+ src/fstab-generator/fstab-generator.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
+index 32aca22..23b5457 100644
+--- a/src/fstab-generator/fstab-generator.c
++++ b/src/fstab-generator/fstab-generator.c
+@@ -476,8 +476,6 @@ static int parse_fstab(bool initrd) {
+                                                       "x-systemd.automount\0");
+                         if (initrd)
+                                 post = SPECIAL_INITRD_FS_TARGET;
+-                        else if (mount_in_initrd(me))
+-                                post = SPECIAL_INITRD_ROOT_FS_TARGET;
+                         else if (mount_is_network(me))
+                                 post = SPECIAL_REMOTE_FS_TARGET;
+                         else
diff --git a/SOURCES/0489-readahead-collect-don-t-print-warning-message-when-h.patch b/SOURCES/0489-readahead-collect-don-t-print-warning-message-when-h.patch
new file mode 100644
index 0000000..39d36d0
--- /dev/null
+++ b/SOURCES/0489-readahead-collect-don-t-print-warning-message-when-h.patch
@@ -0,0 +1,29 @@
+From 530c665c059d3117c21b0dd6c1046accbf07208c Mon Sep 17 00:00:00 2001
+From: Michal Sekletar <msekleta@redhat.com>
+Date: Thu, 4 May 2017 16:53:30 +0200
+Subject: [PATCH] readahead-collect: don't print warning message when handling
+ symlink
+
+Since we call open() with O_NOFOLLOW we can't really open symlinks (we
+would need to add O_PATH and we don't want that). Let's shortcut things
+and return immediately, but don't treat this as an error.
+
+Resolves: #1387095
+---
+ src/readahead/readahead-collect.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/readahead/readahead-collect.c b/src/readahead/readahead-collect.c
+index 822a803..90f7f70 100644
+--- a/src/readahead/readahead-collect.c
++++ b/src/readahead/readahead-collect.c
+@@ -106,6 +106,9 @@ static int pack_file(FILE *pack, const char *fn, bool on_btrfs) {
+                 if (errno == EPERM || errno == EACCES)
+                         return 0;
+ 
++                if (errno == ELOOP)
++                        return 0;
++
+                 log_warning("open(%s) failed: %m", fn);
+                 r = -errno;
+                 goto finish;
diff --git a/SOURCES/0490-tmpfiles-don-t-recursively-descend-into-journal-dire.patch b/SOURCES/0490-tmpfiles-don-t-recursively-descend-into-journal-dire.patch
new file mode 100644
index 0000000..abb27ed
--- /dev/null
+++ b/SOURCES/0490-tmpfiles-don-t-recursively-descend-into-journal-dire.patch
@@ -0,0 +1,38 @@
+From 2a1f91ffc371f2bc3767a806ff387517ff9b9fc8 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Thu, 9 Jul 2015 18:43:55 -0300
+Subject: [PATCH] tmpfiles: don't recursively descend into journal directories
+ in /var
+
+Do so only in /run. We shouldn't alter ACLs for existing files in /var,
+but only for new files. If the admin made changes to the ACLs they
+shouls stay in place.
+
+We should still do recursive ACL changes for files in /run, since those
+are not persistent, and will hence lack ACLs on every boot.
+
+Also, /var/log/journal might be quit large, /run/log/journal is usually
+not, hence we should avoid the recursive descending on /var, but not on
+/run.
+
+Fixes #534
+
+(cherry picked from commit 8b258a645ae63dff3ab8dde6520d2e770e2a40f1)
+Related: #1411199
+---
+ tmpfiles.d/systemd.conf.m4 | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/tmpfiles.d/systemd.conf.m4 b/tmpfiles.d/systemd.conf.m4
+index b447b01..d9d51af 100644
+--- a/tmpfiles.d/systemd.conf.m4
++++ b/tmpfiles.d/systemd.conf.m4
+@@ -35,7 +35,7 @@ z /var/log/journal 2755 root systemd-journal - -
+ z /var/log/journal/%m 2755 root systemd-journal - -
+ m4_ifdef(`HAVE_ACL',``
+ a+ /var/log/journal/%m - - - - d:group:adm:r-x,d:group:wheel:r-x
+-A+ /var/log/journal/%m - - - - group:adm:r-x,group:wheel:r-x
++a+ /var/log/journal/%m - - - - group:adm:r-x,group:wheel:r-x
+ '')m4_dnl
+ 
+ d /var/lib/systemd 0755 root root -
diff --git a/SOURCES/0491-tmpfiles-also-set-acls-on-var-log-journal.patch b/SOURCES/0491-tmpfiles-also-set-acls-on-var-log-journal.patch
new file mode 100644
index 0000000..9b5cf4f
--- /dev/null
+++ b/SOURCES/0491-tmpfiles-also-set-acls-on-var-log-journal.patch
@@ -0,0 +1,29 @@
+From 2b089fee5954986c932845887ed2cfd889bd4410 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Sun, 29 Nov 2015 18:37:01 -0500
+Subject: [PATCH] tmpfiles: also set acls on /var/log/journal
+
+This way, directories created later for containers or for
+journald-remote, will be readable by adm & wheel groups by default,
+similarly to /var/log/journal/%m itself.
+
+https://github.com/systemd/systemd/issues/1971
+(cherry picked from commit 57d5b3130cd34b9a844f4258f55c1134b27bc5ad)
+Related: #1411199
+---
+ tmpfiles.d/systemd.conf.m4 | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/tmpfiles.d/systemd.conf.m4 b/tmpfiles.d/systemd.conf.m4
+index d9d51af..fcd6ec0 100644
+--- a/tmpfiles.d/systemd.conf.m4
++++ b/tmpfiles.d/systemd.conf.m4
+@@ -34,6 +34,8 @@ A+ /run/log/journal/%m - - - - group:adm:r-x,group:wheel:r-x
+ z /var/log/journal 2755 root systemd-journal - -
+ z /var/log/journal/%m 2755 root systemd-journal - -
+ m4_ifdef(`HAVE_ACL',``
++a+ /var/log/journal    - - - - d:group:adm:r-x,d:group:wheel:r-x
++a+ /var/log/journal    - - - - group:adm:r-x,group:wheel:r-x
+ a+ /var/log/journal/%m - - - - d:group:adm:r-x,d:group:wheel:r-x
+ a+ /var/log/journal/%m - - - - group:adm:r-x,group:wheel:r-x
+ '')m4_dnl
diff --git a/SOURCES/0492-tmpfiles-set-acls-on-system.journal-explicitly.patch b/SOURCES/0492-tmpfiles-set-acls-on-system.journal-explicitly.patch
new file mode 100644
index 0000000..50c0149
--- /dev/null
+++ b/SOURCES/0492-tmpfiles-set-acls-on-system.journal-explicitly.patch
@@ -0,0 +1,30 @@
+From d38e703a133487218c91f1e76072fc6b35c0978c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Sun, 29 Nov 2015 18:48:40 -0500
+Subject: [PATCH] tmpfiles: set acls on system.journal explicitly
+
+https://github.com/systemd/systemd/issues/1397
+(cherry picked from commit afae249efa4774c6676738ac5de6aeb4daf4889f)
+Resolves: #1411199
+---
+ tmpfiles.d/systemd.conf.m4 | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/tmpfiles.d/systemd.conf.m4 b/tmpfiles.d/systemd.conf.m4
+index fcd6ec0..0575408 100644
+--- a/tmpfiles.d/systemd.conf.m4
++++ b/tmpfiles.d/systemd.conf.m4
+@@ -33,11 +33,13 @@ A+ /run/log/journal/%m - - - - group:adm:r-x,group:wheel:r-x
+ 
+ z /var/log/journal 2755 root systemd-journal - -
+ z /var/log/journal/%m 2755 root systemd-journal - -
++z /var/log/journal/%m/system.journal 0640 root systemd-journal - -
+ m4_ifdef(`HAVE_ACL',``
+ a+ /var/log/journal    - - - - d:group:adm:r-x,d:group:wheel:r-x
+ a+ /var/log/journal    - - - - group:adm:r-x,group:wheel:r-x
+ a+ /var/log/journal/%m - - - - d:group:adm:r-x,d:group:wheel:r-x
+ a+ /var/log/journal/%m - - - - group:adm:r-x,group:wheel:r-x
++a+ /var/log/journal/%m/system.journal - - - - group:adm:r--,group:wheel:r--
+ '')m4_dnl
+ 
+ d /var/lib/systemd 0755 root root -
diff --git a/SOURCES/0493-sysctl-configure-kernel-parameters-in-the-order-they.patch b/SOURCES/0493-sysctl-configure-kernel-parameters-in-the-order-they.patch
new file mode 100644
index 0000000..7f3d89f
--- /dev/null
+++ b/SOURCES/0493-sysctl-configure-kernel-parameters-in-the-order-they.patch
@@ -0,0 +1,126 @@
+From 0e39139e505a8310ae8530fb2463a9e8f2170d2f Mon Sep 17 00:00:00 2001
+From: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
+Date: Sat, 24 Sep 2016 21:56:07 +0900
+Subject: [PATCH] sysctl: configure kernel parameters in the order they occur
+ in each sysctl configuration files (#4205)
+
+Currently, systemd-sysctl command configures kernel parameters in each sysctl
+configuration files in random order due to characteristics of iterator of
+Hashmap.
+
+However, kernel parameters need to be configured in the order they occur in
+each sysctl configuration files.
+
+- For example, consider fs.suid_coredump and kernel.core_pattern. If
+  fs.suid_coredump=2 is configured before kernel.core_pattern= whose default
+  value is "core", then kernel outputs the following message:
+
+      Unsafe core_pattern used with suid_dumpable=2. Pipe handler or fully qualified core dump path required.
+
+  Note that the security issue mentioned in this message has already been fixed
+  on recent kernels, so this is just a warning message on such kernels. But
+  it's still confusing to users that this message is output on some boot and
+  not output on another boot.
+
+- I don't know but there could be other kernel parameters that are significant
+  in the order they are configured.
+
+- The legacy sysctl command configures kernel parameters in the order they
+  occur in each sysctl configuration files. Although I didn't find any official
+  specification explaining this behavior of sysctl command, I don't think there
+  is any meaningful reason to change this behavior, in particular, to the
+  random one.
+
+This commit does the change by simply using OrderedHashmap instead of
+Hashmap.
+
+(cherry picked from commit 886cf982d3018f7451f0548dadbc05bd2d583bb6)
+
+Resolves: #1382244
+---
+ src/sysctl/sysctl.c | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c
+index 4fb293b..bb2bea7 100644
+--- a/src/sysctl/sysctl.c
++++ b/src/sysctl/sysctl.c
+@@ -90,14 +90,14 @@ static int apply_sysctl(const char *property, const char *value) {
+         return r;
+ }
+ 
+-static int apply_all(Hashmap *sysctl_options) {
+-        int r = 0;
++static int apply_all(OrderedHashmap *sysctl_options) {
++        int r;
+         char *property, *value;
+         Iterator i;
+ 
+         assert(sysctl_options);
+ 
+-        HASHMAP_FOREACH_KEY(value, property, sysctl_options, i) {
++        ORDERED_HASHMAP_FOREACH_KEY(value, property, sysctl_options, i) {
+                 int k;
+ 
+                 k = apply_sysctl(property, value);
+@@ -107,7 +107,7 @@ static int apply_all(Hashmap *sysctl_options) {
+         return r;
+ }
+ 
+-static int parse_file(Hashmap *sysctl_options, const char *path, bool ignore_enoent) {
++static int parse_file(OrderedHashmap *sysctl_options, const char *path, bool ignore_enoent) {
+         _cleanup_fclose_ FILE *f = NULL;
+         int r;
+ 
+@@ -171,13 +171,13 @@ static int parse_file(Hashmap *sysctl_options, const char *path, bool ignore_eno
+                 }
+ 
+ found:
+-                existing = hashmap_get2(sysctl_options, p, &v);
++                existing = ordered_hashmap_get2(sysctl_options, p, &v);
+                 if (existing) {
+                         if (streq(value, existing))
+                                 continue;
+ 
+                         log_debug("Overwriting earlier assignment of %s in file '%s'.", p, path);
+-                        free(hashmap_remove(sysctl_options, p));
++                        free(ordered_hashmap_remove(sysctl_options, p));
+                         free(v);
+                 }
+ 
+@@ -191,7 +191,7 @@ found:
+                         return log_oom();
+                 }
+ 
+-                k = hashmap_put(sysctl_options, property, new_value);
++                k = ordered_hashmap_put(sysctl_options, property, new_value);
+                 if (k < 0) {
+                         log_error_errno(k, "Failed to add sysctl variable %s to hashmap: %m", property);
+                         free(property);
+@@ -277,7 +277,7 @@ static int parse_argv(int argc, char *argv[]) {
+ 
+ int main(int argc, char *argv[]) {
+         int r = 0, k;
+-        Hashmap *sysctl_options;
++        OrderedHashmap *sysctl_options;
+ 
+         r = parse_argv(argc, argv);
+         if (r <= 0)
+@@ -289,7 +289,7 @@ int main(int argc, char *argv[]) {
+ 
+         umask(0022);
+ 
+-        sysctl_options = hashmap_new(&string_hash_ops);
++        sysctl_options = ordered_hashmap_new(&string_hash_ops);
+         if (!sysctl_options) {
+                 r = log_oom();
+                 goto finish;
+@@ -331,7 +331,7 @@ int main(int argc, char *argv[]) {
+                 r = k;
+ 
+ finish:
+-        hashmap_free_free_free(sysctl_options);
++        ordered_hashmap_free_free_free(sysctl_options);
+         strv_free(arg_prefixes);
+ 
+         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/SOURCES/0494-units-drop-explicit-NotifyAccess-setting-from-journa.patch b/SOURCES/0494-units-drop-explicit-NotifyAccess-setting-from-journa.patch
new file mode 100644
index 0000000..7766cd1
--- /dev/null
+++ b/SOURCES/0494-units-drop-explicit-NotifyAccess-setting-from-journa.patch
@@ -0,0 +1,31 @@
+From 3126e1ac82a14399e4a759b68ab85e10ba8ba3b3 Mon Sep 17 00:00:00 2001
+From: Michal Sekletar <msekletar@users.noreply.github.com>
+Date: Wed, 19 Apr 2017 08:52:40 +0200
+Subject: [PATCH] units: drop explicit NotifyAccess setting from journald's
+ unit file (#5749)
+
+systemd-journald service consists of only single process and that is the
+MainPID. Make unit file shorter and drop NotifyAccess=all since it is
+not useful in such case.
+
+https://lists.freedesktop.org/archives/systemd-devel/2017-April/038667.html
+
+(cherry picked from commit 6f0e6bd253f449bedec78ec8a468929d3c5d8faf)
+
+Resolves: #1444356
+---
+ units/systemd-journald.service.in | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/units/systemd-journald.service.in b/units/systemd-journald.service.in
+index 8575912..c85c349 100644
+--- a/units/systemd-journald.service.in
++++ b/units/systemd-journald.service.in
+@@ -19,7 +19,6 @@ Sockets=systemd-journald.socket
+ ExecStart=@rootlibexecdir@/systemd-journald
+ Restart=always
+ RestartSec=0
+-NotifyAccess=all
+ StandardOutput=null
+ CapabilityBoundingSet=CAP_SYS_ADMIN CAP_DAC_OVERRIDE CAP_SYS_PTRACE CAP_SYSLOG CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_CHOWN CAP_DAC_READ_SEARCH CAP_FOWNER CAP_SETUID CAP_SETGID CAP_MAC_OVERRIDE
+ WatchdogSec=3min
diff --git a/SOURCES/0495-systemd-notify-Always-pass-a-valid-pid-to-sd_pid_not.patch b/SOURCES/0495-systemd-notify-Always-pass-a-valid-pid-to-sd_pid_not.patch
new file mode 100644
index 0000000..122feb5
--- /dev/null
+++ b/SOURCES/0495-systemd-notify-Always-pass-a-valid-pid-to-sd_pid_not.patch
@@ -0,0 +1,32 @@
+From 6f755a0934a1806a187076f9757064d3e973d1d2 Mon Sep 17 00:00:00 2001
+From: Benjamin Robin <dev@benjarobin.fr>
+Date: Sat, 19 Sep 2015 21:57:51 +0200
+Subject: [PATCH] systemd-notify: Always pass a valid pid to sd_pid_notify
+
+If the option --pid was used, take the pid from this option, unless take
+the parend pid. Using 0 as pid (ucred of systemd-notify) will result 99% of the
+time in a failure with this error: "Cannot find unit for notify message of PID"
+
+Shouldn't we use always the ppid, since the MAINPID is something else ?
+
+Signed-off-by: Benjamin Robin <dev@benjarobin.fr>
+
+Cherry-picked from: 9de009a9
+Resolves: #1381743
+---
+ src/notify/notify.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/notify/notify.c b/src/notify/notify.c
+index c89a6cc..0d38299 100644
+--- a/src/notify/notify.c
++++ b/src/notify/notify.c
+@@ -209,7 +209,7 @@ int main(int argc, char* argv[]) {
+                 goto finish;
+         }
+ 
+-        r = sd_pid_notify(arg_pid, false, n);
++        r = sd_pid_notify(arg_pid ? arg_pid : getppid(), false, n);
+         if (r < 0) {
+                 log_error_errno(r, "Failed to notify init system: %m");
+                 goto finish;
diff --git a/SOURCES/0496-sd_pid_notify_with_fds-fix-computing-msg_controllen.patch b/SOURCES/0496-sd_pid_notify_with_fds-fix-computing-msg_controllen.patch
new file mode 100644
index 0000000..17e7eea
--- /dev/null
+++ b/SOURCES/0496-sd_pid_notify_with_fds-fix-computing-msg_controllen.patch
@@ -0,0 +1,30 @@
+From 5a282fc000a52fe98a31ac69832678b1d1d5778d Mon Sep 17 00:00:00 2001
+From: Maciej Wereski <m.wereski@partner.samsung.com>
+Date: Tue, 8 Sep 2015 15:36:30 +0200
+Subject: [PATCH] sd_pid_notify_with_fds: fix computing msg_controllen
+
+CMSG_SPACE(0) may return value other than 0. This caused sendmsg to fail
+with EINVAL, when have_pid or n_fds was 0.
+
+Cherry-picked from: a5bd3c32abb00ad945282568fd1a97c180b68047
+Resolves: #1381743
+---
+ src/libsystemd/sd-daemon/sd-daemon.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c
+index 1474321..2c4dd9d 100644
+--- a/src/libsystemd/sd-daemon/sd-daemon.c
++++ b/src/libsystemd/sd-daemon/sd-daemon.c
+@@ -397,8 +397,9 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char
+         have_pid = pid != 0 && pid != getpid();
+ 
+         if (n_fds > 0 || have_pid) {
+-                msghdr.msg_controllen = CMSG_SPACE(sizeof(int) * n_fds) +
+-                                        CMSG_SPACE(sizeof(struct ucred) * have_pid);
++                /* CMSG_SPACE(0) may return value different then zero, which results in miscalculated controllen. */
++                msghdr.msg_controllen = (n_fds ? CMSG_SPACE(sizeof(int) * n_fds) : 0) +
++                                        CMSG_SPACE(sizeof(struct ucred)) * have_pid;
+                 msghdr.msg_control = alloca(msghdr.msg_controllen);
+ 
+                 cmsg = CMSG_FIRSTHDR(&msghdr);
diff --git a/SOURCES/0497-rules-move-cpu-hotplug-rule-to-separate-file.patch b/SOURCES/0497-rules-move-cpu-hotplug-rule-to-separate-file.patch
new file mode 100644
index 0000000..b9f2cb7
--- /dev/null
+++ b/SOURCES/0497-rules-move-cpu-hotplug-rule-to-separate-file.patch
@@ -0,0 +1,58 @@
+From 360d7eb0f8233d16557ef34a9e58055a67ea9b70 Mon Sep 17 00:00:00 2001
+From: Michal Sekletar <msekleta@redhat.com>
+Date: Mon, 12 Jun 2017 13:43:48 +0200
+Subject: [PATCH] rules: move cpu hotplug rule to separate file
+
+In kdump initrd we don't want to automatically bring online all
+available CPUs. Hence, kdump maintainers can easily mask the rule by
+placing symlink to /dev/null with the same name in /etc/udev/rules.d
+
+RHEL-only
+
+Related: #1266322
+
+[msekleta: note that this is just part of the fix for #1266322, in
+order to fix the bug it is necessary to actually mask the newly added
+rule when generating kdump initrd]
+---
+ Makefile.am                       | 1 +
+ rules/40-redhat-cpu-hotplug.rules | 4 ++++
+ rules/40-redhat.rules             | 3 ---
+ 3 files changed, 5 insertions(+), 3 deletions(-)
+ create mode 100644 rules/40-redhat-cpu-hotplug.rules
+
+diff --git a/Makefile.am b/Makefile.am
+index e9ceac9..94fee02 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -3511,6 +3511,7 @@ dist_udevrules_DATA += \
+ 	rules/80-net-setup-link.rules \
+ 	rules/95-udev-late.rules \
+ 	rules/40-redhat.rules \
++	rules/40-redhat-cpu-hotplug.rules \
+ 	rules/73-idrac.rules \
+         rules/80-net-name-slot.rules
+ 
+diff --git a/rules/40-redhat-cpu-hotplug.rules b/rules/40-redhat-cpu-hotplug.rules
+new file mode 100644
+index 0000000..bc5ddc8
+--- /dev/null
++++ b/rules/40-redhat-cpu-hotplug.rules
+@@ -0,0 +1,4 @@
++# do not edit this file, it will be overwritten on update
++
++# CPU hotadd request
++SUBSYSTEM=="cpu", ACTION=="add", TEST=="online", ATTR{online}=="0", ATTR{online}="1"
+diff --git a/rules/40-redhat.rules b/rules/40-redhat.rules
+index 34a1df9..d04c7fc 100644
+--- a/rules/40-redhat.rules
++++ b/rules/40-redhat.rules
+@@ -1,8 +1,5 @@
+ # do not edit this file, it will be overwritten on update
+ 
+-# CPU hotadd request
+-SUBSYSTEM=="cpu", ACTION=="add", TEST=="online", ATTR{online}=="0", ATTR{online}="1"
+-
+ # Memory hotadd request
+ SUBSYSTEM=="memory", ACTION=="add", PROGRAM="/bin/uname -p", RESULT!="s390*", ATTR{state}=="offline", ATTR{state}="online"
+ 
diff --git a/SOURCES/0498-Revert-rules-move-cpu-hotplug-rule-to-separate-file.patch b/SOURCES/0498-Revert-rules-move-cpu-hotplug-rule-to-separate-file.patch
new file mode 100644
index 0000000..7b83053
--- /dev/null
+++ b/SOURCES/0498-Revert-rules-move-cpu-hotplug-rule-to-separate-file.patch
@@ -0,0 +1,49 @@
+From f8747430762d9daad14f71cdd7ee98daf833e161 Mon Sep 17 00:00:00 2001
+From: Lukas Nykryn <lnykryn@redhat.com>
+Date: Tue, 27 Jun 2017 09:21:19 +0200
+Subject: [PATCH] Revert "rules: move cpu hotplug rule to separate file"
+
+This reverts commit 360d7eb0f8233d16557ef34a9e58055a67ea9b70.
+Resolves: #1465108
+---
+ Makefile.am                       | 1 -
+ rules/40-redhat-cpu-hotplug.rules | 4 ----
+ rules/40-redhat.rules             | 3 +++
+ 3 files changed, 3 insertions(+), 5 deletions(-)
+ delete mode 100644 rules/40-redhat-cpu-hotplug.rules
+
+diff --git a/Makefile.am b/Makefile.am
+index 94fee02..e9ceac9 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -3511,7 +3511,6 @@ dist_udevrules_DATA += \
+ 	rules/80-net-setup-link.rules \
+ 	rules/95-udev-late.rules \
+ 	rules/40-redhat.rules \
+-	rules/40-redhat-cpu-hotplug.rules \
+ 	rules/73-idrac.rules \
+         rules/80-net-name-slot.rules
+ 
+diff --git a/rules/40-redhat-cpu-hotplug.rules b/rules/40-redhat-cpu-hotplug.rules
+deleted file mode 100644
+index bc5ddc8..0000000
+--- a/rules/40-redhat-cpu-hotplug.rules
++++ /dev/null
+@@ -1,4 +0,0 @@
+-# do not edit this file, it will be overwritten on update
+-
+-# CPU hotadd request
+-SUBSYSTEM=="cpu", ACTION=="add", TEST=="online", ATTR{online}=="0", ATTR{online}="1"
+diff --git a/rules/40-redhat.rules b/rules/40-redhat.rules
+index d04c7fc..34a1df9 100644
+--- a/rules/40-redhat.rules
++++ b/rules/40-redhat.rules
+@@ -1,5 +1,8 @@
+ # do not edit this file, it will be overwritten on update
+ 
++# CPU hotadd request
++SUBSYSTEM=="cpu", ACTION=="add", TEST=="online", ATTR{online}=="0", ATTR{online}="1"
++
+ # Memory hotadd request
+ SUBSYSTEM=="memory", ACTION=="add", PROGRAM="/bin/uname -p", RESULT!="s390*", ATTR{state}=="offline", ATTR{state}="online"
+ 
diff --git a/SPECS/systemd.spec b/SPECS/systemd.spec
index e16fce3..e279859 100644
--- a/SPECS/systemd.spec
+++ b/SPECS/systemd.spec
@@ -7,12 +7,12 @@
 Name:           systemd
 Url:            http://www.freedesktop.org/wiki/Software/systemd
 Version:        219
-Release:        30%{?dist}.9
+Release:        42%{?dist}
 # For a breakdown of the licensing, see README
 License:        LGPLv2+ and MIT and GPLv2+
 Summary:        A System and Service Manager
 
-Source0:        http://www.freedesktop.org/software/systemd/%{name}-%{version}.tar.xz
+Source0:        https://github.com/systemd/systemd/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz
 # Preset policy is in rhel-release package
 # we are just disabling everything
 Source1:        99-default-disable.preset
@@ -26,6 +26,7 @@ Source4:        rc.local
 Source5:        60-alias-kmsg.rules
 # Stop-gap, just to ensure things work fine with rsyslog without having to change the package right-away
 Source6:        listen.conf
+# Generating translations is sometimes broken, let's ship the translated policy files directly in sources
 Source7:        org.freedesktop.hostname1.policy
 Source8:        org.freedesktop.import1.policy
 Source9:        org.freedesktop.locale1.policy
@@ -449,16 +450,90 @@ Patch0411: 0411-pid1-don-t-return-any-error-in-manager_dispatch_noti.patch
 Patch0412: 0412-pid1-process-zero-length-notification-messages-again.patch
 Patch0413: 0413-pid1-more-informative-error-message-for-ignored-noti.patch
 Patch0414: 0414-manager-219-needs-u-id-in-log_unit_debug.patch
-Patch0415: 0415-mtd_probe-add-include-for-stdint.patch
-Patch0416: 0416-virt-add-possibility-to-skip-the-check-for-chroot.patch
-Patch0417: 0417-load-fragment-fix-parsing-values-in-bytes-and-preven.patch
-Patch0418: 0418-core-fix-assertion-check.patch
-Patch0419: 0419-tmp.mount.hm4-After-swap.target-3087.patch
-Patch0420: 0420-make-sure-all-swap-units-are-ordered-before-the-swap.patch
-Patch0421: 0421-core-reinstate-propagation-of-stop-restart-jobs-via-.patch
-Patch0422: 0422-core-when-propagating-restart-requests-due-to-deps-d.patch
-Patch0423: 0423-core-properly-handle-jobs-that-are-suppressed-to-JOB.patch
-
+Patch0415: 0415-virt-add-possibility-to-skip-the-check-for-chroot.patch
+Patch0416: 0416-load-fragment-fix-parsing-values-in-bytes-and-preven.patch
+Patch0417: 0417-core-fix-assertion-check.patch
+Patch0418: 0418-tmp.mount.hm4-After-swap.target-3087.patch
+Patch0419: 0419-make-sure-all-swap-units-are-ordered-before-the-swap.patch
+Patch0420: 0420-Recognise-Lustre-as-a-remote-file-system-4530.patch
+Patch0421: 0421-unit-don-t-add-Requires-for-tmp.mount.patch
+Patch0422: 0422-core-return-0-from-device_serialize.patch
+Patch0423: 0423-mtd_probe-include-stdint.patch
+Patch0424: 0424-tests-fix-failure-of-test-execute-if-dev-mem-is-not-.patch
+Patch0425: 0425-sd-journal-properly-export-has_-persistent-runtime-_.patch
+Patch0426: 0426-core-add-possibility-to-set-action-for-ctrl-alt-del-.patch
+Patch0427: 0427-failure-action-generalize-failure-action-to-emergenc.patch
+Patch0428: 0428-core-use-emergency_action-for-ctr-alt-del-burst.patch
+Patch0429: 0429-udev-path_id-introduce-support-for-NVMe-devices-4169.patch
+Patch0430: 0430-core-fix-CapabilityBoundingSet-merging.patch
+Patch0431: 0431-core-fix-capability-bounding-set-parsing.patch
+Patch0432: 0432-core-make-parsing-of-RLIMIT_NICE-aware-of-actual-nic.patch
+Patch0433: 0433-shared-fix-double-free-in-unmask-5005.patch
+Patch0434: 0434-shared-fix-double-free-in-link.patch
+Patch0435: 0435-shared-check-strdup-NULL.patch
+Patch0436: 0436-core-improve-error-message-when-RefuseManualStart-St.patch
+Patch0437: 0437-systemctl-fix-is-enabled-exit-status-on-failure-when.patch
+Patch0438: 0438-man-document-that-the-automatic-journal-limits-are-c.patch
+Patch0439: 0439-random-seed-raise-POOL_SIZE_MIN-to-1024.patch
+Patch0440: 0440-bash-completion-add-support-for-now-5155.patch
+Patch0441: 0441-basic-fix-touch-creating-files-with-07777-mode.patch
+Patch0442: 0442-udev-net_id-add-support-for-phys_port_name-attribute.patch
+Patch0443: 0443-install-introduce-UnitFileFlags.patch
+Patch0444: 0444-shared-systemctl-teach-is-enabled-to-show-installati.patch
+Patch0445: 0445-udev-fix-crash-with-invalid-udev.log-priority.patch
+Patch0446: 0446-core-make-exec-code-a-bit-more-readable.patch
+Patch0447: 0447-core-Private-Protect-options-with-RootDirectory.patch
+Patch0448: 0448-core-if-the-start-command-vanishes-during-runtime-do.patch
+Patch0449: 0449-systemctl-make-sure-that-now-is-carried-out-5209.patch
+Patch0450: 0450-udev-inform-systemd-how-many-workers-we-can-potentia.patch
+Patch0451: 0451-service-log_unit-consumes-id-of-unit-not-a-unit.patch
+Patch0452: 0452-automount-add-expire-support.patch
+Patch0453: 0453-fstab-generator-fix-memleak.patch
+Patch0454: 0454-remove-bus-proxyd.patch
+Patch0455: 0455-execute-Add-new-PassEnvironment-directive.patch
+Patch0456: 0456-test-execute-Add-tests-for-new-PassEnvironment-direc.patch
+Patch0457: 0457-test-execute-Clarify-interaction-of-PassEnvironment-.patch
+Patch0458: 0458-load-fragment-resolve-specifiers-in-RuntimeDirectory.patch
+Patch0459: 0459-Add-microphone-mute-keymap-for-Dell-Precision.patch
+Patch0460: 0460-hwdb-update-micmute-YCODE-on-device-node-at-DELL-LAT.patch
+Patch0461: 0461-udev-path_id-improve-and-enhance-bus-detection-for-L.patch
+Patch0462: 0462-core-port-config_parse_bounding_set-to-extract_first.patch
+Patch0463: 0463-core-simplify-parsing-of-capability-bounding-set-set.patch
+Patch0464: 0464-test-add-test-for-capability-bounding-set-parsing.patch
+Patch0465: 0465-capabilities-keep-bounding-set-in-non-inverted-forma.patch
+Patch0466: 0466-capabilities-added-support-for-ambient-capabilities.patch
+Patch0467: 0467-man-add-AmbientCapabilities-entry.patch
+Patch0468: 0468-test-capability-rebase-to-upstream-version.patch
+Patch0469: 0469-namespace-don-t-fail-on-masked-mounts.patch
+Patch0470: 0470-sysv-generator-Provides-network-should-also-pull-net.patch
+Patch0471: 0471-Install-correctly-report-symlink-creations.patch
+Patch0472: 0472-rules-40-redhat.rules-rules-should-be-on-one-line.patch
+Patch0473: 0473-tmpfiles-add-new-e-action-which-cleans-up-a-dir-with.patch
+Patch0474: 0474-util-bind_remount_recursive-handle-return-0-of-set_c.patch
+Patch0475: 0475-core-add-support-for-the-pids-cgroup-controller.patch
+Patch0476: 0476-core-add-new-DefaultTasksMax-setting-for-system.conf.patch
+Patch0477: 0477-logind-add-a-new-UserTasksMax-setting-to-logind.conf.patch
+Patch0478: 0478-core-support-percentage-specifications-on-TasksMax.patch
+Patch0479: 0479-core-reinstate-propagation-of-stop-restart-jobs-via-.patch
+Patch0480: 0480-core-when-propagating-restart-requests-due-to-deps-d.patch
+Patch0481: 0481-core-properly-handle-jobs-that-are-suppressed-to-JOB.patch
+Patch0482: 0482-tests-set-tasks_max-to-infinity.patch
+Patch0483: 0483-Avoid-forever-loop-for-journalctl-list-boots-command.patch
+Patch0484: 0484-sd-journal-return-SD_JOURNAL_INVALIDATE-only-if-jour.patch
+Patch0485: 0485-load-fragment-don-t-print-error-about-incorrect-synt.patch
+Patch0486: 0486-core-manager-add-some-missing-dbus-properties.patch
+Patch0487: 0487-core-manager-expose-DefaultLimit-as-properties-on-db.patch
+Patch0488: 0488-fstab-generator-remove-bogus-condition.patch
+Patch0489: 0489-readahead-collect-don-t-print-warning-message-when-h.patch
+Patch0490: 0490-tmpfiles-don-t-recursively-descend-into-journal-dire.patch
+Patch0491: 0491-tmpfiles-also-set-acls-on-var-log-journal.patch
+Patch0492: 0492-tmpfiles-set-acls-on-system.journal-explicitly.patch
+Patch0493: 0493-sysctl-configure-kernel-parameters-in-the-order-they.patch
+Patch0494: 0494-units-drop-explicit-NotifyAccess-setting-from-journa.patch
+Patch0495: 0495-systemd-notify-Always-pass-a-valid-pid-to-sd_pid_not.patch
+Patch0496: 0496-sd_pid_notify_with_fds-fix-computing-msg_controllen.patch
+Patch0497: 0497-rules-move-cpu-hotplug-rule-to-separate-file.patch
+Patch0498: 0498-Revert-rules-move-cpu-hotplug-rule-to-separate-file.patch
 
 %global num_patches %{lua: c=0; for i,p in ipairs(patches) do c=c+1; end; print(c);}
 
@@ -494,9 +569,6 @@ BuildRequires:  gawk
 BuildRequires:  gtk-doc
 BuildRequires:  python2-devel
 BuildRequires:  python-lxml
-%ifarch x86_64 i686
-#BuildRequires:  libseccomp-devel
-%endif
 BuildRequires:  automake
 BuildRequires:  autoconf
 BuildRequires:  libtool
@@ -515,26 +587,27 @@ Requires:       %{name}-libs = %{version}-%{release}
 Requires:       kmod >= 18-4
 Requires:       redhat-release >= 7.0
 Requires:       diffutils
+
 Provides:       /bin/systemctl
 Provides:       /sbin/shutdown
 Provides:       syslog
 Provides:       systemd-units = %{version}-%{release}
+
+Conflicts:      dracut < 033-499
+Conflicts:      initscripts < 9.49.28-1
+
+#Obsolete packages when we are migrating from rhel6
 Provides:       udev = %{version}
 Obsoletes:      udev < 183
 Obsoletes:      system-setup-keyboard < 0.9
 Provides:       system-setup-keyboard = 0.9
 Obsoletes:      nss-myhostname < 0.4
 Provides:       nss-myhostname = 0.4
-# systemd-analyze got merged in F19, drop at F21
-Obsoletes:      systemd-analyze < 198
-Provides:       systemd-analyze = 198
 Obsoletes:      upstart < 1.2-3
 Obsoletes:      upstart-sysvinit < 1.2-3
 Conflicts:      upstart-sysvinit
 Obsoletes:      hal
 Obsoletes:      ConsoleKit
-Conflicts:      dracut < 033-243
-Conflicts:      initscripts < 9.49.28-1
 
 %description
 systemd is a system and service manager for Linux, compatible with
@@ -550,8 +623,6 @@ work as a drop-in replacement for sysvinit.
 Summary:        systemd libraries
 License:        LGPLv2+ and MIT
 Obsoletes:      libudev < 183
-Obsoletes:      systemd < 185-4
-Conflicts:      systemd < 185-4
 
 %description libs
 Libraries for systemd and udev, as well as the systemd PAM module.
@@ -654,63 +725,25 @@ git add .
 git commit -a -q -m "%{version} baseline."
 
 # Apply all the patches.
-git am \
---exclude .gitignore \
---exclude docs/.gitignore \
---exclude docs/gudev/.gitignore \
---exclude docs/libudev/.gitignore \
---exclude docs/sysvinit/.gitignore \
---exclude docs/var-log/.gitignore \
---exclude hwdb/.gitignore \
---exclude m4/.gitignore \
---exclude man/.gitignore \
---exclude po/.gitignore \
---exclude rules/.gitignore \
---exclude src/.gitignore \
---exclude src/analyze/.gitignore \
---exclude src/core/.gitignore \
---exclude src/gudev/.gitignore \
---exclude src/hostname/.gitignore \
---exclude src/journal/.gitignore \
---exclude src/libsystemd-daemon/.gitignore \
---exclude src/libsystemd-id128/.gitignore \
---exclude src/libudev/.gitignore \
---exclude src/locale/.gitignore \
---exclude src/login/.gitignore \
---exclude src/python-systemd/.gitignore \
---exclude tmpfiles.d/systemd.conf.m4 \
---exclude src/python-systemd/docs/.gitignore \
---exclude src/timedate/.gitignore \
---exclude src/udev/.gitignore \
---exclude src/udev/scsi_id/.gitignore \
---exclude sysctl.d/.gitignore \
---exclude test/.gitignore \
---exclude units/.gitignore \
---exclude units/user/.gitignore \
---exclude src/libsystemd/sd-bus/PORTING-DBUS1 \
---exclude CODING_STYLE \
---exclude src/readahead/Makefile \
---exclude src/libsystemd-terminal/unifont-def.h \
---exclude hwdb/sdio.ids \
-%{patches}
+git am %{patches}
 %endif
 
 %build
-autoreconf -i
+./autogen.sh
 
 CONFIGURE_OPTS=(
---libexecdir=%{_prefix}/lib
---with-sysvinit-path=/etc/rc.d/init.d
---with-rc-local-script-path-start=/etc/rc.d/rc.local
---disable-timesyncd
---disable-kdbus
---disable-terminal
---enable-gtk-doc
---enable-compat-libs
---disable-sysusers
---disable-ldconfig
+    --libexecdir=%{_prefix}/lib
+    --with-sysvinit-path=/etc/rc.d/init.d
+    --with-rc-local-script-path-start=/etc/rc.d/rc.local
+    --disable-timesyncd
+    --disable-kdbus
+    --disable-terminal
+    --enable-gtk-doc
+    --enable-compat-libs
+    --disable-sysusers
+    --disable-ldconfig
 %ifarch s390 s390x ppc %{power64} aarch64
---disable-lto
+    --disable-lto
 %endif
 )
 
@@ -863,6 +896,10 @@ rm -f %{buildroot}%{_prefix}/lib/sysctl.d/50-bridge.conf
 # no networkd in rhel7
 rm -f %{buildroot}%{_prefix}/lib/systemd/network/*
 
+# no sysusers in rhel7
+rm -f %{buildroot}%{_mandir}/man5/sysusers.d.5.gz
+rm -f %{buildroot}%{_mandir}/man8/systemd-sysusers.*
+
 install -m 0644 %{SOURCE5} $RPM_BUILD_ROOT/%{_udevrulesdir}/
 
 %pre
@@ -873,8 +910,6 @@ getent group dialout >/dev/null 2>&1 || groupadd -r -g 18 dialout >/dev/null 2>&
 getent group input >/dev/null 2>&1 || groupadd -r input >/dev/null 2>&1 || :
 getent group floppy >/dev/null 2>&1 || groupadd -r -g 19 floppy >/dev/null 2>&1 || :
 getent group systemd-journal >/dev/null 2>&1 || groupadd -r -g 190 systemd-journal 2>&1 || :
-getent group systemd-bus-proxy >/dev/null 2>&1 || groupadd -r systemd-bus-proxy 2>&1 || :
-getent passwd systemd-bus-proxy >/dev/null 2>&1 || useradd -r -l -g systemd-bus-proxy -d / -s /sbin/nologin -c "systemd Bus Proxy" systemd-bus-proxy >/dev/null 2>&1 || :
 getent group systemd-network >/dev/null 2>&1 || groupadd -r -g 192 systemd-network 2>&1 || :
 getent passwd systemd-network >/dev/null 2>&1 || useradd -r -u 192 -l -g systemd-network -d / -s /sbin/nologin -c "systemd Network Management" systemd-network >/dev/null 2>&1 || :
 
@@ -894,44 +929,44 @@ chgrp systemd-journal /run/log/journal/ /run/log/journal/`cat /etc/machine-id 2>
 chmod g+s /run/log/journal/ /run/log/journal/`cat /etc/machine-id 2> /dev/null` /var/log/journal/ /var/log/journal/`cat /etc/machine-id 2> /dev/null` >/dev/null 2>&1 || :
 
 if [ $1 -eq 1 ] ; then
-# Try to read default runlevel from the old inittab if it exists
-runlevel=$(awk -F ':' '$3 == "initdefault" && $1 !~ "^#" { print $2 }' /etc/inittab 2> /dev/null)
-if [ -z "$runlevel" ] ; then
-target="/usr/lib/systemd/system/graphical.target"
-else
-target="/usr/lib/systemd/system/runlevel$runlevel.target"
-fi
+    # Try to read default runlevel from the old inittab if it exists
+    runlevel=$(awk -F ':' '$3 == "initdefault" && $1 !~ "^#" { print $2 }' /etc/inittab 2> /dev/null)
+    if [ -z "$runlevel" ] ; then
+        target="/usr/lib/systemd/system/graphical.target"
+    else
+        target="/usr/lib/systemd/system/runlevel$runlevel.target"
+    fi
 
-# And symlink what we found to the new-style default.target
-ln -sf "$target" /etc/systemd/system/default.target >/dev/null 2>&1 || :
-
-# Services we install by default, and which are controlled by presets.
-systemctl preset \
-remote-fs.target \
-getty@.service \
-serial-getty@.service \
-console-getty.service \
-console-shell.service \
-debug-shell.service \
-systemd-readahead-replay.service \
-systemd-readahead-collect.service \
->/dev/null 2>&1 || :
+    # And symlink what we found to the new-style default.target
+    ln -sf "$target" /etc/systemd/system/default.target >/dev/null 2>&1 || :
+
+    # Services we install by default, and which are controlled by presets.
+    systemctl preset \
+        remote-fs.target \
+        getty@.service \
+        serial-getty@.service \
+        console-getty.service \
+        console-shell.service \
+        debug-shell.service \
+        systemd-readahead-replay.service \
+        systemd-readahead-collect.service \
+        >/dev/null 2>&1 || :
 else
-# This systemd service does not exist anymore, we now do it
-# internally in PID 1
-rm -f /etc/systemd/system/sysinit.target.wants/hwclock-load.service >/dev/null 2>&1 || :
-
-# This systemd target does not exist anymore. It's been replaced
-# by ntp-units.d.
-rm -f /etc/systemd/system/multi-user.target.wants/systemd-timedated-ntp.target >/dev/null 2>&1 || :
-
-# Enable the units recorded by %%pretrans
-if [ -e /var/lib/rpm-state/systemd/ntp-units ] ; then
-while read service; do
-systemctl enable "$service" >/dev/null 2>&1 || :
-done < /var/lib/rpm-state/systemd/ntp-units
-rm -r /var/lib/rpm-state/systemd/ntp-units >/dev/null 2>&1 || :
-fi
+    # This systemd service does not exist anymore, we now do it
+    # internally in PID 1
+    rm -f /etc/systemd/system/sysinit.target.wants/hwclock-load.service >/dev/null 2>&1 || :
+
+    # This systemd target does not exist anymore. It's been replaced
+    # by ntp-units.d.
+    rm -f /etc/systemd/system/multi-user.target.wants/systemd-timedated-ntp.target >/dev/null 2>&1 || :
+
+    # Enable the units recorded by %%pretrans
+    if [ -e /var/lib/rpm-state/systemd/ntp-units ] ; then
+        while read service; do
+            systemctl enable "$service" >/dev/null 2>&1 || :
+        done < /var/lib/rpm-state/systemd/ntp-units
+        rm -r /var/lib/rpm-state/systemd/ntp-units >/dev/null 2>&1 || :
+    fi
 fi
 
 # Move old stuff around in /var/lib
@@ -940,78 +975,79 @@ mv %{_localstatedir}/lib/backlight %{_localstatedir}/lib/systemd/backlight >/dev
 
 # Migrate /etc/sysconfig/clock
 if [ ! -L /etc/localtime -a -e /etc/sysconfig/clock ] ; then
-. /etc/sysconfig/clock >/dev/null 2>&1 || :
-if [ -n "$ZONE" -a -e "/usr/share/zoneinfo/$ZONE" ] ; then
-ln -sf "../usr/share/zoneinfo/$ZONE" /etc/localtime >/dev/null 2>&1 || :
-fi
+    . /etc/sysconfig/clock >/dev/null 2>&1 || :
+    if [ -n "$ZONE" -a -e "/usr/share/zoneinfo/$ZONE" ] ; then
+        ln -sf "../usr/share/zoneinfo/$ZONE" /etc/localtime >/dev/null 2>&1 || :
+    fi
 fi
 rm -f /etc/sysconfig/clock >/dev/null 2>&1 || :
 
 # Migrate /etc/sysconfig/i18n
 if [ -e /etc/sysconfig/i18n -a ! -e /etc/locale.conf ]; then
-unset LANG
-unset LC_CTYPE
-unset LC_NUMERIC
-unset LC_TIME
-unset LC_COLLATE
-unset LC_MONETARY
-unset LC_MESSAGES
-unset LC_PAPER
-unset LC_NAME
-unset LC_ADDRESS
-unset LC_TELEPHONE
-unset LC_MEASUREMENT
-unset LC_IDENTIFICATION
-. /etc/sysconfig/i18n >/dev/null 2>&1 || :
-[ -n "$LANG" ] && echo LANG=$LANG > /etc/locale.conf 2>&1 || :
-[ -n "$LC_CTYPE" ] && echo LC_CTYPE=$LC_CTYPE >> /etc/locale.conf 2>&1 || :
-[ -n "$LC_NUMERIC" ] && echo LC_NUMERIC=$LC_NUMERIC >> /etc/locale.conf 2>&1 || :
-[ -n "$LC_TIME" ] && echo LC_TIME=$LC_TIME >> /etc/locale.conf 2>&1 || :
-[ -n "$LC_COLLATE" ] && echo LC_COLLATE=$LC_COLLATE >> /etc/locale.conf 2>&1 || :
-[ -n "$LC_MONETARY" ] && echo LC_MONETARY=$LC_MONETARY >> /etc/locale.conf 2>&1 || :
-[ -n "$LC_MESSAGES" ] && echo LC_MESSAGES=$LC_MESSAGES >> /etc/locale.conf 2>&1 || :
-[ -n "$LC_PAPER" ] && echo LC_PAPER=$LC_PAPER >> /etc/locale.conf 2>&1 || :
-[ -n "$LC_NAME" ] && echo LC_NAME=$LC_NAME >> /etc/locale.conf 2>&1 || :
-[ -n "$LC_ADDRESS" ] && echo LC_ADDRESS=$LC_ADDRESS >> /etc/locale.conf 2>&1 || :
-[ -n "$LC_TELEPHONE" ] && echo LC_TELEPHONE=$LC_TELEPHONE >> /etc/locale.conf 2>&1 || :
-[ -n "$LC_MEASUREMENT" ] && echo LC_MEASUREMENT=$LC_MEASUREMENT >> /etc/locale.conf 2>&1 || :
-[ -n "$LC_IDENTIFICATION" ] && echo LC_IDENTIFICATION=$LC_IDENTIFICATION >> /etc/locale.conf 2>&1 || :
+    unset LANG
+    unset LC_CTYPE
+    unset LC_NUMERIC
+    unset LC_TIME
+    unset LC_COLLATE
+    unset LC_MONETARY
+    unset LC_MESSAGES
+    unset LC_PAPER
+    unset LC_NAME
+    unset LC_ADDRESS
+    unset LC_TELEPHONE
+    unset LC_MEASUREMENT
+    unset LC_IDENTIFICATION
+    . /etc/sysconfig/i18n >/dev/null 2>&1 || :
+    [ -n "$LANG" ] && echo LANG=$LANG > /etc/locale.conf 2>&1 || :
+    [ -n "$LC_CTYPE" ] && echo LC_CTYPE=$LC_CTYPE >> /etc/locale.conf 2>&1 || :
+    [ -n "$LC_NUMERIC" ] && echo LC_NUMERIC=$LC_NUMERIC >> /etc/locale.conf 2>&1 || :
+    [ -n "$LC_TIME" ] && echo LC_TIME=$LC_TIME >> /etc/locale.conf 2>&1 || :
+    [ -n "$LC_COLLATE" ] && echo LC_COLLATE=$LC_COLLATE >> /etc/locale.conf 2>&1 || :
+    [ -n "$LC_MONETARY" ] && echo LC_MONETARY=$LC_MONETARY >> /etc/locale.conf 2>&1 || :
+    [ -n "$LC_MESSAGES" ] && echo LC_MESSAGES=$LC_MESSAGES >> /etc/locale.conf 2>&1 || :
+    [ -n "$LC_PAPER" ] && echo LC_PAPER=$LC_PAPER >> /etc/locale.conf 2>&1 || :
+    [ -n "$LC_NAME" ] && echo LC_NAME=$LC_NAME >> /etc/locale.conf 2>&1 || :
+    [ -n "$LC_ADDRESS" ] && echo LC_ADDRESS=$LC_ADDRESS >> /etc/locale.conf 2>&1 || :
+    [ -n "$LC_TELEPHONE" ] && echo LC_TELEPHONE=$LC_TELEPHONE >> /etc/locale.conf 2>&1 || :
+    [ -n "$LC_MEASUREMENT" ] && echo LC_MEASUREMENT=$LC_MEASUREMENT >> /etc/locale.conf 2>&1 || :
+    [ -n "$LC_IDENTIFICATION" ] && echo LC_IDENTIFICATION=$LC_IDENTIFICATION >> /etc/locale.conf 2>&1 || :
 fi
 
 # Migrate /etc/sysconfig/keyboard
 if [ -e /etc/sysconfig/keyboard -a ! -e /etc/vconsole.conf ]; then
-unset SYSFONT
-unset SYSFONTACM
-unset UNIMAP
-unset KEYMAP
-[ -e /etc/sysconfig/i18n ] && . /etc/sysconfig/i18n >/dev/null 2>&1 || :
-. /etc/sysconfig/keyboard >/dev/null 2>&1 || :
-[ -n "$SYSFONT" ] && echo FONT=$SYSFONT > /etc/vconsole.conf 2>&1 || :
-[ -n "$SYSFONTACM" ] && echo FONT_MAP=$SYSFONTACM >> /etc/vconsole.conf 2>&1 || :
-[ -n "$UNIMAP" ] && echo FONT_UNIMAP=$UNIMAP >> /etc/vconsole.conf 2>&1 || :
-[ -n "$KEYTABLE" ] && echo KEYMAP=$KEYTABLE >> /etc/vconsole.conf 2>&1 || :
+    unset SYSFONT
+    unset SYSFONTACM
+    unset UNIMAP
+    unset KEYMAP
+    [ -e /etc/sysconfig/i18n ] && . /etc/sysconfig/i18n >/dev/null 2>&1 || :
+    . /etc/sysconfig/keyboard >/dev/null 2>&1 || :
+    [ -n "$SYSFONT" ] && echo FONT=$SYSFONT > /etc/vconsole.conf 2>&1 || :
+    [ -n "$SYSFONTACM" ] && echo FONT_MAP=$SYSFONTACM >> /etc/vconsole.conf 2>&1 || :
+    [ -n "$UNIMAP" ] && echo FONT_UNIMAP=$UNIMAP >> /etc/vconsole.conf 2>&1 || :
+    [ -n "$KEYTABLE" ] && echo KEYMAP=$KEYTABLE >> /etc/vconsole.conf 2>&1 || :
 fi
 rm -f /etc/sysconfig/i18n >/dev/null 2>&1 || :
 rm -f /etc/sysconfig/keyboard >/dev/null 2>&1 || :
 
 # Migrate HOSTNAME= from /etc/sysconfig/network
 if [ -e /etc/sysconfig/network -a ! -e /etc/hostname ]; then
-unset HOSTNAME
-. /etc/sysconfig/network >/dev/null 2>&1 || :
-[ -n "$HOSTNAME" ] && echo $HOSTNAME > /etc/hostname 2>&1 || :
+    unset HOSTNAME
+    . /etc/sysconfig/network >/dev/null 2>&1 || :
+    [ -n "$HOSTNAME" ] && echo $HOSTNAME > /etc/hostname 2>&1 || :
 fi
 sed -i '/^HOSTNAME=/d' /etc/sysconfig/network >/dev/null 2>&1 || :
 
 # Migrate the old systemd-setup-keyboard X11 configuration fragment
 if [ ! -e /etc/X11/xorg.conf.d/00-keyboard.conf ] ; then
-mv /etc/X11/xorg.conf.d/00-system-setup-keyboard.conf /etc/X11/xorg.conf.d/00-keyboard.conf >/dev/null 2>&1 || :
+    mv /etc/X11/xorg.conf.d/00-system-setup-keyboard.conf /etc/X11/xorg.conf.d/00-keyboard.conf >/dev/null 2>&1 || :
 else
-rm -f /etc/X11/xorg.conf.d/00-system-setup-keyboard.conf >/dev/null 2>&1 || :
+    rm -f /etc/X11/xorg.conf.d/00-system-setup-keyboard.conf >/dev/null 2>&1 || :
 fi
 
 # sed-fu to add myhostname to the hosts line of /etc/nsswitch.conf
-if [ -f /etc/nsswitch.conf ] ; then
-sed -i.bak -e '
+# Only do that when installing, not when updating.
+if [ $1 -eq 1 -a -f /etc/nsswitch.conf ] ; then
+    sed -i.bak -e '
 /^hosts:/ !b
 /\<myhostname\>/ b
 s/[[:blank:]]*$/ myhostname/
@@ -1022,57 +1058,57 @@ fi
 # Convert old /etc/sysconfig/desktop settings
 preferred=
 if [ -f /etc/sysconfig/desktop ]; then
-. /etc/sysconfig/desktop
-if [ "$DISPLAYMANAGER" = GNOME ]; then
-preferred=gdm
-elif [ "$DISPLAYMANAGER" = KDE ]; then
-preferred=kdm
-elif [ "$DISPLAYMANAGER" = WDM ]; then
-preferred=wdm
-elif [ "$DISPLAYMANAGER" = XDM ]; then
-preferred=xdm
-elif [ -n "$DISPLAYMANAGER" ]; then
-preferred=${DISPLAYMANAGER##*/}
-fi
+    . /etc/sysconfig/desktop
+    if [ "$DISPLAYMANAGER" = GNOME ]; then
+        preferred=gdm
+    elif [ "$DISPLAYMANAGER" = KDE ]; then
+        preferred=kdm
+    elif [ "$DISPLAYMANAGER" = WDM ]; then
+        preferred=wdm
+    elif [ "$DISPLAYMANAGER" = XDM ]; then
+        preferred=xdm
+    elif [ -n "$DISPLAYMANAGER" ]; then
+        preferred=${DISPLAYMANAGER##*/}
+    fi
 fi
 if [ -z "$preferred" ]; then
-if [ -x /usr/sbin/gdm ]; then
-preferred=gdm
-elif [ -x /usr/bin/kdm ]; then
-preferred=kdm
-fi
+    if [ -x /usr/sbin/gdm ]; then
+        preferred=gdm
+    elif [ -x /usr/bin/kdm ]; then
+        preferred=kdm
+    fi
 fi
 if [ -n "$preferred" -a -r "/usr/lib/systemd/system/$preferred.service" ]; then
-# This is supposed to fail when the symlink already exists
-ln -s "/usr/lib/systemd/system/$preferred.service" /etc/systemd/system/display-manager.service >/dev/null 2>&1 || :
+    # This is supposed to fail when the symlink already exists
+    ln -s "/usr/lib/systemd/system/$preferred.service" /etc/systemd/system/display-manager.service >/dev/null 2>&1 || :
 fi
 
 %postun
 if [ $1 -ge 1 ] ; then
-systemctl daemon-reload > /dev/null 2>&1 || :
+    systemctl daemon-reload > /dev/null 2>&1 || :
 fi
 
 %preun
 if [ $1 -eq 0 ] ; then
-systemctl disable \
-remote-fs.target \
-getty@.service \
-serial-getty@.service \
-console-getty.service \
-console-shell.service \
-debug-shell.service \
-systemd-readahead-replay.service \
-systemd-readahead-collect.service \
->/dev/null 2>&1 || :
-
-rm -f /etc/systemd/system/default.target >/dev/null 2>&1 || :
-
-if [ -f /etc/nsswitch.conf ] ; then
-sed -i.bak -e '
+    systemctl disable \
+        remote-fs.target \
+        getty@.service \
+        serial-getty@.service \
+        console-getty.service \
+        console-shell.service \
+        debug-shell.service \
+        systemd-readahead-replay.service \
+        systemd-readahead-collect.service \
+        >/dev/null 2>&1 || :
+
+    rm -f /etc/systemd/system/default.target >/dev/null 2>&1 || :
+
+    if [ -f /etc/nsswitch.conf ] ; then
+        sed -i.bak -e '
 /^hosts:/ !b
 s/[[:blank:]]\+myhostname\>//
 ' /etc/nsswitch.conf >/dev/null 2>&1 || :
-fi
+    fi
 fi
 
 %post libs -p /sbin/ldconfig
@@ -1136,6 +1172,9 @@ DRACUT_CONFIG="/etc/dracut.conf.d/90-eno-fix.conf"
 NEED_REBUILD=
 WROTE_MSG=
 
+# systemd-219-30 refuses onboard indexes of network card bigger then 16383
+# and this changes the name of the device. If we are updating on such machine
+# let's keep the old name with udev rule
 for i in /sys/class/net/eno* ; do
     DEVICE=${i##*/}
 
@@ -1182,7 +1221,6 @@ fi
 %dir %{_prefix}/lib/systemd/catalog
 %dir %{_prefix}/lib/systemd/ntp-units.d
 %dir %{_prefix}/lib/tmpfiles.d
-#%dir %{_prefix}/lib/sysusers.d
 %dir %{_prefix}/lib/sysctl.d
 %dir %{_prefix}/lib/modules-load.d
 %dir %{_prefix}/lib/binfmt.d
@@ -1258,7 +1296,6 @@ fi
 %{_bindir}/systemd-detect-virt
 %{_bindir}/systemd-inhibit
 %{_bindir}/systemd-path
-#%{_bindir}/systemd-sysusers
 %{_bindir}/systemd-firstboot
 %{_bindir}/hostnamectl
 %{_bindir}/localectl
@@ -1271,10 +1308,10 @@ fi
 %exclude %{_prefix}/lib/systemd/system/systemd-journal-gatewayd.*
 %exclude %{_prefix}/lib/systemd/system/systemd-journal-remote.*
 %exclude %{_prefix}/lib/systemd/system/systemd-journal-upload.*
-%exclude %{_prefix}/lib/systemd/system/systemd-networkd.service
-%exclude %{_prefix}/lib/systemd/system/systemd-networkd-wait-online.service
+%exclude %{_prefix}/lib/systemd/system/systemd-networkd*
 %exclude %{_prefix}/lib/systemd/system/systemd-resolved.service
 %exclude %{_prefix}/lib/systemd/system/dbus-org.freedesktop.resolve1.service
+%exclude %{_prefix}/lib/systemd/system/dbus-org.freedesktop.network1.service
 %{_prefix}/lib/systemd/system
 %{_prefix}/lib/systemd/user
 %exclude %{_prefix}/lib/systemd/systemd-journal-gatewayd
@@ -1297,8 +1334,6 @@ fi
 %{_prefix}/lib/tmpfiles.d/etc.conf
 %{_prefix}/lib/tmpfiles.d/sap.conf
 %{_prefix}/lib/sysctl.d/50-default.conf
-#%{_prefix}/lib/sysusers.d/basic.conf
-#%{_prefix}/lib/sysusers.d/systemd.conf
 %{_prefix}/lib/systemd/system-preset/90-systemd.preset
 %{_prefix}/lib/systemd/system-preset/99-default-disable.preset
 %{_prefix}/lib/systemd/catalog/systemd.catalog
@@ -1321,12 +1356,9 @@ fi
 %{_mandir}/man7/*
 %exclude %{_mandir}/man8/systemd-journal-gatewayd.*
 %exclude %{_mandir}/man8/systemd-journal-remote.*
-%exclude %{_mandir}/man8/systemd-networkd.*
+%exclude %{_mandir}/man8/systemd-networkd*
 %exclude %{_mandir}/man8/systemd-resolved.*
 %{_mandir}/man8/*
-#%{_datadir}/factory/etc/nsswitch.conf
-#%{_datadir}/factory/etc/pam.d/other
-#%{_datadir}/factory/etc/pam.d/system-auth
 %{_datadir}/systemd/kbd-model-map
 %{_datadir}/dbus-1/services/org.freedesktop.systemd1.service
 %{_datadir}/dbus-1/system-services/org.freedesktop.systemd1.service
@@ -1427,7 +1459,6 @@ fi
 %{_prefix}/lib/systemd/systemd-journal-upload
 %{_prefix}/lib/systemd/systemd-journal-remote
 %{_prefix}/lib/tmpfiles.d/systemd-remote.conf
-#%{_prefix}/lib/sysusers.d/systemd-remote.conf
 %{_mandir}/man8/systemd-journal-gatewayd.*
 %{_mandir}/man8/systemd-journal-remote.*
 %{_datadir}/systemd/gatewayd
@@ -1435,23 +1466,19 @@ fi
 %files networkd
 %dir %{_prefix}/lib/systemd/network
 %{_bindir}/networkctl
-#%{_prefix}/lib/systemd/network/99-default.link
-#%{_prefix}/lib/systemd/network/80-container-host0.network
-#%{_prefix}/lib/systemd/network/80-container-ve.network
-%{_prefix}/lib/systemd/system/systemd-networkd.service
-%{_prefix}/lib/systemd/system/systemd-networkd-wait-online.service
+%{_prefix}/lib/systemd/system/systemd-networkd*
 %{_prefix}/lib/systemd/systemd-networkd
 %{_prefix}/lib/systemd/systemd-networkd-wait-online
 %{_mandir}/man8/systemd-journal-gatewayd.*
 %{_mandir}/man8/systemd-journal-remote.*
-%{_mandir}/man8/systemd-networkd.*
+%{_mandir}/man8/systemd-networkd*
 %{_mandir}/man5/systemd.network.*
 %{_mandir}/man5/systemd.netdev.*
 %{_mandir}/man5/systemd.link.*
 %config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.network1.conf
 %{_datadir}/dbus-1/system-services/org.freedesktop.network1.service
-#%{_datadir}/polkit-1/actions/org.freedesktop.network1.policy
 %{_prefix}/lib/udev/rules.d/80-net-setup-link.rules
+%{_prefix}/lib/systemd/system/dbus-org.freedesktop.network1.service
 
 %files resolved
 %{_prefix}/lib/systemd/systemd-resolved
@@ -1466,18 +1493,122 @@ fi
 %{_mandir}/man8/systemd-resolved.*
 
 %changelog
-* Fri Apr 21 2017 Lukas Nykryn <lnykryn@redhat.com> - 219-30.9
-- core: reinstate propagation of stop/restart jobs via RequsiteOf dependencies (#1436021)
-- core: when propagating restart requests due to deps, downgrade restart to try-restart (#1436021)
+* Tue Jun 27 2017 Lukas Nykryn <lnykryn@redhat.com> - 219-42
+- Revert "rules: move cpu hotplug rule to separate file" (#1465108)
+
+* Mon Jun 12 2017 Lukas Nykryn <lnykryn@redhat.com> - 219-41
+- rules: move cpu hotplug rule to separate file (#1266322)
+
+* Tue May 30 2017 Lukas Nykryn <lnykryn@redhat.com> - 219-40
+- readahead-collect: don't print warning message when handling symlink (#1387095)
+- tmpfiles: don't recursively descend into journal directories in /var (#1411199)
+- tmpfiles: also set acls on /var/log/journal (#1411199)
+- tmpfiles: set acls on system.journal explicitly (#1411199)
+- sysctl: configure kernel parameters in the order they occur in each sysctl configuration files (#4205) (#1382244)
+- units: drop explicit NotifyAccess setting from journald's unit file (#5749) (#1444356)
+- systemd-notify: Always pass a valid pid to sd_pid_notify (#1381743)
+- sd_pid_notify_with_fds: fix computing msg_controllen (#1381743)
+
+* Tue May 02 2017 Lukas Nykryn <lnykryn@redhat.com> - 219-39
+- tests: set tasks_max to infinity (#1337244)
+- Avoid forever loop for journalctl --list-boots command (#4278) (#1294516)
+- sd-journal: return SD_JOURNAL_INVALIDATE only if journal files were actually deleted/moved (#5580) (#1446140)
+- load-fragment: don't print error about incorrect syntax when IPv6 is disabled (#1377055)
+- core: manager: add some missing dbus properties (#1427927)
+- core: manager: expose DefaultLimit* as properties on dbus (#1427927)
+- fstab-generator: remove bogus condition (#1446171)
+
+* Thu Apr 20 2017 Lukas Nykryn <lnykryn@redhat.com> - 219-38
 - core: properly handle jobs that are suppressed to JOB_NOPs when propagating restarts (#1436021)
 
-* Mon Feb 13 2017 Lukas Nykryn <lnykryn@redhat.com> - 219-30.8
-- tmp.mount.hm4: After swap.target (#3087) (#1298355)
-- make sure all swap units are ordered before the swap target (#1298355)
+* Wed Apr 19 2017 Lukas Nykryn <lnykryn@redhat.com> - 219-37
+- core: add support for the "pids" cgroup controller (#1337244)
+- core: add new DefaultTasksMax= setting for system.conf (#1337244)
+- logind: add a new UserTasksMax= setting to logind.conf (#1337244)
+- core: support percentage specifications on TasksMax= (#1337244)
+- core: reinstate propagation of stop/restart jobs via RequsiteOf dependencies (#1436021)
+- core: when propagating restart requests due to deps, downgrade restart to try-restart (#1436021)
 
-* Tue Nov 29 2016 Lukas Nykryn <lnykryn@redhat.com> - 219-30.7
+* Thu Apr 13 2017 Lukáš Nykrýn <lnykryn@redhat.com> - 219-36
+- spec cleanup (#1439787, #1392300, #1368929)
+
+* Tue Apr 11 2017 Lukas Nykryn <lnykryn@redhat.com> - 219-35
+- tmpfiles: add new 'e' action which cleans up a dir without creating it (#1225739)
+- util:bind_remount_recursive(): handle return 0 of set_consume() (#1433687)
+
+* Tue Apr 11 2017 Lukas Nykryn <lnykryn@redhat.com> - 219-34
+- rules/40-redhat.rules: rules should be on one line (#1274401)
+
+* Mon Apr 10 2017 Lukas Nykryn <lnykryn@redhat.com> - 219-33
+- execute: Add new PassEnvironment= directive (#1426214)
+- test-execute: Add tests for new PassEnvironment= directive (#1426214)
+- test-execute: Clarify interaction of PassEnvironment= and MANAGER_USER (#1426214)
+- load-fragment: resolve specifiers in RuntimeDirectory (#1428110)
+- Add microphone mute keymap for Dell Precision (#1413477)
+- hwdb: update micmute YCODE on device node at DELL LATITUDE laptops for mic mute button. (#5012) (#1413477)
+- udev/path_id: improve and enhance bus detection for Linux on z Systems (#1274401)
+- core: port config_parse_bounding_set to extract_first_word (#1387398)
+- core: simplify parsing of capability bounding set settings (#1387398)
+- test: add test for capability bounding set parsing (#1387398)
+- capabilities: keep bounding set in non-inverted format. (#1387398)
+- capabilities: added support for ambient capabilities. (#1387398)
+- man: add AmbientCapabilities entry. (#1387398)
+- test-capability: rebase to upstream version (#1387398)
+- namespace: don't fail on masked mounts (#1433687)
+- sysv-generator: Provides: $network should also pull network.target to transaction (#5652) (#1438749)
+- Install: correctly report symlink creations (#1435098)
+
+* Mon Feb 20 2017 Lukas Nykryn <lnykryn@redhat.com> - 219-32
+- udev: fix crash with invalid udev.log-priority (#1245293)
+- core: make exec code a bit more readable (#1421181)
+- core: Private*/Protect* options with RootDirectory (#1421181)
+- core: if the start command vanishes during runtime don't hit an assert (#1421658)
+- systemctl: make sure that --now is carried out (#5209) (#1417459)
+- udev: inform systemd how many workers we can potentially spawn (#4036) (#1361601)
+- service: log_unit consumes id of unit not a unit (#1421658)
+- automount: add expire support (#1354410)
+- fstab-generator: fix memleak (#1354410)
+- remove bus-proxyd (#1317518)
+
+* Tue Feb 07 2017 Lukas Nykryn <lnykryn@redhat.com> - 219-31
+- If the notification message length is 0, ignore the message (#4237) (#1380175)
+- systemctl: suppress errors with "show" for nonexistent units and properties (#1380259)
+- 40-redhat.rules: disable auto-online of hot-plugged memory on IBM z Systems (#1375603)
+- pid1: don't return any error in manager_dispatch_notify_fd() (#4240) (#1380259)
+- pid1: process zero-length notification messages again (#1380259
+#1380259)
+- pid1: more informative error message for ignored notifications (#1380259)
+- manager: 219 needs u->id in log_unit_debug (#1380259)
+- virt: add possibility to skip the check for chroot (#1379852)
 - load-fragment: fix parsing values in bytes and prevent returning -ERANGE incorrectly (#1396277)
 - core: fix assertion check (#1396312)
+- tmp.mount.hm4: After swap.target (#3087) (#1298355)
+- make sure all swap units are ordered before the swap target (#1298355)
+- Recognise Lustre as a remote file system (#4530) (#1390542)
+- unit: don't add Requires for tmp.mount (#1372249)
+- core: return 0 from device_serialize() (#1403249)
+- mtd_probe: include stdint (#1404251)
+- tests: fix failure of test-execute if /dev/mem is not available (#5028) (#1410056)
+- sd-journal: properly export has_{persistent|runtime}_files() (#1409527)
+- core: add possibility to set action for ctrl-alt-del burst (#4105) (#1353028)
+- failure-action: generalize failure action to emergency action (#1353028)
+- core: use emergency_action for ctr+alt+del burst (#1353028)
+- udev/path_id: introduce support for NVMe devices (#4169) (#1373150)
+- core: fix CapabilityBoundingSet merging (#1409586)
+- core: fix capability bounding set parsing (#1409586)
+- core: make parsing of RLIMIT_NICE aware of actual nice levels (#1409588)
+- shared: fix double free in unmask (#5005) (#1409997)
+- shared: fix double free in link (#1409997)
+- shared: check strdup != NULL (#1409997)
+- core: improve error message when RefuseManualStart(Stop) is hit (#5132) (#1026648)
+- systemctl: fix 'is-enabled' exit status on failure when executed in chroot (#4773) (#1413964)
+- man: document that the automatic journal limits are capped to 4G by default (#1418547)
+- random-seed: raise POOL_SIZE_MIN to 1024 (#1386824)
+- bash-completion: add support for --now (#5155) (#1351806)
+- basic: fix touch() creating files with 07777 mode (#1416062)
+- udev: net_id: add support for phys_port_name attribute (#4506) (#1392426)
+- install: introduce UnitFileFlags (#1413041)
+- shared, systemctl: teach is-enabled to show installation targets (#1413041)
 
 * Mon Nov 07 2016 Lukáš Nykrýn <lnykryn@redhat.com> - 219-30.6
 - better version of vmware trigger