]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/shared/install.c
Merge pull request #11827 from keszybz/pkgconfig-variables
[thirdparty/systemd.git] / src / shared / install.c
index 97c48afe5d8f54d0214b0ca38fe06a582334faee..9e88ac46bd50b2acc7c21695bd9b69bc1c2754f7 100644 (file)
@@ -15,6 +15,7 @@
 #include "alloc-util.h"
 #include "conf-files.h"
 #include "conf-parser.h"
+#include "def.h"
 #include "dirent-util.h"
 #include "extract-word.h"
 #include "fd-util.h"
@@ -68,7 +69,7 @@ typedef struct {
         size_t n_rules;
 } Presets;
 
-static inline bool unit_file_install_info_has_rules(UnitFileInstallInfo *i) {
+static bool unit_file_install_info_has_rules(const UnitFileInstallInfo *i) {
         assert(i);
 
         return !strv_isempty(i->aliases) ||
@@ -76,13 +77,13 @@ static inline bool unit_file_install_info_has_rules(UnitFileInstallInfo *i) {
                !strv_isempty(i->required_by);
 }
 
-static inline bool unit_file_install_info_has_also(UnitFileInstallInfo *i) {
+static bool unit_file_install_info_has_also(const UnitFileInstallInfo *i) {
         assert(i);
 
         return !strv_isempty(i->also);
 }
 
-static inline void presets_freep(Presets *p) {
+static void presets_freep(Presets *p) {
         size_t i;
 
         if (!p)
@@ -346,7 +347,7 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang
                         if (!quiet)
                                 log_info("Created symlink %s %s %s.",
                                          changes[i].path,
-                                         special_glyph(ARROW),
+                                         special_glyph(SPECIAL_GLYPH_ARROW),
                                          changes[i].source);
                         break;
                 case UNIT_FILE_UNLINK:
@@ -477,8 +478,10 @@ static int create_symlink(
         if (!dirname)
                 return -ENOMEM;
 
-        if (chroot_symlinks_same(paths->root_dir, dirname, dest, old_path))
+        if (chroot_symlinks_same(paths->root_dir, dirname, dest, old_path)) {
+                log_debug("Symlink %s → %s already exists", new_path, dest);
                 return 1;
+        }
 
         if (!force) {
                 unit_file_changes_add(changes, n_changes, -EEXIST, new_path, dest);
@@ -711,8 +714,9 @@ static int is_symlink_with_known_name(const UnitFileInstallInfo *i, const char *
 
 static int find_symlinks_fd(
                 const char *root_dir,
-                UnitFileInstallInfo *i,
+                const UnitFileInstallInfo *i,
                 bool match_aliases,
+                bool ignore_same_name,
                 int fd,
                 const char *path,
                 const char *config_path,
@@ -759,7 +763,7 @@ static int find_symlinks_fd(
                         }
 
                         /* This will close nfd, regardless whether it succeeds or not */
-                        q = find_symlinks_fd(root_dir, i, match_aliases, nfd,
+                        q = find_symlinks_fd(root_dir, i, match_aliases, ignore_same_name, nfd,
                                              p, config_path, same_name_link);
                         if (q > 0)
                                 return 1;
@@ -768,7 +772,7 @@ static int find_symlinks_fd(
 
                 } else if (de->d_type == DT_LNK) {
                         _cleanup_free_ char *p = NULL, *dest = NULL;
-                        bool found_path, found_dest, b = false;
+                        bool found_path = false, found_dest, b = false;
                         int q;
 
                         /* Acquire symlink name */
@@ -794,23 +798,20 @@ static int find_symlinks_fd(
                                 if (!x)
                                         return -ENOMEM;
 
-                                free(dest);
-                                dest = x;
+                                free_and_replace(dest, x);
                         }
 
-                        /* Check if the symlink itself matches what we
-                         * are looking for */
-                        if (path_is_absolute(i->name))
-                                found_path = path_equal(p, i->name);
-                        else
-                                found_path = streq(de->d_name, i->name);
+                        assert(unit_name_is_valid(i->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, i->name);
 
-                        /* Check if what the symlink points to
-                         * matches what we are looking for */
-                        if (path_is_absolute(i->name))
-                                found_dest = path_equal(dest, i->name);
-                        else
-                                found_dest = streq(basename(dest), i->name);
+                        /* Check if what the symlink points to matches what we are looking for */
+                        found_dest = streq(basename(dest), i->name);
 
                         if (found_path && found_dest) {
                                 _cleanup_free_ char *t = NULL;
@@ -845,8 +846,9 @@ static int find_symlinks_fd(
 
 static int find_symlinks(
                 const char *root_dir,
-                UnitFileInstallInfo *i,
+                const UnitFileInstallInfo *i,
                 bool match_name,
+                bool ignore_same_name,
                 const char *config_path,
                 bool *same_name_link) {
 
@@ -864,29 +866,34 @@ static int find_symlinks(
         }
 
         /* This takes possession of fd and closes it */
-        return find_symlinks_fd(root_dir, i, match_name, fd,
+        return find_symlinks_fd(root_dir, i, match_name, ignore_same_name, fd,
                                 config_path, config_path, same_name_link);
 }
 
 static int find_symlinks_in_scope(
                 UnitFileScope scope,
                 const LookupPaths *paths,
-                UnitFileInstallInfo *i,
+                const UnitFileInstallInfo *i,
                 bool match_name,
                 UnitFileState *state) {
 
         bool same_name_link_runtime = false, same_name_link_config = false;
         bool enabled_in_runtime = false, enabled_at_all = false;
+        bool ignore_same_name = false;
         char **p;
         int r;
 
         assert(paths);
         assert(i);
 
+        /* As we iterate over the list of search paths in paths->search_path, we may encounter "same name"
+         * symlinks. The ones which are "below" (i.e. have lower priority) than the unit file itself are
+         * efectively masked, so we should ignore them. */
+
         STRV_FOREACH(p, paths->search_path)  {
                 bool same_name_link = false;
 
-                r = find_symlinks(paths->root_dir, i, match_name, *p, &same_name_link);
+                r = find_symlinks(paths->root_dir, i, match_name, ignore_same_name, *p, &same_name_link);
                 if (r < 0)
                         return r;
                 if (r > 0) {
@@ -923,6 +930,11 @@ static int find_symlinks_in_scope(
                                         same_name_link_runtime = true;
                         }
                 }
+
+                /* Check if next iteration will be "below" the unit file (either a regular file
+                 * or a symlink), and hence should be ignored */
+                if (!ignore_same_name && path_startswith(i->path, *p))
+                        ignore_same_name = true;
         }
 
         if (enabled_in_runtime) {
@@ -987,7 +999,7 @@ static UnitFileInstallInfo *install_info_find(InstallContext *c, const char *nam
 }
 
 static int install_info_may_process(
-                UnitFileInstallInfo *i,
+                const UnitFileInstallInfo *i,
                 const LookupPaths *paths,
                 UnitFileChange **changes,
                 size_t *n_changes) {
@@ -1048,11 +1060,14 @@ static int install_info_add(
         if (r < 0)
                 return r;
 
-        i = new0(UnitFileInstallInfo, 1);
+        i = new(UnitFileInstallInfo, 1);
         if (!i)
                 return -ENOMEM;
-        i->type = _UNIT_FILE_TYPE_INVALID;
-        i->auxiliary = auxiliary;
+
+        *i = (UnitFileInstallInfo) {
+                .type = _UNIT_FILE_TYPE_INVALID,
+                .auxiliary = auxiliary,
+        };
 
         i->name = strdup(name);
         if (!i->name) {
@@ -1283,7 +1298,7 @@ static int unit_file_load(
         if (r < 0)
                 return r;
 
-        f = fdopen(fd, "re");
+        f = fdopen(fd, "r");
         if (!f)
                 return -errno;
         fd = -1;
@@ -1461,7 +1476,7 @@ static int unit_file_search(
         STRV_FOREACH(p, paths->search_path) {
                 char *path;
 
-                path = path_join(NULL, *p, dropin_dir_name);
+                path = path_join(*p, dropin_dir_name);
                 if (!path)
                         return -ENOMEM;
 
@@ -1475,7 +1490,7 @@ static int unit_file_search(
                 STRV_FOREACH(p, paths->search_path) {
                         char *path;
 
-                        path = path_join(NULL, *p, dropin_template_dir_name);
+                        path = path_join(*p, dropin_template_dir_name);
                         if (!path)
                                 return -ENOMEM;
 
@@ -1749,12 +1764,16 @@ static int install_info_symlink_wants(
         if (strv_isempty(list))
                 return 0;
 
-        if (unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE) && i->default_instance) {
+        if (unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE)) {
                 UnitFileInstallInfo instance = {
                         .type = _UNIT_FILE_TYPE_INVALID,
                 };
                 _cleanup_free_ char *path = NULL;
 
+                /* If this is a template, and we have no instance, don't do anything */
+                if (!i->default_instance)
+                        return 1;
+
                 r = unit_name_replace_instance(i->name, i->default_instance, &buf);
                 if (r < 0)
                         return r;
@@ -1932,6 +1951,7 @@ static int install_context_mark_for_removal(
                 InstallContext *c,
                 const LookupPaths *paths,
                 Set **remove_symlinks_to,
+                const char *config_path,
                 UnitFileChange **changes,
                 size_t *n_changes) {
 
@@ -1940,6 +1960,7 @@ static int install_context_mark_for_removal(
 
         assert(c);
         assert(paths);
+        assert(config_path);
 
         /* Marks all items for removal */
 
@@ -2049,7 +2070,7 @@ int unit_file_unmask(
         size_t n_todo = 0, n_allocated = 0;
         const char *config_path;
         char **i;
-        bool dry_run = !!(flags & UNIT_FILE_DRY_RUN);
+        bool dry_run;
         int r, q;
 
         assert(scope >= 0);
@@ -2059,71 +2080,73 @@ int unit_file_unmask(
         if (r < 0)
                 return r;
 
+        config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
+        if (!config_path)
+                return -ENXIO;
+
+        dry_run = !!(flags & UNIT_FILE_DRY_RUN);
+
         STRV_FOREACH(i, files) {
+                _cleanup_free_ char *path = NULL;
+
                 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
                         return -EINVAL;
 
-                FOREACH_STRING(config_path, paths.runtime_config, paths.persistent_config) {
-                        _cleanup_free_ char *path = NULL;
-
-                        path = path_make_absolute(*i, config_path);
-                        if (!path)
-                                return -ENOMEM;
+                path = path_make_absolute(*i, config_path);
+                if (!path)
+                        return -ENOMEM;
 
-                        r = null_or_empty_path(path);
-                        if (r == -ENOENT)
-                                continue;
-                        if (r < 0)
-                                return r;
-                        if (r == 0)
-                                continue;
+                r = null_or_empty_path(path);
+                if (r == -ENOENT)
+                        continue;
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        continue;
 
-                        if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
-                                return -ENOMEM;
+                if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
+                        return -ENOMEM;
 
-                        todo[n_todo] = strdup(*i);
-                        if (!todo[n_todo])
-                                return -ENOMEM;
+                todo[n_todo] = strdup(*i);
+                if (!todo[n_todo])
+                        return -ENOMEM;
 
-                        n_todo++;
-                }
+                n_todo++;
         }
 
         strv_uniq(todo);
 
         r = 0;
-        FOREACH_STRING(config_path, paths.runtime_config, paths.persistent_config) {
-                STRV_FOREACH(i, todo) {
-                        _cleanup_free_ char *path = NULL;
-                        const char *rp;
-
-                        path = path_make_absolute(*i, config_path);
-                        if (!path)
-                                return -ENOMEM;
+        STRV_FOREACH(i, todo) {
+                _cleanup_free_ char *path = NULL;
+                const char *rp;
 
-                        if (!dry_run && unlink(path) < 0) {
-                                if (errno != ENOENT) {
-                                        if (r >= 0)
-                                                r = -errno;
-                                        unit_file_changes_add(changes, n_changes, -errno, path, NULL);
-                                }
+                path = path_make_absolute(*i, config_path);
+                if (!path)
+                        return -ENOMEM;
 
-                                continue;
+                if (!dry_run && unlink(path) < 0) {
+                        if (errno != ENOENT) {
+                                if (r >= 0)
+                                        r = -errno;
+                                unit_file_changes_add(changes, n_changes, -errno, path, NULL);
                         }
 
-                        unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
-
-                        rp = skip_root(&paths, path);
-                        q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: path);
-                        if (q < 0)
-                                return q;
+                        continue;
                 }
 
-                q = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, dry_run, changes, n_changes);
-                if (r >= 0)
-                        r = q;
+                unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
+
+                rp = skip_root(&paths, path);
+                q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: path);
+                if (q < 0)
+                        return q;
         }
 
+        q = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, dry_run, changes, n_changes);
+        if (r >= 0)
+                r = q;
+
         return r;
 }
 
@@ -2506,7 +2529,6 @@ int unit_file_disable(
         _cleanup_(lookup_paths_free) LookupPaths paths = {};
         _cleanup_(install_context_done) InstallContext c = {};
         _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
-        bool dry_run = !!(flags & UNIT_FILE_DRY_RUN);
         const char *config_path;
         char **i;
         int r;
@@ -2518,6 +2540,10 @@ int unit_file_disable(
         if (r < 0)
                 return r;
 
+        config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
+        if (!config_path)
+                return -ENXIO;
+
         STRV_FOREACH(i, files) {
                 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
                         return -EINVAL;
@@ -2527,17 +2553,11 @@ int unit_file_disable(
                         return r;
         }
 
-        r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, changes, n_changes);
+        r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, config_path, changes, n_changes);
         if (r < 0)
                 return r;
 
-        FOREACH_STRING(config_path, paths.runtime_config, paths.persistent_config) {
-                r = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, dry_run, changes, n_changes);
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
+        return remove_marked_symlinks(remove_symlinks_to, config_path, &paths, !!(flags & UNIT_FILE_DRY_RUN), changes, n_changes);
 }
 
 int unit_file_reenable(
@@ -2657,7 +2677,11 @@ int unit_file_lookup_state(
         r = install_info_discover(scope, &c, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
                                   &i, NULL, NULL);
         if (r < 0)
-                return r;
+                return log_debug_errno(r, "Failed to discover unit %s: %m", name);
+
+        assert(IN_SET(i->type, UNIT_FILE_TYPE_REGULAR, UNIT_FILE_TYPE_MASKED));
+        log_debug("Found unit %s at %s (%s)", name, strna(i->path),
+                  i->type == UNIT_FILE_TYPE_REGULAR ? "regular file" : "mask");
 
         /* Shortcut things, if the caller just wants to know if this unit exists. */
         if (!ret)
@@ -2797,44 +2821,41 @@ static int split_pattern_into_name_and_instances(const char *pattern, char **out
         return 0;
 }
 
-static int read_presets(UnitFileScope scope, const char *root_dir, Presets *presets) {
-        _cleanup_(presets_freep) Presets ps = {};
-        size_t n_allocated = 0;
-        _cleanup_strv_free_ char **files = NULL;
-        char **p;
-        int r;
+static int presets_find_config(UnitFileScope scope, const char *root_dir, char ***files) {
+        const char* const* dirs;
 
         assert(scope >= 0);
         assert(scope < _UNIT_FILE_SCOPE_MAX);
-        assert(presets);
 
         switch (scope) {
         case UNIT_FILE_SYSTEM:
-                r = conf_files_list(&files, ".preset", root_dir, 0,
-                                    "/etc/systemd/system-preset",
-                                    "/run/systemd/system-preset",
-                                    "/usr/local/lib/systemd/system-preset",
-                                    "/usr/lib/systemd/system-preset",
-#if HAVE_SPLIT_USR
-                                    "/lib/systemd/system-preset",
-#endif
-                                    NULL);
+                dirs = (const char* const*) CONF_PATHS_STRV("systemd/system-preset");
                 break;
 
         case UNIT_FILE_GLOBAL:
         case UNIT_FILE_USER:
-                r = conf_files_list(&files, ".preset", root_dir, 0,
-                                    "/etc/systemd/user-preset",
-                                    "/run/systemd/user-preset",
-                                    "/usr/local/lib/systemd/user-preset",
-                                    "/usr/lib/systemd/user-preset",
-                                    NULL);
+                dirs = (const char* const*) CONF_PATHS_USR_STRV("systemd/user-preset");
                 break;
 
         default:
                 assert_not_reached("Invalid unit file scope");
         }
 
+        return conf_files_list_strv(files, ".preset", root_dir, 0, dirs);
+}
+
+static int read_presets(UnitFileScope scope, const char *root_dir, Presets *presets) {
+        _cleanup_(presets_freep) Presets ps = {};
+        size_t n_allocated = 0;
+        _cleanup_strv_free_ char **files = NULL;
+        char **p;
+        int r;
+
+        assert(scope >= 0);
+        assert(scope < _UNIT_FILE_SCOPE_MAX);
+        assert(presets);
+
+        r = presets_find_config(scope, root_dir, &files);
         if (r < 0)
                 return r;
 
@@ -3022,45 +3043,45 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char
 
 static int execute_preset(
                 UnitFileScope scope,
-                UnitFileFlags flags,
                 InstallContext *plus,
                 InstallContext *minus,
                 const LookupPaths *paths,
+                const char *config_path,
                 char **files,
                 UnitFilePresetMode mode,
+                bool force,
                 UnitFileChange **changes,
                 size_t *n_changes) {
 
-        const char *config_path;
-        bool force = !!(flags & UNIT_FILE_FORCE);
-        bool runtime = !!(flags & UNIT_FILE_RUNTIME);
-        int r = 0, q;
+        int r;
 
         assert(plus);
         assert(minus);
         assert(paths);
+        assert(config_path);
 
         if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) {
                 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
 
-                q = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, changes, n_changes);
-                if (q < 0)
-                        return q;
+                r = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, config_path, changes, n_changes);
+                if (r < 0)
+                        return r;
 
-                FOREACH_STRING(config_path, paths->runtime_config, paths->persistent_config) {
-                        q = remove_marked_symlinks(remove_symlinks_to, config_path, paths, false, changes, n_changes);
-                        if (r == 0)
-                                r = q;
-                }
-        }
+                r = remove_marked_symlinks(remove_symlinks_to, config_path, paths, false, changes, n_changes);
+        } else
+                r = 0;
 
         if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) {
+                int q;
+
                 /* Returns number of symlinks that where supposed to be installed. */
-                q = install_context_apply(scope, plus, paths,
-                                          runtime ? paths->runtime_config : paths->persistent_config,
-                                          force, SEARCH_LOAD, changes, n_changes);
-                if (r == 0)
-                        r = q;
+                q = install_context_apply(scope, plus, paths, config_path, force, SEARCH_LOAD, changes, n_changes);
+                if (r >= 0) {
+                        if (q < 0)
+                                r = q;
+                        else
+                                r += q;
+                }
         }
 
         return r;
@@ -3132,6 +3153,7 @@ int unit_file_preset(
         _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
         _cleanup_(lookup_paths_free) LookupPaths paths = {};
         _cleanup_(presets_freep) Presets presets = {};
+        const char *config_path;
         char **i;
         int r;
 
@@ -3143,6 +3165,10 @@ int unit_file_preset(
         if (r < 0)
                 return r;
 
+        config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
+        if (!config_path)
+                return -ENXIO;
+
         r = read_presets(scope, root_dir, &presets);
         if (r < 0)
                 return r;
@@ -3153,7 +3179,7 @@ int unit_file_preset(
                         return r;
         }
 
-        return execute_preset(scope, flags, &plus, &minus, &paths, files, mode, changes, n_changes);
+        return execute_preset(scope, &plus, &minus, &paths, config_path, files, mode, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
 }
 
 int unit_file_preset_all(
@@ -3167,6 +3193,7 @@ int unit_file_preset_all(
         _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
         _cleanup_(lookup_paths_free) LookupPaths paths = {};
         _cleanup_(presets_freep) Presets presets = {};
+        const char *config_path = NULL;
         char **i;
         int r;
 
@@ -3178,6 +3205,10 @@ int unit_file_preset_all(
         if (r < 0)
                 return r;
 
+        config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
+        if (!config_path)
+                return -ENXIO;
+
         r = read_presets(scope, root_dir, &presets);
         if (r < 0)
                 return r;
@@ -3195,6 +3226,7 @@ int unit_file_preset_all(
                 }
 
                 FOREACH_DIRENT(de, d, return -errno) {
+
                         if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
                                 continue;
 
@@ -3218,7 +3250,7 @@ int unit_file_preset_all(
                 }
         }
 
-        return execute_preset(scope, flags, &plus, &minus, &paths, NULL, mode, changes, n_changes);
+        return execute_preset(scope, &plus, &minus, &paths, config_path, NULL, mode, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
 }
 
 static void unit_file_list_free_one(UnitFileList *f) {