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 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 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?= 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 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 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?= 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?= 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 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 -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 -+#include - - /* 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 +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 +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 -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 +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 -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 -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 +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 +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 -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" +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 -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 -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 +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 +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 -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 -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 +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 ++#include + + /* 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 +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 +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?= +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 @@ + + + ++ CtrlAltDelBurstAction= ++ ++ Defines what action will be performed ++ if user presses Ctr-Alt-Delete more than 7 times in 2s. ++ Can be set to reboot-force, poweroff-force ++ or disabled with ignore. Defaults to ++ reboot-force. ++ ++ ++ ++ + CPUAffinity= + + 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 +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 . + ***/ + +-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 +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 @@ + CtrlAltDelBurstAction= + + Defines what action will be performed +- if user presses Ctr-Alt-Delete more than 7 times in 2s. +- Can be set to reboot-force, poweroff-force +- or disabled with ignore. Defaults to ++ if user presses Ctrl-Alt-Delete more than 7 times in 2s. ++ Can be set to reboot-force, poweroff-force, ++ reboot-immediate, poweroff-immediate ++ or disabled with none. Defaults to + reboot-force. + + +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 +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 +Signed-off-by: Keith Busch + +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 +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 +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 +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 + LimitCPU= will be rounded up implicitly to +- multiples of 1s. ++ multiples of 1s. For LimitNICE= the value ++ may be specified in two syntaxes: if prefixed with + ++ or -, 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). + + 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 +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 +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 +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 +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 +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 +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. + + 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 SystemKeepFree= or + RuntimeKeepFree= 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 +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 +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?= +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?= +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 + +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[d] -- on-board device index number + * s[f][d] -- hotplug slot index number + * x -- MAC address +- * [P]ps[f][d/] ++ * [P]ps[f][n|d/] + * -- PCI geographical location + * [P]ps[f][u][..][c][i] + * -- 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 +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 +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 status, list-units, + list-jobs, and + list-timers. ++ Also, show installation targets in the output of ++ is-enabled. + + + +@@ -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 . ++ To show installation targets, use . + + + +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 @@ + + ++ ++ + + 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 +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 +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 +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 +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 +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 +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 +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 +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. + ++ ++ TimeoutIdleSec= ++ 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. ++ + + + +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 @@ + + + ++ ++ ++ Configures the idleness timeout of the ++ automount unit. See TimeoutIdleSec= in ++ systemd.automount5 ++ for details. ++ ++ ++ + + + 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(¶m); + 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, ¶m) < 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(¶m); ++ param.ioctlfd = data->ioctl_fd; ++ ++ do { ++ r = ioctl(data->dev_autofs_fd, AUTOFS_DEV_IOCTL_EXPIRE, ¶m); ++ } 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?= +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 +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" + kdbus, + sd-bus3, + systemd1, +- systemd-bus-proxyd8, + machinectl1, + wireshark1 + +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 @@ +- +- +- +- +- +- +- +- +- systemd-bus-proxyd +- systemd +- +- +- +- Developer +- Lennart +- Poettering +- lennart@poettering.net +- +- +- +- +- +- systemd-bus-proxyd +- 8 +- +- +- +- systemd-bus-proxyd +- Connect STDIO or a socket to a given bus address +- +- +- +- +- /usr/lib/systemd/systemd-bus-proxyd +- OPTIONS +- PLACEHOLDER +- +- +- +- +- Description +- +- systemd-bus-proxyd will proxy D-Bus +- messages to and from a bus. The will be either the system bus or +- the bus specified with when that option +- is given. Messages will be proxied to/from standard input and +- output, or the socket received through socket activation. +- +- This program can be used to connect a program using classic +- D-Bus to kdbus. +- +- +- +- Options and Arguments +- +- The following options are understood: +- +- +- +- +- +- +- Connect to the bus specified by +- ADDRESS. Multiple colon-separated +- addresses can be specified, in which case +- systemd-bus-proxyd will attempt to +- connect to them in turn. +- +- +- +- +- +- +- +- PLACEHOLDER, if given, must be a string +- of x and will be used to display information about +- the process that systemd-bus-proxyd is forwarding +- messages for. +- +- +- +- See Also +- +- +- dbus-daemon1, +- D-Bus, +- kdbus +- +- +- +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 @@ +- +- +- +- +- +- +- +- +- systemd-bus-proxyd@.service +- systemd +- +- +- +- Developer +- Lennart +- Poettering +- lennart@poettering.net +- +- +- +- +- +- systemd-bus-proxyd@.service +- 8 +- +- +- +- systemd-bus-proxyd@.service +- systemd-bus-proxyd.socket +- Proxy classic D-Bus clients to kdbus +- +- +- +- systemd-bus-proxyd@.service +- systemd-bus-proxyd.socket +- +- +- +- Description +- +- systemd-bus-proxyd.socket will launch +- systemd-bus-proxyd@.service for connections +- to the classic D-Bus socket in +- /var/run/dbus/system_bus_socket. +- +- systemd-bus-proxyd@.service is launched +- for an existing D-Bus connection and will use +- systemd-bus-proxyd to proxy messages from this +- connection to the system bus (either kdbus or classic D-Bus). +- +- +- +- +- See Also +- +- +- systemd-bus-proxyd8, +- dbus-daemon1, +- D-Bus, +- kdbus +- +- +- +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 . +-***/ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#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 . +-***/ +- +-#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 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 %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 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 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 . +-***/ +- +-#include +-#include +- +-#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 . +-***/ +- +-#include +-#include +-#include +-#include +-#include +- +-#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", +- "\n" +- "\n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- " \n" +- "\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 . +-***/ +- +-#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 . +-***/ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#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 . +-***/ +- +-#include +-#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 . +-***/ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#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 . +-***/ +- +-#include +-#include +-#include +-#include +-#include +- +-#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 . +-***/ +- +-#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 . +-***/ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#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 . ++***/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 +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 @@ + + + ++ PassEnvironment= ++ ++ 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. ++ ++ Variables passed from this setting are overridden by those passed ++ from Environment= or ++ EnvironmentFile=. ++ ++ Example: ++ PassEnvironment=VAR1 VAR2 VAR3 ++ passes three variables VAR1, ++ VAR2, VAR3 ++ with the values set for those variables in PID1. ++ ++ ++ See ++ environ7 ++ for details about environment variables. ++ ++ ++ + StandardInput= + 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 +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 +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 +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)" +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 +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 +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--zfcp-: ++# ++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 +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 +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 +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 + #include + #include ++#include + #include + #include + +@@ -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 +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_bits & 1<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 +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_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 +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 @@ + + + ++ AmbientCapabilities= ++ ++ 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 ++ cap_from_name3, ++ e.g. CAP_SYS_ADMIN, ++ CAP_DAC_OVERRIDE, ++ CAP_SYS_PTRACE. This option may appear more than ++ once in which case the ambient capability sets are merged. ++ If the list of capabilities is prefixed with ~, 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 ~ (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. ++ ++ 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 keep-caps is ++ automatically added to SecureBits= to retain the ++ capabilities over the user change. ++ ++ ++ + SecureBits= + 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 +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 . + ***/ + +-#include +-#include +-#include +-#include + #include + #include ++#include ++#include ++#include ++#include + #include + + #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 . + ***/ + ++#include ++#include + #include ++#include ++#include + + #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 +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?= +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 +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 +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 +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 @@ + + + ++ e ++ Clean directory contents based on the age argument. ++ Lines of this type accept shell-style globs in ++ place of normal path names. ++ ++ ++ + v + Create a subvolume if the path does not + exist yet and the file system supports this +@@ -467,7 +474,7 @@ + + The age field only applies to lines + starting with d, +- D, and ++ D, e and + x. If omitted or set to + -, no automatic clean-up is + done. +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 +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 +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 @@ + + + +- /etc/systemd/system.conf +- /etc/systemd/system.conf.d/*.conf +- /run/systemd/system.conf.d/*.conf +- /usr/lib/systemd/system.conf.d/*.conf +- /etc/systemd/user.conf +- /etc/systemd/user.conf.d/*.conf +- /run/systemd/user.conf.d/*.conf +- /usr/lib/systemd/user.conf.d/*.conf ++ /etc/systemd/system.conf, ++ /etc/systemd/system.conf.d/*.conf, ++ /run/systemd/system.conf.d/*.conf, ++ /usr/lib/systemd/system.conf.d/*.conf ++ /etc/systemd/user.conf, ++ /etc/systemd/user.conf.d/*.conf, ++ /run/systemd/user.conf.d/*.conf, ++ /usr/lib/systemd/user.conf.d/*.conf + + + +@@ -307,12 +307,14 @@ + DefaultCPUAccounting= + DefaultBlockIOAccounting= + DefaultMemoryAccounting= ++ DefaultTasksAccounting= + + Configure the default resource accounting + settings, as configured per-unit by + CPUAccounting=, +- BlockIOAccounting= and +- MemoryAccounting=. See ++ BlockIOAccounting=, ++ MemoryAccounting= and ++ TasksAccounting=. See + systemd.resource-control5 + for details on the per-unit settings. + +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 @@ + + 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 + DefaultCPUAccounting= in + systemd-system.conf5. + +@@ -134,7 +134,7 @@ + prioritizing specific services at boot-up differently than + during normal runtime. + +- Those options imply ++ These options imply + CPUAccounting=true. + + +@@ -168,9 +168,10 @@ + + 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 + DefaultMemoryAccounting= in + systemd-system.conf5. + +@@ -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 +- memory.limit_in_bytes control group +- attribute. For details about this control group attribute, +- see infinity no memory limit is applied. This ++ controls the memory.limit_in_bytes ++ control group attribute. For details about this control ++ group attribute, see memory.txt. + + Implies MemoryAccounting=true. +@@ -197,15 +199,52 @@ + + + ++ TasksAccounting= ++ ++ ++ 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 ++ DefaultTasksAccounting= in ++ systemd-system.conf5. ++ ++ ++ ++ ++ TasksMax=N ++ ++ ++ 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 ++ infinity no tasks limit is applied. This ++ controls the pids.max control group ++ attribute. For details about this control group attribute, ++ see pids.txt. ++ ++ Implies TasksAccounting=true. ++ ++ ++ ++ + BlockIOAccounting= + + + 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 + DefaultBlockIOAccounting= in + systemd-system.conf5. + +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 +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 @@ +- ++ + + +@@ -320,6 +320,17 @@ + + + ++ DefaultTasksMax= ++ ++ Configure the default value for the per-unit ++ TasksMax= setting. See ++ systemd.resource-control5 ++ for details. This setting applies to all unit types that ++ support resource control settings, with the exception of slice ++ units. ++ ++ ++ + DefaultLimitCPU= + DefaultLimitFSIZE= + DefaultLimitDATA= +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 pids.txt. + +- Implies TasksAccounting=true. ++ Implies TasksAccounting=true. The ++ system default for this setting may be controlled with ++ DefaultTasksMax= in ++ systemd-system.conf5. + + + +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 +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 @@ +- ++ + + +@@ -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. ++ memory as is needed. ++ ++ ++ ++ UserTasksMax= ++ ++ Sets the maximum number of OS tasks each user ++ may run concurrently. This controls the ++ TasksMax= setting of the per-user slice ++ unit, see ++ systemd.resource-control5 ++ for details. + + + +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 +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 @@ + TasksMax=N + + +- 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 +- infinity no tasks limit is applied. This +- controls the pids.max control group +- attribute. For details about this control group attribute, +- see pids.txt. ++ 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 infinity, no tasks limit is applied. This controls ++ the pids.max control group attribute. For details about this control group attribute, see ++ pids.txt. + + Implies TasksAccounting=true. 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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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?= +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?= +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 +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 +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 +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 + +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 +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 +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 +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 /\/ 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 - 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 - 219-42 +- Revert "rules: move cpu hotplug rule to separate file" (#1465108) + +* Mon Jun 12 2017 Lukas Nykryn - 219-41 +- rules: move cpu hotplug rule to separate file (#1266322) + +* Tue May 30 2017 Lukas Nykryn - 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 - 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 - 219-38 - core: properly handle jobs that are suppressed to JOB_NOPs when propagating restarts (#1436021) -* Mon Feb 13 2017 Lukas Nykryn - 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 - 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 - 219-30.7 +* Thu Apr 13 2017 Lukáš Nykrýn - 219-36 +- spec cleanup (#1439787, #1392300, #1368929) + +* Tue Apr 11 2017 Lukas Nykryn - 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 - 219-34 +- rules/40-redhat.rules: rules should be on one line (#1274401) + +* Mon Apr 10 2017 Lukas Nykryn - 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 - 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 - 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 - 219-30.6 - better version of vmware trigger