summaryrefslogtreecommitdiffstats
path: root/src/shared/install.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 03:50:40 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 03:50:40 +0000
commitfc53809803cd2bc2434e312b19a18fa36776da12 (patch)
treeb4b43bd6538f51965ce32856e9c053d0f90919c8 /src/shared/install.c
parentAdding upstream version 255.5. (diff)
downloadsystemd-fc53809803cd2bc2434e312b19a18fa36776da12.tar.xz
systemd-fc53809803cd2bc2434e312b19a18fa36776da12.zip
Adding upstream version 256.upstream/256
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/shared/install.c')
-rw-r--r--src/shared/install.c505
1 files changed, 290 insertions, 215 deletions
diff --git a/src/shared/install.c b/src/shared/install.c
index 27a421e..dd2bd5c 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -10,6 +10,7 @@
#include <unistd.h>
#include "alloc-util.h"
+#include "bus-common-errors.h"
#include "chase.h"
#include "conf-files.h"
#include "conf-parser.h"
@@ -161,9 +162,10 @@ static int path_is_generator(const LookupPaths *lp, const char *path) {
if (r < 0)
return r;
- return path_equal_ptr(parent, lp->generator) ||
- path_equal_ptr(parent, lp->generator_early) ||
- path_equal_ptr(parent, lp->generator_late);
+ return PATH_IN_SET(parent,
+ lp->generator,
+ lp->generator_early,
+ lp->generator_late);
}
static int path_is_transient(const LookupPaths *lp, const char *path) {
@@ -177,7 +179,7 @@ static int path_is_transient(const LookupPaths *lp, const char *path) {
if (r < 0)
return r;
- return path_equal_ptr(parent, lp->transient);
+ return path_equal(parent, lp->transient);
}
static int path_is_control(const LookupPaths *lp, const char *path) {
@@ -191,8 +193,9 @@ static int path_is_control(const LookupPaths *lp, const char *path) {
if (r < 0)
return r;
- return path_equal_ptr(parent, lp->persistent_control) ||
- path_equal_ptr(parent, lp->runtime_control);
+ return PATH_IN_SET(parent,
+ lp->persistent_control,
+ lp->runtime_control);
}
static int path_is_config(const LookupPaths *lp, const char *path, bool check_parent) {
@@ -213,8 +216,9 @@ static int path_is_config(const LookupPaths *lp, const char *path, bool check_pa
path = parent;
}
- return path_equal_ptr(path, lp->persistent_config) ||
- path_equal_ptr(path, lp->runtime_config);
+ return PATH_IN_SET(path,
+ lp->persistent_config,
+ lp->runtime_config);
}
static int path_is_runtime(const LookupPaths *lp, const char *path, bool check_parent) {
@@ -240,12 +244,13 @@ static int path_is_runtime(const LookupPaths *lp, const char *path, bool check_p
path = parent;
}
- 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);
+ return PATH_IN_SET(path,
+ lp->runtime_config,
+ lp->generator,
+ lp->generator_early,
+ lp->generator_late,
+ lp->transient,
+ lp->runtime_control);
}
static int path_is_vendor_or_generator(const LookupPaths *lp, const char *path) {
@@ -324,130 +329,176 @@ InstallChangeType install_changes_add(
void install_changes_free(InstallChange *changes, size_t n_changes) {
assert(changes || n_changes == 0);
- for (size_t i = 0; i < n_changes; i++) {
- free(changes[i].path);
- free(changes[i].source);
+ FOREACH_ARRAY(i, changes, n_changes) {
+ free(i->path);
+ free(i->source);
}
free(changes);
}
-void install_changes_dump(int r, const char *verb, const InstallChange *changes, size_t n_changes, bool quiet) {
- int err = 0;
+static void install_change_dump_success(const InstallChange *change) {
+ assert(change);
+ assert(change->path);
- assert(changes || n_changes == 0);
- /* If verb is not specified, errors are not allowed! */
- assert(verb || r >= 0);
+ switch (change->type) {
- for (size_t i = 0; i < n_changes; i++) {
- assert(changes[i].path);
- /* This tries to tell the compiler that it's safe to use 'verb' in a string format if there
- * was an error, but the compiler doesn't care and fails anyway, so strna(verb) is used
- * too. */
- assert(verb || changes[i].type >= 0);
- verb = strna(verb);
+ case INSTALL_CHANGE_SYMLINK:
+ return log_info("Created symlink '%s' %s '%s'.",
+ change->path, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), change->source);
- /* When making changes here, make sure to also change install_error() in dbus-manager.c. */
+ case INSTALL_CHANGE_UNLINK:
+ return log_info("Removed '%s'.", change->path);
- switch (changes[i].type) {
- case INSTALL_CHANGE_SYMLINK:
- if (!quiet)
- log_info("Created symlink %s %s %s.",
- changes[i].path,
- special_glyph(SPECIAL_GLYPH_ARROW_RIGHT),
- changes[i].source);
- break;
- case INSTALL_CHANGE_UNLINK:
- if (!quiet)
- log_info("Removed \"%s\".", changes[i].path);
- break;
- case INSTALL_CHANGE_IS_MASKED:
- if (!quiet)
- log_info("Unit %s is masked, ignoring.", changes[i].path);
- break;
- case INSTALL_CHANGE_IS_MASKED_GENERATOR:
- if (!quiet)
- log_info("Unit %s is masked via a generator and cannot be unmasked.",
- changes[i].path);
- break;
- case INSTALL_CHANGE_IS_DANGLING:
- if (!quiet)
- log_info("Unit %s is an alias to a unit that is not present, ignoring.",
- changes[i].path);
- break;
- case INSTALL_CHANGE_DESTINATION_NOT_PRESENT:
- if (!quiet)
- log_warning("Unit %s is added as a dependency to a non-existent unit %s.",
- changes[i].source, changes[i].path);
- break;
- case INSTALL_CHANGE_AUXILIARY_FAILED:
+ case INSTALL_CHANGE_IS_MASKED:
+ return log_info("Unit %s is masked, ignoring.", change->path);
+
+ case INSTALL_CHANGE_IS_MASKED_GENERATOR:
+ return log_info("Unit %s is masked via a generator and cannot be unmasked, skipping.", change->path);
+
+ case INSTALL_CHANGE_IS_DANGLING:
+ return log_info("Unit %s is an alias to a non-existent unit, ignoring.", change->path);
+
+ case INSTALL_CHANGE_DESTINATION_NOT_PRESENT:
+ return log_warning("Unit %s is added as a dependency to a non-existent unit %s.",
+ change->source, change->path);
+
+ case INSTALL_CHANGE_AUXILIARY_FAILED:
+ return log_warning("Failed to enable auxiliary unit %s, ignoring.", change->path);
+
+ default:
+ assert_not_reached();
+ }
+}
+
+int install_change_dump_error(const InstallChange *change, char **ret_errmsg, const char **ret_bus_error) {
+ char *m;
+ const char *bus_error;
+
+ /* Returns 0: known error and ret_errmsg formatted
+ * < 0: non-recognizable error */
+
+ assert(change);
+ assert(change->path);
+ assert(change->type < 0);
+ assert(ret_errmsg);
+
+ switch (change->type) {
+
+ case -EEXIST:
+ m = strjoin("File '", change->path, "' already exists",
+ change->source ? " and is a symlink to " : NULL, change->source);
+ bus_error = BUS_ERROR_UNIT_EXISTS;
+ break;
+
+ case -ERFKILL:
+ m = strjoin("Unit ", change->path, " is masked");
+ bus_error = BUS_ERROR_UNIT_MASKED;
+ break;
+
+ case -EADDRNOTAVAIL:
+ m = strjoin("Unit ", change->path, " is transient or generated");
+ bus_error = BUS_ERROR_UNIT_GENERATED;
+ break;
+
+ case -ETXTBSY:
+ m = strjoin("File '", change->path, "' is under the systemd unit hierarchy already");
+ bus_error = BUS_ERROR_UNIT_BAD_PATH;
+ break;
+
+ case -EBADSLT:
+ m = strjoin("Invalid specifier in unit ", change->path);
+ bus_error = BUS_ERROR_BAD_UNIT_SETTING;
+ break;
+
+ case -EIDRM:
+ m = strjoin("Refusing to operate on template unit ", change->source,
+ " when destination unit ", change->path, " is a non-template unit");
+ bus_error = BUS_ERROR_BAD_UNIT_SETTING;
+ break;
+
+ case -EUCLEAN:
+ m = strjoin("Invalid unit name ", change->path);
+ bus_error = BUS_ERROR_BAD_UNIT_SETTING;
+ break;
+
+ case -ELOOP:
+ m = strjoin("Refusing to operate on linked unit file ", change->path);
+ bus_error = BUS_ERROR_UNIT_LINKED;
+ break;
+
+ case -EXDEV:
+ if (change->source)
+ m = strjoin("Cannot alias ", change->source, " as ", change->path);
+ else
+ m = strjoin("Invalid unit reference ", change->path);
+ bus_error = BUS_ERROR_BAD_UNIT_SETTING;
+ break;
+
+ case -ENOENT:
+ m = strjoin("Unit ", change->path, " does not exist");
+ bus_error = BUS_ERROR_NO_SUCH_UNIT;
+ break;
+
+ case -ENOLINK:
+ m = strjoin("Unit ", change->path, " is an unresolvable alias");
+ bus_error = BUS_ERROR_NO_SUCH_UNIT;
+ break;
+
+ case -EUNATCH:
+ m = strjoin("Cannot resolve specifiers in unit ", change->path);
+ bus_error = BUS_ERROR_BAD_UNIT_SETTING;
+ break;
+
+ default:
+ return change->type;
+ }
+ if (!m)
+ return -ENOMEM;
+
+ *ret_errmsg = m;
+ if (ret_bus_error)
+ *ret_bus_error = bus_error;
+
+ return 0;
+}
+
+void install_changes_dump(
+ int error,
+ const char *verb,
+ const InstallChange *changes,
+ size_t n_changes,
+ bool quiet) {
+
+ bool err_logged = false;
+ int r;
+
+ /* If verb is not specified, errors are not allowed! */
+ assert(verb || error >= 0);
+ assert(changes || n_changes == 0);
+
+ FOREACH_ARRAY(i, changes, n_changes)
+ if (i->type >= 0) {
if (!quiet)
- log_warning("Failed to enable auxiliary unit %s, ignoring.", changes[i].path);
- break;
- case -EEXIST:
- if (changes[i].source)
- err = log_error_errno(changes[i].type,
- "Failed to %s unit, file \"%s\" already exists and is a symlink to \"%s\".",
- verb, changes[i].path, changes[i].source);
- else
- err = log_error_errno(changes[i].type,
- "Failed to %s unit, file \"%s\" already exists.",
- verb, changes[i].path);
- break;
- case -ERFKILL:
- err = log_error_errno(changes[i].type, "Failed to %s unit, unit %s is masked.",
- verb, changes[i].path);
- break;
- case -EADDRNOTAVAIL:
- err = log_error_errno(changes[i].type, "Failed to %s unit, unit %s is transient or generated.",
- verb, changes[i].path);
- break;
- case -ETXTBSY:
- err = log_error_errno(changes[i].type, "Failed to %s unit, file %s is under the systemd unit hierarchy already.",
- verb, changes[i].path);
- break;
- case -EBADSLT:
- err = log_error_errno(changes[i].type, "Failed to %s unit, invalid specifier in \"%s\".",
- verb, changes[i].path);
- break;
- case -EIDRM:
- err = log_error_errno(changes[i].type, "Failed to %s %s, destination unit %s is a non-template unit.",
- verb, changes[i].source, changes[i].path);
- break;
- case -EUCLEAN:
- err = log_error_errno(changes[i].type,
- "Failed to %s unit, \"%s\" is not a valid unit name.",
- verb, changes[i].path);
- break;
- case -ELOOP:
- err = log_error_errno(changes[i].type, "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, "Failed to %s unit, cannot alias %s as %s.",
- verb, changes[i].source, changes[i].path);
+ install_change_dump_success(i);
+ } else {
+ _cleanup_free_ char *err_message = NULL;
+
+ assert(verb);
+
+ r = install_change_dump_error(i, &err_message, /* ret_bus_error = */ NULL);
+ if (r == -ENOMEM)
+ return (void) log_oom();
+ if (r < 0)
+ log_error_errno(r, "Failed to %s unit %s: %m", verb, i->path);
else
- err = log_error_errno(changes[i].type, "Failed to %s unit, invalid unit reference \"%s\".",
- verb, changes[i].path);
- break;
- case -ENOENT:
- err = log_error_errno(changes[i].type, "Failed to %s unit, unit %s does not exist.",
- verb, changes[i].path);
- break;
- case -EUNATCH:
- err = log_error_errno(changes[i].type, "Failed to %s unit, cannot resolve specifiers in \"%s\".",
- verb, changes[i].path);
- break;
- default:
- assert(changes[i].type < 0);
- err = log_error_errno(changes[i].type, "Failed to %s unit, file \"%s\": %m",
- verb, changes[i].path);
+ log_error_errno(i->type, "Failed to %s unit: %s", verb, err_message);
+
+ err_logged = true;
}
- }
- if (r < 0 && err >= 0)
- log_error_errno(r, "Failed to %s: %m.", verb);
+ if (error < 0 && !err_logged)
+ log_error_errno(error, "Failed to %s unit: %m.", verb);
}
/**
@@ -750,7 +801,7 @@ static int remove_marked_symlinks(
assert(config_path);
assert(lp);
- if (set_size(remove_symlinks_to) <= 0)
+ if (set_isempty(remove_symlinks_to))
return 0;
fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC);
@@ -996,7 +1047,7 @@ static int find_symlinks_in_scope(
if (r > 0) {
/* We found symlinks in this dir? Yay! Let's see where precisely it is enabled. */
- if (path_equal_ptr(*p, lp->persistent_config)) {
+ if (path_equal(*p, lp->persistent_config)) {
/* This is the best outcome, let's return it immediately. */
*state = UNIT_FILE_ENABLED;
return 1;
@@ -1017,7 +1068,7 @@ static int find_symlinks_in_scope(
enabled_at_all = true;
} else if (same_name_link) {
- if (path_equal_ptr(*p, lp->persistent_config))
+ if (path_equal(*p, lp->persistent_config))
same_name_link_config = true;
else {
r = path_is_runtime(lp, *p, false);
@@ -1813,7 +1864,7 @@ int unit_file_verify_alias(
_cleanup_free_ char *dir = NULL;
char *p;
- path_alias ++; /* skip over slash */
+ path_alias++; /* skip over slash */
r = path_extract_directory(dst, &dir);
if (r < 0)
@@ -1892,28 +1943,25 @@ static int install_info_symlink_alias(
InstallChange **changes,
size_t *n_changes) {
- int r = 0, q;
+ int r, ret = 0;
assert(info);
assert(lp);
assert(config_path);
STRV_FOREACH(s, info->aliases) {
- _cleanup_free_ char *alias_path = NULL, *dst = NULL, *dst_updated = NULL;
- bool broken;
+ _cleanup_free_ char *alias_path = NULL, *alias_target = NULL, *dst = NULL, *dst_updated = NULL;
- q = install_name_printf(scope, info, *s, &dst);
- if (q < 0) {
- install_changes_add(changes, n_changes, q, *s, NULL);
- r = r < 0 ? r : q;
+ r = install_name_printf(scope, info, *s, &dst);
+ if (r < 0) {
+ RET_GATHER(ret, install_changes_add(changes, n_changes, r, *s, NULL));
continue;
}
- q = unit_file_verify_alias(info, dst, &dst_updated, changes, n_changes);
- if (q == -ELOOP)
- continue;
- if (q < 0) {
- r = r < 0 ? r : q;
+ r = unit_file_verify_alias(info, dst, &dst_updated, changes, n_changes);
+ if (r < 0) {
+ if (r != -ELOOP)
+ RET_GATHER(ret, r);
continue;
}
@@ -1921,18 +1969,30 @@ static int install_info_symlink_alias(
if (!alias_path)
return -ENOMEM;
- q = chase(alias_path, lp->root_dir, CHASE_NONEXISTENT, NULL, NULL);
- if (q < 0 && q != -ENOENT) {
- r = r < 0 ? r : q;
+ r = in_search_path(lp, info->path);
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ /* The unit path itself is outside of the search path. To
+ * correctly apply the alias, we need the alias symlink to
+ * point to the symlink that was created in the search path. */
+ alias_target = path_join(config_path, info->name);
+ if (!alias_target)
+ return -ENOMEM;
+ }
+
+ bool broken;
+ r = chase(alias_path, lp->root_dir, CHASE_NONEXISTENT, /* ret_path = */ NULL, /* ret_fd = */ NULL);
+ if (r < 0 && r != -ENOENT) {
+ RET_GATHER(ret, r);
continue;
}
- broken = q == 0; /* symlink target does not exist? */
+ broken = r == 0; /* symlink target does not exist? */
- q = create_symlink(lp, info->path, alias_path, force || broken, changes, n_changes);
- r = r < 0 ? r : q;
+ RET_GATHER(ret, create_symlink(lp, alias_target ?: info->path, alias_path, force || broken, changes, n_changes));
}
- return r;
+ return ret;
}
static int install_info_symlink_wants(
@@ -1995,10 +2055,7 @@ static int install_info_symlink_wants(
q = install_name_printf(scope, info, *s, &dst);
if (q < 0) {
- install_changes_add(changes, n_changes, q, *s, NULL);
- if (r >= 0)
- r = q;
-
+ RET_GATHER(r, install_changes_add(changes, n_changes, q, *s, NULL));
continue;
}
@@ -2010,15 +2067,13 @@ static int install_info_symlink_wants(
* 'systemctl enable serial-getty@.service' should fail, the user should specify an
* instance like in 'systemctl enable serial-getty@ttyS0.service'.
*/
- if (file_flags & UNIT_FILE_IGNORE_AUXILIARY_FAILURE)
+ if (FLAGS_SET(file_flags, UNIT_FILE_IGNORE_AUXILIARY_FAILURE))
continue;
if (unit_name_is_valid(dst, UNIT_NAME_ANY))
- q = install_changes_add(changes, n_changes, -EIDRM, dst, n);
+ RET_GATHER(r, install_changes_add(changes, n_changes, -EIDRM, dst, n));
else
- q = install_changes_add(changes, n_changes, -EUCLEAN, dst, NULL);
- if (r >= 0)
- r = q;
+ RET_GATHER(r, install_changes_add(changes, n_changes, -EUCLEAN, dst, NULL));
continue;
}
@@ -2027,7 +2082,7 @@ static int install_info_symlink_wants(
if (!path)
return -ENOMEM;
- q = create_symlink(lp, info->path, path, true, changes, n_changes);
+ q = create_symlink(lp, info->path, path, /* force = */ true, changes, n_changes);
if ((q < 0 && r >= 0) || r == 0)
r = q;
@@ -2259,7 +2314,7 @@ int unit_file_mask(
InstallChange **changes,
size_t *n_changes) {
- _cleanup_(lookup_paths_free) LookupPaths lp = {};
+ _cleanup_(lookup_paths_done) LookupPaths lp = {};
const char *config_path;
int r;
@@ -2274,13 +2329,13 @@ int unit_file_mask(
if (!config_path)
return -ENXIO;
+ r = 0;
+
STRV_FOREACH(name, names) {
_cleanup_free_ char *path = NULL;
- int q;
if (!unit_name_is_valid(*name, UNIT_NAME_ANY)) {
- if (r == 0)
- r = -EINVAL;
+ RET_GATHER(r, -EINVAL);
continue;
}
@@ -2288,9 +2343,7 @@ int unit_file_mask(
if (!path)
return -ENOMEM;
- q = create_symlink(&lp, "/dev/null", path, flags & UNIT_FILE_FORCE, changes, n_changes);
- if (q < 0 && r >= 0)
- r = q;
+ RET_GATHER(r, create_symlink(&lp, "/dev/null", path, flags & UNIT_FILE_FORCE, changes, n_changes));
}
return r;
@@ -2304,7 +2357,7 @@ int unit_file_unmask(
InstallChange **changes,
size_t *n_changes) {
- _cleanup_(lookup_paths_free) LookupPaths lp = {};
+ _cleanup_(lookup_paths_done) LookupPaths lp = {};
_cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
_cleanup_strv_free_ char **todo = NULL;
const char *config_path;
@@ -2386,8 +2439,7 @@ int unit_file_unmask(
if (!dry_run && unlink(path) < 0) {
if (errno != ENOENT) {
- if (r >= 0)
- r = -errno;
+ RET_GATHER(r, -errno);
install_changes_add(changes, n_changes, -errno, path, NULL);
}
@@ -2404,9 +2456,7 @@ int unit_file_unmask(
return q;
}
- q = remove_marked_symlinks(remove_symlinks_to, config_path, &lp, dry_run, changes, n_changes);
- if (r >= 0)
- r = q;
+ RET_GATHER(r, remove_marked_symlinks(remove_symlinks_to, config_path, &lp, dry_run, changes, n_changes));
return r;
}
@@ -2419,11 +2469,11 @@ int unit_file_link(
InstallChange **changes,
size_t *n_changes) {
- _cleanup_(lookup_paths_free) LookupPaths lp = {};
+ _cleanup_(lookup_paths_done) LookupPaths lp = {};
_cleanup_strv_free_ char **todo = NULL;
const char *config_path;
size_t n_todo = 0;
- int r, q;
+ int r;
assert(scope >= 0);
assert(scope < _RUNTIME_SCOPE_MAX);
@@ -2492,9 +2542,7 @@ int unit_file_link(
if (!new_path)
return -ENOMEM;
- q = create_symlink(&lp, *i, new_path, flags & UNIT_FILE_FORCE, changes, n_changes);
- if (q < 0 && r >= 0)
- r = q;
+ RET_GATHER(r, create_symlink(&lp, *i, new_path, flags & UNIT_FILE_FORCE, changes, n_changes));
}
return r;
@@ -2527,7 +2575,7 @@ int unit_file_revert(
size_t *n_changes) {
_cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
- _cleanup_(lookup_paths_free) LookupPaths lp = {};
+ _cleanup_(lookup_paths_done) LookupPaths lp = {};
_cleanup_strv_free_ char **todo = NULL;
size_t n_todo = 0;
int r, q;
@@ -2685,7 +2733,7 @@ int unit_file_add_dependency(
InstallChange **changes,
size_t *n_changes) {
- _cleanup_(lookup_paths_free) LookupPaths lp = {};
+ _cleanup_(lookup_paths_done) LookupPaths lp = {};
_cleanup_(install_context_done) InstallContext ctx = { .scope = scope };
InstallInfo *info, *target_info;
const char *config_path;
@@ -2786,7 +2834,7 @@ int unit_file_enable(
InstallChange **changes,
size_t *n_changes) {
- _cleanup_(lookup_paths_free) LookupPaths lp = {};
+ _cleanup_(lookup_paths_done) LookupPaths lp = {};
int r;
assert(scope >= 0);
@@ -2814,11 +2862,12 @@ static int do_unit_file_disable(
_cleanup_(install_context_done) InstallContext ctx = { .scope = scope };
_cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
- InstallInfo *info;
bool has_install_info = false;
int r;
STRV_FOREACH(name, names) {
+ InstallInfo *info;
+
if (!unit_name_is_valid(*name, UNIT_NAME_ANY))
return install_changes_add(changes, n_changes, -EUCLEAN, *name, NULL);
@@ -2838,7 +2887,6 @@ static int do_unit_file_disable(
r = install_context_mark_for_removal(&ctx, lp, &remove_symlinks_to, config_path, changes, n_changes);
if (r >= 0)
r = remove_marked_symlinks(remove_symlinks_to, config_path, lp, flags & UNIT_FILE_DRY_RUN, changes, n_changes);
-
if (r < 0)
return r;
@@ -2854,7 +2902,7 @@ int unit_file_disable(
InstallChange **changes,
size_t *n_changes) {
- _cleanup_(lookup_paths_free) LookupPaths lp = {};
+ _cleanup_(lookup_paths_done) LookupPaths lp = {};
int r;
assert(scope >= 0);
@@ -2897,7 +2945,7 @@ static int normalize_linked_files(
return log_debug_errno(SYNTHETIC_ERRNO(EISDIR),
"Unexpected path to a directory \"%s\", refusing.", *a);
- if (!is_path(*a)) {
+ if (!is_path(*a) && !unit_name_is_valid(*a, UNIT_NAME_INSTANCE)) {
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);
@@ -2937,7 +2985,7 @@ int unit_file_reenable(
InstallChange **changes,
size_t *n_changes) {
- _cleanup_(lookup_paths_free) LookupPaths lp = {};
+ _cleanup_(lookup_paths_done) LookupPaths lp = {};
_cleanup_strv_free_ char **names = NULL, **files = NULL;
int r;
@@ -2973,7 +3021,7 @@ int unit_file_set_default(
InstallChange **changes,
size_t *n_changes) {
- _cleanup_(lookup_paths_free) LookupPaths lp = {};
+ _cleanup_(lookup_paths_done) LookupPaths lp = {};
_cleanup_(install_context_done) InstallContext ctx = { .scope = scope };
InstallInfo *info;
const char *new_path;
@@ -3003,17 +3051,16 @@ int unit_file_set_default(
int unit_file_get_default(
RuntimeScope scope,
const char *root_dir,
- char **name) {
+ char **ret) {
- _cleanup_(lookup_paths_free) LookupPaths lp = {};
+ _cleanup_(lookup_paths_done) LookupPaths lp = {};
_cleanup_(install_context_done) InstallContext ctx = { .scope = scope };
InstallInfo *info;
- char *n;
int r;
assert(scope >= 0);
assert(scope < _RUNTIME_SCOPE_MAX);
- assert(name);
+ assert(ret);
r = lookup_paths_init(&lp, scope, 0, root_dir);
if (r < 0)
@@ -3024,12 +3071,7 @@ int unit_file_get_default(
if (r < 0)
return r;
- n = strdup(info->name);
- if (!n)
- return -ENOMEM;
-
- *name = n;
- return 0;
+ return strdup_to(ret, info->name);
}
int unit_file_lookup_state(
@@ -3136,7 +3178,7 @@ int unit_file_get_state(
const char *name,
UnitFileState *ret) {
- _cleanup_(lookup_paths_free) LookupPaths lp = {};
+ _cleanup_(lookup_paths_done) LookupPaths lp = {};
int r;
assert(scope >= 0);
@@ -3150,8 +3192,10 @@ int unit_file_get_state(
return unit_file_lookup_state(scope, &lp, name, ret);
}
-int unit_file_exists(RuntimeScope scope, const LookupPaths *lp, const char *name) {
- _cleanup_(install_context_done) InstallContext c = { .scope = scope };
+int unit_file_exists_full(RuntimeScope scope, const LookupPaths *lp, const char *name, char **ret_path) {
+ _cleanup_(install_context_done) InstallContext c = {
+ .scope = scope,
+ };
int r;
assert(lp);
@@ -3160,12 +3204,31 @@ int unit_file_exists(RuntimeScope scope, const LookupPaths *lp, const char *name
if (!unit_name_is_valid(name, UNIT_NAME_ANY))
return -EINVAL;
- r = install_info_discover(&c, lp, name, 0, NULL, NULL, NULL);
- if (r == -ENOENT)
+ InstallInfo *info = NULL;
+ r = install_info_discover(
+ &c,
+ lp,
+ name,
+ /* flags= */ 0,
+ ret_path ? &info : NULL,
+ /* changes= */ NULL,
+ /* n_changes= */ NULL);
+ if (r == -ENOENT) {
+ if (ret_path)
+ *ret_path = NULL;
return 0;
+ }
if (r < 0)
return r;
+ if (ret_path) {
+ assert(info);
+
+ r = strdup_to(ret_path, info->path);
+ if (r < 0)
+ return r;
+ }
+
return 1;
}
@@ -3203,8 +3266,8 @@ static int split_pattern_into_name_and_instances(const char *pattern, char **out
}
static int presets_find_config(RuntimeScope 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};
+ static const char* const system_dirs[] = { CONF_PATHS("systemd/system-preset"), NULL };
+ static const char* const user_dirs[] = { CONF_PATHS("systemd/user-preset"), NULL };
const char* const* dirs;
assert(scope >= 0);
@@ -3540,7 +3603,7 @@ int unit_file_preset(
size_t *n_changes) {
_cleanup_(install_context_done) InstallContext plus = {}, minus = {};
- _cleanup_(lookup_paths_free) LookupPaths lp = {};
+ _cleanup_(lookup_paths_done) LookupPaths lp = {};
_cleanup_(unit_file_presets_done) UnitFilePresets presets = {};
const char *config_path;
int r;
@@ -3579,7 +3642,7 @@ int unit_file_preset_all(
size_t *n_changes) {
_cleanup_(install_context_done) InstallContext plus = {}, minus = {};
- _cleanup_(lookup_paths_free) LookupPaths lp = {};
+ _cleanup_(lookup_paths_done) LookupPaths lp = {};
_cleanup_(unit_file_presets_done) UnitFilePresets presets = {};
const char *config_path = NULL;
int r;
@@ -3600,18 +3663,19 @@ int unit_file_preset_all(
if (r < 0)
return r;
+ r = 0;
STRV_FOREACH(i, lp.search_path) {
_cleanup_closedir_ DIR *d = NULL;
d = opendir(*i);
if (!d) {
- if (errno == ENOENT)
- continue;
-
- return -errno;
+ if (errno != ENOENT)
+ RET_GATHER(r, -errno);
+ continue;
}
- FOREACH_DIRENT(de, d, return -errno) {
+ FOREACH_DIRENT(de, d, RET_GATHER(r, -errno)) {
+ int k;
if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
continue;
@@ -3619,12 +3683,23 @@ int unit_file_preset_all(
if (!IN_SET(de->d_type, DT_LNK, DT_REG))
continue;
- r = preset_prepare_one(scope, &plus, &minus, &lp, de->d_name, &presets, changes, n_changes);
- if (r < 0 &&
- !IN_SET(r, -EEXIST, -ERFKILL, -EADDRNOTAVAIL, -EBADSLT, -EIDRM, -EUCLEAN, -ELOOP, -ENOENT, -EUNATCH, -EXDEV))
+ k = preset_prepare_one(scope, &plus, &minus, &lp, de->d_name, &presets, changes, n_changes);
+ if (k < 0 &&
+ !IN_SET(k, -EEXIST,
+ -ERFKILL,
+ -EADDRNOTAVAIL,
+ -ETXTBSY,
+ -EBADSLT,
+ -EIDRM,
+ -EUCLEAN,
+ -ELOOP,
+ -EXDEV,
+ -ENOENT,
+ -ENOLINK,
+ -EUNATCH))
/* Ignore generated/transient/missing/invalid units when applying preset, propagate other errors.
- * Coordinate with install_changes_dump() above. */
- return r;
+ * Coordinate with install_change_dump_error() above. */
+ RET_GATHER(r, k);
}
}
@@ -3656,7 +3731,7 @@ int unit_file_get_list(
char **states,
char **patterns) {
- _cleanup_(lookup_paths_free) LookupPaths lp = {};
+ _cleanup_(lookup_paths_done) LookupPaths lp = {};
int r;
assert(scope >= 0);