diff options
Diffstat (limited to '')
-rw-r--r-- | src/shared/install.c | 505 |
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); |