} SearchFlags;
typedef struct {
+ LookupScope scope;
OrderedHashmap *will_process;
OrderedHashmap *have_processed;
} InstallContext;
static const char *const unit_file_type_table[_UNIT_FILE_TYPE_MAX] = {
[UNIT_FILE_TYPE_REGULAR] = "regular",
- [UNIT_FILE_TYPE_SYMLINK] = "symlink",
- [UNIT_FILE_TYPE_MASKED] = "masked",
+ [UNIT_FILE_TYPE_LINKED] = "linked",
+ [UNIT_FILE_TYPE_ALIAS] = "alias",
+ [UNIT_FILE_TYPE_MASKED] = "masked",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type, UnitFileType);
-static int in_search_path(const LookupPaths *p, const char *path) {
+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(p->search_path, parent);
+ return path_strv_contains(lp->search_path, parent);
}
-static const char* skip_root(const LookupPaths *p, const char *path) {
- char *e;
-
- assert(p);
+static const char* skip_root(const char *root_dir, const char *path) {
assert(path);
- if (!p->root_dir)
+ if (!root_dir)
return path;
- e = path_startswith(path, p->root_dir);
+ const char *e = path_startswith(path, root_dir);
if (!e)
return NULL;
return e;
}
-static int path_is_generator(const LookupPaths *p, const char *path) {
+static int path_is_generator(const LookupPaths *lp, const char *path) {
_cleanup_free_ char *parent = NULL;
+ int r;
- assert(p);
+ 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, p->generator) ||
- path_equal_ptr(parent, p->generator_early) ||
- path_equal_ptr(parent, p->generator_late);
+ return path_equal_ptr(parent, lp->generator) ||
+ path_equal_ptr(parent, lp->generator_early) ||
+ path_equal_ptr(parent, lp->generator_late);
}
-static int path_is_transient(const LookupPaths *p, const char *path) {
+static int path_is_transient(const LookupPaths *lp, const char *path) {
_cleanup_free_ char *parent = NULL;
+ int r;
- assert(p);
+ 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, p->transient);
+ return path_equal_ptr(parent, lp->transient);
}
-static int path_is_control(const LookupPaths *p, const char *path) {
+static int path_is_control(const LookupPaths *lp, const char *path) {
_cleanup_free_ char *parent = NULL;
+ int r;
- assert(p);
+ 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, p->persistent_control) ||
- path_equal_ptr(parent, p->runtime_control);
+ return path_equal_ptr(parent, lp->persistent_control) ||
+ path_equal_ptr(parent, lp->runtime_control);
}
-static int path_is_config(const LookupPaths *p, const char *path, bool check_parent) {
+static int path_is_config(const LookupPaths *lp, const char *path, bool check_parent) {
_cleanup_free_ char *parent = NULL;
+ int r;
- assert(p);
+ assert(lp);
assert(path);
/* Note that we do *not* have generic checks for /etc or /run in place, since with
* 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;
}
- return path_equal_ptr(path, p->persistent_config) ||
- path_equal_ptr(path, p->runtime_config);
+ return path_equal_ptr(path, lp->persistent_config) ||
+ path_equal_ptr(path, lp->runtime_config);
}
-static int path_is_runtime(const LookupPaths *p, const char *path, bool check_parent) {
+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(p);
+ assert(lp);
assert(path);
/* Everything in /run is considered runtime. On top of that we also add
* explicit checks for the various runtime directories, as safety net. */
- rpath = skip_root(p, path);
+ rpath = skip_root(lp->root_dir, path);
if (rpath && path_startswith(rpath, "/run"))
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;
}
- return path_equal_ptr(path, p->runtime_config) ||
- path_equal_ptr(path, p->generator) ||
- path_equal_ptr(path, p->generator_early) ||
- path_equal_ptr(path, p->generator_late) ||
- path_equal_ptr(path, p->transient) ||
- path_equal_ptr(path, p->runtime_control);
+ return path_equal_ptr(path, lp->runtime_config) ||
+ path_equal_ptr(path, lp->generator) ||
+ path_equal_ptr(path, lp->generator_early) ||
+ path_equal_ptr(path, lp->generator_late) ||
+ path_equal_ptr(path, lp->transient) ||
+ path_equal_ptr(path, lp->runtime_control);
}
-static int path_is_vendor_or_generator(const LookupPaths *p, const char *path) {
+static int path_is_vendor_or_generator(const LookupPaths *lp, const char *path) {
const char *rpath;
- assert(p);
+ assert(lp);
assert(path);
- rpath = skip_root(p, path);
+ rpath = skip_root(lp->root_dir, path);
if (!rpath)
return 0;
return true;
#endif
- if (path_is_generator(p, rpath))
+ if (path_is_generator(lp, rpath))
return true;
return path_equal(rpath, SYSTEM_DATA_UNIT_DIR);
}
-static const char* config_path_from_flags(const LookupPaths *paths, UnitFileFlags flags) {
- assert(paths);
+static const char* config_path_from_flags(const LookupPaths *lp, UnitFileFlags flags) {
+ assert(lp);
if (FLAGS_SET(flags, UNIT_FILE_PORTABLE))
- return FLAGS_SET(flags, UNIT_FILE_RUNTIME) ? paths->runtime_attached : paths->persistent_attached;
+ return FLAGS_SET(flags, UNIT_FILE_RUNTIME) ? lp->runtime_attached : lp->persistent_attached;
else
- return FLAGS_SET(flags, UNIT_FILE_RUNTIME) ? paths->runtime_config : paths->persistent_config;
+ return FLAGS_SET(flags, UNIT_FILE_RUNTIME) ? lp->runtime_config : lp->persistent_config;
}
int unit_file_changes_add(
}
void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *changes, size_t n_changes, bool quiet) {
- bool logged = false;
+ int err = 0;
assert(changes || n_changes == 0);
/* If verb is not specified, errors are not allowed! */
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.",
changes[i].path,
- special_glyph(SPECIAL_GLYPH_ARROW),
+ special_glyph(SPECIAL_GLYPH_ARROW_RIGHT),
changes[i].source);
break;
case UNIT_FILE_UNLINK:
if (!quiet)
- log_info("Removed %s.", changes[i].path);
+ log_info("Removed \"%s\".", changes[i].path);
break;
case UNIT_FILE_IS_MASKED:
if (!quiet)
break;
case -EEXIST:
if (changes[i].source)
- log_error_errno(changes[i].type_or_errno,
- "Failed to %s unit, file %s already exists and is a symlink to %s.",
- verb, changes[i].path, changes[i].source);
+ err = log_error_errno(changes[i].type_or_errno,
+ "Failed to %s unit, file \"%s\" already exists and is a symlink to \"%s\".",
+ verb, changes[i].path, changes[i].source);
else
- log_error_errno(changes[i].type_or_errno,
- "Failed to %s unit, file %s already exists.",
- verb, changes[i].path);
- logged = true;
+ err = log_error_errno(changes[i].type_or_errno,
+ "Failed to %s unit, file \"%s\" already exists.",
+ verb, changes[i].path);
break;
case -ERFKILL:
- log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s is masked.",
- verb, changes[i].path);
- logged = true;
+ err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s is masked.",
+ verb, changes[i].path);
break;
case -EADDRNOTAVAIL:
- log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s is transient or generated.",
- verb, changes[i].path);
- logged = true;
+ err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s is transient or generated.",
+ verb, changes[i].path);
+ break;
+ case -EBADSLT:
+ err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, invalid specifier in \"%s\".",
+ verb, changes[i].path);
break;
case -EIDRM:
- log_error_errno(changes[i].type_or_errno, "Failed to %s %s, destination unit %s is a non-template unit.",
- verb, changes[i].source, changes[i].path);
- logged = true;
+ err = log_error_errno(changes[i].type_or_errno, "Failed to %s %s, destination unit %s is a non-template unit.",
+ verb, changes[i].source, changes[i].path);
break;
case -EUCLEAN:
- log_error_errno(changes[i].type_or_errno,
- "Failed to %s unit, \"%s\" is not a valid unit name.",
- verb, changes[i].path);
- logged = true;
+ err = log_error_errno(changes[i].type_or_errno,
+ "Failed to %s unit, \"%s\" is not a valid unit name.",
+ verb, changes[i].path);
break;
case -ELOOP:
- log_error_errno(changes[i].type_or_errno, "Failed to %s unit, refusing to operate on linked unit file %s",
- verb, changes[i].path);
- logged = true;
+ err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, refusing to operate on linked unit file %s.",
+ verb, changes[i].path);
+ break;
+ case -EXDEV:
+ if (changes[i].source)
+ err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, cannot alias %s as %s.",
+ verb, changes[i].source, changes[i].path);
+ else
+ err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, invalid unit reference \"%s\".",
+ verb, changes[i].path);
break;
-
case -ENOENT:
- log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s does not exist.", verb, changes[i].path);
- logged = true;
+ err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s does not exist.",
+ verb, changes[i].path);
+ break;
+ case -EUNATCH:
+ err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, cannot resolve specifiers in \"%s\".",
+ verb, changes[i].path);
break;
-
default:
assert(changes[i].type_or_errno < 0);
- log_error_errno(changes[i].type_or_errno, "Failed to %s unit, file %s: %m.",
- verb, changes[i].path);
- logged = true;
+ err = log_error_errno(changes[i].type_or_errno, "Failed to %s unit, file \"%s\": %m",
+ verb, changes[i].path);
}
}
- if (r < 0 && !logged)
+ if (r < 0 && err >= 0)
log_error_errno(r, "Failed to %s: %m.", verb);
}
/**
- * 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;
+ }
- 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);
+ _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();
+
+ 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(
- const LookupPaths *paths,
+ const LookupPaths *lp,
const char *old_path,
const char *new_path,
bool force,
UnitFileChange **changes,
size_t *n_changes) {
- _cleanup_free_ char *dest = NULL, *dirname = NULL;
+ _cleanup_free_ char *dest = NULL;
const char *rp;
int r;
assert(old_path);
assert(new_path);
- rp = skip_root(paths, old_path);
+ rp = skip_root(lp->root_dir, old_path);
if (rp)
old_path = rp;
- /* Actually create a symlink, and remember that we did. Is
- * smart enough to check if there's already a valid symlink in
- * place.
+ /* Actually create a symlink, and remember that we did. This function is
+ * smart enough to check if there's already a valid symlink in place.
*
- * Returns 1 if a symlink was created or already exists and points to
- * the right place, or negative on error.
+ * Returns 1 if a symlink was created or already exists and points to the
+ * right place, or negative on error.
*/
(void) mkdir_parents_label(new_path, 0755);
return r;
}
- dirname = dirname_malloc(new_path);
- if (!dirname)
- return -ENOMEM;
-
- if (chroot_symlinks_same(paths->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;
}
size_t *n_changes) {
_cleanup_closedir_ DIR *d = NULL;
- struct dirent *de;
int r = 0;
assert(remove_symlinks_to);
rewinddir(d);
- FOREACH_DIRENT(de, d, return -errno) {
+ FOREACH_DIRENT(de, d, return -errno)
if (de->d_type == DT_DIR) {
_cleanup_free_ char *p = NULL;
r = q;
} else if (de->d_type == DT_LNK) {
- _cleanup_free_ char *p = NULL, *dest = NULL;
- const char *rp;
+ _cleanup_free_ char *p = NULL;
bool found;
int q;
return -ENOMEM;
path_simplify(p);
- q = chase_symlinks(p, NULL, CHASE_NONEXISTENT, &dest, NULL);
- if (q == -ENOENT)
- continue;
- if (q < 0) {
- if (r == 0)
- r = q;
- continue;
+ /* We remove all links pointing to a file or path that is marked, as well as all
+ * files sharing the same name as a file that is marked, and files sharing the same
+ * name after the instance has been removed. Do path chasing only if we don't already
+ * know that we want to remove the symlink. */
+ found = set_contains(remove_symlinks_to, de->d_name);
+
+ if (!found) {
+ _cleanup_free_ char *template = NULL;
+
+ q = unit_name_template(de->d_name, &template);
+ if (q < 0 && q != -EINVAL)
+ return q;
+ if (q >= 0)
+ found = set_contains(remove_symlinks_to, template);
}
- /* We remove all links pointing to a file or path that is marked, as well as all files sharing
- * the same name as a file that is marked. */
+ if (!found) {
+ _cleanup_free_ char *dest = NULL;
+
+ q = chase_symlinks(p, lp->root_dir, CHASE_NONEXISTENT, &dest, NULL);
+ if (q == -ENOENT)
+ continue;
+ if (q < 0) {
+ log_debug_errno(q, "Failed to resolve symlink \"%s\": %m", p);
+ unit_file_changes_add(changes, n_changes, q, p, NULL);
+
+ if (r == 0)
+ r = q;
+ continue;
+ }
+
+ found = set_contains(remove_symlinks_to, dest) ||
+ set_contains(remove_symlinks_to, basename(dest));
+
+ }
- found = set_contains(remove_symlinks_to, dest) ||
- set_contains(remove_symlinks_to, basename(dest)) ||
- set_contains(remove_symlinks_to, de->d_name);
if (!found)
continue;
/* Now, remember the full path (but with the root prefix removed) of
* the symlink we just removed, and remove any symlinks to it, too. */
- rp = skip_root(lp, p);
+ const char *rp = skip_root(lp->root_dir, p);
q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: p);
if (q < 0)
return q;
if (q > 0 && !dry_run)
*restart = true;
}
- }
return r;
}
DIR *dir,
const char *dir_path,
const char *root_dir,
- const UnitFileInstallInfo *i,
- bool match_aliases,
+ const UnitFileInstallInfo *info,
+ bool ignore_destination,
+ bool match_name,
bool ignore_same_name,
const char *config_path,
bool *same_name_link) {
- struct dirent *de;
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;
+
+ /* 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;
+ }
- /* Make absolute */
- if (!path_is_absolute(dest)) {
- char *x;
+ /* Make absolute */
+ if (!path_is_absolute(dest)) {
+ char *x;
- x = path_join(dir_path, dest);
- if (!x)
- return -ENOMEM;
+ x = path_join(dir_path, dest);
+ if (!x)
+ return -ENOMEM;
- free_and_replace(dest, x);
+ 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(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);
+ assert(unit_name_is_valid(info->name, UNIT_NAME_ANY));
+
+ /* 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. */
- /* Check if what the symlink points to matches what we are looking for */
- found_dest = streq(basename(dest), i->name);
+ 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(i->name, config_path);
+ t = path_make_absolute(info->name, config_path);
if (!p || !t)
return -ENOMEM;
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] */
- q = is_symlink_with_known_name(i, de->d_name);
+ q = is_symlink_with_known_name(info, de->d_name);
if (q < 0)
return q;
if (q > 0)
bool *same_name_link) {
_cleanup_closedir_ DIR *config_dir = NULL;
- struct dirent *de;
int r = 0;
assert(i);
d = opendir(path);
if (!d) {
- log_error_errno(errno, "Failed to open directory '%s' while scanning for symlinks, ignoring: %m", path);
+ log_error_errno(errno, "Failed to open directory \"%s\" while scanning for symlinks, ignoring: %m", path);
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)
- log_debug_errno(r, "Failed to lookup for symlinks in '%s': %m", path);
+ log_debug_errno(r, "Failed to look up symlinks in \"%s\": %m", path);
}
/* 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(
- UnitFileScope scope,
- const LookupPaths *paths,
- const UnitFileInstallInfo *i,
+ LookupScope scope,
+ const LookupPaths *lp,
+ const UnitFileInstallInfo *info,
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);
+ assert(lp);
+ assert(info);
- /* As we iterate over the list of search paths in paths->search_path, we may encounter "same name"
+ /* As we iterate over the list of search paths in lp->search_path, we may encounter "same name"
* symlinks. The ones which are "below" (i.e. have lower priority) than the unit file itself are
* effectively masked, so we should ignore them. */
- STRV_FOREACH(p, paths->search_path) {
+ STRV_FOREACH(p, lp->search_path) {
bool same_name_link = false;
- r = find_symlinks(paths->root_dir, i, match_name, ignore_same_name, *p, &same_name_link);
+ r = find_symlinks(lp->root_dir, info, match_name, ignore_same_name, *p, &same_name_link);
if (r < 0)
return r;
if (r > 0) {
/* We found symlinks in this dir? Yay! Let's see where precisely it is enabled. */
- if (path_equal_ptr(*p, paths->persistent_config)) {
+ if (path_equal_ptr(*p, lp->persistent_config)) {
/* This is the best outcome, let's return it immediately. */
*state = UNIT_FILE_ENABLED;
return 1;
}
/* 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;
}
- r = path_is_runtime(paths, *p, false);
+ r = path_is_runtime(lp, *p, false);
if (r < 0)
return r;
if (r > 0)
enabled_at_all = true;
} else if (same_name_link) {
- if (path_equal_ptr(*p, paths->persistent_config))
+ if (path_equal_ptr(*p, lp->persistent_config))
same_name_link_config = true;
else {
- r = path_is_runtime(paths, *p, false);
+ r = path_is_runtime(lp, *p, false);
if (r < 0)
return r;
if (r > 0)
/* 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))
+ if (!ignore_same_name && path_startswith(info->path, *p))
ignore_same_name = true;
}
* outside of runtime and configuration directory, then we consider it statically enabled. Note we do that only
* for instance, not for regular names, as those are merely aliases, while instances explicitly instantiate
* something, and hence are a much stronger concept. */
- if (enabled_at_all && unit_name_is_valid(i->name, UNIT_NAME_INSTANCE)) {
+ if (enabled_at_all && unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
*state = UNIT_FILE_STATIC;
return 1;
}
}
static void install_info_free(UnitFileInstallInfo *i) {
-
if (!i)
return;
free(i);
}
-static void install_context_done(InstallContext *c) {
- assert(c);
+static void install_context_done(InstallContext *ctx) {
+ assert(ctx);
- c->will_process = ordered_hashmap_free_with_destructor(c->will_process, install_info_free);
- c->have_processed = ordered_hashmap_free_with_destructor(c->have_processed, install_info_free);
+ ctx->will_process = ordered_hashmap_free_with_destructor(ctx->will_process, install_info_free);
+ ctx->have_processed = ordered_hashmap_free_with_destructor(ctx->have_processed, install_info_free);
}
-static UnitFileInstallInfo *install_info_find(InstallContext *c, const char *name) {
+static UnitFileInstallInfo *install_info_find(InstallContext *ctx, const char *name) {
UnitFileInstallInfo *i;
- i = ordered_hashmap_get(c->have_processed, name);
+ i = ordered_hashmap_get(ctx->have_processed, name);
if (i)
return i;
- return ordered_hashmap_get(c->will_process, name);
+ return ordered_hashmap_get(ctx->will_process, name);
}
static int install_info_may_process(
const UnitFileInstallInfo *i,
- const LookupPaths *paths,
+ const LookupPaths *lp,
UnitFileChange **changes,
size_t *n_changes) {
assert(i);
- assert(paths);
+ assert(lp);
/* Checks whether the loaded unit file is one we should process, or is masked,
* transient or generated and thus not subject to enable/disable operations. */
unit_file_changes_add(changes, n_changes, -ERFKILL, i->path, NULL);
return -ERFKILL;
}
- if (path_is_generator(paths, i->path) ||
- path_is_transient(paths, i->path)) {
+ if (path_is_generator(lp, i->path) ||
+ path_is_transient(lp, i->path)) {
unit_file_changes_add(changes, n_changes, -EADDRNOTAVAIL, i->path, NULL);
return -EADDRNOTAVAIL;
}
* Returns negative on error, 0 if the unit was already known, 1 otherwise.
*/
static int install_info_add(
- InstallContext *c,
+ InstallContext *ctx,
const char *name,
const char *path,
const char *root,
UnitFileInstallInfo *i = NULL;
int r;
- assert(c);
+ assert(ctx);
if (!name) {
/* 'name' and 'path' must not both be null. Check here 'path' using assert_se() to
if (!unit_name_is_valid(name, UNIT_NAME_ANY))
return -EINVAL;
- i = install_info_find(c, name);
+ i = install_info_find(ctx, name);
if (i) {
i->auxiliary = i->auxiliary && auxiliary;
}
}
- r = ordered_hashmap_ensure_put(&c->will_process, &string_hash_ops, i->name, i);
+ r = ordered_hashmap_ensure_put(&ctx->will_process, &string_hash_ops, i->name, i);
if (r < 0)
goto fail;
void *data,
void *userdata) {
- UnitFileInstallInfo *info = userdata;
- InstallContext *c = data;
+ UnitFileInstallInfo *info = ASSERT_PTR(userdata);
+ InstallContext *ctx = ASSERT_PTR(data);
int r;
assert(unit);
if (r == 0)
break;
- r = install_name_printf(info, word, info->root, &printed);
+ r = install_name_printf(ctx->scope, info, word, &printed);
if (r < 0)
- return r;
+ return log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to resolve unit name in Also=\"%s\": %m", word);
- r = install_info_add(c, printed, NULL, info->root, /* auxiliary= */ true, NULL);
+ r = install_info_add(ctx, printed, NULL, info->root, /* auxiliary= */ true, NULL);
if (r < 0)
return r;
void *data,
void *userdata) {
- UnitFileInstallInfo *i = data;
+ InstallContext *ctx = ASSERT_PTR(data);
+ UnitFileInstallInfo *info = ASSERT_PTR(userdata);
_cleanup_free_ char *printed = NULL;
int r;
return log_syntax(unit, LOG_WARNING, filename, line, 0,
"DefaultInstance= only makes sense for template units, ignoring.");
- r = install_name_printf(i, rvalue, i->root, &printed);
+ r = install_name_printf(ctx->scope, info, rvalue, &printed);
if (r < 0)
- return r;
+ return log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to resolve instance name in DefaultInstance=\"%s\": %m", rvalue);
- if (isempty(printed)) {
- i->default_instance = mfree(i->default_instance);
- return 0;
- }
+ if (isempty(printed))
+ printed = mfree(printed);
- if (!unit_instance_is_valid(printed))
+ if (printed && !unit_instance_is_valid(printed))
return log_syntax(unit, LOG_WARNING, filename, line, SYNTHETIC_ERRNO(EINVAL),
"Invalid DefaultInstance= value \"%s\".", printed);
- return free_and_replace(i->default_instance, printed);
+ return free_and_replace(info->default_instance, printed);
}
static int unit_file_load(
- InstallContext *c,
+ InstallContext *ctx,
UnitFileInstallInfo *info,
const char *path,
const char *root_dir,
{ "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
{ "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
{ "Install", "DefaultInstance", config_parse_default_instance, 0, info },
- { "Install", "Also", config_parse_also, 0, c },
+ { "Install", "Also", config_parse_also, 0, ctx },
{}
};
if (!f)
return -errno;
- /* c is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */
- assert(c);
+ /* ctx is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */
+ assert(ctx);
r = config_parse(info->name, path, f,
"Install\0"
0, info,
NULL);
if (r < 0)
- return log_debug_errno(r, "Failed to parse %s: %m", info->name);
+ return log_debug_errno(r, "Failed to parse \"%s\": %m", info->name);
if ((flags & SEARCH_DROPIN) == 0)
info->type = UNIT_FILE_TYPE_REGULAR;
}
static int unit_file_load_or_readlink(
- InstallContext *c,
+ InstallContext *ctx,
UnitFileInstallInfo *info,
const char *path,
- const char *root_dir,
+ const LookupPaths *lp,
SearchFlags flags) {
-
- _cleanup_free_ char *resolved = NULL;
int r;
- r = unit_file_load(c, info, path, root_dir, flags);
+ r = unit_file_load(ctx, info, path, lp->root_dir, flags);
if (r != -ELOOP || (flags & SEARCH_DROPIN))
return r;
- r = chase_symlinks(path, root_dir, CHASE_WARN | CHASE_NONEXISTENT, &resolved, NULL);
- if (r >= 0 &&
- root_dir &&
- path_equal_ptr(path_startswith(resolved, root_dir), "dev/null"))
- /* When looking under root_dir, we can't expect /dev/ to be mounted,
- * so let's see if the path is a (possibly dangling) symlink to /dev/null. */
- info->type = UNIT_FILE_TYPE_MASKED;
-
- else if (r > 0 && null_or_empty_path(resolved) > 0)
+ /* This is a symlink, let's read and verify it. */
+ r = unit_file_resolve_symlink(lp->root_dir, lp->search_path,
+ NULL, AT_FDCWD, path,
+ true, &info->symlink_target);
+ if (r < 0)
+ return r;
+ bool outside_search_path = r > 0;
+ r = null_or_empty_path_with_root(info->symlink_target, lp->root_dir);
+ if (r < 0 && r != -ENOENT)
+ return log_debug_errno(r, "Failed to stat %s: %m", info->symlink_target);
+ if (r > 0)
info->type = UNIT_FILE_TYPE_MASKED;
-
- else {
- _cleanup_free_ char *target = NULL;
- const char *bn;
- UnitType a, b;
-
- /* This is a symlink, let's read it. We read the link again, because last time
- * we followed the link until resolution, and here we need to do one step. */
-
- r = readlink_malloc(path, &target);
- if (r < 0)
- return r;
-
- bn = basename(target);
-
- if (unit_name_is_valid(info->name, UNIT_NAME_PLAIN)) {
-
- if (!unit_name_is_valid(bn, UNIT_NAME_PLAIN))
- return -EINVAL;
-
- } else if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
-
- if (!unit_name_is_valid(bn, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
- return -EINVAL;
-
- } else if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE)) {
-
- if (!unit_name_is_valid(bn, UNIT_NAME_TEMPLATE))
- return -EINVAL;
- } else
- return -EINVAL;
-
- /* Enforce that the symlink destination does not
- * change the unit file type. */
-
- a = unit_name_to_type(info->name);
- b = unit_name_to_type(bn);
- if (a < 0 || b < 0 || a != b)
- return -EINVAL;
-
- if (path_is_absolute(target))
- /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
- info->symlink_target = path_join(root_dir, target);
- else
- /* This is a relative path, take it relative to the dir the symlink is located in. */
- info->symlink_target = file_in_same_dir(path, target);
- if (!info->symlink_target)
- return -ENOMEM;
-
- info->type = UNIT_FILE_TYPE_SYMLINK;
- }
+ else if (outside_search_path)
+ info->type = UNIT_FILE_TYPE_LINKED;
+ else
+ info->type = UNIT_FILE_TYPE_ALIAS;
return 0;
}
static int unit_file_search(
- InstallContext *c,
+ InstallContext *ctx,
UnitFileInstallInfo *info,
- const LookupPaths *paths,
+ const LookupPaths *lp,
SearchFlags flags) {
const char *dropin_dir_name = NULL, *dropin_template_dir_name = NULL;
_cleanup_free_ char *template = NULL;
bool found_unit = false;
int r, result;
- char **p;
assert(info);
- assert(paths);
+ assert(lp);
/* Was this unit already loaded? */
if (info->type != _UNIT_FILE_TYPE_INVALID)
return 0;
if (info->path)
- return unit_file_load_or_readlink(c, info, info->path, paths->root_dir, flags);
+ return unit_file_load_or_readlink(ctx, info, info->path, lp, flags);
assert(info->name);
return r;
}
- STRV_FOREACH(p, paths->search_path) {
+ STRV_FOREACH(p, lp->search_path) {
_cleanup_free_ char *path = NULL;
path = path_join(*p, info->name);
if (!path)
return -ENOMEM;
- r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
+ r = unit_file_load_or_readlink(ctx, info, path, lp, flags);
if (r >= 0) {
info->path = TAKE_PTR(path);
result = r;
* enablement was requested. We will check if it is
* possible to load template unit file. */
- STRV_FOREACH(p, paths->search_path) {
+ STRV_FOREACH(p, lp->search_path) {
_cleanup_free_ char *path = NULL;
path = path_join(*p, template);
if (!path)
return -ENOMEM;
- r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
+ r = unit_file_load_or_readlink(ctx, info, path, lp, flags);
if (r >= 0) {
info->path = TAKE_PTR(path);
result = r;
/* Search for drop-in directories */
dropin_dir_name = strjoina(info->name, ".d");
- STRV_FOREACH(p, paths->search_path) {
+ STRV_FOREACH(p, lp->search_path) {
char *path;
path = path_join(*p, dropin_dir_name);
if (template) {
dropin_template_dir_name = strjoina(template, ".d");
- STRV_FOREACH(p, paths->search_path) {
+ STRV_FOREACH(p, lp->search_path) {
char *path;
path = path_join(*p, dropin_template_dir_name);
return log_debug_errno(r, "Failed to get list of conf files: %m");
STRV_FOREACH(p, files) {
- r = unit_file_load_or_readlink(c, info, *p, paths->root_dir, flags | SEARCH_DROPIN);
+ r = unit_file_load_or_readlink(ctx, info, *p, lp, flags | SEARCH_DROPIN);
if (r < 0)
- return log_debug_errno(r, "Failed to load conf file %s: %m", *p);
+ return log_debug_errno(r, "Failed to load conf file \"%s\": %m", *p);
}
return result;
}
static int install_info_follow(
- InstallContext *c,
- UnitFileInstallInfo *i,
- const char *root_dir,
+ InstallContext *ctx,
+ UnitFileInstallInfo *info,
+ const LookupPaths *lp,
SearchFlags flags,
bool ignore_different_name) {
- assert(c);
- assert(i);
+ assert(ctx);
+ assert(info);
- if (i->type != UNIT_FILE_TYPE_SYMLINK)
+ if (!IN_SET(info->type, UNIT_FILE_TYPE_ALIAS, UNIT_FILE_TYPE_LINKED))
return -EINVAL;
- if (!i->symlink_target)
+ if (!info->symlink_target)
return -EINVAL;
- /* If the basename doesn't match, the caller should add a
- * complete new entry for this. */
+ /* If the basename doesn't match, the caller should add a complete new entry for this. */
- if (!ignore_different_name && !streq(basename(i->symlink_target), i->name))
+ if (!ignore_different_name && !streq(basename(info->symlink_target), info->name))
return -EXDEV;
- free_and_replace(i->path, i->symlink_target);
- i->type = _UNIT_FILE_TYPE_INVALID;
+ free_and_replace(info->path, info->symlink_target);
+ info->type = _UNIT_FILE_TYPE_INVALID;
- return unit_file_load_or_readlink(c, i, i->path, root_dir, flags);
+ return unit_file_load_or_readlink(ctx, info, info->path, lp, flags);
}
/**
* target, maybe more than once. Propagate the instance name if present.
*/
static int install_info_traverse(
- UnitFileScope scope,
- InstallContext *c,
- const LookupPaths *paths,
+ InstallContext *ctx,
+ const LookupPaths *lp,
UnitFileInstallInfo *start,
SearchFlags flags,
UnitFileInstallInfo **ret) {
unsigned k = 0;
int r;
- assert(paths);
+ assert(lp);
assert(start);
- assert(c);
+ assert(ctx);
- r = unit_file_search(c, start, paths, flags);
+ r = unit_file_search(ctx, start, lp, flags);
if (r < 0)
return r;
i = start;
- while (i->type == UNIT_FILE_TYPE_SYMLINK) {
+ while (IN_SET(i->type, UNIT_FILE_TYPE_ALIAS, UNIT_FILE_TYPE_LINKED)) {
/* Follow the symlink */
if (++k > UNIT_FILE_FOLLOW_SYMLINK_MAX)
return -ELOOP;
if (!(flags & SEARCH_FOLLOW_CONFIG_SYMLINKS)) {
- r = path_is_config(paths, i->path, true);
+ r = path_is_config(lp, i->path, true);
if (r < 0)
return r;
if (r > 0)
return -ELOOP;
}
- r = install_info_follow(c, i, paths->root_dir, 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;
- /* Target has a different name, create a new
- * install info object for that, and continue
- * with that. */
+ /* Target is an alias, create a new install info object and continue with that. */
bn = basename(i->symlink_target);
if (streq(buffer, i->name)) {
- /* We filled in the instance, and the target stayed the same? If so, then let's
- * honour the link as it is. */
+ /* We filled in the instance, and the target stayed the same? If so,
+ * then let's honour the link as it is. */
- r = install_info_follow(c, i, paths->root_dir, flags, true);
+ r = install_info_follow(ctx, i, lp, flags, true);
if (r < 0)
return r;
bn = buffer;
}
- r = install_info_add(c, bn, NULL, paths->root_dir, /* auxiliary= */ false, &i);
+ r = install_info_add(ctx, bn, NULL, lp->root_dir, /* auxiliary= */ false, &i);
if (r < 0)
return r;
/* Try again, with the new target we found. */
- r = unit_file_search(c, i, paths, flags);
+ r = unit_file_search(ctx, i, lp, flags);
if (r == -ENOENT)
/* Translate error code to highlight this specific case */
return -ENOLINK;
* or the name (otherwise). root_dir is prepended to the path.
*/
static int install_info_add_auto(
- InstallContext *c,
- const LookupPaths *paths,
+ InstallContext *ctx,
+ const LookupPaths *lp,
const char *name_or_path,
UnitFileInstallInfo **ret) {
- assert(c);
+ assert(ctx);
assert(name_or_path);
if (path_is_absolute(name_or_path)) {
const char *pp;
- pp = prefix_roota(paths->root_dir, name_or_path);
+ pp = prefix_roota(lp->root_dir, name_or_path);
- return install_info_add(c, NULL, pp, paths->root_dir, /* auxiliary= */ false, ret);
+ return install_info_add(ctx, NULL, pp, lp->root_dir, /* auxiliary= */ false, ret);
} else
- return install_info_add(c, name_or_path, NULL, paths->root_dir, /* auxiliary= */ false, ret);
+ return install_info_add(ctx, name_or_path, NULL, lp->root_dir, /* auxiliary= */ false, ret);
}
static int install_info_discover(
- UnitFileScope scope,
- InstallContext *c,
- const LookupPaths *paths,
- const char *name,
+ InstallContext *ctx,
+ const LookupPaths *lp,
+ const char *name_or_path,
SearchFlags flags,
UnitFileInstallInfo **ret,
UnitFileChange **changes,
size_t *n_changes) {
- UnitFileInstallInfo *i;
+ UnitFileInstallInfo *info;
int r;
- assert(c);
- assert(paths);
- assert(name);
+ assert(ctx);
+ assert(lp);
+ assert(name_or_path);
- r = install_info_add_auto(c, paths, name, &i);
+ r = install_info_add_auto(ctx, lp, name_or_path, &info);
if (r >= 0)
- r = install_info_traverse(scope, c, paths, i, flags, ret);
+ 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(
- UnitFileScope scope,
- InstallContext *c,
- const LookupPaths *paths,
- const char *name,
- SearchFlags flags,
- UnitFileInstallInfo **ret,
- UnitFileChange **changes,
- size_t *n_changes) {
+ InstallContext *ctx,
+ const LookupPaths *lp,
+ const char *name_or_path,
+ SearchFlags flags,
+ UnitFileInstallInfo **ret,
+ UnitFileChange **changes,
+ size_t *n_changes) {
int r;
- r = install_info_discover(scope, c, paths, 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;
- return install_info_may_process(ret ? *ret : NULL, paths, changes, n_changes);
+ return install_info_may_process(ret ? *ret : NULL, lp, changes, n_changes);
}
-int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char **ret_dst) {
+int unit_file_verify_alias(
+ const UnitFileInstallInfo *info,
+ const char *dst,
+ char **ret_dst,
+ UnitFileChange **changes,
+ size_t *n_changes) {
+
_cleanup_free_ char *dst_updated = NULL;
int r;
* ret_dst is set in cases where "instance propagation" happens, i.e. when the instance part is
* inserted into dst. It is not normally set, even on success, so that the caller can easily
* distinguish the case where instance propagation occurred.
+ *
+ * Returns:
+ * -EXDEV when the alias doesn't match the unit,
+ * -EUCLEAN when the name is invalid,
+ * -ELOOP when the alias it to the unit itself.
*/
const char *path_alias = strrchr(dst, '/');
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)
p = endswith(dir, ".requires");
- if (!p)
- return log_warning_errno(SYNTHETIC_ERRNO(EXDEV),
- "Invalid path \"%s\" in alias.", dir);
+ if (!p) {
+ unit_file_changes_add(changes, n_changes, -EXDEV, dst, NULL);
+ return log_debug_errno(SYNTHETIC_ERRNO(EXDEV), "Invalid path \"%s\" in alias.", dir);
+ }
+
*p = '\0'; /* dir should now be a unit name */
UnitNameFlags type = unit_name_classify(dir);
- if (type < 0)
- return log_warning_errno(SYNTHETIC_ERRNO(EXDEV),
- "Invalid unit name component \"%s\" in alias.", dir);
+ if (type < 0) {
+ unit_file_changes_add(changes, n_changes, -EXDEV, dst, NULL);
+ return log_debug_errno(SYNTHETIC_ERRNO(EXDEV),
+ "Invalid unit name component \"%s\" in alias.", dir);
+ }
const bool instance_propagation = type == UNIT_NAME_TEMPLATE;
/* That's the name we want to use for verification. */
- r = unit_symlink_name_compatible(path_alias, i->name, instance_propagation);
+ r = unit_symlink_name_compatible(path_alias, info->name, instance_propagation);
if (r < 0)
return log_error_errno(r, "Failed to verify alias validity: %m");
- if (r == 0)
- return log_warning_errno(SYNTHETIC_ERRNO(EXDEV),
- "Invalid unit %s symlink %s.",
- i->name, dst);
+ if (r == 0) {
+ unit_file_changes_add(changes, n_changes, -EXDEV, dst, info->name);
+ return log_debug_errno(SYNTHETIC_ERRNO(EXDEV),
+ "Invalid unit \"%s\" symlink \"%s\".",
+ info->name, dst);
+ }
} else {
/* If the symlink target has an instance set and the symlink source doesn't, we "propagate
if (unit_name_is_valid(dst, UNIT_NAME_TEMPLATE)) {
_cleanup_free_ char *inst = NULL;
- UnitNameFlags type = unit_name_to_instance(i->name, &inst);
- if (type < 0)
- return log_error_errno(type, "Failed to extract instance name from %s: %m", i->name);
+ UnitNameFlags type = unit_name_to_instance(info->name, &inst);
+ if (type < 0) {
+ unit_file_changes_add(changes, n_changes, -EUCLEAN, info->name, NULL);
+ return log_debug_errno(type, "Failed to extract instance name from \"%s\": %m", info->name);
+ }
if (type == UNIT_NAME_INSTANCE) {
r = unit_name_replace_instance(dst, inst, &dst_updated);
}
}
- r = unit_validate_alias_symlink_and_warn(dst_updated ?: dst, i->name);
- if (r < 0)
+ r = unit_validate_alias_symlink_or_warn(LOG_DEBUG, dst_updated ?: dst, info->name);
+ if (r == -ELOOP) /* -ELOOP means self-alias, which we (quietly) ignore */
return r;
-
+ if (r < 0) {
+ unit_file_changes_add(changes, n_changes,
+ r == -EINVAL ? -EXDEV : r,
+ dst_updated ?: dst,
+ info->name);
+ return r;
+ }
}
*ret_dst = TAKE_PTR(dst_updated);
}
static int install_info_symlink_alias(
- UnitFileInstallInfo *i,
- const LookupPaths *paths,
+ LookupScope scope,
+ UnitFileInstallInfo *info,
+ const LookupPaths *lp,
const char *config_path,
bool force,
UnitFileChange **changes,
size_t *n_changes) {
- char **s;
int r = 0, q;
- assert(i);
- assert(paths);
+ assert(info);
+ assert(lp);
assert(config_path);
- STRV_FOREACH(s, i->aliases) {
+ STRV_FOREACH(s, info->aliases) {
_cleanup_free_ char *alias_path = NULL, *dst = NULL, *dst_updated = NULL;
- q = install_path_printf(i, *s, i->root, &dst);
- if (q < 0)
- return q;
+ q = install_name_printf(scope, info, *s, &dst);
+ if (q < 0) {
+ unit_file_changes_add(changes, n_changes, q, *s, NULL);
+ r = r < 0 ? r : q;
+ continue;
+ }
- q = unit_file_verify_alias(i, dst, &dst_updated);
- if (q < 0)
+ q = unit_file_verify_alias(info, dst, &dst_updated, changes, n_changes);
+ if (q == -ELOOP)
continue;
+ if (q < 0) {
+ r = r < 0 ? r : q;
+ continue;
+ }
alias_path = path_make_absolute(dst_updated ?: dst, config_path);
if (!alias_path)
return -ENOMEM;
- q = create_symlink(paths, i->path, alias_path, force, changes, n_changes);
- if (r == 0)
- r = q;
+ q = create_symlink(lp, info->path, alias_path, force, changes, n_changes);
+ r = r < 0 ? r : q;
}
return r;
}
static int install_info_symlink_wants(
- UnitFileScope scope,
+ LookupScope scope,
UnitFileFlags file_flags,
- UnitFileInstallInfo *i,
- const LookupPaths *paths,
+ UnitFileInstallInfo *info,
+ const LookupPaths *lp,
const char *config_path,
char **list,
const char *suffix,
_cleanup_free_ char *buf = NULL;
UnitNameFlags valid_dst_type = UNIT_NAME_ANY;
const char *n;
- char **s;
int r = 0, q;
- assert(i);
- assert(paths);
+ assert(info);
+ assert(lp);
assert(config_path);
if (strv_isempty(list))
return 0;
- if (unit_name_is_valid(i->name, UNIT_NAME_PLAIN | UNIT_NAME_INSTANCE))
+ if (unit_name_is_valid(info->name, UNIT_NAME_PLAIN | UNIT_NAME_INSTANCE))
/* Not a template unit. Use the name directly. */
- n = i->name;
+ n = info->name;
- else if (i->default_instance) {
+ else if (info->default_instance) {
UnitFileInstallInfo instance = {
.type = _UNIT_FILE_TYPE_INVALID,
};
/* If this is a template, and we have a default instance, use it. */
- r = unit_name_replace_instance(i->name, i->default_instance, &buf);
+ r = unit_name_replace_instance(info->name, info->default_instance, &buf);
if (r < 0)
return r;
instance.name = buf;
- r = unit_file_search(NULL, &instance, paths, SEARCH_FOLLOW_CONFIG_SYMLINKS);
+ r = unit_file_search(NULL, &instance, lp, SEARCH_FOLLOW_CONFIG_SYMLINKS);
if (r < 0)
return r;
* the instance from that unit. Cannot be used with non-instance units. */
valid_dst_type = UNIT_NAME_INSTANCE | UNIT_NAME_TEMPLATE;
- n = i->name;
+ n = info->name;
}
STRV_FOREACH(s, list) {
_cleanup_free_ char *path = NULL, *dst = NULL;
- q = install_name_printf(i, *s, i->root, &dst);
- if (q < 0)
+ q = install_name_printf(scope, info, *s, &dst);
+ if (q < 0) {
+ unit_file_changes_add(changes, n_changes, q, *s, NULL);
return q;
+ }
if (!unit_name_is_valid(dst, valid_dst_type)) {
/* Generate a proper error here: EUCLEAN if the name is generally bad, EIDRM if the
if (!path)
return -ENOMEM;
- q = create_symlink(paths, i->path, path, true, changes, n_changes);
+ q = create_symlink(lp, info->path, path, true, changes, n_changes);
if (r == 0)
r = q;
- if (unit_file_exists(scope, paths, dst) == 0)
- unit_file_changes_add(changes, n_changes, UNIT_FILE_DESTINATION_NOT_PRESENT, dst, i->path);
+ if (unit_file_exists(scope, lp, dst) == 0)
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_DESTINATION_NOT_PRESENT, dst, info->path);
}
return r;
}
static int install_info_symlink_link(
- UnitFileInstallInfo *i,
- const LookupPaths *paths,
+ UnitFileInstallInfo *info,
+ const LookupPaths *lp,
const char *config_path,
bool force,
UnitFileChange **changes,
_cleanup_free_ char *path = NULL;
int r;
- assert(i);
- assert(paths);
+ assert(info);
+ assert(lp);
assert(config_path);
- assert(i->path);
+ assert(info->path);
- r = in_search_path(paths, i->path);
+ r = in_search_path(lp, info->path);
if (r < 0)
return r;
if (r > 0)
return 0;
- path = path_join(config_path, i->name);
+ path = path_join(config_path, info->name);
if (!path)
return -ENOMEM;
- return create_symlink(paths, i->path, path, force, changes, n_changes);
+ return create_symlink(lp, info->path, path, force, changes, n_changes);
}
static int install_info_apply(
- UnitFileScope scope,
+ LookupScope scope,
UnitFileFlags file_flags,
- UnitFileInstallInfo *i,
- const LookupPaths *paths,
+ UnitFileInstallInfo *info,
+ const LookupPaths *lp,
const char *config_path,
UnitFileChange **changes,
size_t *n_changes) {
int r, q;
- assert(i);
- assert(paths);
+ assert(info);
+ assert(lp);
assert(config_path);
- if (i->type != UNIT_FILE_TYPE_REGULAR)
+ if (info->type != UNIT_FILE_TYPE_REGULAR)
return 0;
bool force = file_flags & UNIT_FILE_FORCE;
- r = install_info_symlink_alias(i, paths, config_path, force, changes, n_changes);
+ r = install_info_symlink_link(info, lp, config_path, force, changes, n_changes);
+ /* Do not count links to the unit file towards the "carries_install_info" count */
+ if (r < 0)
+ /* If linking of the file failed, do not try to create other symlinks,
+ * because they might would pointing to a non-existent or wrong unit. */
+ return r;
- q = install_info_symlink_wants(scope, file_flags, i, paths, config_path, i->wanted_by, ".wants/", changes, n_changes);
- if (r == 0)
- r = q;
+ r = install_info_symlink_alias(scope, info, lp, config_path, force, changes, n_changes);
- q = install_info_symlink_wants(scope, file_flags, i, paths, config_path, i->required_by, ".requires/", changes, n_changes);
+ q = install_info_symlink_wants(scope, file_flags, info, lp, config_path, info->wanted_by, ".wants/", changes, n_changes);
if (r == 0)
r = q;
- q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
- /* Do not count links to the unit file towards the "carries_install_info" count */
- if (r == 0 && q < 0)
+ q = install_info_symlink_wants(scope, file_flags, info, lp, config_path, info->required_by, ".requires/", changes, n_changes);
+ if (r == 0)
r = q;
return r;
}
static int install_context_apply(
- UnitFileScope scope,
+ InstallContext *ctx,
+ const LookupPaths *lp,
UnitFileFlags file_flags,
- InstallContext *c,
- const LookupPaths *paths,
const char *config_path,
SearchFlags flags,
UnitFileChange **changes,
UnitFileInstallInfo *i;
int r;
- assert(c);
- assert(paths);
+ assert(ctx);
+ assert(lp);
assert(config_path);
- if (ordered_hashmap_isempty(c->will_process))
+ if (ordered_hashmap_isempty(ctx->will_process))
return 0;
- r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops);
+ r = ordered_hashmap_ensure_allocated(&ctx->have_processed, &string_hash_ops);
if (r < 0)
return r;
r = 0;
- while ((i = ordered_hashmap_first(c->will_process))) {
+ while ((i = ordered_hashmap_first(ctx->will_process))) {
int q;
- q = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name);
+ q = ordered_hashmap_move_one(ctx->have_processed, ctx->will_process, i->name);
if (q < 0)
return q;
- q = install_info_traverse(scope, c, paths, i, flags, NULL);
+ q = install_info_traverse(ctx, lp, i, flags, NULL);
if (q < 0) {
if (i->auxiliary) {
q = unit_file_changes_add(changes, n_changes, UNIT_FILE_AUXILIARY_FAILED, NULL, i->name);
if (i->type != UNIT_FILE_TYPE_REGULAR)
continue;
- q = install_info_apply(scope, file_flags, i, paths, config_path, changes, n_changes);
+ q = install_info_apply(ctx->scope, file_flags, i, lp, config_path, changes, n_changes);
if (r >= 0) {
if (q < 0)
r = q;
}
static int install_context_mark_for_removal(
- UnitFileScope scope,
- InstallContext *c,
- const LookupPaths *paths,
+ InstallContext *ctx,
+ const LookupPaths *lp,
Set **remove_symlinks_to,
const char *config_path,
UnitFileChange **changes,
UnitFileInstallInfo *i;
int r;
- assert(c);
- assert(paths);
+ assert(ctx);
+ assert(lp);
assert(config_path);
/* Marks all items for removal */
- if (ordered_hashmap_isempty(c->will_process))
+ if (ordered_hashmap_isempty(ctx->will_process))
return 0;
- r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops);
+ r = ordered_hashmap_ensure_allocated(&ctx->have_processed, &string_hash_ops);
if (r < 0)
return r;
- while ((i = ordered_hashmap_first(c->will_process))) {
+ while ((i = ordered_hashmap_first(ctx->will_process))) {
- r = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name);
+ r = ordered_hashmap_move_one(ctx->have_processed, ctx->will_process, i->name);
if (r < 0)
return r;
- r = install_info_traverse(scope, c, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL);
+ r = install_info_traverse(ctx, lp, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL);
if (r == -ENOLINK) {
log_debug_errno(r, "Name %s leads to a dangling symlink, removing name.", i->name);
unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_DANGLING, i->path ?: i->name, NULL);
}
int unit_file_mask(
- UnitFileScope scope,
+ LookupScope scope,
UnitFileFlags flags,
const char *root_dir,
- char **files,
+ char **names,
UnitFileChange **changes,
size_t *n_changes) {
- _cleanup_(lookup_paths_free) LookupPaths paths = {};
+ _cleanup_(lookup_paths_free) LookupPaths lp = {};
const char *config_path;
- char **i;
int r;
assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
+ assert(scope < _LOOKUP_SCOPE_MAX);
- r = lookup_paths_init(&paths, scope, 0, root_dir);
+ r = lookup_paths_init(&lp, scope, 0, root_dir);
if (r < 0)
return r;
- config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
+ config_path = (flags & UNIT_FILE_RUNTIME) ? lp.runtime_config : lp.persistent_config;
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;
- q = create_symlink(&paths, "/dev/null", path, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
+ q = create_symlink(&lp, "/dev/null", path, flags & UNIT_FILE_FORCE, changes, n_changes);
if (q < 0 && r >= 0)
r = q;
}
}
int unit_file_unmask(
- UnitFileScope scope,
+ LookupScope scope,
UnitFileFlags flags,
const char *root_dir,
- char **files,
+ char **names,
UnitFileChange **changes,
size_t *n_changes) {
- _cleanup_(lookup_paths_free) LookupPaths paths = {};
+ _cleanup_(lookup_paths_free) LookupPaths lp = {};
_cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
_cleanup_strv_free_ char **todo = NULL;
const char *config_path;
size_t n_todo = 0;
- bool dry_run;
- char **i;
int r, q;
assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
+ assert(scope < _LOOKUP_SCOPE_MAX);
- r = lookup_paths_init(&paths, scope, 0, root_dir);
+ r = lookup_paths_init(&lp, scope, 0, root_dir);
if (r < 0)
return r;
- config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
+ config_path = (flags & UNIT_FILE_RUNTIME) ? lp.runtime_config : lp.persistent_config;
if (!config_path)
return -ENXIO;
- dry_run = !!(flags & UNIT_FILE_DRY_RUN);
+ 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;
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;
unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
- rp = skip_root(&paths, path);
+ rp = skip_root(lp.root_dir, 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);
+ q = remove_marked_symlinks(remove_symlinks_to, config_path, &lp, dry_run, changes, n_changes);
if (r >= 0)
r = q;
}
int unit_file_link(
- UnitFileScope scope,
+ LookupScope scope,
UnitFileFlags flags,
const char *root_dir,
char **files,
UnitFileChange **changes,
size_t *n_changes) {
- _cleanup_(lookup_paths_free) LookupPaths paths = {};
+ _cleanup_(lookup_paths_free) LookupPaths lp = {};
_cleanup_strv_free_ char **todo = NULL;
const char *config_path;
size_t n_todo = 0;
- char **i;
int r, q;
assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
+ assert(scope < _LOOKUP_SCOPE_MAX);
- r = lookup_paths_init(&paths, scope, 0, root_dir);
+ r = lookup_paths_init(&lp, scope, 0, root_dir);
if (r < 0)
return r;
- config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
+ config_path = (flags & UNIT_FILE_RUNTIME) ? lp.runtime_config : lp.persistent_config;
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(paths.root_dir, *i);
+ full = path_join(lp.root_dir, *file);
if (!full)
return -ENOMEM;
if (r < 0)
return r;
- q = in_search_path(&paths, *i);
+ q = in_search_path(&lp, *file);
if (q < 0)
return q;
if (q > 0)
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;
if (!new_path)
return -ENOMEM;
- q = create_symlink(&paths, *i, new_path, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
+ q = create_symlink(&lp, *i, new_path, flags & UNIT_FILE_FORCE, changes, n_changes);
if (q < 0 && r >= 0)
r = q;
}
return r;
}
-static int path_shall_revert(const LookupPaths *paths, const char *path) {
+static int path_shall_revert(const LookupPaths *lp, const char *path) {
int r;
- assert(paths);
+ assert(lp);
assert(path);
/* Checks whether the path is one where the drop-in directories shall be removed. */
- r = path_is_config(paths, path, true);
+ r = path_is_config(lp, path, true);
if (r != 0)
return r;
- r = path_is_control(paths, path);
+ r = path_is_control(lp, path);
if (r != 0)
return r;
- return path_is_transient(paths, path);
+ return path_is_transient(lp, path);
}
int unit_file_revert(
- UnitFileScope scope,
+ LookupScope scope,
const char *root_dir,
- char **files,
+ char **names,
UnitFileChange **changes,
size_t *n_changes) {
_cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
- _cleanup_(lookup_paths_free) LookupPaths paths = {};
+ _cleanup_(lookup_paths_free) LookupPaths lp = {};
_cleanup_strv_free_ char **todo = NULL;
size_t n_todo = 0;
- char **i;
int r, q;
/* 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.
*/
- r = lookup_paths_init(&paths, scope, 0, root_dir);
+ r = lookup_paths_init(&lp, scope, 0, root_dir);
if (r < 0)
return r;
- STRV_FOREACH(i, files) {
+ STRV_FOREACH(name, names) {
bool has_vendor = false;
- char **p;
- if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
+ if (!unit_name_is_valid(*name, UNIT_NAME_ANY))
return -EINVAL;
- STRV_FOREACH(p, paths.search_path) {
+ 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;
return -errno;
} else if (S_ISREG(st.st_mode)) {
/* Check if there's a vendor version */
- r = path_is_vendor_or_generator(&paths, path);
+ r = path_is_vendor_or_generator(&lp, path);
if (r < 0)
return r;
if (r > 0)
return -errno;
} else if (S_ISDIR(st.st_mode)) {
/* Remove the drop-ins */
- r = path_shall_revert(&paths, dropin);
+ r = path_shall_revert(&lp, dropin);
if (r < 0)
return r;
if (r > 0) {
continue;
/* OK, there's a vendor version, hence drop all configuration versions */
- STRV_FOREACH(p, paths.search_path) {
+ STRV_FOREACH(p, lp.search_path) {
_cleanup_free_ char *path = NULL;
struct stat st;
- path = path_make_absolute(*i, *p);
+ path = path_make_absolute(*name, *p);
if (!path)
return -ENOMEM;
if (errno != ENOENT)
return -errno;
} else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
- r = path_is_config(&paths, path, true);
+ r = path_is_config(&lp, path, true);
if (r < 0)
return r;
if (r > 0) {
STRV_FOREACH(i, todo) {
_cleanup_strv_free_ char **fs = NULL;
const char *rp;
- char **j;
(void) get_files_in_directory(*i, &fs);
unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, *i, NULL);
- rp = skip_root(&paths, *i);
+ rp = skip_root(lp.root_dir, *i);
q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: *i);
if (q < 0)
return q;
}
- q = remove_marked_symlinks(remove_symlinks_to, paths.runtime_config, &paths, false, changes, n_changes);
+ q = remove_marked_symlinks(remove_symlinks_to, lp.runtime_config, &lp, false, changes, n_changes);
if (r >= 0)
r = q;
- q = remove_marked_symlinks(remove_symlinks_to, paths.persistent_config, &paths, false, changes, n_changes);
+ q = remove_marked_symlinks(remove_symlinks_to, lp.persistent_config, &lp, false, changes, n_changes);
if (r >= 0)
r = q;
}
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,
size_t *n_changes) {
- _cleanup_(lookup_paths_free) LookupPaths paths = {};
- _cleanup_(install_context_done) InstallContext c = {};
- UnitFileInstallInfo *i, *target_info;
+ _cleanup_(lookup_paths_free) LookupPaths lp = {};
+ _cleanup_(install_context_done) InstallContext ctx = { .scope = scope };
+ UnitFileInstallInfo *info, *target_info;
const char *config_path;
- char **f;
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))
if (!unit_name_is_valid(target, UNIT_NAME_ANY))
return -EINVAL;
- r = lookup_paths_init(&paths, scope, 0, root_dir);
+ r = lookup_paths_init(&lp, scope, 0, root_dir);
if (r < 0)
return r;
- config_path = (file_flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
+ config_path = (file_flags & UNIT_FILE_RUNTIME) ? lp.runtime_config : lp.persistent_config;
if (!config_path)
return -ENXIO;
- r = install_info_discover_and_check(scope, &c, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS,
+ r = install_info_discover_and_check(&ctx, &lp, target, SEARCH_FOLLOW_CONFIG_SYMLINKS,
&target_info, changes, n_changes);
if (r < 0)
return r;
assert(target_info->type == UNIT_FILE_TYPE_REGULAR);
- STRV_FOREACH(f, files) {
+ STRV_FOREACH(name, names) {
char ***l;
- r = install_info_discover_and_check(scope, &c, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS,
- &i, changes, n_changes);
+ r = install_info_discover_and_check(&ctx, &lp, *name,
+ SEARCH_FOLLOW_CONFIG_SYMLINKS,
+ &info, changes, n_changes);
if (r < 0)
return r;
- assert(i->type == UNIT_FILE_TYPE_REGULAR);
+ assert(info->type == UNIT_FILE_TYPE_REGULAR);
/* We didn't actually load anything from the unit
* file, but instead just add in our new symlink to
* create. */
if (dep == UNIT_WANTS)
- l = &i->wanted_by;
+ l = &info->wanted_by;
else
- l = &i->required_by;
+ l = &info->required_by;
strv_free(*l);
*l = strv_new(target_info->name);
return -ENOMEM;
}
- return install_context_apply(scope, file_flags, &c, &paths, config_path,
+ return install_context_apply(&ctx, &lp, file_flags, config_path,
SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes);
}
+static int do_unit_file_enable(
+ const LookupPaths *lp,
+ LookupScope scope,
+ UnitFileFlags flags,
+ const char *config_path,
+ char **names_or_paths,
+ UnitFileChange **changes,
+ size_t *n_changes) {
+
+ _cleanup_(install_context_done) InstallContext ctx = { .scope = scope };
+ UnitFileInstallInfo *info;
+ int r;
+
+ 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;
+
+ assert(info->type == UNIT_FILE_TYPE_REGULAR);
+ }
+
+ /* 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 units had any
+ installation data at all. */
+
+ return install_context_apply(&ctx, lp, flags, config_path,
+ SEARCH_LOAD, changes, n_changes);
+}
+
int unit_file_enable(
- UnitFileScope scope,
- UnitFileFlags file_flags,
+ LookupScope scope,
+ UnitFileFlags flags,
const char *root_dir,
- char **files,
+ char **names_or_paths,
UnitFileChange **changes,
size_t *n_changes) {
- _cleanup_(lookup_paths_free) LookupPaths paths = {};
- _cleanup_(install_context_done) InstallContext c = {};
- const char *config_path;
- UnitFileInstallInfo *i;
- char **f;
+ _cleanup_(lookup_paths_free) LookupPaths lp = {};
int r;
assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
+ assert(scope < _LOOKUP_SCOPE_MAX);
- r = lookup_paths_init(&paths, scope, 0, root_dir);
+ r = lookup_paths_init(&lp, scope, 0, root_dir);
if (r < 0)
return r;
- config_path = config_path_from_flags(&paths, file_flags);
+ const char *config_path = config_path_from_flags(&lp, flags);
if (!config_path)
return -ENXIO;
- STRV_FOREACH(f, files) {
- r = install_info_discover_and_check(scope, &c, &paths, *f, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
- &i, 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,
+ LookupScope scope,
+ UnitFileFlags flags,
+ const char *config_path,
+ char **names,
+ UnitFileChange **changes,
+ size_t *n_changes) {
+
+ _cleanup_(install_context_done) InstallContext ctx = { .scope = scope };
+ _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
+ int r;
+
+ STRV_FOREACH(name, names) {
+ if (!unit_name_is_valid(*name, UNIT_NAME_ANY))
+ return -EINVAL;
+
+ r = install_info_add(&ctx, *name, NULL, lp->root_dir, /* auxiliary= */ false, NULL);
if (r < 0)
return r;
-
- assert(i->type == UNIT_FILE_TYPE_REGULAR);
}
- /* 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
- installation data at all. */
+ r = install_context_mark_for_removal(&ctx, lp, &remove_symlinks_to, config_path, changes, n_changes);
+ if (r < 0)
+ return r;
- return install_context_apply(scope, file_flags, &c, &paths, config_path, SEARCH_LOAD, changes, n_changes);
+ return remove_marked_symlinks(remove_symlinks_to, config_path, lp, flags & UNIT_FILE_DRY_RUN, changes, n_changes);
}
+
int unit_file_disable(
- UnitFileScope scope,
+ LookupScope scope,
UnitFileFlags flags,
const char *root_dir,
char **files,
UnitFileChange **changes,
size_t *n_changes) {
- _cleanup_(lookup_paths_free) LookupPaths paths = {};
- _cleanup_(install_context_done) InstallContext c = {};
- _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
- const char *config_path;
- char **i;
+ _cleanup_(lookup_paths_free) LookupPaths lp = {};
int r;
assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
+ assert(scope < _LOOKUP_SCOPE_MAX);
- r = lookup_paths_init(&paths, scope, 0, root_dir);
+ r = lookup_paths_init(&lp, scope, 0, root_dir);
if (r < 0)
return r;
- config_path = config_path_from_flags(&paths, flags);
+ const char *config_path = config_path_from_flags(&lp, flags);
if (!config_path)
return -ENXIO;
- STRV_FOREACH(i, files) {
- if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
- return -EINVAL;
+ return do_unit_file_disable(&lp, scope, flags, config_path, files, changes, n_changes);
+}
+
+static int normalize_linked_files(
+ LookupScope scope,
+ const LookupPaths *lp,
+ char **names_or_paths,
+ char ***ret_names,
+ char ***ret_files) {
- r = install_info_add(&c, *i, NULL, paths.root_dir, /* auxiliary= */ false, NULL);
+ /* 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 re-enabled successfully. */
+
+ _cleanup_strv_free_ char **files = NULL, **names = NULL;
+ int r;
+
+ STRV_FOREACH(a, names_or_paths) {
+ _cleanup_(install_context_done) InstallContext ctx = { .scope = scope };
+ UnitFileInstallInfo *i = NULL;
+ _cleanup_free_ char *n = NULL;
+
+ r = path_extract_filename(*a, &n);
if (r < 0)
return r;
- }
+ if (r == O_DIRECTORY)
+ return log_debug_errno(SYNTHETIC_ERRNO(EISDIR),
+ "Unexpected path to a directory \"%s\", refusing.", *a);
- r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, config_path, changes, n_changes);
- if (r < 0)
- return r;
+ if (!is_path(*a)) {
+ r = install_info_discover(&ctx, lp, n, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i, NULL, NULL);
+ if (r < 0)
+ log_debug_errno(r, "Failed to discover unit \"%s\", operating on name: %m", n);
+ }
- return remove_marked_symlinks(remove_symlinks_to, config_path, &paths, !!(flags & UNIT_FILE_DRY_RUN), changes, n_changes);
+ r = strv_consume(&names, TAKE_PTR(n));
+ if (r < 0)
+ return r;
+
+ const char *p = NULL;
+ 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.
+ *
+ * In other words: /var/tmp/instroot.1234/etc/systemd/system/frobnicator.service
+ * is replaced by /etc/systemd/system/frobnicator.service, which is "absolute"
+ * in a sense, but only makes sense "relative" to /var/tmp/instroot.1234/.
+ */
+ p = startswith(i->path, i->root);
+
+ r = strv_extend(&files, p ?: *a);
+ if (r < 0)
+ return r;
+ }
+
+ *ret_names = TAKE_PTR(names);
+ *ret_files = TAKE_PTR(files);
+ return 0;
}
int unit_file_reenable(
- UnitFileScope scope,
+ LookupScope scope,
UnitFileFlags flags,
const char *root_dir,
- char **files,
+ char **names_or_paths,
UnitFileChange **changes,
size_t *n_changes) {
- char **n;
+ _cleanup_(lookup_paths_free) LookupPaths lp = {};
+ _cleanup_strv_free_ char **names = NULL, **files = NULL;
int r;
- size_t l, i;
- /* First, we invoke the disable command with only the basename... */
- l = strv_length(files);
- n = newa(char*, l+1);
- for (i = 0; i < l; i++)
- n[i] = basename(files[i]);
- n[i] = NULL;
+ assert(scope >= 0);
+ assert(scope < _LOOKUP_SCOPE_MAX);
+
+ r = lookup_paths_init(&lp, scope, 0, root_dir);
+ if (r < 0)
+ return r;
+
+ const char *config_path = config_path_from_flags(&lp, flags);
+ if (!config_path)
+ return -ENXIO;
- r = unit_file_disable(scope, flags, root_dir, n, changes, n_changes);
+ r = normalize_linked_files(scope, &lp, names_or_paths, &names, &files);
+ if (r < 0)
+ return r;
+
+ /* First, we invoke the disable command with only the basename... */
+ r = do_unit_file_disable(&lp, scope, flags, config_path, names, changes, n_changes);
if (r < 0)
return r;
/* But the enable command with the full name */
- return unit_file_enable(scope, flags, root_dir, files, changes, n_changes);
+ return do_unit_file_enable(&lp, scope, flags, config_path, files, changes, n_changes);
}
int unit_file_set_default(
- UnitFileScope scope,
+ LookupScope scope,
UnitFileFlags flags,
const char *root_dir,
const char *name,
UnitFileChange **changes,
size_t *n_changes) {
- _cleanup_(lookup_paths_free) LookupPaths paths = {};
- _cleanup_(install_context_done) InstallContext c = {};
- UnitFileInstallInfo *i;
+ _cleanup_(lookup_paths_free) LookupPaths lp = {};
+ _cleanup_(install_context_done) InstallContext ctx = { .scope = scope };
+ UnitFileInstallInfo *info;
const char *new_path;
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 */
if (streq(name, SPECIAL_DEFAULT_TARGET))
return -EINVAL;
- r = lookup_paths_init(&paths, scope, 0, root_dir);
+ r = lookup_paths_init(&lp, scope, 0, root_dir);
if (r < 0)
return r;
- r = install_info_discover_and_check(scope, &c, &paths, name, 0, &i, changes, n_changes);
+ r = install_info_discover_and_check(&ctx, &lp, name, 0, &info, changes, n_changes);
if (r < 0)
return r;
- new_path = strjoina(paths.persistent_config, "/" SPECIAL_DEFAULT_TARGET);
- return create_symlink(&paths, i->path, new_path, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
+ new_path = strjoina(lp.persistent_config, "/" SPECIAL_DEFAULT_TARGET);
+ 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) {
- _cleanup_(lookup_paths_free) LookupPaths paths = {};
- _cleanup_(install_context_done) InstallContext c = {};
- UnitFileInstallInfo *i;
+ _cleanup_(lookup_paths_free) LookupPaths lp = {};
+ _cleanup_(install_context_done) InstallContext ctx = { .scope = scope };
+ UnitFileInstallInfo *info;
char *n;
int r;
assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
+ assert(scope < _LOOKUP_SCOPE_MAX);
assert(name);
- r = lookup_paths_init(&paths, scope, 0, root_dir);
+ r = lookup_paths_init(&lp, scope, 0, root_dir);
if (r < 0)
return r;
- r = install_info_discover(scope, &c, &paths, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS,
- &i, NULL, NULL);
+ r = install_info_discover(&ctx, &lp, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS,
+ &info, NULL, NULL);
if (r < 0)
return r;
- r = install_info_may_process(i, &paths, NULL, 0);
+ r = install_info_may_process(info, &lp, NULL, 0);
if (r < 0)
return r;
- n = strdup(i->name);
+ n = strdup(info->name);
if (!n)
return -ENOMEM;
}
int unit_file_lookup_state(
- UnitFileScope scope,
- const LookupPaths *paths,
+ LookupScope scope,
+ const LookupPaths *lp,
const char *name,
UnitFileState *ret) {
- _cleanup_(install_context_done) InstallContext c = {};
- UnitFileInstallInfo *i;
+ _cleanup_(install_context_done) InstallContext ctx = { .scope = scope };
+ UnitFileInstallInfo *info;
UnitFileState state;
int r;
- assert(paths);
+ assert(lp);
assert(name);
if (!unit_name_is_valid(name, UNIT_NAME_ANY))
return -EINVAL;
- r = install_info_discover(scope, &c, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
- &i, NULL, NULL);
+ r = install_info_discover(&ctx, lp, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
+ &info, NULL, NULL);
if (r < 0)
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");
+ assert(IN_SET(info->type, UNIT_FILE_TYPE_REGULAR, UNIT_FILE_TYPE_MASKED));
+ log_debug("Found unit %s at %s (%s)", name, strna(info->path),
+ info->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;
- switch (i->type) {
+ switch (info->type) {
case UNIT_FILE_TYPE_MASKED:
- r = path_is_runtime(paths, i->path, true);
+ r = path_is_runtime(lp, info->path, true);
if (r < 0)
return r;
case UNIT_FILE_TYPE_REGULAR:
/* Check if the name we were querying is actually an alias */
- if (!streq(name, basename(i->path)) && !unit_name_is_valid(i->name, UNIT_NAME_INSTANCE)) {
+ if (!streq(name, basename(info->path)) && !unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
state = UNIT_FILE_ALIAS;
break;
}
- r = path_is_generator(paths, i->path);
+ r = path_is_generator(lp, info->path);
if (r < 0)
return r;
if (r > 0) {
break;
}
- r = path_is_transient(paths, i->path);
+ r = path_is_transient(lp, info->path);
if (r < 0)
return r;
if (r > 0) {
/* Check if any of the Alias= symlinks have been created.
* We ignore other aliases, and only check those that would
* be created by systemctl enable for this unit. */
- r = find_symlinks_in_scope(scope, paths, i, true, &state);
+ r = find_symlinks_in_scope(scope, lp, info, true, &state);
if (r < 0)
return r;
if (r > 0)
/* Check if the file is known under other names. If it is,
* it might be in use. Report that as UNIT_FILE_INDIRECT. */
- r = find_symlinks_in_scope(scope, paths, i, false, &state);
+ r = find_symlinks_in_scope(scope, lp, info, false, &state);
if (r < 0)
return r;
if (r > 0)
state = UNIT_FILE_INDIRECT;
else {
- if (unit_file_install_info_has_rules(i))
+ if (unit_file_install_info_has_rules(info))
state = UNIT_FILE_DISABLED;
- else if (unit_file_install_info_has_also(i))
+ else if (unit_file_install_info_has_also(info))
state = UNIT_FILE_INDIRECT;
else
state = UNIT_FILE_STATIC;
}
int unit_file_get_state(
- UnitFileScope scope,
+ LookupScope scope,
const char *root_dir,
const char *name,
UnitFileState *ret) {
- _cleanup_(lookup_paths_free) LookupPaths paths = {};
+ _cleanup_(lookup_paths_free) LookupPaths lp = {};
int r;
assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
+ assert(scope < _LOOKUP_SCOPE_MAX);
assert(name);
- r = lookup_paths_init(&paths, scope, 0, root_dir);
+ r = lookup_paths_init(&lp, scope, 0, root_dir);
if (r < 0)
return r;
- return unit_file_lookup_state(scope, &paths, name, ret);
+ return unit_file_lookup_state(scope, &lp, name, ret);
}
-int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name) {
- _cleanup_(install_context_done) InstallContext c = {};
+int unit_file_exists(LookupScope scope, const LookupPaths *lp, const char *name) {
+ _cleanup_(install_context_done) InstallContext c = { .scope = scope };
int r;
- assert(paths);
+ assert(lp);
assert(name);
if (!unit_name_is_valid(name, UNIT_NAME_ANY))
return -EINVAL;
- r = install_info_discover(scope, &c, paths, name, 0, NULL, NULL, NULL);
+ r = install_info_discover(&c, lp, name, 0, NULL, NULL, NULL);
if (r == -ENOENT)
return 0;
if (r < 0)
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();
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;
- char **p;
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);
if (unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
_cleanup_strv_free_ char **out_strv = NULL;
- char **iter;
STRV_FOREACH(iter, rule.instances) {
_cleanup_free_ char *name = NULL;
log_debug("Preset files don't specify rule for %s. Enabling.", name);
return 1;
case PRESET_ENABLE:
- if (instance_name_list && *instance_name_list) {
- char **s;
+ if (instance_name_list && *instance_name_list)
STRV_FOREACH(s, *instance_name_list)
log_debug("Preset files say enable %s.", *s);
- } else
+ else
log_debug("Preset files say enable %s.", name);
return 1;
case PRESET_DISABLE:
}
}
-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;
}
static int execute_preset(
- UnitFileScope scope,
UnitFileFlags file_flags,
InstallContext *plus,
InstallContext *minus,
- const LookupPaths *paths,
+ const LookupPaths *lp,
const char *config_path,
char **files,
UnitFilePresetMode mode,
assert(plus);
assert(minus);
- assert(paths);
+ assert(lp);
assert(config_path);
if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) {
_cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
- r = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, config_path, changes, n_changes);
+ r = install_context_mark_for_removal(minus, lp, &remove_symlinks_to, config_path, changes, n_changes);
if (r < 0)
return r;
- r = remove_marked_symlinks(remove_symlinks_to, config_path, paths, false, changes, n_changes);
+ r = remove_marked_symlinks(remove_symlinks_to, config_path, lp, false, changes, n_changes);
} else
r = 0;
int q;
/* Returns number of symlinks that where supposed to be installed. */
- q = install_context_apply(scope,
+ q = install_context_apply(plus, lp,
file_flags | UNIT_FILE_IGNORE_AUXILIARY_FAILURE,
- plus, paths, config_path, SEARCH_LOAD, changes, n_changes);
+ config_path,
+ SEARCH_LOAD, changes, n_changes);
if (r >= 0) {
if (q < 0)
r = q;
}
static int preset_prepare_one(
- UnitFileScope scope,
+ LookupScope scope,
InstallContext *plus,
InstallContext *minus,
- LookupPaths *paths,
+ LookupPaths *lp,
const char *name,
const UnitFilePresets *presets,
UnitFileChange **changes,
size_t *n_changes) {
- _cleanup_(install_context_done) InstallContext tmp = {};
+ _cleanup_(install_context_done) InstallContext tmp = { .scope = scope };
_cleanup_strv_free_ char **instance_name_list = NULL;
- UnitFileInstallInfo *i;
+ UnitFileInstallInfo *info;
int r;
if (install_info_find(plus, name) || install_info_find(minus, name))
return 0;
- r = install_info_discover(scope, &tmp, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS,
- &i, changes, n_changes);
+ r = install_info_discover(&tmp, lp, name, SEARCH_FOLLOW_CONFIG_SYMLINKS,
+ &info, changes, n_changes);
if (r < 0)
return r;
- if (!streq(name, i->name)) {
- log_debug("Skipping %s because it is an alias for %s.", name, i->name);
+ if (!streq(name, info->name)) {
+ log_debug("Skipping %s because it is an alias for %s.", name, info->name);
return 0;
}
return r;
if (r > 0) {
- if (instance_name_list) {
- char **s;
+ if (instance_name_list)
STRV_FOREACH(s, instance_name_list) {
- r = install_info_discover_and_check(scope, plus, paths, *s, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
- &i, changes, n_changes);
+ r = install_info_discover_and_check(plus, lp, *s, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
+ &info, changes, n_changes);
if (r < 0)
return r;
}
- } else {
- r = install_info_discover_and_check(scope, plus, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
- &i, changes, n_changes);
+ else {
+ r = install_info_discover_and_check(plus, lp, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
+ &info, changes, n_changes);
if (r < 0)
return r;
}
} else
- r = install_info_discover(scope, minus, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS,
- &i, changes, n_changes);
+ r = install_info_discover(minus, lp, name, SEARCH_FOLLOW_CONFIG_SYMLINKS,
+ &info, changes, n_changes);
return r;
}
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) {
_cleanup_(install_context_done) InstallContext plus = {}, minus = {};
- _cleanup_(lookup_paths_free) LookupPaths paths = {};
+ _cleanup_(lookup_paths_free) LookupPaths lp = {};
_cleanup_(unit_file_presets_freep) UnitFilePresets presets = {};
const char *config_path;
- char **i;
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(&paths, scope, 0, root_dir);
+ r = lookup_paths_init(&lp, scope, 0, root_dir);
if (r < 0)
return r;
- config_path = (file_flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
+ config_path = (file_flags & UNIT_FILE_RUNTIME) ? lp.runtime_config : lp.persistent_config;
if (!config_path)
return -ENXIO;
if (r < 0)
return r;
- STRV_FOREACH(i, files) {
- r = preset_prepare_one(scope, &plus, &minus, &paths, *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(scope, file_flags, &plus, &minus, &paths, 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,
size_t *n_changes) {
_cleanup_(install_context_done) InstallContext plus = {}, minus = {};
- _cleanup_(lookup_paths_free) LookupPaths paths = {};
+ _cleanup_(lookup_paths_free) LookupPaths lp = {};
_cleanup_(unit_file_presets_freep) UnitFilePresets presets = {};
const char *config_path = NULL;
- char **i;
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(&paths, scope, 0, root_dir);
+ r = lookup_paths_init(&lp, scope, 0, root_dir);
if (r < 0)
return r;
- config_path = (file_flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
+ config_path = (file_flags & UNIT_FILE_RUNTIME) ? lp.runtime_config : lp.persistent_config;
if (!config_path)
return -ENXIO;
if (r < 0)
return r;
- STRV_FOREACH(i, paths.search_path) {
+ STRV_FOREACH(i, lp.search_path) {
_cleanup_closedir_ DIR *d = NULL;
- struct dirent *de;
d = opendir(*i);
if (!d) {
if (!IN_SET(de->d_type, DT_LNK, DT_REG))
continue;
- r = preset_prepare_one(scope, &plus, &minus, &paths, de->d_name, &presets, changes, n_changes);
+ r = preset_prepare_one(scope, &plus, &minus, &lp, de->d_name, &presets, changes, n_changes);
if (r < 0 &&
- !IN_SET(r, -EEXIST, -ERFKILL, -EADDRNOTAVAIL, -EIDRM, -EUCLEAN, -ELOOP, -ENOENT))
+ !IN_SET(r, -EEXIST, -ERFKILL, -EADDRNOTAVAIL, -EBADSLT, -EIDRM, -EUCLEAN, -ELOOP, -ENOENT, -EUNATCH, -EXDEV))
/* Ignore generated/transient/missing/invalid units when applying preset, propagate other errors.
* Coordinate with unit_file_dump_changes() above. */
return r;
}
}
- return execute_preset(scope, file_flags, &plus, &minus, &paths, config_path, NULL, mode, changes, n_changes);
+ return execute_preset(file_flags, &plus, &minus, &lp, config_path, NULL, mode, changes, n_changes);
}
static UnitFileList* unit_file_list_free_one(UnitFileList *f) {
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,
char **patterns) {
- _cleanup_(lookup_paths_free) LookupPaths paths = {};
- char **dirname;
+ _cleanup_(lookup_paths_free) LookupPaths lp = {};
int r;
assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
+ assert(scope < _LOOKUP_SCOPE_MAX);
assert(h);
- r = lookup_paths_init(&paths, scope, 0, root_dir);
+ r = lookup_paths_init(&lp, scope, 0, root_dir);
if (r < 0)
return r;
- STRV_FOREACH(dirname, paths.search_path) {
+ STRV_FOREACH(dirname, lp.search_path) {
_cleanup_closedir_ DIR *d = NULL;
- struct dirent *de;
d = opendir(*dirname);
if (!d) {
if (!f->path)
return -ENOMEM;
- r = unit_file_lookup_state(scope, &paths, de->d_name, &f->state);
+ r = unit_file_lookup_state(scope, &lp, de->d_name, &f->state);
if (r < 0)
f->state = UNIT_FILE_BAD;