|
|
8d419f |
From dc017e5c51e61ddd96d2a94f35223ac7788c8454 Mon Sep 17 00:00:00 2001
|
|
|
8d419f |
From: Andreas Rammhold <andreas@rammhold.de>
|
|
|
8d419f |
Date: Wed, 18 Aug 2021 19:10:08 +0200
|
|
|
8d419f |
Subject: [PATCH] core: handle lookup paths being symlinks
|
|
|
8d419f |
MIME-Version: 1.0
|
|
|
8d419f |
Content-Type: text/plain; charset=UTF-8
|
|
|
8d419f |
Content-Transfer-Encoding: 8bit
|
|
|
8d419f |
|
|
|
8d419f |
With a recent change paths leaving the statically known lookup paths would be
|
|
|
8d419f |
treated differently then those that remained within those. That was done
|
|
|
8d419f |
(AFAIK) to consistently handle alias names. Unfortunately that means that on
|
|
|
8d419f |
some distributions, especially those where /etc/ consists mostly of symlinks,
|
|
|
8d419f |
would trigger that new detection for every single unit in /etc/systemd/system.
|
|
|
8d419f |
The reason for that is that the units directory itself is already a symlink.
|
|
|
8d419f |
|
|
|
8d419f |
Rebased-by: Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
|
|
|
8d419f |
(cherry picked from commit 66c38cd0536c50769eba6abccf383bbaceb268ca)
|
|
|
8d419f |
|
|
|
8d419f |
Resolves: #2082131
|
|
|
8d419f |
---
|
|
|
8d419f |
src/basic/unit-file.c | 41 ++++++++++++++++++++++++++++++++++++++++-
|
|
|
8d419f |
1 file changed, 40 insertions(+), 1 deletion(-)
|
|
|
8d419f |
|
|
|
8d419f |
diff --git a/src/basic/unit-file.c b/src/basic/unit-file.c
|
|
|
8d419f |
index 7c1ae515e1..83c29bb25f 100644
|
|
|
8d419f |
--- a/src/basic/unit-file.c
|
|
|
8d419f |
+++ b/src/basic/unit-file.c
|
|
|
8d419f |
@@ -388,6 +388,7 @@ int unit_file_build_name_map(
|
|
|
8d419f |
|
|
|
8d419f |
_cleanup_hashmap_free_ Hashmap *ids = NULL, *names = NULL;
|
|
|
8d419f |
_cleanup_set_free_free_ Set *paths = NULL;
|
|
|
8d419f |
+ _cleanup_strv_free_ char **expanded_search_path = NULL;
|
|
|
8d419f |
uint64_t timestamp_hash;
|
|
|
8d419f |
int r;
|
|
|
8d419f |
|
|
|
8d419f |
@@ -406,6 +407,44 @@ int unit_file_build_name_map(
|
|
|
8d419f |
return log_oom();
|
|
|
8d419f |
}
|
|
|
8d419f |
|
|
|
8d419f |
+ /* Go over all our search paths, chase their symlinks and store the result in the
|
|
|
8d419f |
+ * expanded_search_path list.
|
|
|
8d419f |
+ *
|
|
|
8d419f |
+ * This is important for cases where any of the unit directories itself are symlinks into other
|
|
|
8d419f |
+ * directories and would therefore cause all of the unit files to be recognized as linked units.
|
|
|
8d419f |
+ *
|
|
|
8d419f |
+ * This is important for distributions such as NixOS where most paths in /etc/ are symlinks to some
|
|
|
8d419f |
+ * other location on the filesystem (e.g. into /nix/store/).
|
|
|
8d419f |
+ *
|
|
|
8d419f |
+ * Search paths are ordered by priority (highest first), and we need to maintain this order.
|
|
|
8d419f |
+ * If a resolved path is already in the list, we don't need to include.
|
|
|
8d419f |
+ *
|
|
|
8d419f |
+ * Note that we build a list that contains both the original paths and the resolved symlinks:
|
|
|
8d419f |
+ * we need the latter for the case where the directory is symlinked, as described above, and
|
|
|
8d419f |
+ * the former for the case where some unit file alias is a dangling symlink that points to one
|
|
|
8d419f |
+ * of the "original" directories (and can't be followed).
|
|
|
8d419f |
+ */
|
|
|
8d419f |
+ STRV_FOREACH(dir, lp->search_path) {
|
|
|
8d419f |
+ _cleanup_free_ char *resolved_dir = NULL;
|
|
|
8d419f |
+
|
|
|
8d419f |
+ r = strv_extend(&expanded_search_path, *dir);
|
|
|
8d419f |
+ if (r < 0)
|
|
|
8d419f |
+ return log_oom();
|
|
|
8d419f |
+
|
|
|
8d419f |
+ r = chase_symlinks(*dir, NULL, 0, &resolved_dir, NULL);
|
|
|
8d419f |
+ if (r < 0) {
|
|
|
8d419f |
+ if (r != -ENOENT)
|
|
|
8d419f |
+ log_warning_errno(r, "Failed to resolve symlink %s, ignoring: %m", *dir);
|
|
|
8d419f |
+ continue;
|
|
|
8d419f |
+ }
|
|
|
8d419f |
+
|
|
|
8d419f |
+ if (strv_contains(expanded_search_path, resolved_dir))
|
|
|
8d419f |
+ continue;
|
|
|
8d419f |
+
|
|
|
8d419f |
+ if (strv_consume(&expanded_search_path, TAKE_PTR(resolved_dir)) < 0)
|
|
|
8d419f |
+ return log_oom();
|
|
|
8d419f |
+ }
|
|
|
8d419f |
+
|
|
|
8d419f |
STRV_FOREACH(dir, lp->search_path) {
|
|
|
8d419f |
_cleanup_closedir_ DIR *d = NULL;
|
|
|
8d419f |
|
|
|
8d419f |
@@ -504,7 +543,7 @@ int unit_file_build_name_map(
|
|
|
8d419f |
/* We don't explicitly check for alias loops here. unit_ids_map_get() which
|
|
|
8d419f |
* limits the number of hops should be used to access the map. */
|
|
|
8d419f |
|
|
|
8d419f |
- r = unit_file_resolve_symlink(lp->root_dir, lp->search_path,
|
|
|
8d419f |
+ r = unit_file_resolve_symlink(lp->root_dir, expanded_search_path,
|
|
|
8d419f |
*dir, dirfd(d), de->d_name,
|
|
|
8d419f |
/* resolve_destination_target= */ false,
|
|
|
8d419f |
&dst);
|