|
|
eb6853 |
From b864dc9ef4aa00191dfa81accbe93f9ed0382261 Mon Sep 17 00:00:00 2001
|
|
|
eb6853 |
From: Michal Sekletar <msekleta@redhat.com>
|
|
|
eb6853 |
Date: Tue, 9 Mar 2021 17:22:32 +0100
|
|
|
eb6853 |
Subject: [PATCH] install: refactor find_symlinks() and don't search for
|
|
|
eb6853 |
symlinks recursively
|
|
|
eb6853 |
|
|
|
eb6853 |
After all we are only interested in symlinks either in top-level config
|
|
|
eb6853 |
directory or in .wants and .requires sub-directories.
|
|
|
eb6853 |
|
|
|
eb6853 |
As a bonus this should speed up ListUnitFiles() roughly 3-4x on systems
|
|
|
eb6853 |
with a lot of units that use drop-ins (e.g. SSH jump hosts with a lot of
|
|
|
eb6853 |
user session scopes).
|
|
|
eb6853 |
|
|
|
eb6853 |
(cherry picked from commit 43b4e3058c106e663bbd5413e7bd106e55d6fd79)
|
|
|
eb6853 |
|
|
|
eb6853 |
Resolves: #1828758
|
|
|
eb6853 |
---
|
|
|
eb6853 |
src/shared/install.c | 207 ++++++++++++++++++++-----------------------
|
|
|
eb6853 |
1 file changed, 96 insertions(+), 111 deletions(-)
|
|
|
eb6853 |
|
|
|
eb6853 |
diff --git a/src/shared/install.c b/src/shared/install.c
|
|
|
eb6853 |
index f2f968e329..761bf8074e 100644
|
|
|
eb6853 |
--- a/src/shared/install.c
|
|
|
eb6853 |
+++ b/src/shared/install.c
|
|
|
eb6853 |
@@ -503,137 +503,88 @@ static int remove_marked_symlinks(
|
|
|
eb6853 |
return r;
|
|
|
eb6853 |
}
|
|
|
eb6853 |
|
|
|
eb6853 |
-static int find_symlinks_fd(
|
|
|
eb6853 |
+static int find_symlinks_in_directory(
|
|
|
eb6853 |
+ DIR *dir,
|
|
|
eb6853 |
+ const char *dir_path,
|
|
|
eb6853 |
const char *root_dir,
|
|
|
eb6853 |
const char *name,
|
|
|
eb6853 |
- int fd,
|
|
|
eb6853 |
- const char *path,
|
|
|
eb6853 |
const char *config_path,
|
|
|
eb6853 |
bool *same_name_link) {
|
|
|
eb6853 |
|
|
|
eb6853 |
+ struct dirent *de;
|
|
|
eb6853 |
int r = 0;
|
|
|
eb6853 |
- _cleanup_closedir_ DIR *d = NULL;
|
|
|
eb6853 |
|
|
|
eb6853 |
- assert(name);
|
|
|
eb6853 |
- assert(fd >= 0);
|
|
|
eb6853 |
- assert(path);
|
|
|
eb6853 |
- assert(config_path);
|
|
|
eb6853 |
- assert(same_name_link);
|
|
|
eb6853 |
-
|
|
|
eb6853 |
- d = fdopendir(fd);
|
|
|
eb6853 |
- if (!d) {
|
|
|
eb6853 |
- safe_close(fd);
|
|
|
eb6853 |
- return -errno;
|
|
|
eb6853 |
- }
|
|
|
eb6853 |
-
|
|
|
eb6853 |
- for (;;) {
|
|
|
eb6853 |
- struct dirent *de;
|
|
|
eb6853 |
-
|
|
|
eb6853 |
- errno = 0;
|
|
|
eb6853 |
- de = readdir(d);
|
|
|
eb6853 |
- if (!de && errno != 0)
|
|
|
eb6853 |
- return -errno;
|
|
|
eb6853 |
+ FOREACH_DIRENT(de, dir, return -errno) {
|
|
|
eb6853 |
+ _cleanup_free_ char *p = NULL, *dest = NULL;
|
|
|
eb6853 |
+ bool found_path = false, found_dest, b = false;
|
|
|
eb6853 |
+ int q;
|
|
|
eb6853 |
|
|
|
eb6853 |
- if (!de)
|
|
|
eb6853 |
- return r;
|
|
|
eb6853 |
+ dirent_ensure_type(dir, de);
|
|
|
eb6853 |
|
|
|
eb6853 |
- if (hidden_file(de->d_name))
|
|
|
eb6853 |
+ if (de->d_type != DT_LNK)
|
|
|
eb6853 |
continue;
|
|
|
eb6853 |
|
|
|
eb6853 |
- dirent_ensure_type(d, de);
|
|
|
eb6853 |
-
|
|
|
eb6853 |
- if (de->d_type == DT_DIR) {
|
|
|
eb6853 |
- int nfd, q;
|
|
|
eb6853 |
- _cleanup_free_ char *p = NULL;
|
|
|
eb6853 |
-
|
|
|
eb6853 |
- nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
|
|
|
eb6853 |
- if (nfd < 0) {
|
|
|
eb6853 |
- if (errno == ENOENT)
|
|
|
eb6853 |
- continue;
|
|
|
eb6853 |
-
|
|
|
eb6853 |
- if (r == 0)
|
|
|
eb6853 |
- r = -errno;
|
|
|
eb6853 |
- continue;
|
|
|
eb6853 |
- }
|
|
|
eb6853 |
-
|
|
|
eb6853 |
- p = path_make_absolute(de->d_name, path);
|
|
|
eb6853 |
- if (!p) {
|
|
|
eb6853 |
- safe_close(nfd);
|
|
|
eb6853 |
- return -ENOMEM;
|
|
|
eb6853 |
- }
|
|
|
eb6853 |
+ /* Acquire symlink name */
|
|
|
eb6853 |
+ p = path_make_absolute(de->d_name, dir_path);
|
|
|
eb6853 |
+ if (!p)
|
|
|
eb6853 |
+ return -ENOMEM;
|
|
|
eb6853 |
|
|
|
eb6853 |
- /* This will close nfd, regardless whether it succeeds or not */
|
|
|
eb6853 |
- q = find_symlinks_fd(root_dir, name, nfd, p, config_path, same_name_link);
|
|
|
eb6853 |
- if (q > 0)
|
|
|
eb6853 |
- return 1;
|
|
|
eb6853 |
+ /* Acquire symlink destination */
|
|
|
eb6853 |
+ q = readlinkat_malloc(dirfd(dir), de->d_name, &dest);
|
|
|
eb6853 |
+ if (q == -ENOENT)
|
|
|
eb6853 |
+ continue;
|
|
|
eb6853 |
+ if (q < 0) {
|
|
|
eb6853 |
if (r == 0)
|
|
|
eb6853 |
r = q;
|
|
|
eb6853 |
+ continue;
|
|
|
eb6853 |
+ }
|
|
|
eb6853 |
|
|
|
eb6853 |
- } else if (de->d_type == DT_LNK) {
|
|
|
eb6853 |
- _cleanup_free_ char *p = NULL, *dest = NULL;
|
|
|
eb6853 |
- bool found_path, found_dest, b = false;
|
|
|
eb6853 |
- int q;
|
|
|
eb6853 |
+ /* Make absolute */
|
|
|
eb6853 |
+ if (!path_is_absolute(dest)) {
|
|
|
eb6853 |
+ char *x;
|
|
|
eb6853 |
|
|
|
eb6853 |
- /* Acquire symlink name */
|
|
|
eb6853 |
- p = path_make_absolute(de->d_name, path);
|
|
|
eb6853 |
- if (!p)
|
|
|
eb6853 |
+ x = path_join(dir_path, dest, NULL);
|
|
|
eb6853 |
+ if (!x)
|
|
|
eb6853 |
return -ENOMEM;
|
|
|
eb6853 |
|
|
|
eb6853 |
- /* Acquire symlink destination */
|
|
|
eb6853 |
- q = readlink_malloc(p, &dest);
|
|
|
eb6853 |
- if (q < 0) {
|
|
|
eb6853 |
- if (q == -ENOENT)
|
|
|
eb6853 |
- continue;
|
|
|
eb6853 |
+ free(dest);
|
|
|
eb6853 |
+ dest = x;
|
|
|
eb6853 |
|
|
|
eb6853 |
- if (r == 0)
|
|
|
eb6853 |
- r = q;
|
|
|
eb6853 |
- continue;
|
|
|
eb6853 |
- }
|
|
|
eb6853 |
-
|
|
|
eb6853 |
- /* Make absolute */
|
|
|
eb6853 |
- if (!path_is_absolute(dest)) {
|
|
|
eb6853 |
- char *x;
|
|
|
eb6853 |
-
|
|
|
eb6853 |
- x = prefix_root(root_dir, dest);
|
|
|
eb6853 |
- if (!x)
|
|
|
eb6853 |
- return -ENOMEM;
|
|
|
eb6853 |
-
|
|
|
eb6853 |
- free(dest);
|
|
|
eb6853 |
- dest = x;
|
|
|
eb6853 |
- }
|
|
|
eb6853 |
+ }
|
|
|
eb6853 |
|
|
|
eb6853 |
- /* Check if the symlink itself matches what we
|
|
|
eb6853 |
- * are looking for */
|
|
|
eb6853 |
- if (path_is_absolute(name))
|
|
|
eb6853 |
- found_path = path_equal(p, name);
|
|
|
eb6853 |
- else
|
|
|
eb6853 |
- found_path = streq(de->d_name, name);
|
|
|
eb6853 |
+ /* Check if the symlink itself matches what we
|
|
|
eb6853 |
+ * are looking for */
|
|
|
eb6853 |
+ if (path_is_absolute(name))
|
|
|
eb6853 |
+ found_path = path_equal(p, name);
|
|
|
eb6853 |
+ else
|
|
|
eb6853 |
+ found_path = streq(de->d_name, name);
|
|
|
eb6853 |
|
|
|
eb6853 |
- /* Check if what the symlink points to
|
|
|
eb6853 |
- * matches what we are looking for */
|
|
|
eb6853 |
- if (path_is_absolute(name))
|
|
|
eb6853 |
- found_dest = path_equal(dest, name);
|
|
|
eb6853 |
- else
|
|
|
eb6853 |
- found_dest = streq(basename(dest), name);
|
|
|
eb6853 |
+ /* Check if what the symlink points to
|
|
|
eb6853 |
+ * matches what we are looking for */
|
|
|
eb6853 |
+ if (path_is_absolute(name))
|
|
|
eb6853 |
+ found_dest = path_equal(dest, name);
|
|
|
eb6853 |
+ else
|
|
|
eb6853 |
+ found_dest = streq(basename(dest), name);
|
|
|
eb6853 |
|
|
|
eb6853 |
- if (found_path && found_dest) {
|
|
|
eb6853 |
- _cleanup_free_ char *t = NULL;
|
|
|
eb6853 |
+ if (found_path && found_dest) {
|
|
|
eb6853 |
+ _cleanup_free_ char *t = NULL;
|
|
|
eb6853 |
|
|
|
eb6853 |
- /* Filter out same name links in the main
|
|
|
eb6853 |
- * config path */
|
|
|
eb6853 |
- t = path_make_absolute(name, config_path);
|
|
|
eb6853 |
- if (!t)
|
|
|
eb6853 |
- return -ENOMEM;
|
|
|
eb6853 |
-
|
|
|
eb6853 |
- b = path_equal(t, p);
|
|
|
eb6853 |
- }
|
|
|
eb6853 |
+ /* Filter out same name links in the main
|
|
|
eb6853 |
+ * config path */
|
|
|
eb6853 |
+ t = path_make_absolute(name, config_path);
|
|
|
eb6853 |
+ if (!t)
|
|
|
eb6853 |
+ return -ENOMEM;
|
|
|
eb6853 |
|
|
|
eb6853 |
- if (b)
|
|
|
eb6853 |
- *same_name_link = true;
|
|
|
eb6853 |
- else if (found_path || found_dest)
|
|
|
eb6853 |
- return 1;
|
|
|
eb6853 |
+ b = path_equal(p, t);
|
|
|
eb6853 |
}
|
|
|
eb6853 |
+
|
|
|
eb6853 |
+ if (b)
|
|
|
eb6853 |
+ *same_name_link = true;
|
|
|
eb6853 |
+ else if (found_path || found_dest)
|
|
|
eb6853 |
+ return 1;
|
|
|
eb6853 |
}
|
|
|
eb6853 |
+
|
|
|
eb6853 |
+ return r;
|
|
|
eb6853 |
}
|
|
|
eb6853 |
|
|
|
eb6853 |
static int find_symlinks(
|
|
|
eb6853 |
@@ -642,21 +593,55 @@ static int find_symlinks(
|
|
|
eb6853 |
const char *config_path,
|
|
|
eb6853 |
bool *same_name_link) {
|
|
|
eb6853 |
|
|
|
eb6853 |
- int fd;
|
|
|
eb6853 |
+ _cleanup_closedir_ DIR *config_dir = NULL;
|
|
|
eb6853 |
+ struct dirent *de;
|
|
|
eb6853 |
+ int r = 0;
|
|
|
eb6853 |
|
|
|
eb6853 |
assert(name);
|
|
|
eb6853 |
assert(config_path);
|
|
|
eb6853 |
assert(same_name_link);
|
|
|
eb6853 |
|
|
|
eb6853 |
- fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
|
|
|
eb6853 |
- if (fd < 0) {
|
|
|
eb6853 |
- if (errno == ENOENT)
|
|
|
eb6853 |
+ config_dir = opendir(config_path);
|
|
|
eb6853 |
+ if (!config_dir) {
|
|
|
eb6853 |
+ if (IN_SET(errno, ENOENT, ENOTDIR, EACCES))
|
|
|
eb6853 |
return 0;
|
|
|
eb6853 |
return -errno;
|
|
|
eb6853 |
}
|
|
|
eb6853 |
|
|
|
eb6853 |
- /* This takes possession of fd and closes it */
|
|
|
eb6853 |
- return find_symlinks_fd(root_dir, name, fd, config_path, config_path, same_name_link);
|
|
|
eb6853 |
+ FOREACH_DIRENT(de, config_dir, return -errno) {
|
|
|
eb6853 |
+ const char *suffix;
|
|
|
eb6853 |
+ _cleanup_free_ const char *path = NULL;
|
|
|
eb6853 |
+ _cleanup_closedir_ DIR *d = NULL;
|
|
|
eb6853 |
+
|
|
|
eb6853 |
+ dirent_ensure_type(config_dir, de);
|
|
|
eb6853 |
+
|
|
|
eb6853 |
+ if (de->d_type != DT_DIR)
|
|
|
eb6853 |
+ continue;
|
|
|
eb6853 |
+
|
|
|
eb6853 |
+ suffix = strrchr(de->d_name, '.');
|
|
|
eb6853 |
+ if (!streq(suffix, ".wants") && !streq(suffix, ".requires"))
|
|
|
eb6853 |
+ continue;
|
|
|
eb6853 |
+
|
|
|
eb6853 |
+ path = path_join(config_path, de->d_name, NULL);
|
|
|
eb6853 |
+ if (!path)
|
|
|
eb6853 |
+ return -ENOMEM;
|
|
|
eb6853 |
+
|
|
|
eb6853 |
+ d = opendir(path);
|
|
|
eb6853 |
+ if (!d) {
|
|
|
eb6853 |
+ log_error_errno(errno, "Failed to open directory '%s' while scanning for symlinks, ignoring: %m", path);
|
|
|
eb6853 |
+ continue;
|
|
|
eb6853 |
+ }
|
|
|
eb6853 |
+
|
|
|
eb6853 |
+ r = find_symlinks_in_directory(d, path, root_dir, name, config_path, same_name_link);
|
|
|
eb6853 |
+ if (r > 0)
|
|
|
eb6853 |
+ return 1;
|
|
|
eb6853 |
+ else if (r < 0)
|
|
|
eb6853 |
+ log_debug_errno(r, "Failed to lookup for symlinks in '%s': %m", path);
|
|
|
eb6853 |
+ }
|
|
|
eb6853 |
+
|
|
|
eb6853 |
+ /* We didn't find any suitable symlinks in .wants or .requires directories, let's look for linked unit files in this directory. */
|
|
|
eb6853 |
+ rewinddir(config_dir);
|
|
|
eb6853 |
+ return find_symlinks_in_directory(config_dir, config_path, root_dir, name, config_path, same_name_link);
|
|
|
eb6853 |
}
|
|
|
eb6853 |
|
|
|
eb6853 |
static int find_symlinks_in_scope(
|