594167
From 43f62843fbc5e5d085874393c24cf52ebb6658eb Mon Sep 17 00:00:00 2001
594167
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
594167
Date: Wed, 16 Mar 2022 17:37:58 +0100
594167
Subject: [PATCH] shared/install: when looking for symlinks in
594167
 .wants/.requires, ignore symlink target
594167
MIME-Version: 1.0
594167
Content-Type: text/plain; charset=UTF-8
594167
Content-Transfer-Encoding: 8bit
594167
594167
We'd say that file is enabled indirectly if we had a symlink like:
594167
  foo@.service ← bar.target.wants/foo@one.service
594167
but not when we had
594167
  foo@one.service ← bar.target.wants/foo@one.service
594167
594167
The effect of both link types is the same. In fact we don't care
594167
about the symlink target. (We'll warn if it is mismatched, but we honour
594167
it anyway.)
594167
594167
So let's use the original match logic only for aliases.
594167
For .wants/.requires we instead look for a matching source name,
594167
or a source name that matches after stripping of instance.
594167
594167
(cherry picked from commit 466f6979c90aaee62c33723392cc49c6638a3f46)
594167
594167
Related: #2082131
594167
---
594167
 src/shared/install.c | 93 ++++++++++++++++++++++++++++----------------
594167
 1 file changed, 60 insertions(+), 33 deletions(-)
