#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"
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) ||
!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)
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:
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);
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,
}
/* 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;
} 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 */
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;
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) {
}
/* 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) {
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) {
}
static int install_info_may_process(
- UnitFileInstallInfo *i,
+ const UnitFileInstallInfo *i,
const LookupPaths *paths,
UnitFileChange **changes,
size_t *n_changes) {
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) {
if (r < 0)
return r;
- f = fdopen(fd, "re");
+ f = fdopen(fd, "r");
if (!f)
return -errno;
fd = -1;
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;
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;
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;
InstallContext *c,
const LookupPaths *paths,
Set **remove_symlinks_to,
+ const char *config_path,
UnitFileChange **changes,
size_t *n_changes) {
assert(c);
assert(paths);
+ assert(config_path);
/* Marks all items for removal */
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);
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;
}
_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;
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;
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(
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)
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;
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;
_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;
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;
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(
_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;
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;
}
FOREACH_DIRENT(de, d, return -errno) {
+
if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
continue;
}
}
- 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) {