]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/shared/install.c
shared/install: rename 'files' param to 'names'
[thirdparty/systemd.git] / src / shared / install.c
index 6aacdcf967c58cdf964ac1dc6633f59da2e41a45..5da26eeb218cb17daea8c6eb5e3c4a78aebcba82 100644 (file)
@@ -47,7 +47,7 @@ typedef enum SearchFlags {
 } SearchFlags;
 
 typedef struct {
-        UnitFileScope scope;
+        LookupScope scope;
         OrderedHashmap *will_process;
         OrderedHashmap *have_processed;
 } InstallContext;
@@ -102,12 +102,13 @@ DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type, UnitFileType);
 
 static int in_search_path(const LookupPaths *lp, const char *path) {
         _cleanup_free_ char *parent = NULL;
+        int r;
 
         assert(path);
 
-        parent = dirname_malloc(path);
-        if (!parent)
-                return -ENOMEM;
+        r = path_extract_directory(path, &parent);
+        if (r < 0)
+                return r;
 
         return path_strv_contains(lp->search_path, parent);
 }
@@ -135,13 +136,14 @@ static const char* skip_root(const char *root_dir, const char *path) {
 
 static int path_is_generator(const LookupPaths *lp, const char *path) {
         _cleanup_free_ char *parent = NULL;
+        int r;
 
         assert(lp);
         assert(path);
 
-        parent = dirname_malloc(path);
-        if (!parent)
-                return -ENOMEM;
+        r = path_extract_directory(path, &parent);
+        if (r < 0)
+                return r;
 
         return path_equal_ptr(parent, lp->generator) ||
                path_equal_ptr(parent, lp->generator_early) ||
@@ -150,26 +152,28 @@ static int path_is_generator(const LookupPaths *lp, const char *path) {
 
 static int path_is_transient(const LookupPaths *lp, const char *path) {
         _cleanup_free_ char *parent = NULL;
+        int r;
 
         assert(lp);
         assert(path);
 
-        parent = dirname_malloc(path);
-        if (!parent)
-                return -ENOMEM;
+        r = path_extract_directory(path, &parent);
+        if (r < 0)
+                return r;
 
         return path_equal_ptr(parent, lp->transient);
 }
 
 static int path_is_control(const LookupPaths *lp, const char *path) {
         _cleanup_free_ char *parent = NULL;
+        int r;
 
         assert(lp);
         assert(path);
 
-        parent = dirname_malloc(path);
-        if (!parent)
-                return -ENOMEM;
+        r = path_extract_directory(path, &parent);
+        if (r < 0)
+                return r;
 
         return path_equal_ptr(parent, lp->persistent_control) ||
                path_equal_ptr(parent, lp->runtime_control);
@@ -177,6 +181,7 @@ static int path_is_control(const LookupPaths *lp, const char *path) {
 
 static int path_is_config(const LookupPaths *lp, const char *path, bool check_parent) {
         _cleanup_free_ char *parent = NULL;
+        int r;
 
         assert(lp);
         assert(path);
@@ -185,9 +190,9 @@ static int path_is_config(const LookupPaths *lp, const char *path, bool check_pa
          * them we couldn't discern configuration from transient or generated units */
 
         if (check_parent) {
-                parent = dirname_malloc(path);
-                if (!parent)
-                        return -ENOMEM;
+                r = path_extract_directory(path, &parent);
+                if (r < 0)
+                        return r;
 
                 path = parent;
         }
@@ -199,6 +204,7 @@ static int path_is_config(const LookupPaths *lp, const char *path, bool check_pa
 static int path_is_runtime(const LookupPaths *lp, const char *path, bool check_parent) {
         _cleanup_free_ char *parent = NULL;
         const char *rpath;
+        int r;
 
         assert(lp);
         assert(path);
@@ -211,9 +217,9 @@ static int path_is_runtime(const LookupPaths *lp, const char *path, bool check_p
                 return true;
 
         if (check_parent) {
-                parent = dirname_malloc(path);
-                if (!parent)
-                        return -ENOMEM;
+                r = path_extract_directory(path, &parent);
+                if (r < 0)
+                        return r;
 
                 path = parent;
         }
@@ -330,7 +336,7 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang
         for (size_t i = 0; i < n_changes; i++) {
                 assert(verb || changes[i].type_or_errno >= 0);
 
-                switch(changes[i].type_or_errno) {
+                switch (changes[i].type_or_errno) {
                 case UNIT_FILE_SYMLINK:
                         if (!quiet)
                                 log_info("Created symlink %s %s %s.",
@@ -423,21 +429,54 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang
 }
 
 /**
- * Checks if two paths or symlinks from wd are the same, when root is the root of the filesystem.
- * wc should be the full path in the host file system.
+ * Checks if two symlink targets (starting from src) are equivalent as far as the unit enablement logic is
+ * concerned. If the target is in the unit search path, then anything with the same name is equivalent.
+ * If outside the unit search path, paths must be identical.
  */
-static bool chroot_symlinks_same(const char *root, const char *wd, const char *a, const char *b) {
-        assert(path_is_absolute(wd));
+static int chroot_unit_symlinks_equivalent(
+                const LookupPaths *lp,
+                const char *src,
+                const char *target_a,
+                const char *target_b) {
+
+        assert(lp);
+        assert(src);
+        assert(target_a);
+        assert(target_b);
 
         /* This will give incorrect results if the paths are relative and go outside
          * of the chroot. False negatives are possible. */
 
-        if (!root)
-                root = "/";
+        const char *root = lp->root_dir ?: "/";
+        _cleanup_free_ char *dirname = NULL;
+        int r;
+
+        if (!path_is_absolute(target_a) || !path_is_absolute(target_b)) {
+                r = path_extract_directory(src, &dirname);
+                if (r < 0)
+                        return r;
+        }
+
+        _cleanup_free_ char *a = path_join(path_is_absolute(target_a) ? root : dirname, target_a);
+        _cleanup_free_ char *b = path_join(path_is_absolute(target_b) ? root : dirname, target_b);
+        if (!a || !b)
+                return log_oom();
 
-        a = strjoina(path_is_absolute(a) ? root : wd, "/", a);
-        b = strjoina(path_is_absolute(b) ? root : wd, "/", b);
-        return path_equal_or_files_same(a, b, 0);
+        r = path_equal_or_files_same(a, b, 0);
+        if (r != 0)
+                return r;
+
+        _cleanup_free_ char *a_name = NULL, *b_name = NULL;
+        r = path_extract_filename(a, &a_name);
+        if (r < 0)
+                return r;
+        r = path_extract_filename(b, &b_name);
+        if (r < 0)
+                return r;
+
+        return streq(a_name, b_name) &&
+               path_startswith_strv(a, lp->search_path) &&
+               path_startswith_strv(b, lp->search_path);
 }
 
 static int create_symlink(
@@ -448,7 +487,7 @@ static int create_symlink(
                 UnitFileChange **changes,
                 size_t *n_changes) {
 
-        _cleanup_free_ char *dest = NULL, *dirname = NULL;
+        _cleanup_free_ char *dest = NULL;
         const char *rp;
         int r;
 
@@ -488,12 +527,9 @@ static int create_symlink(
                 return r;
         }
 
-        dirname = dirname_malloc(new_path);
-        if (!dirname)
-                return -ENOMEM;
-
-        if (chroot_symlinks_same(lp->root_dir, dirname, dest, old_path)) {
-                log_debug("Symlink %s → %s already exists", new_path, dest);
+        if (chroot_unit_symlinks_equivalent(lp, new_path, dest, old_path)) {
+                log_debug("Symlink %s %s %s already exists",
+                          new_path, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), dest);
                 return 1;
         }
 
@@ -911,7 +947,7 @@ static int find_symlinks(
 }
 
 static int find_symlinks_in_scope(
-                UnitFileScope scope,
+                LookupScope scope,
                 const LookupPaths *lp,
                 const UnitFileInstallInfo *info,
                 bool match_name,
@@ -945,7 +981,7 @@ static int find_symlinks_in_scope(
                         }
 
                         /* look for global enablement of user units */
-                        if (scope == UNIT_FILE_USER && path_is_user_config_dir(*p)) {
+                        if (scope == LOOKUP_SCOPE_USER && path_is_user_config_dir(*p)) {
                                 *state = UNIT_FILE_ENABLED;
                                 return 1;
                         }
@@ -1606,7 +1642,9 @@ static int install_info_traverse(
                                 return -ELOOP;
                 }
 
-                r = install_info_follow(ctx, i, lp, flags, false);
+                r = install_info_follow(ctx, i, lp, flags,
+                                        /* If linked, don't look at the target name */
+                                        /* ignore_different_name= */ i->type == UNIT_FILE_TYPE_LINKED);
                 if (r == -EXDEV) {
                         _cleanup_free_ char *buffer = NULL;
                         const char *bn;
@@ -1690,7 +1728,7 @@ static int install_info_add_auto(
 static int install_info_discover(
                 InstallContext *ctx,
                 const LookupPaths *lp,
-                const char *name,
+                const char *name_or_path,
                 SearchFlags flags,
                 UnitFileInstallInfo **ret,
                 UnitFileChange **changes,
@@ -1701,21 +1739,21 @@ static int install_info_discover(
 
         assert(ctx);
         assert(lp);
-        assert(name);
+        assert(name_or_path);
 
-        r = install_info_add_auto(ctx, lp, name, &info);
+        r = install_info_add_auto(ctx, lp, name_or_path, &info);
         if (r >= 0)
                 r = install_info_traverse(ctx, lp, info, flags, ret);
 
         if (r < 0)
-                unit_file_changes_add(changes, n_changes, r, name, NULL);
+                unit_file_changes_add(changes, n_changes, r, name_or_path, NULL);
         return r;
 }
 
 static int install_info_discover_and_check(
                 InstallContext *ctx,
                 const LookupPaths *lp,
-                const char *name,
+                const char *name_or_path,
                 SearchFlags flags,
                 UnitFileInstallInfo **ret,
                 UnitFileChange **changes,
@@ -1723,7 +1761,7 @@ static int install_info_discover_and_check(
 
         int r;
 
-        r = install_info_discover(ctx, lp, name, flags, ret, changes, n_changes);
+        r = install_info_discover(ctx, lp, name_or_path, flags, ret, changes, n_changes);
         if (r < 0)
                 return r;
 
@@ -1761,9 +1799,9 @@ int unit_file_verify_alias(
 
                 path_alias ++; /* skip over slash */
 
-                dir = dirname_malloc(dst);
-                if (!dir)
-                        return log_oom();
+                r = path_extract_directory(dst, &dir);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to extract parent directory from '%s': %m", dst);
 
                 p = endswith(dir, ".wants");
                 if (!p)
@@ -1832,7 +1870,7 @@ int unit_file_verify_alias(
 }
 
 static int install_info_symlink_alias(
-                UnitFileScope scope,
+                LookupScope scope,
                 UnitFileInstallInfo *info,
                 const LookupPaths *lp,
                 const char *config_path,
@@ -1868,7 +1906,7 @@ static int install_info_symlink_alias(
                 if (!alias_path)
                         return -ENOMEM;
 
-                q = create_symlink(lp, info->name, alias_path, force, changes, n_changes);
+                q = create_symlink(lp, info->path, alias_path, force, changes, n_changes);
                 r = r < 0 ? r : q;
         }
 
@@ -1876,7 +1914,7 @@ static int install_info_symlink_alias(
 }
 
 static int install_info_symlink_wants(
-                UnitFileScope scope,
+                LookupScope scope,
                 UnitFileFlags file_flags,
                 UnitFileInstallInfo *info,
                 const LookupPaths *lp,
@@ -1937,7 +1975,7 @@ static int install_info_symlink_wants(
         }
 
         STRV_FOREACH(s, list) {
-                _cleanup_free_ char *dst = NULL;
+                _cleanup_free_ char *path = NULL, *dst = NULL;
 
                 q = install_name_printf(scope, info, *s, &dst);
                 if (q < 0) {
@@ -1967,15 +2005,11 @@ static int install_info_symlink_wants(
                         continue;
                 }
 
-                _cleanup_free_ char *path = strjoin(config_path, "/", dst, suffix, n);
+                path = strjoin(config_path, "/", dst, suffix, n);
                 if (!path)
                         return -ENOMEM;
 
-                _cleanup_free_ char *target = strjoin("../", info->name);
-                if (!target)
-                        return -ENOMEM;
-
-                q = create_symlink(lp, target, path, true, changes, n_changes);
+                q = create_symlink(lp, info->path, path, true, changes, n_changes);
                 if (r == 0)
                         r = q;
 
@@ -2016,7 +2050,7 @@ static int install_info_symlink_link(
 }
 
 static int install_info_apply(
-                UnitFileScope scope,
+                LookupScope scope,
                 UnitFileFlags file_flags,
                 UnitFileInstallInfo *info,
                 const LookupPaths *lp,
@@ -2189,10 +2223,10 @@ static int install_context_mark_for_removal(
 }
 
 int unit_file_mask(
-                UnitFileScope scope,
+                LookupScope scope,
                 UnitFileFlags flags,
                 const char *root_dir,
-                char **files,
+                char **names,
                 UnitFileChange **changes,
                 size_t *n_changes) {
 
@@ -2201,7 +2235,7 @@ int unit_file_mask(
         int r;
 
         assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
+        assert(scope < _LOOKUP_SCOPE_MAX);
 
         r = lookup_paths_init(&lp, scope, 0, root_dir);
         if (r < 0)
@@ -2211,17 +2245,17 @@ int unit_file_mask(
         if (!config_path)
                 return -ENXIO;
 
-        STRV_FOREACH(i, files) {
+        STRV_FOREACH(name, names) {
                 _cleanup_free_ char *path = NULL;
                 int q;
 
-                if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) {
+                if (!unit_name_is_valid(*name, UNIT_NAME_ANY)) {
                         if (r == 0)
                                 r = -EINVAL;
                         continue;
                 }
 
-                path = path_make_absolute(*i, config_path);
+                path = path_make_absolute(*name, config_path);
                 if (!path)
                         return -ENOMEM;
 
@@ -2234,10 +2268,10 @@ int unit_file_mask(
 }
 
 int unit_file_unmask(
-                UnitFileScope scope,
+                LookupScope scope,
                 UnitFileFlags flags,
                 const char *root_dir,
-                char **files,
+                char **names,
                 UnitFileChange **changes,
                 size_t *n_changes) {
 
@@ -2249,7 +2283,7 @@ int unit_file_unmask(
         int r, q;
 
         assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
+        assert(scope < _LOOKUP_SCOPE_MAX);
 
         r = lookup_paths_init(&lp, scope, 0, root_dir);
         if (r < 0)
@@ -2261,13 +2295,13 @@ int unit_file_unmask(
 
         bool dry_run = flags & UNIT_FILE_DRY_RUN;
 
-        STRV_FOREACH(i, files) {
+        STRV_FOREACH(name, names) {
                 _cleanup_free_ char *path = NULL;
 
-                if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
+                if (!unit_name_is_valid(*name, UNIT_NAME_ANY))
                         return -EINVAL;
 
-                path = path_make_absolute(*i, config_path);
+                path = path_make_absolute(*name, config_path);
                 if (!path)
                         return -ENOMEM;
 
@@ -2282,7 +2316,7 @@ int unit_file_unmask(
                 if (!GREEDY_REALLOC0(todo, n_todo + 2))
                         return -ENOMEM;
 
-                todo[n_todo] = strdup(*i);
+                todo[n_todo] = strdup(*name);
                 if (!todo[n_todo])
                         return -ENOMEM;
 
@@ -2326,7 +2360,7 @@ int unit_file_unmask(
 }
 
 int unit_file_link(
-                UnitFileScope scope,
+                LookupScope scope,
                 UnitFileFlags flags,
                 const char *root_dir,
                 char **files,
@@ -2340,7 +2374,7 @@ int unit_file_link(
         int r, q;
 
         assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
+        assert(scope < _LOOKUP_SCOPE_MAX);
 
         r = lookup_paths_init(&lp, scope, 0, root_dir);
         if (r < 0)
@@ -2350,19 +2384,19 @@ int unit_file_link(
         if (!config_path)
                 return -ENXIO;
 
-        STRV_FOREACH(i, files) {
+        STRV_FOREACH(file, files) {
                 _cleanup_free_ char *full = NULL;
                 struct stat st;
                 char *fn;
 
-                if (!path_is_absolute(*i))
+                if (!path_is_absolute(*file))
                         return -EINVAL;
 
-                fn = basename(*i);
+                fn = basename(*file);
                 if (!unit_name_is_valid(fn, UNIT_NAME_ANY))
                         return -EINVAL;
 
-                full = path_join(lp.root_dir, *i);
+                full = path_join(lp.root_dir, *file);
                 if (!full)
                         return -ENOMEM;
 
@@ -2372,7 +2406,7 @@ int unit_file_link(
                 if (r < 0)
                         return r;
 
-                q = in_search_path(&lp, *i);
+                q = in_search_path(&lp, *file);
                 if (q < 0)
                         return q;
                 if (q > 0)
@@ -2381,7 +2415,7 @@ int unit_file_link(
                 if (!GREEDY_REALLOC0(todo, n_todo + 2))
                         return -ENOMEM;
 
-                todo[n_todo] = strdup(*i);
+                todo[n_todo] = strdup(*file);
                 if (!todo[n_todo])
                         return -ENOMEM;
 
@@ -2426,9 +2460,9 @@ static int path_shall_revert(const LookupPaths *lp, const char *path) {
 }
 
 int unit_file_revert(
-                UnitFileScope scope,
+                LookupScope scope,
                 const char *root_dir,
-                char **files,
+                char **names,
                 UnitFileChange **changes,
                 size_t *n_changes) {
 
@@ -2440,11 +2474,12 @@ int unit_file_revert(
 
         /* Puts a unit file back into vendor state. This means:
          *
-         * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
-         *    added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
+         * a) we remove all drop-in snippets added by the user ("config"), add to transient units
+         *    ("transient"), and added via "systemctl set-property" ("control"), but not if the drop-in is
+         *    generated ("generated").
          *
-         * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
-         *    "config", but not in "transient" or "control" or even "generated").
+         * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files
+         *    (i.e. in "config", but not in "transient" or "control" or even "generated").
          *
          * We remove all that in both the runtime and the persistent directories, if that applies.
          */
@@ -2453,17 +2488,17 @@ int unit_file_revert(
         if (r < 0)
                 return r;
 
-        STRV_FOREACH(i, files) {
+        STRV_FOREACH(name, names) {
                 bool has_vendor = false;
 
-                if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
+                if (!unit_name_is_valid(*name, UNIT_NAME_ANY))
                         return -EINVAL;
 
                 STRV_FOREACH(p, lp.search_path) {
                         _cleanup_free_ char *path = NULL, *dropin = NULL;
                         struct stat st;
 
-                        path = path_make_absolute(*i, *p);
+                        path = path_make_absolute(*name, *p);
                         if (!path)
                                 return -ENOMEM;
 
@@ -2510,7 +2545,7 @@ int unit_file_revert(
                         _cleanup_free_ char *path = NULL;
                         struct stat st;
 
-                        path = path_make_absolute(*i, *p);
+                        path = path_make_absolute(*name, *p);
                         if (!path)
                                 return -ENOMEM;
 
@@ -2577,10 +2612,10 @@ int unit_file_revert(
 }
 
 int unit_file_add_dependency(
-                UnitFileScope scope,
+                LookupScope scope,
                 UnitFileFlags file_flags,
                 const char *root_dir,
-                char **files,
+                char **names,
                 const char *target,
                 UnitDependency dep,
                 UnitFileChange **changes,
@@ -2593,7 +2628,7 @@ int unit_file_add_dependency(
         int r;
 
         assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
+        assert(scope < _LOOKUP_SCOPE_MAX);
         assert(target);
 
         if (!IN_SET(dep, UNIT_WANTS, UNIT_REQUIRES))
@@ -2617,10 +2652,11 @@ int unit_file_add_dependency(
 
         assert(target_info->type == UNIT_FILE_TYPE_REGULAR);
 
-        STRV_FOREACH(f, files) {
+        STRV_FOREACH(name, names) {
                 char ***l;
 
-                r = install_info_discover_and_check(&ctx, &lp, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS,
+                r = install_info_discover_and_check(&ctx, &lp, *name,
+                                                    SEARCH_FOLLOW_CONFIG_SYMLINKS,
                                                     &info, changes, n_changes);
                 if (r < 0)
                         return r;
@@ -2648,10 +2684,10 @@ int unit_file_add_dependency(
 
 static int do_unit_file_enable(
                 const LookupPaths *lp,
-                UnitFileScope scope,
+                LookupScope scope,
                 UnitFileFlags flags,
                 const char *config_path,
-                char **files,
+                char **names_or_paths,
                 UnitFileChange **changes,
                 size_t *n_changes) {
 
@@ -2659,8 +2695,9 @@ static int do_unit_file_enable(
         UnitFileInstallInfo *info;
         int r;
 
-        STRV_FOREACH(f, files) {
-                r = install_info_discover_and_check(&ctx, lp, *f, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
+        STRV_FOREACH(name, names_or_paths) {
+                r = install_info_discover_and_check(&ctx, lp, *name,
+                                                    SEARCH_LOAD | SEARCH_FOLLOW_CONFIG_SYMLINKS,
                                                     &info, changes, n_changes);
                 if (r < 0)
                         return r;
@@ -2670,7 +2707,7 @@ static int do_unit_file_enable(
 
         /* This will return the number of symlink rules that were
            supposed to be created, not the ones actually created. This
-           is useful to determine whether the passed files had any
+           is useful to determine whether the passed units had any
            installation data at all. */
 
         return install_context_apply(&ctx, lp, flags, config_path,
@@ -2678,10 +2715,10 @@ static int do_unit_file_enable(
 }
 
 int unit_file_enable(
-                UnitFileScope scope,
+                LookupScope scope,
                 UnitFileFlags flags,
                 const char *root_dir,
-                char **files,
+                char **names_or_paths,
                 UnitFileChange **changes,
                 size_t *n_changes) {
 
@@ -2689,7 +2726,7 @@ int unit_file_enable(
         int r;
 
         assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
+        assert(scope < _LOOKUP_SCOPE_MAX);
 
         r = lookup_paths_init(&lp, scope, 0, root_dir);
         if (r < 0)
@@ -2699,15 +2736,15 @@ int unit_file_enable(
         if (!config_path)
                 return -ENXIO;
 
-        return do_unit_file_enable(&lp, scope, flags, config_path, files, changes, n_changes);
+        return do_unit_file_enable(&lp, scope, flags, config_path, names_or_paths, changes, n_changes);
 }
 
 static int do_unit_file_disable(
                 const LookupPaths *lp,
-                UnitFileScope scope,
+                LookupScope scope,
                 UnitFileFlags flags,
                 const char *config_path,
-                char **files,
+                char **names,
                 UnitFileChange **changes,
                 size_t *n_changes) {
 
@@ -2715,11 +2752,11 @@ static int do_unit_file_disable(
         _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
         int r;
 
-        STRV_FOREACH(i, files) {
-                if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
+        STRV_FOREACH(name, names) {
+                if (!unit_name_is_valid(*name, UNIT_NAME_ANY))
                         return -EINVAL;
 
-                r = install_info_add(&ctx, *i, NULL, lp->root_dir, /* auxiliary= */ false, NULL);
+                r = install_info_add(&ctx, *name, NULL, lp->root_dir, /* auxiliary= */ false, NULL);
                 if (r < 0)
                         return r;
         }
@@ -2733,7 +2770,7 @@ static int do_unit_file_disable(
 
 
 int unit_file_disable(
-                UnitFileScope scope,
+                LookupScope scope,
                 UnitFileFlags flags,
                 const char *root_dir,
                 char **files,
@@ -2744,7 +2781,7 @@ int unit_file_disable(
         int r;
 
         assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
+        assert(scope < _LOOKUP_SCOPE_MAX);
 
         r = lookup_paths_init(&lp, scope, 0, root_dir);
         if (r < 0)
@@ -2758,7 +2795,7 @@ int unit_file_disable(
 }
 
 static int normalize_linked_files(
-                UnitFileScope scope,
+                LookupScope scope,
                 const LookupPaths *lp,
                 char **names_or_paths,
                 char ***ret_names,
@@ -2766,9 +2803,9 @@ static int normalize_linked_files(
 
         /* This is similar to normalize_filenames()/normalize_names() in src/systemctl/,
          * but operates on real unit names. For each argument we we look up the actual path
-         * where the unit is found. This way linked units can be reenabled successfully. */
+         * where the unit is found. This way linked units can be re-enabled successfully. */
 
-        _cleanup_free_ char **files = NULL, **names = NULL;
+        _cleanup_strv_free_ char **files = NULL, **names = NULL;
         int r;
 
         STRV_FOREACH(a, names_or_paths) {
@@ -2794,7 +2831,7 @@ static int normalize_linked_files(
                         return r;
 
                 const char *p = NULL;
-                if (i && i->path)
+                if (i && i->path && i->root)
                         /* Use startswith here, because we know that paths are normalized, and
                          * path_startswith() would give us a relative path, but we need an absolute path
                          * relative to i->root.
@@ -2816,7 +2853,7 @@ static int normalize_linked_files(
 }
 
 int unit_file_reenable(
-                UnitFileScope scope,
+                LookupScope scope,
                 UnitFileFlags flags,
                 const char *root_dir,
                 char **names_or_paths,
@@ -2828,7 +2865,7 @@ int unit_file_reenable(
         int r;
 
         assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
+        assert(scope < _LOOKUP_SCOPE_MAX);
 
         r = lookup_paths_init(&lp, scope, 0, root_dir);
         if (r < 0)
@@ -2852,7 +2889,7 @@ int unit_file_reenable(
 }
 
 int unit_file_set_default(
-                UnitFileScope scope,
+                LookupScope scope,
                 UnitFileFlags flags,
                 const char *root_dir,
                 const char *name,
@@ -2866,7 +2903,7 @@ int unit_file_set_default(
         int r;
 
         assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
+        assert(scope < _LOOKUP_SCOPE_MAX);
         assert(name);
 
         if (unit_name_to_type(name) != UNIT_TARGET) /* this also validates the name */
@@ -2883,11 +2920,11 @@ int unit_file_set_default(
                 return r;
 
         new_path = strjoina(lp.persistent_config, "/" SPECIAL_DEFAULT_TARGET);
-        return create_symlink(&lp, info->name, new_path, flags & UNIT_FILE_FORCE, changes, n_changes);
+        return create_symlink(&lp, info->path, new_path, flags & UNIT_FILE_FORCE, changes, n_changes);
 }
 
 int unit_file_get_default(
-                UnitFileScope scope,
+                LookupScope scope,
                 const char *root_dir,
                 char **name) {
 
@@ -2898,7 +2935,7 @@ int unit_file_get_default(
         int r;
 
         assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
+        assert(scope < _LOOKUP_SCOPE_MAX);
         assert(name);
 
         r = lookup_paths_init(&lp, scope, 0, root_dir);
@@ -2922,7 +2959,7 @@ int unit_file_get_default(
 }
 
 int unit_file_lookup_state(
-                UnitFileScope scope,
+                LookupScope scope,
                 const LookupPaths *lp,
                 const char *name,
                 UnitFileState *ret) {
@@ -3020,7 +3057,7 @@ int unit_file_lookup_state(
 }
 
 int unit_file_get_state(
-                UnitFileScope scope,
+                LookupScope scope,
                 const char *root_dir,
                 const char *name,
                 UnitFileState *ret) {
@@ -3029,7 +3066,7 @@ int unit_file_get_state(
         int r;
 
         assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
+        assert(scope < _LOOKUP_SCOPE_MAX);
         assert(name);
 
         r = lookup_paths_init(&lp, scope, 0, root_dir);
@@ -3039,7 +3076,7 @@ int unit_file_get_state(
         return unit_file_lookup_state(scope, &lp, name, ret);
 }
 
-int unit_file_exists(UnitFileScope scope, const LookupPaths *lp, const char *name) {
+int unit_file_exists(LookupScope scope, const LookupPaths *lp, const char *name) {
         _cleanup_(install_context_done) InstallContext c = { .scope = scope };
         int r;
 
@@ -3091,17 +3128,17 @@ static int split_pattern_into_name_and_instances(const char *pattern, char **out
         return 0;
 }
 
-static int presets_find_config(UnitFileScope scope, const char *root_dir, char ***files) {
+static int presets_find_config(LookupScope scope, const char *root_dir, char ***files) {
         static const char* const system_dirs[] = {CONF_PATHS("systemd/system-preset"), NULL};
         static const char* const user_dirs[] = {CONF_PATHS_USR("systemd/user-preset"), NULL};
         const char* const* dirs;
 
         assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
+        assert(scope < _LOOKUP_SCOPE_MAX);
 
-        if (scope == UNIT_FILE_SYSTEM)
+        if (scope == LOOKUP_SCOPE_SYSTEM)
                 dirs = system_dirs;
-        else if (IN_SET(scope, UNIT_FILE_GLOBAL, UNIT_FILE_USER))
+        else if (IN_SET(scope, LOOKUP_SCOPE_GLOBAL, LOOKUP_SCOPE_USER))
                 dirs = user_dirs;
         else
                 assert_not_reached();
@@ -3109,13 +3146,13 @@ static int presets_find_config(UnitFileScope scope, const char *root_dir, char *
         return conf_files_list_strv(files, ".preset", root_dir, 0, dirs);
 }
 
-static int read_presets(UnitFileScope scope, const char *root_dir, UnitFilePresets *presets) {
+static int read_presets(LookupScope scope, const char *root_dir, UnitFilePresets *presets) {
         _cleanup_(unit_file_presets_freep) UnitFilePresets ps = {};
         _cleanup_strv_free_ char **files = NULL;
         int r;
 
         assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
+        assert(scope < _LOOKUP_SCOPE_MAX);
         assert(presets);
 
         r = presets_find_config(scope, root_dir, &files);
@@ -3289,7 +3326,7 @@ static int query_presets(const char *name, const UnitFilePresets *presets, char
         }
 }
 
-int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name, UnitFilePresets *cached) {
+int unit_file_query_preset(LookupScope scope, const char *root_dir, const char *name, UnitFilePresets *cached) {
         _cleanup_(unit_file_presets_freep) UnitFilePresets tmp = {};
         int r;
 
@@ -3353,7 +3390,7 @@ static int execute_preset(
 }
 
 static int preset_prepare_one(
-                UnitFileScope scope,
+                LookupScope scope,
                 InstallContext *plus,
                 InstallContext *minus,
                 LookupPaths *lp,
@@ -3406,10 +3443,10 @@ static int preset_prepare_one(
 }
 
 int unit_file_preset(
-                UnitFileScope scope,
+                LookupScope scope,
                 UnitFileFlags file_flags,
                 const char *root_dir,
-                char **files,
+                char **names,
                 UnitFilePresetMode mode,
                 UnitFileChange **changes,
                 size_t *n_changes) {
@@ -3421,7 +3458,7 @@ int unit_file_preset(
         int r;
 
         assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
+        assert(scope < _LOOKUP_SCOPE_MAX);
         assert(mode < _UNIT_FILE_PRESET_MAX);
 
         r = lookup_paths_init(&lp, scope, 0, root_dir);
@@ -3436,17 +3473,17 @@ int unit_file_preset(
         if (r < 0)
                 return r;
 
-        STRV_FOREACH(i, files) {
-                r = preset_prepare_one(scope, &plus, &minus, &lp, *i, &presets, changes, n_changes);
+        STRV_FOREACH(name, names) {
+                r = preset_prepare_one(scope, &plus, &minus, &lp, *name, &presets, changes, n_changes);
                 if (r < 0)
                         return r;
         }
 
-        return execute_preset(file_flags, &plus, &minus, &lp, config_path, files, mode, changes, n_changes);
+        return execute_preset(file_flags, &plus, &minus, &lp, config_path, names, mode, changes, n_changes);
 }
 
 int unit_file_preset_all(
-                UnitFileScope scope,
+                LookupScope scope,
                 UnitFileFlags file_flags,
                 const char *root_dir,
                 UnitFilePresetMode mode,
@@ -3460,7 +3497,7 @@ int unit_file_preset_all(
         int r;
 
         assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
+        assert(scope < _LOOKUP_SCOPE_MAX);
         assert(mode < _UNIT_FILE_PRESET_MAX);
 
         r = lookup_paths_init(&lp, scope, 0, root_dir);
@@ -3521,7 +3558,7 @@ Hashmap* unit_file_list_free(Hashmap *h) {
 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList*, unit_file_list_free_one);
 
 int unit_file_get_list(
-                UnitFileScope scope,
+                LookupScope scope,
                 const char *root_dir,
                 Hashmap *h,
                 char **states,
@@ -3531,7 +3568,7 @@ int unit_file_get_list(
         int r;
 
         assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
+        assert(scope < _LOOKUP_SCOPE_MAX);
         assert(h);
 
         r = lookup_paths_init(&lp, scope, 0, root_dir);