594167
594167
diff --git a/src/shared/install.c b/src/shared/install.c
594167
index 1a2b0ccf24..a864039f44 100644
594167
--- a/src/shared/install.c
594167
+++ b/src/shared/install.c
594167
@@ -748,7 +748,8 @@ static int find_symlinks_in_directory(
594167
                 const char *dir_path,
594167
                 const char *root_dir,
594167
                 const UnitFileInstallInfo *info,
594167
-                bool match_aliases,
594167
+                bool ignore_destination,
594167
+                bool match_name,
594167
                 bool ignore_same_name,
594167
                 const char *config_path,
594167
                 bool *same_name_link) {
594167
@@ -756,51 +757,67 @@ static int find_symlinks_in_directory(
594167
         int r = 0;
594167
 
594167
         FOREACH_DIRENT(de, dir, return -errno) {
594167
-                _cleanup_free_ char *dest = NULL;
594167
-                bool found_path = false, found_dest, b = false;
594167
+                bool found_path = false, found_dest = false, b = false;
594167
                 int q;
594167
 
594167
                 if (de->d_type != DT_LNK)
594167
                         continue;
594167
 
594167
-                /* Acquire symlink destination */
594167
-                q = readlinkat_malloc(dirfd(dir), de->d_name, &dest);
594167
-                if (q == -ENOENT)
594167
-                        continue;
594167
-                if (q < 0) {
594167
-                        if (r == 0)
594167
-                                r = q;
594167
-                        continue;
594167
-                }
594167
+                if (!ignore_destination) {
594167
+                        _cleanup_free_ char *dest = NULL;
594167
+
594167
+                        /* Acquire symlink destination */
594167
+                        q = readlinkat_malloc(dirfd(dir), de->d_name, &dest);
594167
+                        if (q == -ENOENT)
594167
+                                continue;
594167
+                        if (q < 0) {
594167
+                                if (r == 0)
594167
+                                        r = q;
594167
+                                continue;
594167
+                        }
594167
 
594167
-                /* Make absolute */
594167
-                if (!path_is_absolute(dest)) {
594167
-                        char *x;
594167
+                        /* Make absolute */
594167
+                        if (!path_is_absolute(dest)) {
594167
+                                char *x;
594167
 
594167
-                        x = path_join(dir_path, dest);
594167
-                        if (!x)
594167
-                                return -ENOMEM;
594167
+                                x = path_join(dir_path, dest);
594167
+                                if (!x)
594167
+                                        return -ENOMEM;
594167
 
594167
-                        free_and_replace(dest, x);
594167
+                                free_and_replace(dest, x);
594167
+                        }
594167
+
594167
+                        /* Check if what the symlink points to matches what we are looking for */
594167
+                        found_dest = streq(basename(dest), info->name);
594167
                 }
594167
 
594167
                 assert(unit_name_is_valid(info->name, UNIT_NAME_ANY));
594167
-                if (!ignore_same_name)
594167
-                               /* Check if the symlink itself matches what we are looking for.
594167
-                                *
594167
-                                * If ignore_same_name is specified, we are in one of the directories which
594167
-                                * have lower priority than the unit file, and even if a file or symlink with
594167
-                                * this name was found, we should ignore it. */
594167
-                                found_path = streq(de->d_name, info->name);
594167
 
594167
-                /* Check if what the symlink points to matches what we are looking for */
594167
-                found_dest = streq(basename(dest), info->name);
594167
+                /* Check if the symlink itself matches what we are looking for.
594167
+                 *
594167
+                 * If ignore_destination is specified, we only look at the source name.
594167
+                 *
594167
+                 * If ignore_same_name is specified, we are in one of the directories which
594167
+                 * have lower priority than the unit file, and even if a file or symlink with
594167
+                 * this name was found, we should ignore it. */
594167
+
594167
+                if (ignore_destination || !ignore_same_name)
594167
+                        found_path = streq(de->d_name, info->name);
594167
+
594167
+                if (!found_path && ignore_destination) {
594167
+                        _cleanup_free_ char *template = NULL;
594167
+
594167
+                        q = unit_name_template(de->d_name, &template);
594167
+                        if (q < 0 && q != -EINVAL)
594167
+                                return q;
594167
+                        if (q >= 0)
594167
+                                found_dest = streq(template, info->name);
594167
+                }
594167
 
594167
                 if (found_path && found_dest) {
594167
                         _cleanup_free_ char *p = NULL, *t = NULL;
594167
 
594167
-                        /* Filter out same name links in the main
594167
-                         * config path */
594167
+                        /* Filter out same name links in the main config path */
594167
                         p = path_make_absolute(de->d_name, dir_path);
594167
                         t = path_make_absolute(info->name, config_path);
594167
 
594167
@@ -813,7 +830,7 @@ static int find_symlinks_in_directory(
594167
                 if (b)
594167
                         *same_name_link = true;
594167
                 else if (found_path || found_dest) {
594167
-                        if (!match_aliases)
594167
+                        if (!match_name)
594167
                                 return 1;
594167
 
594167
                         /* Check if symlink name is in the set of names used by [Install] */
594167
@@ -872,7 +889,12 @@ static int find_symlinks(
594167
                         continue;
594167
                 }
594167
 
594167
-                r = find_symlinks_in_directory(d, path, root_dir, i, match_name, ignore_same_name, config_path, same_name_link);
594167
+                r = find_symlinks_in_directory(d, path, root_dir, i,
594167
+                                               /* ignore_destination= */ true,
594167
+                                               /* match_name= */ match_name,
594167
+                                               /* ignore_same_name= */ ignore_same_name,
594167
+                                               config_path,
594167
+                                               same_name_link);
594167
                 if (r > 0)
594167
                         return 1;
594167
                 else if (r < 0)
594167
@@ -881,7 +903,12 @@ static int find_symlinks(
594167
 
594167
         /* We didn't find any suitable symlinks in .wants or .requires directories, let's look for linked unit files in this directory. */
594167
         rewinddir(config_dir);
594167
-        return find_symlinks_in_directory(config_dir, config_path, root_dir, i, match_name, ignore_same_name, config_path, same_name_link);
594167
+        return find_symlinks_in_directory(config_dir, config_path, root_dir, i,
594167
+                                          /* ignore_destination= */ false,
594167
+                                          /* match_name= */ match_name,
594167
+                                          /* ignore_same_name= */ ignore_same_name,
594167
+                                          config_path,
594167
+                                          same_name_link);
594167
 }
594167
 
594167
 static int find_symlinks_in_scope(