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