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