diff --git a/fix-capsh-drop-but-ping-success.patch b/0017-fix-capsh-drop-but-ping-success.patch similarity index 100% rename from fix-capsh-drop-but-ping-success.patch rename to 0017-fix-capsh-drop-but-ping-success.patch diff --git a/0998-resolved-create-etc-resolv.conf-symlink-at-runtime.patch b/0018-resolved-create-etc-resolv.conf-symlink-at-runtime.patch similarity index 100% rename from 0998-resolved-create-etc-resolv.conf-symlink-at-runtime.patch rename to 0018-resolved-create-etc-resolv.conf-symlink-at-runtime.patch diff --git a/core-serialize-u-pids-until-the-processes-have-been-.patch b/0019-core-serialize-u-pids-until-the-processes-have-been-.patch similarity index 100% rename from core-serialize-u-pids-until-the-processes-have-been-.patch rename to 0019-core-serialize-u-pids-until-the-processes-have-been-.patch diff --git a/scope-on-unified-make-sure-to-unwatch-all-PIDs-once-.patch b/0020-scope-on-unified-make-sure-to-unwatch-all-PIDs-once-.patch similarity index 100% rename from scope-on-unified-make-sure-to-unwatch-all-PIDs-once-.patch rename to 0020-scope-on-unified-make-sure-to-unwatch-all-PIDs-once-.patch diff --git a/backport-RFC-Make-user-instance-aware-of-delegated-cgroup-controllers.patch b/backport-RFC-Make-user-instance-aware-of-delegated-cgroup-controllers.patch deleted file mode 100644 index b8f46e4..0000000 --- a/backport-RFC-Make-user-instance-aware-of-delegated-cgroup-controllers.patch +++ /dev/null @@ -1,99 +0,0 @@ -From 81504017f462db1ef4ce2c1f617535f261fe01cc Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20Koutn=C3=BD?= -Date: Tue, 26 Jan 2021 17:07:00 +0100 -Subject: [PATCH] cgroup: Simplify cg_get_path_and_check - -The function controller_is_accessible() doesn't do really much in case -of the unified hierarchy. Move common parts into cg_get_path_and_check -and make controller check v1 specific. This is refactoring only. ---- - src/basic/cgroup-util.c | 56 ++++++++++++++++------------------------- - 1 file changed, 22 insertions(+), 34 deletions(-) - -diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c -index bb20a12294d..fcab1775bd5 100644 ---- a/src/basic/cgroup-util.c -+++ b/src/basic/cgroup-util.c -@@ -527,41 +527,16 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch - return 0; - } - --static int controller_is_accessible(const char *controller) { -- int r; -+static int controller_is_v1_accessible(const char *controller) { -+ const char *cc, *dn; - - assert(controller); - -- /* Checks whether a specific controller is accessible, -- * i.e. its hierarchy mounted. In the unified hierarchy all -- * controllers are considered accessible, except for the named -- * hierarchies */ -- -- if (!cg_controller_is_valid(controller)) -- return -EINVAL; -- -- r = cg_all_unified(); -- if (r < 0) -- return r; -- if (r > 0) { -- /* We don't support named hierarchies if we are using -- * the unified hierarchy. */ -- -- if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) -- return 0; -- -- if (startswith(controller, "name=")) -- return -EOPNOTSUPP; -- -- } else { -- const char *cc, *dn; -- -- dn = controller_to_dirname(controller); -- cc = strjoina("/sys/fs/cgroup/", dn); -+ dn = controller_to_dirname(controller); -+ cc = strjoina("/sys/fs/cgroup/", dn); - -- if (laccess(cc, F_OK) < 0) -- return -errno; -- } -+ if (laccess(cc, F_OK) < 0) -+ return -errno; - - return 0; - } -@@ -572,10 +547,23 @@ int cg_get_path_and_check(const char *controller, const char *path, const char * - assert(controller); - assert(fs); - -- /* Check if the specified controller is actually accessible */ -- r = controller_is_accessible(controller); -+ if (!cg_controller_is_valid(controller)) -+ return -EINVAL; -+ -+ r = cg_all_unified(); - if (r < 0) - return r; -+ if (r > 0) { -+ /* In the unified hierarchy all controllers are considered accessible, -+ * except for the named hierarchies */ -+ if (startswith(controller, "name=")) -+ return -EOPNOTSUPP; -+ } else { -+ /* Check if the specified controller is actually accessible */ -+ r = controller_is_v1_accessible(controller); -+ if (r < 0) -+ return r; -+ } - - return cg_get_path(controller, path, suffix, fs); - } -@@ -1909,7 +1897,7 @@ int cg_mask_supported(CGroupMask *ret) { - continue; - - n = cgroup_controller_to_string(c); -- if (controller_is_accessible(n) >= 0) -+ if (controller_is_v1_accessible(n) >= 0) - mask |= bit; - } - } diff --git a/backport-core-Make-user-instance-aware-of-delegated-cgroup.patch b/backport-core-Make-user-instance-aware-of-delegated-cgroup.patch deleted file mode 100644 index b181fa7..0000000 --- a/backport-core-Make-user-instance-aware-of-delegated-cgroup.patch +++ /dev/null @@ -1,163 +0,0 @@ -From 0fa7b50053695a3012af71c719dd86c12ab10fc6 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20Koutn=C3=BD?= -Date: Tue, 26 Jan 2021 19:15:45 +0100 -Subject: [PATCH] core: Make (user) instance aware of delegated cgroup - controllers - -systemd user instance assumed same controllers are available to it as to -PID 1. That is not true generally, in v1 (legacy, hybrid) we don't delegate any -controllers to anyone and in v2 (unified) we may delegate only subset of -controllers. -The user instance would fail silently when the controller cgroup cannot -be created or the controller cannot be enabled on the unified hierarchy. - -The changes in 7b63961415 ("cgroup: Swap cgroup v1 deletion and -migration") caused some attempts of operating on non-delegated -controllers to be logged. - -Make the user instance first check what controllers are availble to it -and narrow operations only to these controllers. The original checks are -kept in place. - -Note that daemon-reexec needs to be invoked in order to update the set -of unabled controllers after a change. - -Fixes: #18047 -Fixes: #17862 ---- - src/basic/cgroup-util.c | 41 +++++++++++++++++++++++++++-------------- - src/basic/cgroup-util.h | 1 + - src/core/cgroup.c | 2 +- - 3 files changed, 29 insertions(+), 15 deletions(-) - -diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c -index 19c0a9d..7ef30f2 100644 ---- a/src/basic/cgroup-util.c -+++ b/src/basic/cgroup-util.c -@@ -527,15 +527,21 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch - return 0; - } - --static int controller_is_v1_accessible(const char *controller) { -- const char *cc, *dn; -+static int controller_is_v1_accessible(const char *root, const char *controller) { -+ const char *cpath, *dn; - - assert(controller); - - dn = controller_to_dirname(controller); -- cc = strjoina("/sys/fs/cgroup/", dn); -- -- if (laccess(cc, F_OK) < 0) -+ cpath = strjoina("/sys/fs/cgroup/", dn); -+ if (root) -+ /* Also check that: -+ * - possible subcgroup is created at root, -+ * - we can modify the hierarchy. -+ * "Leak" cpath on stack */ -+ cpath = strjoina(cpath, root, "/cgroup.procs"); -+ -+ if (laccess(cpath, root ? W_OK : F_OK) < 0) - return -errno; - - return 0; -@@ -560,7 +566,7 @@ int cg_get_path_and_check(const char *controller, const char *path, const char * - return -EOPNOTSUPP; - } else { - /* Check if the specified controller is actually accessible */ -- r = controller_is_v1_accessible(controller); -+ r = controller_is_v1_accessible(NULL, controller); - if (r < 0) - return r; - } -@@ -1829,7 +1835,7 @@ int cg_mask_from_string(const char *value, CGroupMask *ret) { - return 0; - } - --int cg_mask_supported(CGroupMask *ret) { -+int cg_mask_supported_subtree(const char *root, CGroupMask *ret) { - CGroupMask mask; - int r; - -@@ -1841,16 +1847,12 @@ int cg_mask_supported(CGroupMask *ret) { - if (r < 0) - return r; - if (r > 0) { -- _cleanup_free_ char *root = NULL, *controllers = NULL, *path = NULL; -+ _cleanup_free_ char *controllers = NULL, *path = NULL; - - /* In the unified hierarchy we can read the supported - * and accessible controllers from a the top-level - * cgroup attribute */ - -- r = cg_get_root_path(&root); -- if (r < 0) -- return r; -- - r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, root, "cgroup.controllers", &path); - if (r < 0) - return r; -@@ -1869,7 +1871,7 @@ int cg_mask_supported(CGroupMask *ret) { - } else { - CGroupController c; - -- /* In the legacy hierarchy, we check which hierarchies are mounted. */ -+ /* In the legacy hierarchy, we check which hierarchies are accessible. */ - - mask = 0; - for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) { -@@ -1880,7 +1882,7 @@ int cg_mask_supported(CGroupMask *ret) { - continue; - - n = cgroup_controller_to_string(c); -- if (controller_is_v1_accessible(n) >= 0) -+ if (controller_is_v1_accessible(root, n) >= 0) - mask |= bit; - } - } -@@ -1889,6 +1891,17 @@ int cg_mask_supported(CGroupMask *ret) { - return 0; - } - -+int cg_mask_supported(CGroupMask *ret) { -+ _cleanup_free_ char *root = NULL; -+ int r; -+ -+ r = cg_get_root_path(&root); -+ if (r < 0) -+ return r; -+ -+ return cg_mask_supported_subtree(root, ret); -+} -+ - int cg_kernel_controllers(Set **ret) { - _cleanup_set_free_free_ Set *controllers = NULL; - _cleanup_fclose_ FILE *f = NULL; -diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h -index 2b88571..2b3b068 100644 ---- a/src/basic/cgroup-util.h -+++ b/src/basic/cgroup-util.h -@@ -254,6 +254,7 @@ int cg_slice_to_path(const char *unit, char **ret); - typedef const char* (*cg_migrate_callback_t)(CGroupMask mask, void *userdata); - - int cg_mask_supported(CGroupMask *ret); -+int cg_mask_supported_subtree(const char *root, CGroupMask *ret); - int cg_mask_from_string(const char *s, CGroupMask *ret); - int cg_mask_to_string(CGroupMask mask, char **ret); - -diff --git a/src/core/cgroup.c b/src/core/cgroup.c -index 8b97d15..57b4974 100644 ---- a/src/core/cgroup.c -+++ b/src/core/cgroup.c -@@ -3010,7 +3010,7 @@ int manager_setup_cgroup(Manager *m) { - (void) cg_set_attribute("memory", "/", "memory.use_hierarchy", "1"); - - /* 8. Figure out which controllers are supported */ -- r = cg_mask_supported(&m->cgroup_supported); -+ r = cg_mask_supported_subtree(m->cgroup_root, &m->cgroup_supported); - if (r < 0) - return log_error_errno(r, "Failed to determine supported controllers: %m"); - --- -2.23.0 - diff --git a/backport-process-util-dont-allocate-max-length-to-read-proc-P.patch b/backport-process-util-dont-allocate-max-length-to-read-proc-P.patch deleted file mode 100644 index a910eb0..0000000 --- a/backport-process-util-dont-allocate-max-length-to-read-proc-P.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 7b7a060e83d6c7de8705904d71978ba4664f0a65 Mon Sep 17 00:00:00 2001 -From: Anita Zhang -Date: Tue, 23 Mar 2021 00:49:28 -0700 -Subject: [PATCH] process-util: dont allocate max length to read - /proc/PID/cmdline - -Alternative title: Replace get_process_cmdline()'s fopen()/fread() with -read_full_virtual_file(). - -When RLIMIT_STACK is set to infinity:infinity, _SC_ARG_MAX will -return 4611686018427387903 (depending on the system, but definitely -something larger than most systems have). It's impractical to allocate this -in one go when most cmdlines are much shorter than that. - -Instead use read_full_virtual_file() which seems to increase the buffer -depending on the size of the contents. ---- - src/basic/process-util.c | 28 +++------------------------- - src/test/test-process-util.c | 5 +++++ - 2 files changed, 8 insertions(+), 25 deletions(-) - -diff --git a/src/basic/process-util.c b/src/basic/process-util.c -index 264ecc276b..7d4301eadb 100644 ---- a/src/basic/process-util.c -+++ b/src/basic/process-util.c -@@ -124,14 +124,10 @@ int get_process_comm(pid_t pid, char **ret) { - } - - int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags, char **line) { -- _cleanup_fclose_ FILE *f = NULL; - _cleanup_free_ char *t = NULL, *ans = NULL; - const char *p; -- int r; - size_t k; -- -- /* This is supposed to be a safety guard against runaway command lines. */ -- size_t max_length = sc_arg_max(); -+ int r; - - assert(line); - assert(pid >= 0); -@@ -147,36 +143,18 @@ int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags - * comm_fallback is false). Returns 0 and sets *line otherwise. */ - - p = procfs_file_alloca(pid, "cmdline"); -- r = fopen_unlocked(p, "re", &f); -+ r = read_full_virtual_file(p, &t, &k); - if (r == -ENOENT) - return -ESRCH; - if (r < 0) - return r; - -- /* We assume that each four-byte character uses one or two columns. If we ever check for combining -- * characters, this assumption will need to be adjusted. */ -- if ((size_t) 4 * max_columns + 1 < max_columns) -- max_length = MIN(max_length, (size_t) 4 * max_columns + 1); -- -- t = new(char, max_length); -- if (!t) -- return -ENOMEM; -- -- k = fread(t, 1, max_length, f); - if (k > 0) { - /* Arguments are separated by NULs. Let's replace those with spaces. */ - for (size_t i = 0; i < k - 1; i++) - if (t[i] == '\0') - t[i] = ' '; -- -- t[k] = '\0'; /* Normally, t[k] is already NUL, so this is just a guard in case of short read */ - } else { -- /* We only treat getting nothing as an error. We *could* also get an error after reading some -- * data, but we ignore that case, as such an error is rather unlikely and we prefer to get -- * some data rather than none. */ -- if (ferror(f)) -- return -errno; -- - if (!(flags & PROCESS_CMDLINE_COMM_FALLBACK)) - return -ENOENT; - -@@ -187,7 +165,7 @@ int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags - if (r < 0) - return r; - -- mfree(t); -+ free(t); - t = strjoin("[", t2, "]"); - if (!t) - return -ENOMEM; -diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c -index 0ebef530a0..5ca654e193 100644 ---- a/src/test/test-process-util.c -+++ b/src/test/test-process-util.c -@@ -236,6 +236,11 @@ static void test_get_process_cmdline_harder(void) { - return; - } - -+ /* Set RLIMIT_STACK to infinity to test we don't try to allocate unncessarily large values to read -+ * the cmdline. */ -+ if (setrlimit(RLIMIT_STACK, &RLIMIT_MAKE_CONST(RLIM_INFINITY)) < 0) -+ log_warning("Testing without RLIMIT_STACK=infinity"); -+ - assert_se(unlink(path) >= 0); - - assert_se(prctl(PR_SET_NAME, "testa") >= 0); --- -2.23.0 - diff --git a/backport-varlink-make-userdata-pointer-inheritance-from-varli.patch b/backport-varlink-make-userdata-pointer-inheritance-from-varli.patch deleted file mode 100644 index fd0c489..0000000 --- a/backport-varlink-make-userdata-pointer-inheritance-from-varli.patch +++ /dev/null @@ -1,160 +0,0 @@ -From 9807fdc1da8e037ddedfa4e2c6d2728b6e60051e Mon Sep 17 00:00:00 2001 -From: Lennart Poettering -Date: Wed, 20 Jan 2021 19:15:55 +0100 -Subject: [PATCH] varlink: make 'userdata' pointer inheritance from varlink - server to connection optional - -@keszybz's right on -https://github.com/systemd/systemd/pull/18248#issuecomment-760798473: -swapping out the userdata pointer of a live varlink connection is iffy. - -Let's fix this by making the userdata inheritance from VarlinkServer -object to the Varlink connection object optional: we want it for most -cases, but not all, i.e. all those cases where the calls implemented as -varlink methods are stateless and can be answered synchronously. For the -other cases (i.e. where we want per-connection objects that wrap the -asynchronous operation as it goes on) let's not do such inheritance but -initialize the userdata pointer only once we have it. THis means the -original manager object must be manually retrieved from the -VarlinkServer object, which in turn needs to be requested from the -Varlink connection object. - -The userdata inheritance is now controlled by the -VARLINK_INHERIT_USERDATA flag passed at VarlinkServer construction. - -Alternative-to: #18248 ---- - src/core/core-varlink.c | 2 +- - src/home/homed-manager.c | 2 +- - src/journal/journald-server.c | 2 +- - src/machine/machined-varlink.c | 2 +- - src/resolve/resolved-varlink.c | 8 ++++++-- - src/shared/varlink.c | 4 +++- - src/shared/varlink.h | 9 +++++---- - 7 files changed, 18 insertions(+), 11 deletions(-) - -diff --git a/src/core/core-varlink.c b/src/core/core-varlink.c -index dd6c11ab4d..d695106658 100644 ---- a/src/core/core-varlink.c -+++ b/src/core/core-varlink.c -@@ -432,7 +432,7 @@ int manager_varlink_init(Manager *m) { - if (!MANAGER_IS_SYSTEM(m)) - return 0; - -- r = varlink_server_new(&s, VARLINK_SERVER_ACCOUNT_UID); -+ r = varlink_server_new(&s, VARLINK_SERVER_ACCOUNT_UID|VARLINK_SERVER_INHERIT_USERDATA); - if (r < 0) - return log_error_errno(r, "Failed to allocate varlink server object: %m"); - -diff --git a/src/home/homed-manager.c b/src/home/homed-manager.c -index 365ea4d234..91cabd5cef 100644 ---- a/src/home/homed-manager.c -+++ b/src/home/homed-manager.c -@@ -956,7 +956,7 @@ static int manager_bind_varlink(Manager *m) { - assert(m); - assert(!m->varlink_server); - -- r = varlink_server_new(&m->varlink_server, VARLINK_SERVER_ACCOUNT_UID); -+ r = varlink_server_new(&m->varlink_server, VARLINK_SERVER_ACCOUNT_UID|VARLINK_SERVER_INHERIT_USERDATA); - if (r < 0) - return log_error_errno(r, "Failed to allocate varlink server object: %m"); - -diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c -index 10ebc3e22e..5cad374083 100644 ---- a/src/journal/journald-server.c -+++ b/src/journal/journald-server.c -@@ -2033,7 +2033,7 @@ static int server_open_varlink(Server *s, const char *socket, int fd) { - - assert(s); - -- r = varlink_server_new(&s->varlink_server, VARLINK_SERVER_ROOT_ONLY); -+ r = varlink_server_new(&s->varlink_server, VARLINK_SERVER_ROOT_ONLY|VARLINK_SERVER_INHERIT_USERDATA); - if (r < 0) - return r; - -diff --git a/src/machine/machined-varlink.c b/src/machine/machined-varlink.c -index 2d6c1991a4..009d283acc 100644 ---- a/src/machine/machined-varlink.c -+++ b/src/machine/machined-varlink.c -@@ -388,7 +388,7 @@ int manager_varlink_init(Manager *m) { - if (m->varlink_server) - return 0; - -- r = varlink_server_new(&s, VARLINK_SERVER_ACCOUNT_UID); -+ r = varlink_server_new(&s, VARLINK_SERVER_ACCOUNT_UID|VARLINK_SERVER_INHERIT_USERDATA); - if (r < 0) - return log_error_errno(r, "Failed to allocate varlink server object: %m"); - -diff --git a/src/resolve/resolved-varlink.c b/src/resolve/resolved-varlink.c -index 70d6f9056d..2fb9d38dfa 100644 ---- a/src/resolve/resolved-varlink.c -+++ b/src/resolve/resolved-varlink.c -@@ -269,11 +269,13 @@ static int vl_method_resolve_hostname(Varlink *link, JsonVariant *parameters, Va - _cleanup_(lookup_parameters_destroy) LookupParameters p = { - .family = AF_UNSPEC, - }; -- Manager *m = userdata; - DnsQuery *q; -+ Manager *m; - int r; - - assert(link); -+ -+ m = varlink_server_get_userdata(varlink_get_server(link)); - assert(m); - - if (FLAGS_SET(flags, VARLINK_METHOD_ONEWAY)) -@@ -447,11 +449,13 @@ static int vl_method_resolve_address(Varlink *link, JsonVariant *parameters, Var - _cleanup_(lookup_parameters_destroy) LookupParameters p = { - .family = AF_UNSPEC, - }; -- Manager *m = userdata; - DnsQuery *q; -+ Manager *m; - int r; - - assert(link); -+ -+ m = varlink_server_get_userdata(varlink_get_server(link)); - assert(m); - - if (FLAGS_SET(flags, VARLINK_METHOD_ONEWAY)) -diff --git a/src/shared/varlink.c b/src/shared/varlink.c -index 274709abd5..24865fa07e 100644 ---- a/src/shared/varlink.c -+++ b/src/shared/varlink.c -@@ -2137,7 +2137,9 @@ int varlink_server_add_connection(VarlinkServer *server, int fd, Varlink **ret) - return r; - - v->fd = fd; -- v->userdata = server->userdata; -+ if (server->flags & VARLINK_SERVER_INHERIT_USERDATA) -+ v->userdata = server->userdata; -+ - if (ucred_acquired) { - v->ucred = ucred; - v->ucred_acquired = true; -diff --git a/src/shared/varlink.h b/src/shared/varlink.h -index 7ea1f9113f..66a1ff630e 100644 ---- a/src/shared/varlink.h -+++ b/src/shared/varlink.h -@@ -41,11 +41,12 @@ typedef enum VarlinkMethodFlags { - } VarlinkMethodFlags; - - typedef enum VarlinkServerFlags { -- VARLINK_SERVER_ROOT_ONLY = 1 << 0, /* Only accessible by root */ -- VARLINK_SERVER_MYSELF_ONLY = 1 << 1, /* Only accessible by our own UID */ -- VARLINK_SERVER_ACCOUNT_UID = 1 << 2, /* Do per user accounting */ -+ VARLINK_SERVER_ROOT_ONLY = 1 << 0, /* Only accessible by root */ -+ VARLINK_SERVER_MYSELF_ONLY = 1 << 1, /* Only accessible by our own UID */ -+ VARLINK_SERVER_ACCOUNT_UID = 1 << 2, /* Do per user accounting */ -+ VARLINK_SERVER_INHERIT_USERDATA = 1 << 3, /* Initialize Varlink connection userdata from VarlinkServer userdata */ - -- _VARLINK_SERVER_FLAGS_ALL = (1 << 3) - 1, -+ _VARLINK_SERVER_FLAGS_ALL = (1 << 4) - 1, - } VarlinkServerFlags; - - typedef int (*VarlinkMethod)(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata); --- -2.23.0 - diff --git a/backport-xdg-autostart-Lower-most-info-messages-to-debug-leve.patch b/backport-xdg-autostart-Lower-most-info-messages-to-debug-leve.patch deleted file mode 100644 index 91e0c2f..0000000 --- a/backport-xdg-autostart-Lower-most-info-messages-to-debug-leve.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 47c1db6730b8a81b01e8505a648624fa6ad0bbd7 Mon Sep 17 00:00:00 2001 -From: Benjamin Berg -Date: Mon, 12 Oct 2020 11:02:26 +0200 -Subject: [PATCH] xdg-autostart: Lower most info messages to debug level - -It is expected for numerous autostart files to not be convertible to -corresponding units. The information is only useful for someone -debugging why a file might not be started, but it is not generally -useful for users in most situations. - -As such, lower the warnings. Anyone wondering why an application is not -started will easily notice that the unit is not generated. From there it -will be somewhat harder to figure out why, but the overall trade-off is -still improved. - -Fixes: #17305 ---- - src/xdg-autostart-generator/xdg-autostart-service.c | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) - -diff --git a/src/xdg-autostart-generator/xdg-autostart-service.c b/src/xdg-autostart-generator/xdg-autostart-service.c -index c6f39f2..6324c50 100644 ---- a/src/xdg-autostart-generator/xdg-autostart-service.c -+++ b/src/xdg-autostart-generator/xdg-autostart-service.c -@@ -483,7 +483,7 @@ static int xdg_autostart_generate_desktop_condition( - - r = find_binary(test_binary, &gnome_autostart_condition_path); - if (r < 0) { -- log_full_errno(r == -ENOENT ? LOG_INFO : LOG_WARNING, r, -+ log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r, - "%s not found: %m", test_binary); - fprintf(f, "# ExecCondition using %s skipped due to missing binary.\n", test_binary); - return r; -@@ -514,18 +514,18 @@ int xdg_autostart_service_generate_unit( - - /* Nothing to do for hidden services. */ - if (service->hidden) { -- log_info("Not generating service for XDG autostart %s, it is hidden.", service->name); -+ log_debug("Not generating service for XDG autostart %s, it is hidden.", service->name); - return 0; - } - - if (service->systemd_skip) { -- log_info("Not generating service for XDG autostart %s, should be skipped by generator.", service->name); -+ log_debug("Not generating service for XDG autostart %s, should be skipped by generator.", service->name); - return 0; - } - - /* Nothing to do if type is not Application. */ - if (!streq_ptr(service->type, "Application")) { -- log_info("Not generating service for XDG autostart %s, only Type=Application is supported.", service->name); -+ log_debug("Not generating service for XDG autostart %s, only Type=Application is supported.", service->name); - return 0; - } - -@@ -541,7 +541,7 @@ int xdg_autostart_service_generate_unit( - if (service->try_exec) { - r = find_binary(service->try_exec, NULL); - if (r < 0) { -- log_full_errno(r == -ENOENT ? LOG_INFO : LOG_WARNING, r, -+ log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r, - "Not generating service for XDG autostart %s, could not find TryExec= binary %s: %m", - service->name, service->try_exec); - return 0; -@@ -558,7 +558,7 @@ int xdg_autostart_service_generate_unit( - - if (service->gnome_autostart_phase) { - /* There is no explicit value for the "Application" phase. */ -- log_info("Not generating service for XDG autostart %s, startup phases are not supported.", -+ log_debug("Not generating service for XDG autostart %s, startup phases are not supported.", - service->name); - return 0; - } --- -2.23.0 - diff --git a/revert-analyze-add-unit-files-to-dump-the-unit-fragm.patch b/revert-analyze-add-unit-files-to-dump-the-unit-fragm.patch deleted file mode 100644 index 65c5162..0000000 --- a/revert-analyze-add-unit-files-to-dump-the-unit-fragm.patch +++ /dev/null @@ -1,93 +0,0 @@ -From e67cd21d7d174cdafd12beca4cfb6e19e61f6fb5 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= -Date: Mon, 8 Jul 2019 17:33:25 +0200 -Subject: [PATCH] analyze: add "unit-files" to dump the unit fragment map - -I'm not convinced that this is useful enough to be included... But it is -certainly nice when debugging. - -revert analyze add unit files to dump the unit fragment map ---- - src/analyze/analyze.c | 50 -------------------------------------------------- - 1 file changed, 50 deletions(-) - -diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c -index 322be1a..6de26f4 100644 ---- a/src/analyze/analyze.c -+++ b/src/analyze/analyze.c -@@ -1546,53 +1546,6 @@ static int get_or_set_log_target(int argc, char *argv[], void *userdata) { - return (argc == 1) ? get_log_target(argc, argv, userdata) : set_log_target(argc, argv, userdata); - } - --static bool strv_fnmatch_strv_or_empty(char* const* patterns, char **strv, int flags) { -- char **s; -- STRV_FOREACH(s, strv) -- if (strv_fnmatch_or_empty(patterns, *s, flags)) -- return true; -- -- return false; --} -- --static int do_unit_files(int argc, char *argv[], void *userdata) { -- _cleanup_(lookup_paths_free) LookupPaths lp = {}; -- _cleanup_hashmap_free_ Hashmap *unit_ids = NULL; -- _cleanup_hashmap_free_ Hashmap *unit_names = NULL; -- char **patterns = strv_skip(argv, 1); -- Iterator i; -- const char *k, *dst; -- char **v; -- int r; -- -- r = lookup_paths_init(&lp, arg_scope, 0, NULL); -- if (r < 0) -- return log_error_errno(r, "lookup_paths_init() failed: %m"); -- -- r = unit_file_build_name_map(&lp, &unit_ids, &unit_names, NULL); -- if (r < 0) -- return log_error_errno(r, "unit_file_build_name_map() failed: %m"); -- -- HASHMAP_FOREACH_KEY(dst, k, unit_ids, i) { -- if (!strv_fnmatch_or_empty(patterns, k, FNM_NOESCAPE) && -- !strv_fnmatch_or_empty(patterns, dst, FNM_NOESCAPE)) -- continue; -- -- printf("ids: %s → %s\n", k, dst); -- } -- -- HASHMAP_FOREACH_KEY(v, k, unit_names, i) { -- if (!strv_fnmatch_or_empty(patterns, k, FNM_NOESCAPE) && -- !strv_fnmatch_strv_or_empty(patterns, v, FNM_NOESCAPE)) -- continue; -- -- _cleanup_free_ char *j = strv_join(v, ", "); -- printf("aliases: %s ← %s\n", k, j); -- } -- -- return 0; --} -- - static int dump_unit_paths(int argc, char *argv[], void *userdata) { - _cleanup_(lookup_paths_free) LookupPaths paths = {}; - int r; -@@ -2263,7 +2216,6 @@ static int help(int argc, char *argv[], void *userdata) { - " log-target [TARGET] Get/set logging target for manager\n" - " dump Output state serialization of service manager\n" - " cat-config Show configuration file and drop-ins\n" -- " unit-files List files and symlinks for units\n" - " unit-paths List load directories for units\n" - " exit-status [STATUS...] List exit status definitions\n" - " syscall-filter [NAME...] Print list of syscalls in seccomp filter\n" -@@ -2467,10 +2419,8 @@ static int run(int argc, char *argv[]) { - { "get-log-level", VERB_ANY, 1, 0, get_log_level }, - { "set-log-target", 2, 2, 0, set_log_target }, - { "get-log-target", VERB_ANY, 1, 0, get_log_target }, -- - { "dump", VERB_ANY, 1, 0, dump }, - { "cat-config", 2, VERB_ANY, 0, cat_config }, -- { "unit-files", VERB_ANY, VERB_ANY, 0, do_unit_files }, - { "unit-paths", 1, 1, 0, dump_unit_paths }, - { "exit-status", VERB_ANY, VERB_ANY, 0, dump_exit_status }, - { "syscall-filter", VERB_ANY, VERB_ANY, 0, dump_syscall_filters }, --- -1.8.3.1 - diff --git a/revert-pid1-drop-unit-caches-only-based-on-mtime.patch b/revert-pid1-drop-unit-caches-only-based-on-mtime.patch deleted file mode 100644 index e12236a..0000000 --- a/revert-pid1-drop-unit-caches-only-based-on-mtime.patch +++ /dev/null @@ -1,289 +0,0 @@ -From 91e0ee5f16321656ed6f827742ecbeb2b36027f2 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= -Date: Wed, 10 Jul 2019 18:01:13 +0200 -Subject: [PATCH] pid1: drop unit caches only based on mtime - -v2: -- do not watch mtime of transient and generated dirs - - We'd reload the map after every transient unit we created, which we don't - need to do, since we create those units ourselves and know their fragment - path. - -revert pid1 drop unit caches only based on mtime ---- - src/analyze/analyze.c | 2 +- - src/core/load-fragment.c | 9 -------- - src/core/manager.c | 14 ++++++++++-- - src/core/manager.h | 1 - - src/shared/unit-file.c | 57 +---------------------------------------------- - src/shared/unit-file.h | 2 -- - src/systemctl/systemctl.c | 2 +- - src/test/test-unit-file.c | 13 +---------- - 8 files changed, 16 insertions(+), 84 deletions(-) - -diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c -index 4d81026..322be1a 100644 ---- a/src/analyze/analyze.c -+++ b/src/analyze/analyze.c -@@ -1569,7 +1569,7 @@ static int do_unit_files(int argc, char *argv[], void *userdata) { - if (r < 0) - return log_error_errno(r, "lookup_paths_init() failed: %m"); - -- r = unit_file_build_name_map(&lp, NULL, &unit_ids, &unit_names, NULL); -+ r = unit_file_build_name_map(&lp, &unit_ids, &unit_names, NULL); - if (r < 0) - return log_error_errno(r, "unit_file_build_name_map() failed: %m"); - -diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c -index 8eaf8b3..9821a92 100644 ---- a/src/core/load-fragment.c -+++ b/src/core/load-fragment.c -@@ -4605,15 +4605,6 @@ int unit_load_fragment(Unit *u) { - return 0; - } - -- /* Possibly rebuild the fragment map to catch new units */ -- r = unit_file_build_name_map(&u->manager->lookup_paths, -- &u->manager->unit_cache_mtime, -- &u->manager->unit_id_map, -- &u->manager->unit_name_map, -- &u->manager->unit_path_cache); -- if (r < 0) -- log_error_errno(r, "Failed to rebuild name map: %m"); -- - r = unit_file_find_fragment(u->manager->unit_id_map, - u->manager->unit_name_map, - u->id, -diff --git a/src/core/manager.c b/src/core/manager.c -index 5efcf45..8b1ce70 100644 ---- a/src/core/manager.c -+++ b/src/core/manager.c -@@ -693,7 +693,6 @@ static void manager_free_unit_name_maps(Manager *m) { - m->unit_id_map = hashmap_free(m->unit_id_map); - m->unit_name_map = hashmap_free(m->unit_name_map); - m->unit_path_cache = set_free_free(m->unit_path_cache); -- m->unit_cache_mtime = 0; - } - - static int manager_setup_run_queue(Manager *m) { -@@ -1642,6 +1641,11 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { - - lookup_paths_log(&m->lookup_paths); - -+ manager_free_unit_name_maps(m); -+ r = unit_file_build_name_map(&m->lookup_paths, &m->unit_id_map, &m->unit_name_map, &m->unit_path_cache); -+ if (r < 0) -+ return log_error_errno(r, "Failed to build name map: %m"); -+ - { - /* This block is (optionally) done with the reloading counter bumped */ - _cleanup_(manager_reloading_stopp) Manager *reloading = NULL; -@@ -2858,6 +2862,10 @@ int manager_loop(Manager *m) { - assert(m); - assert(m->objective == MANAGER_OK); /* Ensure manager_startup() has been called */ - -+ /* Release the path and unit name caches */ -+ manager_free_unit_name_maps(m); -+ // FIXME: once this happens, we cannot load any more units -+ - manager_check_finished(m); - - /* There might still be some zombies hanging around from before we were exec()'ed. Let's reap them. */ -@@ -3531,8 +3539,10 @@ int manager_reload(Manager *m) { - - lookup_paths_log(&m->lookup_paths); - -- /* We flushed out generated files, for which we don't watch mtime, so we should flush the old map. */ - manager_free_unit_name_maps(m); -+ r = unit_file_build_name_map(&m->lookup_paths, &m->unit_id_map, &m->unit_name_map, &m->unit_path_cache); -+ if (r < 0) -+ log_warning_errno(r, "Failed to build name map: %m"); - - /* First, enumerate what we can from kernel and suchlike */ - manager_enumerate_perpetual(m); -diff --git a/src/core/manager.h b/src/core/manager.h -index 815c5ec..9ca82ac 100644 ---- a/src/core/manager.h -+++ b/src/core/manager.h -@@ -223,7 +223,6 @@ struct Manager { - Hashmap *unit_id_map; - Hashmap *unit_name_map; - Set *unit_path_cache; -- usec_t unit_cache_mtime; - - char **transient_environment; /* The environment, as determined from config files, kernel cmdline and environment generators */ - char **client_environment; /* Environment variables created by clients through the bus API */ -diff --git a/src/shared/unit-file.c b/src/shared/unit-file.c -index 4a5f23e..bad92a3 100644 ---- a/src/shared/unit-file.c -+++ b/src/shared/unit-file.c -@@ -152,47 +152,8 @@ static int unit_ids_map_get( - return -ELOOP; - } - --static bool lookup_paths_mtime_exclude(const LookupPaths *lp, const char *path) { -- /* Paths that are under our exclusive control. Users shall not alter those directly. */ -- -- return streq_ptr(path, lp->generator) || -- streq_ptr(path, lp->generator_early) || -- streq_ptr(path, lp->generator_late) || -- streq_ptr(path, lp->transient) || -- streq_ptr(path, lp->persistent_control) || -- streq_ptr(path, lp->runtime_control); --} -- --static bool lookup_paths_mtime_good(const LookupPaths *lp, usec_t mtime) { -- char **dir; -- -- STRV_FOREACH(dir, (char**) lp->search_path) { -- struct stat st; -- -- if (lookup_paths_mtime_exclude(lp, *dir)) -- continue; -- -- /* Determine the latest lookup path modification time */ -- if (stat(*dir, &st) < 0) { -- if (errno == ENOENT) -- continue; -- -- log_debug_errno(errno, "Failed to stat %s, ignoring: %m", *dir); -- continue; -- } -- -- if (timespec_load(&st.st_mtim) > mtime) { -- log_debug_errno(errno, "Unit dir %s has changed, need to update cache.", *dir); -- return false; -- } -- } -- -- return true; --} -- - int unit_file_build_name_map( - const LookupPaths *lp, -- usec_t *cache_mtime, - Hashmap **ret_unit_ids_map, - Hashmap **ret_unit_names_map, - Set **ret_path_cache) { -@@ -210,12 +171,6 @@ int unit_file_build_name_map( - _cleanup_set_free_free_ Set *paths = NULL; - char **dir; - int r; -- usec_t mtime = 0; -- -- /* Before doing anything, check if the mtime that was passed is still valid. If -- * yes, do nothing. If *cache_time == 0, always build the cache. */ -- if (cache_mtime && *cache_mtime > 0 && lookup_paths_mtime_good(lp, *cache_mtime)) -- return 0; - - if (ret_path_cache) { - paths = set_new(&path_hash_ops); -@@ -226,7 +181,6 @@ int unit_file_build_name_map( - STRV_FOREACH(dir, (char**) lp->search_path) { - struct dirent *de; - _cleanup_closedir_ DIR *d = NULL; -- struct stat st; - - d = opendir(*dir); - if (!d) { -@@ -235,13 +189,6 @@ int unit_file_build_name_map( - continue; - } - -- /* Determine the latest lookup path modification time */ -- if (fstat(dirfd(d), &st) < 0) -- return log_error_errno(errno, "Failed to fstat %s: %m", *dir); -- -- if (!lookup_paths_mtime_exclude(lp, *dir)) -- mtime = MAX(mtime, timespec_load(&st.st_mtim)); -- - FOREACH_DIRENT_ALL(de, d, log_warning_errno(errno, "Failed to read \"%s\", ignoring: %m", *dir)) { - char *filename; - _cleanup_free_ char *_filename_free = NULL, *simplified = NULL; -@@ -378,14 +325,12 @@ int unit_file_build_name_map( - basename(dst), src); - } - -- if (cache_mtime) -- *cache_mtime = mtime; - *ret_unit_ids_map = TAKE_PTR(ids); - *ret_unit_names_map = TAKE_PTR(names); - if (ret_path_cache) - *ret_path_cache = TAKE_PTR(paths); - -- return 1; -+ return 0; - } - - int unit_file_find_fragment( -diff --git a/src/shared/unit-file.h b/src/shared/unit-file.h -index 54cc787..52e17f7 100644 ---- a/src/shared/unit-file.h -+++ b/src/shared/unit-file.h -@@ -4,7 +4,6 @@ - #include - - #include "hashmap.h" --#include "time-util.h" - #include "unit-name.h" - - typedef enum UnitFileState UnitFileState; -@@ -43,7 +42,6 @@ int unit_validate_alias_symlink_and_warn(const char *filename, const char *targe - - int unit_file_build_name_map( - const LookupPaths *lp, -- usec_t *ret_time, - Hashmap **ret_unit_ids_map, - Hashmap **ret_unit_names_map, - Set **ret_path_cache); -diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c -index dcf76be..69063ee 100644 ---- a/src/systemctl/systemctl.c -+++ b/src/systemctl/systemctl.c -@@ -2594,7 +2594,7 @@ static int unit_find_paths( - _cleanup_set_free_free_ Set *names = NULL; - - if (!cached_name_map) { -- r = unit_file_build_name_map(lp, NULL, &cached_id_map, &cached_name_map, NULL); -+ r = unit_file_build_name_map(lp, &cached_id_map, &cached_name_map, NULL); - if (r < 0) - return r; - } -diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c -index 8bc5bf6..988ac15 100644 ---- a/src/test/test-unit-file.c -+++ b/src/test/test-unit-file.c -@@ -32,12 +32,10 @@ static void test_unit_file_build_name_map(char **ids) { - Iterator i; - const char *k, *dst; - char **v; -- usec_t mtime = 0; -- int r; - - assert_se(lookup_paths_init(&lp, UNIT_FILE_SYSTEM, 0, NULL) >= 0); - -- assert_se(unit_file_build_name_map(&lp, &mtime, &unit_ids, &unit_names, NULL) == 1); -+ assert_se(unit_file_build_name_map(&lp, &unit_ids, &unit_names, NULL) == 0); - - HASHMAP_FOREACH_KEY(dst, k, unit_ids, i) - log_info("ids: %s → %s", k, dst); -@@ -47,15 +45,6 @@ static void test_unit_file_build_name_map(char **ids) { - log_info("aliases: %s ← %s", k, j); - } - -- char buf[FORMAT_TIMESTAMP_MAX]; -- log_debug("Last modification time: %s", format_timestamp(buf, sizeof buf, mtime)); -- -- r = unit_file_build_name_map(&lp, &mtime, &unit_ids, &unit_names, NULL); -- assert_se(IN_SET(r, 0, 1)); -- if (r == 0) -- log_debug("Cache rebuild skipped based on mtime."); -- -- - char **id; - STRV_FOREACH(id, ids) { - const char *fragment, *name; --- -1.8.3.1 - diff --git a/revert-pid1-use-a-cache-for-all-unit-aliases.patch b/revert-pid1-use-a-cache-for-all-unit-aliases.patch deleted file mode 100644 index 7dc96a5..0000000 --- a/revert-pid1-use-a-cache-for-all-unit-aliases.patch +++ /dev/null @@ -1,1226 +0,0 @@ -From e8630e695232bdfcd16b55f3faafb4329c961104 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= -Date: Thu, 18 Jul 2019 13:11:28 +0200 -Subject: [PATCH] pid1: use a cache for all unit aliases - -This reworks how we load units from disk. Instead of chasing symlinks every -time we are asked to load a unit by name, we slurp all symlinks from disk -and build two hashmaps: -1. from unit name to either alias target, or fragment on disk - (if an alias, we put just the target name in the hashmap, if a fragment - we put an absolute path, so we can distinguish both). -2. from a unit name to all aliases - -Reading all this data can be pretty costly (40 ms) on my machine, so we keep it -around for reuse. - -The advantage is that we can reliably know what all the aliases of a given unit -are. This means we can reliably load dropins under all names. This fixes #11972. - -revert pid1 use a cache for all unit aliases ---- - src/core/load-fragment.c | 350 +++++++++++++++++++++++++++-------- - src/core/manager.c | 73 ++++++-- - src/core/manager.h | 2 - - src/core/unit.c | 3 - - src/shared/unit-file.c | 362 ------------------------------------- - src/shared/unit-file.h | 15 -- - src/systemctl/systemctl.c | 47 +++-- - src/test/test-unit-file.c | 40 ---- - test/TEST-15-DROPIN/test-dropin.sh | 33 ++-- - 9 files changed, 378 insertions(+), 547 deletions(-) - -diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c -index 9821a92..9dd86e8 100644 ---- a/src/core/load-fragment.c -+++ b/src/core/load-fragment.c -@@ -4553,48 +4553,251 @@ int config_parse_ip_filter_bpf_progs( - return 0; - } - -+#define FOLLOW_MAX 8 -+ -+static int open_follow(char **filename, FILE **_f, Set *names, char **_final) { -+ char *id = NULL; -+ unsigned c = 0; -+ int fd, r; -+ FILE *f; -+ -+ assert(filename); -+ assert(*filename); -+ assert(_f); -+ assert(names); -+ -+ /* This will update the filename pointer if the loaded file is -+ * reached by a symlink. The old string will be freed. */ -+ -+ for (;;) { -+ char *target, *name; -+ -+ if (c++ >= FOLLOW_MAX) -+ return -ELOOP; -+ -+ path_simplify(*filename, false); -+ -+ /* Add the file name we are currently looking at to -+ * the names of this unit, but only if it is a valid -+ * unit name. */ -+ name = basename(*filename); -+ if (unit_name_is_valid(name, UNIT_NAME_ANY)) { -+ -+ id = set_get(names, name); -+ if (!id) { -+ id = strdup(name); -+ if (!id) -+ return -ENOMEM; -+ -+ r = set_consume(names, id); -+ if (r < 0) -+ return r; -+ } -+ } -+ -+ /* Try to open the file name, but don't if its a symlink */ -+ fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); -+ if (fd >= 0) -+ break; -+ -+ if (errno != ELOOP) -+ return -errno; -+ -+ /* Hmm, so this is a symlink. Let's read the name, and follow it manually */ -+ r = readlink_and_make_absolute(*filename, &target); -+ if (r < 0) -+ return r; -+ -+ free_and_replace(*filename, target); -+ } -+ -+ f = fdopen(fd, "r"); -+ if (!f) { -+ safe_close(fd); -+ return -errno; -+ } -+ -+ *_f = f; -+ *_final = id; -+ -+ return 0; -+} -+ - static int merge_by_names(Unit **u, Set *names, const char *id) { - char *k; - int r; - - assert(u); - assert(*u); -+ assert(names); - -- /* Let's try to add in all names that are aliases of this unit */ -+ /* Let's try to add in all symlink names we found */ - while ((k = set_steal_first(names))) { -- _cleanup_free_ _unused_ char *free_k = k; - -- /* First try to merge in the other name into our unit */ -+ /* First try to merge in the other name into our -+ * unit */ - r = unit_merge_by_name(*u, k); - if (r < 0) { - Unit *other; - -- /* Hmm, we couldn't merge the other unit into ours? Then let's try it the other way -- * round. */ -+ /* Hmm, we couldn't merge the other unit into -+ * ours? Then let's try it the other way -+ * round */ - -- other = manager_get_unit((*u)->manager, k); -- if (!other) -- return r; /* return previous failure */ -+ /* If the symlink name we are looking at is unit template, then -+ we must search for instance of this template */ -+ if (unit_name_is_valid(k, UNIT_NAME_TEMPLATE) && (*u)->instance) { -+ _cleanup_free_ char *instance = NULL; - -- r = unit_merge(other, *u); -- if (r < 0) -- return r; -+ r = unit_name_replace_instance(k, (*u)->instance, &instance); -+ if (r < 0) -+ return r; - -- *u = other; -- return merge_by_names(u, names, NULL); -+ other = manager_get_unit((*u)->manager, instance); -+ } else -+ other = manager_get_unit((*u)->manager, k); -+ -+ free(k); -+ -+ if (other) { -+ r = unit_merge(other, *u); -+ if (r >= 0) { -+ *u = other; -+ return merge_by_names(u, names, NULL); -+ } -+ } -+ -+ return r; - } - -- if (streq_ptr(id, k)) -+ if (id == k) - unit_choose_id(*u, id); -+ -+ free(k); -+ } -+ -+ return 0; -+} -+ -+static int load_from_path(Unit *u, const char *path) { -+ _cleanup_set_free_free_ Set *symlink_names = NULL; -+ _cleanup_fclose_ FILE *f = NULL; -+ _cleanup_free_ char *filename = NULL; -+ char *id = NULL; -+ Unit *merged; -+ struct stat st; -+ int r; -+ -+ assert(u); -+ assert(path); -+ -+ symlink_names = set_new(&string_hash_ops); -+ if (!symlink_names) -+ return -ENOMEM; -+ -+ if (path_is_absolute(path)) { -+ -+ filename = strdup(path); -+ if (!filename) -+ return -ENOMEM; -+ -+ r = open_follow(&filename, &f, symlink_names, &id); -+ if (r < 0) { -+ filename = mfree(filename); -+ if (r != -ENOENT) -+ return r; -+ } -+ -+ } else { -+ char **p; -+ -+ STRV_FOREACH(p, u->manager->lookup_paths.search_path) { -+ -+ /* Instead of opening the path right away, we manually -+ * follow all symlinks and add their name to our unit -+ * name set while doing so */ -+ filename = path_make_absolute(path, *p); -+ if (!filename) -+ return -ENOMEM; -+ -+ if (u->manager->unit_path_cache && -+ !set_get(u->manager->unit_path_cache, filename)) -+ r = -ENOENT; -+ else -+ r = open_follow(&filename, &f, symlink_names, &id); -+ if (r >= 0) -+ break; -+ -+ /* ENOENT means that the file is missing or is a dangling symlink. -+ * ENOTDIR means that one of paths we expect to be is a directory -+ * is not a directory, we should just ignore that. -+ * EACCES means that the directory or file permissions are wrong. -+ */ -+ if (r == -EACCES) -+ log_debug_errno(r, "Cannot access \"%s\": %m", filename); -+ else if (!IN_SET(r, -ENOENT, -ENOTDIR)) -+ return r; -+ -+ filename = mfree(filename); -+ /* Empty the symlink names for the next run */ -+ set_clear_free(symlink_names); -+ } -+ } -+ -+ if (!filename) -+ /* Hmm, no suitable file found? */ -+ return 0; -+ -+ if (!unit_type_may_alias(u->type) && set_size(symlink_names) > 1) { -+ log_unit_warning(u, "Unit type of %s does not support alias names, refusing loading via symlink.", u->id); -+ return -ELOOP; -+ } -+ -+ merged = u; -+ r = merge_by_names(&merged, symlink_names, id); -+ if (r < 0) -+ return r; -+ -+ if (merged != u) { -+ u->load_state = UNIT_MERGED; -+ return 0; -+ } -+ -+ if (fstat(fileno(f), &st) < 0) -+ return -errno; -+ -+ if (null_or_empty(&st)) { -+ u->load_state = UNIT_MASKED; -+ u->fragment_mtime = 0; -+ } else { -+ u->load_state = UNIT_LOADED; -+ u->fragment_mtime = timespec_load(&st.st_mtim); -+ -+ /* Now, parse the file contents */ -+ r = config_parse(u->id, filename, f, -+ UNIT_VTABLE(u)->sections, -+ config_item_perf_lookup, load_fragment_gperf_lookup, -+ CONFIG_PARSE_ALLOW_INCLUDE, u); -+ if (r < 0) -+ return r; -+ } -+ -+ free_and_replace(u->fragment_path, filename); -+ -+ if (u->source_path) { -+ if (stat(u->source_path, &st) >= 0) -+ u->source_mtime = timespec_load(&st.st_mtim); -+ else -+ u->source_mtime = 0; - } - - return 0; - } - - int unit_load_fragment(Unit *u) { -- const char *fragment; -- _cleanup_set_free_free_ Set *names = NULL; - int r; -+ Iterator i; -+ const char *t; - - assert(u); - assert(u->load_state == UNIT_STUB); -@@ -4605,79 +4808,78 @@ int unit_load_fragment(Unit *u) { - return 0; - } - -- r = unit_file_find_fragment(u->manager->unit_id_map, -- u->manager->unit_name_map, -- u->id, -- &fragment, -- &names); -- if (r < 0 && r != -ENOENT) -+ /* First, try to find the unit under its id. We always look -+ * for unit files in the default directories, to make it easy -+ * to override things by placing things in /etc/systemd/system */ -+ r = load_from_path(u, u->id); -+ if (r < 0) - return r; - -- if (fragment) { -- /* Open the file, check if this is a mask, otherwise read. */ -- _cleanup_fclose_ FILE *f = NULL; -- struct stat st; -+ /* Try to find an alias we can load this with */ -+ if (u->load_state == UNIT_STUB) { -+ SET_FOREACH(t, u->names, i) { - -- /* Try to open the file name. A symlink is OK, for example for linked files or masks. We -- * expect that all symlinks within the lookup paths have been already resolved, but we don't -- * verify this here. */ -- f = fopen(fragment, "re"); -- if (!f) -- return log_unit_notice_errno(u, errno, "Failed to open %s: %m", fragment); -+ if (t == u->id) -+ continue; - -- if (fstat(fileno(f), &st) < 0) -- return -errno; -+ r = load_from_path(u, t); -+ if (r < 0) -+ return r; - -- r = free_and_strdup(&u->fragment_path, fragment); -+ if (u->load_state != UNIT_STUB) -+ break; -+ } -+ } -+ -+ /* And now, try looking for it under the suggested (originally linked) path */ -+ if (u->load_state == UNIT_STUB && u->fragment_path) { -+ -+ r = load_from_path(u, u->fragment_path); - if (r < 0) - return r; - -- if (null_or_empty(&st)) { -- u->load_state = UNIT_MASKED; -- u->fragment_mtime = 0; -- } else { -- u->load_state = UNIT_LOADED; -- u->fragment_mtime = timespec_load(&st.st_mtim); -- -- /* Now, parse the file contents */ -- r = config_parse(u->id, fragment, f, -- UNIT_VTABLE(u)->sections, -- config_item_perf_lookup, load_fragment_gperf_lookup, -- CONFIG_PARSE_ALLOW_INCLUDE, u); -- if (r == -ENOEXEC) -- log_unit_notice_errno(u, r, "Unit configuration has fatal error, unit will not be started."); -- if (r < 0) -- return r; -- } -+ if (u->load_state == UNIT_STUB) -+ /* Hmm, this didn't work? Then let's get rid -+ * of the fragment path stored for us, so that -+ * we don't point to an invalid location. */ -+ u->fragment_path = mfree(u->fragment_path); - } - -- /* We do the merge dance here because for some unit types, the unit might have aliases which are not -- * declared in the file system. In particular, this is true (and frequent) for device and swap units. -- */ -- Unit *merged; -- const char *id = u->id; -- _cleanup_free_ char *free_id = NULL; -+ /* Look for a template */ -+ if (u->load_state == UNIT_STUB && u->instance) { -+ _cleanup_free_ char *k = NULL; - -- if (fragment) { -- id = basename(fragment); -- if (unit_name_is_valid(id, UNIT_NAME_TEMPLATE)) { -- assert(u->instance); /* If we're not trying to use a template for non-instanced unit, -- * this must be set. */ -+ r = unit_name_template(u->id, &k); -+ if (r < 0) -+ return r; - -- r = unit_name_replace_instance(id, u->instance, &free_id); -- if (r < 0) -- return log_debug_errno(r, "Failed to build id (%s + %s): %m", id, u->instance); -- id = free_id; -+ r = load_from_path(u, k); -+ if (r < 0) { -+ if (r == -ENOEXEC) -+ log_unit_notice(u, "Unit configuration has fatal error, unit will not be started."); -+ return r; - } -- } - -- merged = u; -- r = merge_by_names(&merged, names, id); -- if (r < 0) -- return r; -+ if (u->load_state == UNIT_STUB) { -+ SET_FOREACH(t, u->names, i) { -+ _cleanup_free_ char *z = NULL; - -- if (merged != u) -- u->load_state = UNIT_MERGED; -+ if (t == u->id) -+ continue; -+ -+ r = unit_name_template(t, &z); -+ if (r < 0) -+ return r; -+ -+ r = load_from_path(u, z); -+ if (r < 0) -+ return r; -+ -+ if (u->load_state != UNIT_STUB) -+ break; -+ } -+ } -+ } - - return 0; - } -diff --git a/src/core/manager.c b/src/core/manager.c -index 8b1ce70..cfeaca6 100644 ---- a/src/core/manager.c -+++ b/src/core/manager.c -@@ -689,12 +689,6 @@ static int manager_setup_prefix(Manager *m) { - return 0; - } - --static void manager_free_unit_name_maps(Manager *m) { -- m->unit_id_map = hashmap_free(m->unit_id_map); -- m->unit_name_map = hashmap_free(m->unit_name_map); -- m->unit_path_cache = set_free_free(m->unit_path_cache); --} -- - static int manager_setup_run_queue(Manager *m) { - int r; - -@@ -1383,7 +1377,7 @@ Manager* manager_free(Manager *m) { - strv_free(m->client_environment); - - hashmap_free(m->cgroup_unit); -- manager_free_unit_name_maps(m); -+ set_free_free(m->unit_path_cache); - - free(m->switch_root); - free(m->switch_root_init); -@@ -1487,6 +1481,56 @@ static void manager_catchup(Manager *m) { - } - } - -+static void manager_build_unit_path_cache(Manager *m) { -+ char **i; -+ int r; -+ -+ assert(m); -+ -+ set_free_free(m->unit_path_cache); -+ -+ m->unit_path_cache = set_new(&path_hash_ops); -+ if (!m->unit_path_cache) { -+ r = -ENOMEM; -+ goto fail; -+ } -+ -+ /* This simply builds a list of files we know exist, so that -+ * we don't always have to go to disk */ -+ -+ STRV_FOREACH(i, m->lookup_paths.search_path) { -+ _cleanup_closedir_ DIR *d = NULL; -+ struct dirent *de; -+ -+ d = opendir(*i); -+ if (!d) { -+ if (errno != ENOENT) -+ log_warning_errno(errno, "Failed to open directory %s, ignoring: %m", *i); -+ continue; -+ } -+ -+ FOREACH_DIRENT(de, d, r = -errno; goto fail) { -+ char *p; -+ -+ p = path_join(*i, de->d_name); -+ if (!p) { -+ r = -ENOMEM; -+ goto fail; -+ } -+ -+ r = set_consume(m->unit_path_cache, p); -+ if (r < 0) -+ goto fail; -+ } -+ } -+ -+ return; -+ -+fail: -+ log_warning_errno(r, "Failed to build unit path cache, proceeding without: %m"); -+ m->unit_path_cache = set_free_free(m->unit_path_cache); -+} -+ - static void manager_distribute_fds(Manager *m, FDSet *fds) { - Iterator i; - Unit *u; -@@ -1641,10 +1685,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { - - lookup_paths_log(&m->lookup_paths); - -- manager_free_unit_name_maps(m); -- r = unit_file_build_name_map(&m->lookup_paths, &m->unit_id_map, &m->unit_name_map, &m->unit_path_cache); -- if (r < 0) -- return log_error_errno(r, "Failed to build name map: %m"); -+ manager_build_unit_path_cache(m); - - { - /* This block is (optionally) done with the reloading counter bumped */ -@@ -2862,9 +2903,8 @@ int manager_loop(Manager *m) { - assert(m); - assert(m->objective == MANAGER_OK); /* Ensure manager_startup() has been called */ - -- /* Release the path and unit name caches */ -- manager_free_unit_name_maps(m); -- // FIXME: once this happens, we cannot load any more units -+ /* Release the path cache */ -+ m->unit_path_cache = set_free_free(m->unit_path_cache); - - manager_check_finished(m); - -@@ -3539,10 +3579,7 @@ int manager_reload(Manager *m) { - - lookup_paths_log(&m->lookup_paths); - -- manager_free_unit_name_maps(m); -- r = unit_file_build_name_map(&m->lookup_paths, &m->unit_id_map, &m->unit_name_map, &m->unit_path_cache); -- if (r < 0) -- log_warning_errno(r, "Failed to build name map: %m"); -+ manager_build_unit_path_cache(m); - - /* First, enumerate what we can from kernel and suchlike */ - manager_enumerate_perpetual(m); -diff --git a/src/core/manager.h b/src/core/manager.h -index 9ca82ac..daeb454 100644 ---- a/src/core/manager.h -+++ b/src/core/manager.h -@@ -220,8 +220,6 @@ struct Manager { - - UnitFileScope unit_file_scope; - LookupPaths lookup_paths; -- Hashmap *unit_id_map; -- Hashmap *unit_name_map; - Set *unit_path_cache; - - char **transient_environment; /* The environment, as determined from config files, kernel cmdline and environment generators */ -diff --git a/src/core/unit.c b/src/core/unit.c -index f96e6e4..1b8d5d9 100644 ---- a/src/core/unit.c -+++ b/src/core/unit.c -@@ -959,9 +959,6 @@ int unit_merge_by_name(Unit *u, const char *name) { - Unit *other; - int r; - -- /* Either add name to u, or if a unit with name already exists, merge it with u. -- * If name is a template, do the same for name@instance, where instance is u's instance. */ -- - assert(u); - assert(name); - -diff --git a/src/shared/unit-file.c b/src/shared/unit-file.c -index bad92a3..cde38c4 100644 ---- a/src/shared/unit-file.c -+++ b/src/shared/unit-file.c -@@ -1,14 +1,7 @@ - /* SPDX-License-Identifier: LGPL-2.1+ */ - --#include "dirent-util.h" --#include "fd-util.h" --#include "fs-util.h" - #include "macro.h" --#include "path-lookup.h" --#include "set.h" --#include "stat-util.h" - #include "string-util.h" --#include "strv.h" - #include "unit-file.h" - - bool unit_type_may_alias(UnitType type) { -@@ -101,358 +94,3 @@ int unit_validate_alias_symlink_and_warn(const char *filename, const char *targe - - return 0; - } -- --#define FOLLOW_MAX 8 -- --static int unit_ids_map_get( -- Hashmap *unit_ids_map, -- const char *unit_name, -- const char **ret_fragment_path) { -- -- /* Resolve recursively until we hit an absolute path, i.e. a non-aliased unit. -- * -- * We distinguish the case where unit_name was not found in the hashmap at all, and the case where -- * some symlink was broken. -- * -- * If a symlink target points to an instance name, then we also check for the template. */ -- -- const char *id = NULL; -- int r; -- -- for (unsigned n = 0; n < FOLLOW_MAX; n++) { -- const char *t = hashmap_get(unit_ids_map, id ?: unit_name); -- if (!t) { -- _cleanup_free_ char *template = NULL; -- -- if (!id) -- return -ENOENT; -- -- r = unit_name_template(id, &template); -- if (r == -EINVAL) -- return -ENXIO; /* we failed to find the symlink target */ -- if (r < 0) -- return log_error_errno(r, "Failed to determine template name for %s: %m", id); -- -- t = hashmap_get(unit_ids_map, template); -- if (!t) -- return -ENXIO; -- -- /* We successfully switched from instanced name to a template, let's continue */ -- } -- -- if (path_is_absolute(t)) { -- if (ret_fragment_path) -- *ret_fragment_path = t; -- return 0; -- } -- -- id = t; -- } -- -- return -ELOOP; --} -- --int unit_file_build_name_map( -- const LookupPaths *lp, -- Hashmap **ret_unit_ids_map, -- Hashmap **ret_unit_names_map, -- Set **ret_path_cache) { -- -- /* Build two mappings: any name → main unit (i.e. the end result of symlink resolution), unit name → -- * all aliases (i.e. the entry for a given key is a a list of all names which point to this key). The -- * key is included in the value iff we saw a file or symlink with that name. In other words, if we -- * have a key, but it is not present in the value for itself, there was an alias pointing to it, but -- * the unit itself is not loadable. -- * -- * At the same, build a cache of paths where to find units. -- */ -- -- _cleanup_hashmap_free_ Hashmap *ids = NULL, *names = NULL; -- _cleanup_set_free_free_ Set *paths = NULL; -- char **dir; -- int r; -- -- if (ret_path_cache) { -- paths = set_new(&path_hash_ops); -- if (!paths) -- return log_oom(); -- } -- -- STRV_FOREACH(dir, (char**) lp->search_path) { -- struct dirent *de; -- _cleanup_closedir_ DIR *d = NULL; -- -- d = opendir(*dir); -- if (!d) { -- if (errno != ENOENT) -- log_warning_errno(errno, "Failed to open \"%s\", ignoring: %m", *dir); -- continue; -- } -- -- FOREACH_DIRENT_ALL(de, d, log_warning_errno(errno, "Failed to read \"%s\", ignoring: %m", *dir)) { -- char *filename; -- _cleanup_free_ char *_filename_free = NULL, *simplified = NULL; -- const char *suffix, *dst = NULL; -- bool valid_unit_name; -- -- valid_unit_name = unit_name_is_valid(de->d_name, UNIT_NAME_ANY); -- -- /* We only care about valid units and dirs with certain suffixes, let's ignore the -- * rest. */ -- if (!valid_unit_name && -- !ENDSWITH_SET(de->d_name, ".wants", ".requires", ".d")) -- continue; -- -- filename = path_join(*dir, de->d_name); -- if (!filename) -- return log_oom(); -- -- if (ret_path_cache) { -- r = set_consume(paths, filename); -- if (r < 0) -- return log_oom(); -- /* We will still use filename below. This is safe because we know the set -- * holds a reference. */ -- } else -- _filename_free = filename; /* Make sure we free the filename. */ -- -- if (!valid_unit_name) -- continue; -- assert_se(suffix = strrchr(de->d_name, '.')); -- -- /* search_path is ordered by priority (highest first). If the name is already mapped -- * to something (incl. itself), it means that we have already seen it, and we should -- * ignore it here. */ -- if (hashmap_contains(ids, de->d_name)) -- continue; -- -- if (de->d_type == DT_LNK) { -- /* We don't explicitly check for alias loops here. unit_ids_map_get() which -- * limits the number of hops should be used to access the map. */ -- -- _cleanup_free_ char *target = NULL, *target_abs = NULL; -- -- r = readlinkat_malloc(dirfd(d), de->d_name, &target); -- if (r < 0) { -- log_warning_errno(r, "Failed to read symlink %s/%s, ignoring: %m", -- *dir, de->d_name); -- continue; -- } -- -- if (!path_is_absolute(target)) { -- target_abs = path_join(*dir, target); -- if (!target_abs) -- return log_oom(); -- -- free_and_replace(target, target_abs); -- } -- -- /* Get rid of "." and ".." components in target path */ -- r = chase_symlinks(target, lp->root_dir, CHASE_NOFOLLOW | CHASE_NONEXISTENT, &simplified); -- if (r < 0) { -- log_warning_errno(r, "Failed to resolve symlink %s pointing to %s, ignoring: %m", -- filename, target); -- continue; -- } -- -- /* Check if the symlink goes outside of our search path. -- * If yes, it's a linked unit file or mask, and we don't care about the target name. -- * Let's just store the link destination directly. -- * If not, let's verify that it's a good symlink. */ -- char *tail = path_startswith_strv(simplified, lp->search_path); -- if (tail) { -- bool self_alias; -- -- dst = basename(simplified); -- self_alias = streq(dst, de->d_name); -- -- if (is_path(tail)) -- log_full(self_alias ? LOG_DEBUG : LOG_WARNING, -- "Suspicious symlink %s→%s, treating as alias.", -- filename, simplified); -- -- r = unit_validate_alias_symlink_and_warn(filename, simplified); -- if (r < 0) -- continue; -- -- if (self_alias) { -- /* A self-alias that has no effect */ -- log_debug("%s: self-alias: %s/%s → %s, ignoring.", -- __func__, *dir, de->d_name, dst); -- continue; -- } -- -- log_debug("%s: alias: %s/%s → %s", __func__, *dir, de->d_name, dst); -- } else { -- dst = simplified; -- -- log_debug("%s: linked unit file: %s/%s → %s", __func__, *dir, de->d_name, dst); -- } -- -- } else { -- dst = filename; -- log_debug("%s: normal unit file: %s", __func__, dst); -- } -- -- r = hashmap_put_strdup(&ids, de->d_name, dst); -- if (r < 0) -- return log_warning_errno(r, "Failed to add entry to hashmap (%s→%s): %m", -- de->d_name, dst); -- } -- } -- -- /* Let's also put the names in the reverse db. */ -- Iterator it; -- const char *dummy, *src; -- HASHMAP_FOREACH_KEY(dummy, src, ids, it) { -- const char *dst; -- -- r = unit_ids_map_get(ids, src, &dst); -- if (r < 0) -- continue; -- -- if (null_or_empty_path(dst) != 0) -- continue; -- -- /* Do not treat instance symlinks that point to the template as aliases */ -- if (unit_name_is_valid(basename(dst), UNIT_NAME_TEMPLATE) && -- unit_name_is_valid(src, UNIT_NAME_INSTANCE)) -- continue; -- -- r = string_strv_hashmap_put(&names, basename(dst), src); -- if (r < 0) -- return log_warning_errno(r, "Failed to add entry to hashmap (%s→%s): %m", -- basename(dst), src); -- } -- -- *ret_unit_ids_map = TAKE_PTR(ids); -- *ret_unit_names_map = TAKE_PTR(names); -- if (ret_path_cache) -- *ret_path_cache = TAKE_PTR(paths); -- -- return 0; --} -- --int unit_file_find_fragment( -- Hashmap *unit_ids_map, -- Hashmap *unit_name_map, -- const char *unit_name, -- const char **ret_fragment_path, -- Set **ret_names) { -- -- const char *fragment = NULL; -- _cleanup_free_ char *template = NULL, *instance = NULL; -- _cleanup_set_free_free_ Set *names = NULL; -- char **t, **nnn; -- int r, name_type; -- -- /* Finds a fragment path, and returns the set of names: -- * if we have …/foo.service and …/foo-alias.service→foo.service, -- * and …/foo@.service and …/foo-alias@.service→foo@.service, -- * and …/foo@inst.service, -- * this should return: -- * foo.service → …/foo.service, {foo.service, foo-alias.service}, -- * foo-alias.service → …/foo.service, {foo.service, foo-alias.service}, -- * foo@.service → …/foo@.service, {foo@.service, foo-alias@.service}, -- * foo-alias@.service → …/foo@.service, {foo@.service, foo-alias@.service}, -- * foo@bar.service → …/foo@.service, {foo@bar.service, foo-alias@bar.service}, -- * foo-alias@bar.service → …/foo@.service, {foo@bar.service, foo-alias@bar.service}, -- * foo-alias@inst.service → …/foo@inst.service, {foo@inst.service, foo-alias@inst.service}. -- */ -- -- name_type = unit_name_to_instance(unit_name, &instance); -- if (name_type < 0) -- return name_type; -- -- names = set_new(&string_hash_ops); -- if (!names) -- return -ENOMEM; -- -- /* The unit always has its own name if it's not a template. */ -- if (IN_SET(name_type, UNIT_NAME_PLAIN, UNIT_NAME_INSTANCE)) { -- r = set_put_strdup(names, unit_name); -- if (r < 0) -- return r; -- } -- -- /* First try to load fragment under the original name */ -- r = unit_ids_map_get(unit_ids_map, unit_name, &fragment); -- if (r < 0 && !IN_SET(r, -ENOENT, -ENXIO)) -- return log_debug_errno(r, "Cannot load unit %s: %m", unit_name); -- -- if (fragment) { -- /* Add any aliases of the original name to the set of names */ -- nnn = hashmap_get(unit_name_map, basename(fragment)); -- STRV_FOREACH(t, nnn) { -- if (name_type == UNIT_NAME_INSTANCE && unit_name_is_valid(*t, UNIT_NAME_TEMPLATE)) { -- char *inst; -- -- r = unit_name_replace_instance(*t, instance, &inst); -- if (r < 0) -- return log_debug_errno(r, "Cannot build instance name %s+%s: %m", *t, instance); -- -- if (!streq(unit_name, inst)) -- log_debug("%s: %s has alias %s", __func__, unit_name, inst); -- -- log_info("%s: %s+%s → %s", __func__, *t, instance, inst); -- r = set_consume(names, inst); -- } else { -- if (!streq(unit_name, *t)) -- log_debug("%s: %s has alias %s", __func__, unit_name, *t); -- -- r = set_put_strdup(names, *t); -- } -- if (r < 0) -- return r; -- } -- } -- -- if (!fragment && name_type == UNIT_NAME_INSTANCE) { -- /* Look for a fragment under the template name */ -- -- r = unit_name_template(unit_name, &template); -- if (r < 0) -- return log_error_errno(r, "Failed to determine template name: %m"); -- -- r = unit_ids_map_get(unit_ids_map, template, &fragment); -- if (r < 0 && !IN_SET(r, -ENOENT, -ENXIO)) -- return log_debug_errno(r, "Cannot load template %s: %m", template); -- -- if (fragment) { -- /* Add any aliases of the original name to the set of names */ -- nnn = hashmap_get(unit_name_map, basename(fragment)); -- STRV_FOREACH(t, nnn) { -- _cleanup_free_ char *inst = NULL; -- const char *inst_fragment = NULL; -- -- r = unit_name_replace_instance(*t, instance, &inst); -- if (r < 0) -- return log_debug_errno(r, "Cannot build instance name %s+%s: %m", template, instance); -- -- /* Exclude any aliases that point in some other direction. */ -- r = unit_ids_map_get(unit_ids_map, inst, &inst_fragment); -- if (r < 0 && !IN_SET(r, -ENOENT, -ENXIO)) -- return log_debug_errno(r, "Cannot find instance fragment %s: %m", inst); -- -- if (inst_fragment && -- !streq(basename(inst_fragment), basename(fragment))) { -- log_debug("Instance %s has fragment %s and is not an alias of %s.", -- inst, inst_fragment, unit_name); -- continue; -- } -- -- if (!streq(unit_name, inst)) -- log_debug("%s: %s has alias %s", __func__, unit_name, inst); -- r = set_consume(names, TAKE_PTR(inst)); -- if (r < 0) -- return r; -- } -- } -- } -- -- *ret_fragment_path = fragment; -- *ret_names = TAKE_PTR(names); -- -- // FIXME: if instance, consider any unit names with different template name -- return 0; --} -diff --git a/src/shared/unit-file.h b/src/shared/unit-file.h -index 52e17f7..e57f472 100644 ---- a/src/shared/unit-file.h -+++ b/src/shared/unit-file.h -@@ -3,12 +3,10 @@ - - #include - --#include "hashmap.h" - #include "unit-name.h" - - typedef enum UnitFileState UnitFileState; - typedef enum UnitFileScope UnitFileScope; --typedef struct LookupPaths LookupPaths; - - enum UnitFileState { - UNIT_FILE_ENABLED, -@@ -39,16 +37,3 @@ bool unit_type_may_alias(UnitType type) _const_; - bool unit_type_may_template(UnitType type) _const_; - - int unit_validate_alias_symlink_and_warn(const char *filename, const char *target); -- --int unit_file_build_name_map( -- const LookupPaths *lp, -- Hashmap **ret_unit_ids_map, -- Hashmap **ret_unit_names_map, -- Set **ret_path_cache); -- --int unit_file_find_fragment( -- Hashmap *unit_ids_map, -- Hashmap *unit_name_map, -- const char *unit_name, -- const char **ret_fragment_path, -- Set **names); -diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c -index 69063ee..48e0bad 100644 ---- a/src/systemctl/systemctl.c -+++ b/src/systemctl/systemctl.c -@@ -33,7 +33,6 @@ - #include "cgroup-util.h" - #include "copy.h" - #include "cpu-set-util.h" --#include "dirent-util.h" - #include "dropin.h" - #include "efivars.h" - #include "env-util.h" -@@ -167,18 +166,12 @@ static bool arg_jobs_before = false; - static bool arg_jobs_after = false; - static char **arg_clean_what = NULL; - --/* This is a global cache that will be constructed on first use. */ --static Hashmap *cached_id_map = NULL; --static Hashmap *cached_name_map = NULL; -- - STATIC_DESTRUCTOR_REGISTER(arg_wall, strv_freep); - STATIC_DESTRUCTOR_REGISTER(arg_root, freep); - STATIC_DESTRUCTOR_REGISTER(arg_types, strv_freep); - STATIC_DESTRUCTOR_REGISTER(arg_states, strv_freep); - STATIC_DESTRUCTOR_REGISTER(arg_properties, strv_freep); - STATIC_DESTRUCTOR_REGISTER(arg_clean_what, strv_freep); --STATIC_DESTRUCTOR_REGISTER(cached_id_map, hashmap_freep); --STATIC_DESTRUCTOR_REGISTER(cached_name_map, hashmap_freep); - - static int daemon_reload(int argc, char *argv[], void* userdata); - static int trivial_method(int argc, char *argv[], void *userdata); -@@ -2590,24 +2583,38 @@ static int unit_find_paths( - return log_error_errno(r, "Failed to get DropInPaths: %s", bus_error_message(&error, r)); - } - } else { -- const char *_path; -- _cleanup_set_free_free_ Set *names = NULL; -+ _cleanup_set_free_ Set *names = NULL; -+ _cleanup_free_ char *template = NULL; - -- if (!cached_name_map) { -- r = unit_file_build_name_map(lp, &cached_id_map, &cached_name_map, NULL); -- if (r < 0) -- return r; -- } -+ names = set_new(NULL); -+ if (!names) -+ return log_oom(); - -- r = unit_file_find_fragment(cached_id_map, cached_name_map, unit_name, &_path, &names); -+ r = unit_find_template_path(unit_name, lp, &path, &template); - if (r < 0) - return r; -+ if (r > 0) { -+ if (null_or_empty_path(path)) -+ /* The template is masked. Let's cut the process short. */ -+ return -ERFKILL; -+ -+ /* We found the unit file. If we followed symlinks, this name might be -+ * different then the unit_name with started with. Look for dropins matching -+ * that "final" name. */ -+ r = set_put(names, basename(path)); -+ } else if (!template) -+ /* No unit file, let's look for dropins matching the original name. -+ * systemd has fairly complicated rules (based on unit type and provenience), -+ * which units are allowed not to have the main unit file. We err on the -+ * side of including too many files, and always try to load dropins. */ -+ r = set_put(names, unit_name); -+ else -+ /* The cases where we allow a unit to exist without the main file are -+ * never valid for templates. Don't try to load dropins in this case. */ -+ goto not_found; - -- if (_path) { -- path = strdup(_path); -- if (!path) -- return log_oom(); -- } -+ if (r < 0) -+ return log_error_errno(r, "Failed to add unit name: %m"); - - if (ret_dropin_paths) { - r = unit_file_find_dropin_paths(arg_root, lp->search_path, NULL, -diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c -index 988ac15..b626b5f 100644 ---- a/src/test/test-unit-file.c -+++ b/src/test/test-unit-file.c -@@ -25,50 +25,10 @@ static void test_unit_validate_alias_symlink_and_warn(void) { - assert_se(unit_validate_alias_symlink_and_warn("/path/a.slice", "/other/b.slice") == -EINVAL); - } - --static void test_unit_file_build_name_map(char **ids) { -- _cleanup_(lookup_paths_free) LookupPaths lp = {}; -- _cleanup_hashmap_free_ Hashmap *unit_ids = NULL; -- _cleanup_hashmap_free_ Hashmap *unit_names = NULL; -- Iterator i; -- const char *k, *dst; -- char **v; -- -- assert_se(lookup_paths_init(&lp, UNIT_FILE_SYSTEM, 0, NULL) >= 0); -- -- assert_se(unit_file_build_name_map(&lp, &unit_ids, &unit_names, NULL) == 0); -- -- HASHMAP_FOREACH_KEY(dst, k, unit_ids, i) -- log_info("ids: %s → %s", k, dst); -- -- HASHMAP_FOREACH_KEY(v, k, unit_names, i) { -- _cleanup_free_ char *j = strv_join(v, ", "); -- log_info("aliases: %s ← %s", k, j); -- } -- -- char **id; -- STRV_FOREACH(id, ids) { -- const char *fragment, *name; -- Iterator it; -- _cleanup_set_free_free_ Set *names = NULL; -- log_info("*** %s ***", *id); -- r = unit_file_find_fragment(unit_ids, -- unit_names, -- *id, -- &fragment, -- &names); -- assert(r == 0); -- log_info("fragment: %s", fragment); -- log_info("names:"); -- SET_FOREACH(name, names, it) -- log_info(" %s", name); -- } --} -- - int main(int argc, char **argv) { - test_setup_logging(LOG_DEBUG); - - test_unit_validate_alias_symlink_and_warn(); -- test_unit_file_build_name_map(strv_skip(argv, 1)); - - return 0; - } -diff --git a/test/TEST-15-DROPIN/test-dropin.sh b/test/TEST-15-DROPIN/test-dropin.sh -index 2cef5a3..f785680 100755 ---- a/test/TEST-15-DROPIN/test-dropin.sh -+++ b/test/TEST-15-DROPIN/test-dropin.sh -@@ -158,14 +158,14 @@ EOF - systemctl show -p Names,Requires bar@0 - systemctl show -p Names,Requires bar-alias@0 - check_ok bar@0 Names bar@0 -- check_ok bar@0 Names bar-alias@0 -+ check_ko bar@0 Names bar-alias@0 - - check_ok bar@0 After bar-template-after.device - - check_ok bar@0 Requires bar-0-requires.device -- check_ok bar@0 Requires bar-alias-0-requires.device -+ check_ko bar@0 Requires bar-alias-0-requires.device - check_ok bar@0 Requires bar-template-requires.device -- check_ok bar@0 Requires bar-alias-template-requires.device -+ check_ko bar@0 Requires bar-alias-template-requires.device - check_ko bar@0 Requires yup-template-requires.device - - check_ok bar-alias@0 After bar-template-after.device -@@ -181,15 +181,15 @@ EOF - systemctl show -p Names,Requires bar@1 - systemctl show -p Names,Requires bar-alias@1 - check_ok bar@1 Names bar@1 -- check_ok bar@1 Names bar-alias@1 -+ check_ko bar@1 Names bar-alias@1 - - check_ok bar@1 After bar-template-after.device - - check_ok bar@1 Requires bar-1-requires.device -- check_ok bar@1 Requires bar-alias-1-requires.device -+ check_ko bar@1 Requires bar-alias-1-requires.device - check_ok bar@1 Requires bar-template-requires.device - # See https://github.com/systemd/systemd/pull/13119#discussion_r308145418 -- check_ok bar@1 Requires bar-alias-template-requires.device -+ check_ko bar@1 Requires bar-alias-template-requires.device - check_ko bar@1 Requires yup-template-requires.device - check_ko bar@1 Requires yup-1-requires.device - -@@ -241,14 +241,14 @@ EOF - check_ko bar@3 Requires yup-template-requires.device - check_ko bar@3 Requires yup-3-requires.device - -- check_ko bar-alias@3 After bar-template-after.device -+ check_ok bar-alias@3 After bar-template-after.device - -- check_ko bar-alias@3 Requires bar-3-requires.device -+ check_ok bar-alias@3 Requires bar-3-requires.device - check_ok bar-alias@3 Requires bar-alias-3-requires.device -- check_ko bar-alias@3 Requires bar-template-requires.device -+ check_ok bar-alias@3 Requires bar-template-requires.device - check_ok bar-alias@3 Requires bar-alias-template-requires.device -- check_ok bar-alias@3 Requires yup-template-requires.device -- check_ok bar-alias@3 Requires yup-3-requires.device -+ check_ko bar-alias@3 Requires yup-template-requires.device -+ check_ko bar-alias@3 Requires yup-3-requires.device - - clear_services foo {bar,yup,bar-alias}@{,1,2,3} - } -@@ -267,7 +267,14 @@ test_alias_dropins () { - rm /etc/systemd/system/b1.service - clear_services a b - -- # Check that dependencies don't vary. -+ # A weird behavior: the dependencies for 'a' may vary. It can be -+ # changed by loading an alias... -+ # -+ # [1] 'a1' is loaded and then "renamed" into 'a'. 'a1' is therefore -+ # part of the names set so all its specific dropins are loaded. -+ # -+ # [2] 'a' is already loaded. 'a1' is simply only merged into 'a' so -+ # none of its dropins are loaded ('y' is missing from the deps). - echo "*** test 2" - create_services a x y - mkdir -p /etc/systemd/system/a1.service.wants/ -@@ -278,7 +285,7 @@ test_alias_dropins () { - check_ok a1 Wants y.service - systemctl start a - check_ok a1 Wants x.service # see [2] -- check_ok a1 Wants y.service -+ check_ko a1 Wants y.service - systemctl stop a x y - rm /etc/systemd/system/a1.service - --- -1.8.3.1 - diff --git a/revert-shared-unit-file-add-a-function-to-validate-u.patch b/revert-shared-unit-file-add-a-function-to-validate-u.patch deleted file mode 100644 index 8966756..0000000 --- a/revert-shared-unit-file-add-a-function-to-validate-u.patch +++ /dev/null @@ -1,177 +0,0 @@ -From 7d1e91d1a9504ab1bc03894038f90a8e87a4e982 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= -Date: Tue, 2 Apr 2019 11:22:56 +0200 -Subject: [PATCH] shared/unit-file: add a function to validate unit alias - symlinks - -It turns out most possible symlinks are invalid, because the type has to match, -and template units can only be linked to template units. - -I'm not sure if the existing code made the same checks consistently. At least -I don't see the same rules expressed in a single place. - -revert shared unit file add a function to validate unit alias symlinks ---- - src/shared/unit-file.c | 73 ----------------------------------------------- - src/shared/unit-file.h | 2 -- - src/test/meson.build | 4 --- - src/test/test-unit-file.c | 34 ---------------------- - 4 files changed, 113 deletions(-) - delete mode 100644 src/test/test-unit-file.c - -diff --git a/src/shared/unit-file.c b/src/shared/unit-file.c -index cde38c4..deed7dc 100644 ---- a/src/shared/unit-file.c -+++ b/src/shared/unit-file.c -@@ -1,7 +1,6 @@ - /* SPDX-License-Identifier: LGPL-2.1+ */ - - #include "macro.h" --#include "string-util.h" - #include "unit-file.h" - - bool unit_type_may_alias(UnitType type) { -@@ -22,75 +21,3 @@ bool unit_type_may_template(UnitType type) { - UNIT_TIMER, - UNIT_PATH); - } -- --int unit_validate_alias_symlink_and_warn(const char *filename, const char *target) { -- const char *src, *dst; -- _cleanup_free_ char *src_instance = NULL, *dst_instance = NULL; -- UnitType src_unit_type, dst_unit_type; -- int src_name_type, dst_name_type; -- -- /* Check if the *alias* symlink is valid. This applies to symlinks like -- * /etc/systemd/system/dbus.service → dbus-broker.service, but not to .wants or .requires symlinks -- * and such. Neither does this apply to symlinks which *link* units, i.e. symlinks to outside of the -- * unit lookup path. -- * -- * -EINVAL is returned if the something is wrong with the source filename or the source unit type is -- * not allowed to symlink, -- * -EXDEV if the target filename is not a valid unit name or doesn't match the source. -- */ -- -- src = basename(filename); -- dst = basename(target); -- -- /* src checks */ -- -- src_name_type = unit_name_to_instance(src, &src_instance); -- if (src_name_type < 0) -- return log_notice_errno(src_name_type, -- "%s: not a valid unit name \"%s\": %m", filename, src); -- -- src_unit_type = unit_name_to_type(src); -- assert(src_unit_type >= 0); /* unit_name_to_instance() checked the suffix already */ -- -- if (!unit_type_may_alias(src_unit_type)) -- return log_notice_errno(SYNTHETIC_ERRNO(EINVAL), -- "%s: symlinks are not allowed for units of this type, rejecting.", -- filename); -- -- if (src_name_type != UNIT_NAME_PLAIN && -- !unit_type_may_template(src_unit_type)) -- return log_notice_errno(SYNTHETIC_ERRNO(EINVAL), -- "%s: templates not allowed for %s units, rejecting.", -- filename, unit_type_to_string(src_unit_type)); -- -- /* dst checks */ -- -- dst_name_type = unit_name_to_instance(dst, &dst_instance); -- if (dst_name_type < 0) -- return log_notice_errno(dst_name_type == -EINVAL ? SYNTHETIC_ERRNO(EXDEV) : dst_name_type, -- "%s points to \"%s\" which is not a valid unit name: %m", -- filename, dst); -- -- if (!(dst_name_type == src_name_type || -- (src_name_type == UNIT_NAME_INSTANCE && dst_name_type == UNIT_NAME_TEMPLATE))) -- return log_notice_errno(SYNTHETIC_ERRNO(EXDEV), -- "%s: symlink target name type \"%s\" does not match source, rejecting.", -- filename, dst); -- -- if (dst_name_type == UNIT_NAME_INSTANCE) { -- assert(src_instance); -- assert(dst_instance); -- if (!streq(src_instance, dst_instance)) -- return log_notice_errno(SYNTHETIC_ERRNO(EXDEV), -- "%s: unit symlink target \"%s\" instance name doesn't match, rejecting.", -- filename, dst); -- } -- -- dst_unit_type = unit_name_to_type(dst); -- if (dst_unit_type != src_unit_type) -- return log_notice_errno(SYNTHETIC_ERRNO(EXDEV), -- "%s: symlink target \"%s\" has incompatible suffix, rejecting.", -- filename, dst); -- -- return 0; --} -diff --git a/src/shared/unit-file.h b/src/shared/unit-file.h -index e57f472..2b9df65 100644 ---- a/src/shared/unit-file.h -+++ b/src/shared/unit-file.h -@@ -35,5 +35,3 @@ enum UnitFileScope { - - bool unit_type_may_alias(UnitType type) _const_; - bool unit_type_may_template(UnitType type) _const_; -- --int unit_validate_alias_symlink_and_warn(const char *filename, const char *target); -diff --git a/src/test/meson.build b/src/test/meson.build -index de31e97..5625e68 100644 ---- a/src/test/meson.build -+++ b/src/test/meson.build -@@ -137,10 +137,6 @@ tests += [ - [], - 'ENABLE_EFI'], - -- [['src/test/test-unit-file.c'], -- [], -- []], -- - [['src/test/test-unit-name.c', - 'src/test/test-helper.c'], - [libcore, -diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c -deleted file mode 100644 -index b626b5f..0000000 ---- a/src/test/test-unit-file.c -+++ /dev/null -@@ -1,34 +0,0 @@ --/* SPDX-License-Identifier: LGPL-2.1+ */ -- --#include "path-lookup.h" --#include "set.h" --#include "strv.h" --#include "tests.h" --#include "unit-file.h" -- --static void test_unit_validate_alias_symlink_and_warn(void) { -- log_info("/* %s */", __func__); -- -- assert_se(unit_validate_alias_symlink_and_warn("/path/a.service", "/other/b.service") == 0); -- assert_se(unit_validate_alias_symlink_and_warn("/path/a.service", "/other/b.socket") == -EXDEV); -- assert_se(unit_validate_alias_symlink_and_warn("/path/a.service", "/other/b.foobar") == -EXDEV); -- assert_se(unit_validate_alias_symlink_and_warn("/path/a@.service", "/other/b@.service") == 0); -- assert_se(unit_validate_alias_symlink_and_warn("/path/a@.service", "/other/b@.socket") == -EXDEV); -- assert_se(unit_validate_alias_symlink_and_warn("/path/a@XXX.service", "/other/b@YYY.service") == -EXDEV); -- assert_se(unit_validate_alias_symlink_and_warn("/path/a@XXX.service", "/other/b@YYY.socket") == -EXDEV); -- assert_se(unit_validate_alias_symlink_and_warn("/path/a@.service", "/other/b@YYY.service") == -EXDEV); -- assert_se(unit_validate_alias_symlink_and_warn("/path/a@XXX.service", "/other/b@XXX.service") == 0); -- assert_se(unit_validate_alias_symlink_and_warn("/path/a@XXX.service", "/other/b@.service") == 0); -- assert_se(unit_validate_alias_symlink_and_warn("/path/a@.service", "/other/b.service") == -EXDEV); -- assert_se(unit_validate_alias_symlink_and_warn("/path/a.service", "/other/b@.service") == -EXDEV); -- assert_se(unit_validate_alias_symlink_and_warn("/path/a@.slice", "/other/b.slice") == -EINVAL); -- assert_se(unit_validate_alias_symlink_and_warn("/path/a.slice", "/other/b.slice") == -EINVAL); --} -- --int main(int argc, char **argv) { -- test_setup_logging(LOG_DEBUG); -- -- test_unit_validate_alias_symlink_and_warn(); -- -- return 0; --} --- -1.8.3.1 - diff --git a/systemd.spec b/systemd.spec index d5d82e6..a5f0397 100644 --- a/systemd.spec +++ b/systemd.spec @@ -20,7 +20,7 @@ Name: systemd Url: https://www.freedesktop.org/wiki/Software/systemd Version: 248 -Release: 1 +Release: 2 License: MIT and LGPLv2+ and GPLv2+ Summary: System and Service Manager @@ -62,10 +62,10 @@ Patch0013: 0013-sd-bus-properly-initialize-containers.patch Patch0014: 0014-Revert-core-one-step-back-again-for-nspawn-we-actual.patch Patch0015: 0015-journal-don-t-enable-systemd-journald-audit.socket-b.patch Patch0016: 0016-systemd-change-time-log-level.patch -#Patch0017: fix-capsh-drop-but-ping-success.patch -#Patch0018: 0998-resolved-create-etc-resolv.conf-symlink-at-runtime.patch -#Patch0019: core-serialize-u-pids-until-the-processes-have-been-.patch -#Patch0020: scope-on-unified-make-sure-to-unwatch-all-PIDs-once-.patch +#Patch0017: 0017-fix-capsh-drop-but-ping-success.patch +#Patch0018: 0018-resolved-create-etc-resolv.conf-symlink-at-runtime.patch +#Patch0019: 0019-core-serialize-u-pids-until-the-processes-have-been-.patch +#Patch0020: 0020-scope-on-unified-make-sure-to-unwatch-all-PIDs-once-.patch BuildRequires: gcc, gcc-c++ BuildRequires: libcap-devel, libmount-devel, pam-devel, libselinux-devel @@ -1528,6 +1528,9 @@ fi %exclude /usr/share/man/man3/* %changelog +* Fri 30 Apr 2021 hexiaowen - 248-2 +- delete unused patches + * Fri 30 Apr 2021 hexiaowen - 248-1 - Rebase to version 248