diff options
Diffstat (limited to 'src/shared/install.c')
-rw-r--r-- | src/shared/install.c | 479 |
1 files changed, 317 insertions, 162 deletions
diff --git a/src/shared/install.c b/src/shared/install.c index 77ae812878..3104043af6 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -60,6 +60,7 @@ typedef enum { typedef struct { char *pattern; PresetAction action; + char **instances; } PresetRule; typedef struct { @@ -67,7 +68,7 @@ typedef struct { size_t n_rules; } Presets; -static inline bool unit_file_install_info_has_rules(UnitFileInstallInfo *i) { +static inline bool unit_file_install_info_has_rules(const UnitFileInstallInfo *i) { assert(i); return !strv_isempty(i->aliases) || @@ -75,7 +76,7 @@ static inline bool unit_file_install_info_has_rules(UnitFileInstallInfo *i) { !strv_isempty(i->required_by); } -static inline bool unit_file_install_info_has_also(UnitFileInstallInfo *i) { +static inline bool unit_file_install_info_has_also(const UnitFileInstallInfo *i) { assert(i); return !strv_isempty(i->also); @@ -87,8 +88,10 @@ static inline void presets_freep(Presets *p) { if (!p) return; - for (i = 0; i < p->n_rules; i++) + for (i = 0; i < p->n_rules; i++) { free(p->rules[i].pattern); + strv_free(p->rules[i].instances); + } free(p->rules); p->n_rules = 0; @@ -343,7 +346,7 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang if (!quiet) log_info("Created symlink %s %s %s.", changes[i].path, - special_glyph(ARROW), + special_glyph(SPECIAL_GLYPH_ARROW), changes[i].source); break; case UNIT_FILE_UNLINK: @@ -474,8 +477,10 @@ static int create_symlink( if (!dirname) return -ENOMEM; - if (chroot_symlinks_same(paths->root_dir, dirname, dest, old_path)) + if (chroot_symlinks_same(paths->root_dir, dirname, dest, old_path)) { + log_debug("Symlink %s → %s already exists", new_path, dest); return 1; + } if (!force) { unit_file_changes_add(changes, n_changes, -EEXIST, new_path, dest); @@ -681,7 +686,7 @@ static int remove_marked_symlinks( return r; } -static bool is_symlink_with_known_name(const UnitFileInstallInfo *i, const char *name) { +static int is_symlink_with_known_name(const UnitFileInstallInfo *i, const char *name) { int r; if (streq(name, i->name)) @@ -708,8 +713,9 @@ static bool is_symlink_with_known_name(const UnitFileInstallInfo *i, const char static int find_symlinks_fd( const char *root_dir, - UnitFileInstallInfo *i, + const UnitFileInstallInfo *i, bool match_aliases, + bool ignore_same_name, int fd, const char *path, const char *config_path, @@ -756,7 +762,7 @@ static int find_symlinks_fd( } /* This will close nfd, regardless whether it succeeds or not */ - q = find_symlinks_fd(root_dir, i, match_aliases, nfd, + q = find_symlinks_fd(root_dir, i, match_aliases, ignore_same_name, nfd, p, config_path, same_name_link); if (q > 0) return 1; @@ -765,7 +771,7 @@ static int find_symlinks_fd( } else if (de->d_type == DT_LNK) { _cleanup_free_ char *p = NULL, *dest = NULL; - bool found_path, found_dest, b = false; + bool found_path = false, found_dest, b = false; int q; /* Acquire symlink name */ @@ -791,23 +797,20 @@ static int find_symlinks_fd( if (!x) return -ENOMEM; - free(dest); - dest = x; + free_and_replace(dest, x); } - /* Check if the symlink itself matches what we - * are looking for */ - if (path_is_absolute(i->name)) - found_path = path_equal(p, i->name); - else - found_path = streq(de->d_name, i->name); + assert(unit_name_is_valid(i->name, UNIT_NAME_ANY)); + if (!ignore_same_name) + /* Check if the symlink itself matches what we are looking for. + * + * If ignore_same_name is specified, we are in one of the directories which + * have lower priority than the unit file, and even if a file or symlink with + * this name was found, we should ignore it. */ + found_path = streq(de->d_name, i->name); - /* Check if what the symlink points to - * matches what we are looking for */ - if (path_is_absolute(i->name)) - found_dest = path_equal(dest, i->name); - else - found_dest = streq(basename(dest), i->name); + /* Check if what the symlink points to matches what we are looking for */ + found_dest = streq(basename(dest), i->name); if (found_path && found_dest) { _cleanup_free_ char *t = NULL; @@ -842,8 +845,9 @@ static int find_symlinks_fd( static int find_symlinks( const char *root_dir, - UnitFileInstallInfo *i, + const UnitFileInstallInfo *i, bool match_name, + bool ignore_same_name, const char *config_path, bool *same_name_link) { @@ -861,29 +865,34 @@ static int find_symlinks( } /* This takes possession of fd and closes it */ - return find_symlinks_fd(root_dir, i, match_name, fd, + return find_symlinks_fd(root_dir, i, match_name, ignore_same_name, fd, config_path, config_path, same_name_link); } static int find_symlinks_in_scope( UnitFileScope scope, const LookupPaths *paths, - UnitFileInstallInfo *i, + const UnitFileInstallInfo *i, bool match_name, UnitFileState *state) { bool same_name_link_runtime = false, same_name_link_config = false; bool enabled_in_runtime = false, enabled_at_all = false; + bool ignore_same_name = false; char **p; int r; assert(paths); assert(i); + /* As we iterate over the list of search paths in paths->search_path, we may encounter "same name" + * symlinks. The ones which are "below" (i.e. have lower priority) than the unit file itself are + * efectively masked, so we should ignore them. */ + STRV_FOREACH(p, paths->search_path) { bool same_name_link = false; - r = find_symlinks(paths->root_dir, i, match_name, *p, &same_name_link); + r = find_symlinks(paths->root_dir, i, match_name, ignore_same_name, *p, &same_name_link); if (r < 0) return r; if (r > 0) { @@ -920,6 +929,11 @@ static int find_symlinks_in_scope( same_name_link_runtime = true; } } + + /* Check if next iteration will be "below" the unit file (either a regular file + * or a symlink), and hence should be ignored */ + if (!ignore_same_name && path_startswith(i->path, *p)) + ignore_same_name = true; } if (enabled_in_runtime) { @@ -984,7 +998,7 @@ static UnitFileInstallInfo *install_info_find(InstallContext *c, const char *nam } static int install_info_may_process( - UnitFileInstallInfo *i, + const UnitFileInstallInfo *i, const LookupPaths *paths, UnitFileChange **changes, size_t *n_changes) { @@ -1045,11 +1059,14 @@ static int install_info_add( if (r < 0) return r; - i = new0(UnitFileInstallInfo, 1); + i = new(UnitFileInstallInfo, 1); if (!i) return -ENOMEM; - i->type = _UNIT_FILE_TYPE_INVALID; - i->auxiliary = auxiliary; + + *i = (UnitFileInstallInfo) { + .type = _UNIT_FILE_TYPE_INVALID, + .auxiliary = auxiliary, + }; i->name = strdup(name); if (!i->name) { @@ -1229,10 +1246,9 @@ static int unit_file_load( type = unit_name_to_type(info->name); if (type < 0) return -EINVAL; - if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE|UNIT_NAME_INSTANCE) && !unit_type_may_template(type)) { - log_error("Unit type %s cannot be templated.", unit_type_to_string(type)); - return -EINVAL; - } + if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE|UNIT_NAME_INSTANCE) && !unit_type_may_template(type)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Unit type %s cannot be templated.", unit_type_to_string(type)); if (!(flags & SEARCH_LOAD)) { r = lstat(path, &st); @@ -1281,7 +1297,7 @@ static int unit_file_load( if (r < 0) return r; - f = fdopen(fd, "re"); + f = fdopen(fd, "r"); if (!f) return -errno; fd = -1; @@ -1445,10 +1461,10 @@ static int unit_file_search( } } - if (!found_unit) { - log_debug("Cannot find unit %s%s%s.", info->name, template ? " or " : "", strempty(template)); - return -ENOENT; - } + if (!found_unit) + return log_debug_errno(SYNTHETIC_ERRNO(ENOENT), + "Cannot find unit %s%s%s.", + info->name, template ? " or " : "", strempty(template)); if (info->type == UNIT_FILE_TYPE_MASKED) return result; @@ -1459,7 +1475,7 @@ static int unit_file_search( STRV_FOREACH(p, paths->search_path) { char *path; - path = path_join(NULL, *p, dropin_dir_name); + path = path_join(*p, dropin_dir_name); if (!path) return -ENOMEM; @@ -1473,7 +1489,7 @@ static int unit_file_search( STRV_FOREACH(p, paths->search_path) { char *path; - path = path_join(NULL, *p, dropin_template_dir_name); + path = path_join(*p, dropin_template_dir_name); if (!path) return -ENOMEM; @@ -1673,6 +1689,25 @@ static int install_info_discover( 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) { + + int r; + + r = install_info_discover(scope, c, paths, name, flags, ret, changes, n_changes); + if (r < 0) + return r; + + return install_info_may_process(ret ? *ret : NULL, paths, changes, n_changes); +} + static int install_info_symlink_alias( UnitFileInstallInfo *i, const LookupPaths *paths, @@ -1728,12 +1763,16 @@ static int install_info_symlink_wants( if (strv_isempty(list)) return 0; - if (unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE) && i->default_instance) { + if (unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE)) { UnitFileInstallInfo instance = { .type = _UNIT_FILE_TYPE_INVALID, }; _cleanup_free_ char *path = NULL; + /* If this is a template, and we have no instance, don't do anything */ + if (!i->default_instance) + return 1; + r = unit_name_replace_instance(i->name, i->default_instance, &buf); if (r < 0) return r; @@ -1874,10 +1913,10 @@ static int install_context_apply( if (q < 0) return q; - r = install_info_traverse(scope, c, paths, i, flags, NULL); - if (r < 0) { + q = install_info_traverse(scope, c, paths, i, flags, NULL); + if (q < 0) { unit_file_changes_add(changes, n_changes, r, i->name, NULL); - return r; + return q; } /* We can attempt to process a masked unit when a different unit @@ -1911,6 +1950,7 @@ static int install_context_mark_for_removal( InstallContext *c, const LookupPaths *paths, Set **remove_symlinks_to, + const char *config_path, UnitFileChange **changes, size_t *n_changes) { @@ -1919,6 +1959,7 @@ static int install_context_mark_for_removal( assert(c); assert(paths); + assert(config_path); /* Marks all items for removal */ @@ -2028,7 +2069,7 @@ int unit_file_unmask( size_t n_todo = 0, n_allocated = 0; const char *config_path; char **i; - bool dry_run = !!(flags & UNIT_FILE_DRY_RUN); + bool dry_run; int r, q; assert(scope >= 0); @@ -2038,71 +2079,73 @@ int unit_file_unmask( if (r < 0) return r; + config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config; + if (!config_path) + return -ENXIO; + + dry_run = !!(flags & UNIT_FILE_DRY_RUN); + STRV_FOREACH(i, files) { + _cleanup_free_ char *path = NULL; + if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) return -EINVAL; - FOREACH_STRING(config_path, paths.runtime_config, paths.persistent_config) { - _cleanup_free_ char *path = NULL; - - path = path_make_absolute(*i, config_path); - if (!path) - return -ENOMEM; + path = path_make_absolute(*i, config_path); + if (!path) + return -ENOMEM; - r = null_or_empty_path(path); - if (r == -ENOENT) - continue; - if (r < 0) - return r; - if (r == 0) - continue; + r = null_or_empty_path(path); + if (r == -ENOENT) + continue; + if (r < 0) + return r; + if (r == 0) + continue; - if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2)) - return -ENOMEM; + if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2)) + return -ENOMEM; - todo[n_todo] = strdup(*i); - if (!todo[n_todo]) - return -ENOMEM; + todo[n_todo] = strdup(*i); + if (!todo[n_todo]) + return -ENOMEM; - n_todo++; - } + n_todo++; } strv_uniq(todo); r = 0; - FOREACH_STRING(config_path, paths.runtime_config, paths.persistent_config) { - STRV_FOREACH(i, todo) { - _cleanup_free_ char *path = NULL; - const char *rp; - - path = path_make_absolute(*i, config_path); - if (!path) - return -ENOMEM; + STRV_FOREACH(i, todo) { + _cleanup_free_ char *path = NULL; + const char *rp; - if (!dry_run && unlink(path) < 0) { - if (errno != ENOENT) { - if (r >= 0) - r = -errno; - unit_file_changes_add(changes, n_changes, -errno, path, NULL); - } + path = path_make_absolute(*i, config_path); + if (!path) + return -ENOMEM; - continue; + if (!dry_run && unlink(path) < 0) { + if (errno != ENOENT) { + if (r >= 0) + r = -errno; + unit_file_changes_add(changes, n_changes, -errno, path, NULL); } - unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); - - rp = skip_root(&paths, path); - q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: path); - if (q < 0) - return q; + continue; } - q = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, dry_run, changes, n_changes); - if (r >= 0) - r = q; + unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); + + rp = skip_root(&paths, path); + q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: path); + if (q < 0) + return q; } + q = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, dry_run, changes, n_changes); + if (r >= 0) + r = q; + return r; } @@ -2396,11 +2439,8 @@ int unit_file_add_dependency( if (!config_path) return -ENXIO; - r = install_info_discover(scope, &c, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, - &target_info, changes, n_changes); - if (r < 0) - return r; - r = install_info_may_process(target_info, &paths, changes, n_changes); + r = install_info_discover_and_check(scope, &c, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, + &target_info, changes, n_changes); if (r < 0) return r; @@ -2409,11 +2449,8 @@ int unit_file_add_dependency( STRV_FOREACH(f, files) { char ***l; - r = install_info_discover(scope, &c, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS, - &i, changes, n_changes); - if (r < 0) - return r; - r = install_info_may_process(i, &paths, changes, n_changes); + r = install_info_discover_and_check(scope, &c, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS, + &i, changes, n_changes); if (r < 0) return r; @@ -2429,7 +2466,7 @@ int unit_file_add_dependency( l = &i->required_by; strv_free(*l); - *l = strv_new(target_info->name, NULL); + *l = strv_new(target_info->name); if (!*l) return -ENOMEM; } @@ -2464,11 +2501,8 @@ int unit_file_enable( return -ENXIO; STRV_FOREACH(f, files) { - r = install_info_discover(scope, &c, &paths, *f, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, - &i, changes, n_changes); - if (r < 0) - return r; - r = install_info_may_process(i, &paths, changes, n_changes); + r = install_info_discover_and_check(scope, &c, &paths, *f, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, + &i, changes, n_changes); if (r < 0) return r; @@ -2494,7 +2528,6 @@ int unit_file_disable( _cleanup_(lookup_paths_free) LookupPaths paths = {}; _cleanup_(install_context_done) InstallContext c = {}; _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; - bool dry_run = !!(flags & UNIT_FILE_DRY_RUN); const char *config_path; char **i; int r; @@ -2506,6 +2539,10 @@ int unit_file_disable( if (r < 0) return r; + config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config; + if (!config_path) + return -ENXIO; + STRV_FOREACH(i, files) { if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) return -EINVAL; @@ -2515,17 +2552,11 @@ int unit_file_disable( return r; } - r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, changes, n_changes); + r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, config_path, changes, n_changes); if (r < 0) return r; - FOREACH_STRING(config_path, paths.runtime_config, paths.persistent_config) { - r = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, dry_run, changes, n_changes); - if (r < 0) - return r; - } - - return 0; + return remove_marked_symlinks(remove_symlinks_to, config_path, &paths, !!(flags & UNIT_FILE_DRY_RUN), changes, n_changes); } int unit_file_reenable( @@ -2582,10 +2613,7 @@ int unit_file_set_default( if (r < 0) return r; - r = install_info_discover(scope, &c, &paths, name, 0, &i, changes, n_changes); - if (r < 0) - return r; - r = install_info_may_process(i, &paths, changes, n_changes); + r = install_info_discover_and_check(scope, &c, &paths, name, 0, &i, changes, n_changes); if (r < 0) return r; @@ -2648,7 +2676,11 @@ int unit_file_lookup_state( r = install_info_discover(scope, &c, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i, NULL, NULL); if (r < 0) - return r; + return log_debug_errno(r, "Failed to discover unit %s: %m", name); + + assert(IN_SET(i->type, UNIT_FILE_TYPE_REGULAR, UNIT_FILE_TYPE_MASKED)); + log_debug("Found unit %s at %s (%s)", name, strna(i->path), + i->type == UNIT_FILE_TYPE_REGULAR ? "regular file" : "mask"); /* Shortcut things, if the caller just wants to know if this unit exists. */ if (!ret) @@ -2755,6 +2787,39 @@ int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char * return 1; } +static int split_pattern_into_name_and_instances(const char *pattern, char **out_unit_name, char ***out_instances) { + _cleanup_strv_free_ char **instances = NULL; + _cleanup_free_ char *unit_name = NULL; + int r; + + assert(pattern); + assert(out_instances); + assert(out_unit_name); + + r = extract_first_word(&pattern, &unit_name, NULL, 0); + if (r < 0) + return r; + + /* We handle the instances logic when unit name is extracted */ + if (pattern) { + /* We only create instances when a rule of templated unit + * is seen. A rule like enable foo@.service a b c will + * result in an array of (a, b, c) as instance names */ + if (!unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) + return -EINVAL; + + instances = strv_split(pattern, WHITESPACE); + if (!instances) + return -ENOMEM; + + *out_instances = TAKE_PTR(instances); + } + + *out_unit_name = TAKE_PTR(unit_name); + + return 0; +} + static int read_presets(UnitFileScope scope, const char *root_dir, Presets *presets) { _cleanup_(presets_freep) Presets ps = {}; size_t n_allocated = 0; @@ -2798,7 +2863,6 @@ static int read_presets(UnitFileScope scope, const char *root_dir, Presets *pres STRV_FOREACH(p, files) { _cleanup_fclose_ FILE *f; - char line[LINE_MAX]; int n = 0; f = fopen(*p, "re"); @@ -2809,11 +2873,18 @@ static int read_presets(UnitFileScope scope, const char *root_dir, Presets *pres return -errno; } - FOREACH_LINE(line, f, return -errno) { + for (;;) { + _cleanup_free_ char *line = NULL; PresetRule rule = {}; const char *parameter; char *l; + r = read_line(f, LONG_LINE_MAX, &line); + if (r < 0) + return r; + if (r == 0) + break; + l = strstrip(line); n++; @@ -2824,15 +2895,20 @@ static int read_presets(UnitFileScope scope, const char *root_dir, Presets *pres parameter = first_word(l, "enable"); if (parameter) { - char *pattern; + char *unit_name; + char **instances = NULL; - pattern = strdup(parameter); - if (!pattern) - return -ENOMEM; + /* Unit_name will remain the same as parameter when no instances are specified */ + r = split_pattern_into_name_and_instances(parameter, &unit_name, &instances); + if (r < 0) { + log_syntax(NULL, LOG_WARNING, *p, n, r, "Couldn't parse line '%s'. Ignoring.", line); + continue; + } rule = (PresetRule) { - .pattern = pattern, + .pattern = unit_name, .action = PRESET_ENABLE, + .instances = instances, }; } @@ -2868,15 +2944,71 @@ static int read_presets(UnitFileScope scope, const char *root_dir, Presets *pres return 0; } -static int query_presets(const char *name, const Presets presets) { +static int pattern_match_multiple_instances( + const PresetRule rule, + const char *unit_name, + char ***ret) { + + _cleanup_free_ char *templated_name = NULL; + int r; + + /* If no ret is needed or the rule itself does not have instances + * initalized, we return not matching */ + if (!ret || !rule.instances) + return 0; + + r = unit_name_template(unit_name, &templated_name); + if (r < 0) + return r; + if (!streq(rule.pattern, templated_name)) + return 0; + + /* Compose a list of specified instances when unit name is a template */ + if (unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) { + _cleanup_free_ char *prefix = NULL; + _cleanup_strv_free_ char **out_strv = NULL; + char **iter; + + r = unit_name_to_prefix(unit_name, &prefix); + if (r < 0) + return r; + + STRV_FOREACH(iter, rule.instances) { + _cleanup_free_ char *name = NULL; + r = unit_name_build(prefix, *iter, ".service", &name); + if (r < 0) + return r; + r = strv_extend(&out_strv, name); + if (r < 0) + return r; + } + + *ret = TAKE_PTR(out_strv); + return 1; + } else { + /* We now know the input unit name is an instance name */ + _cleanup_free_ char *instance_name = NULL; + + r = unit_name_to_instance(unit_name, &instance_name); + if (r < 0) + return r; + + if (strv_find(rule.instances, instance_name)) + return 1; + } + return 0; +} + +static int query_presets(const char *name, const Presets presets, char ***instance_name_list) { PresetAction action = PRESET_UNKNOWN; size_t i; - + char **s; if (!unit_name_is_valid(name, UNIT_NAME_ANY)) return -EINVAL; for (i = 0; i < presets.n_rules; i++) - if (fnmatch(presets.rules[i].pattern, name, FNM_NOESCAPE) == 0) { + if (pattern_match_multiple_instances(presets.rules[i], name, instance_name_list) > 0 || + fnmatch(presets.rules[i].pattern, name, FNM_NOESCAPE) == 0) { action = presets.rules[i].action; break; } @@ -2886,7 +3018,11 @@ static int query_presets(const char *name, const Presets presets) { log_debug("Preset files don't specify rule for %s. Enabling.", name); return 1; case PRESET_ENABLE: - log_debug("Preset files say enable %s.", name); + if (instance_name_list && *instance_name_list) + STRV_FOREACH(s, *instance_name_list) + log_debug("Preset files say enable %s.", *s); + else + log_debug("Preset files say enable %s.", name); return 1; case PRESET_DISABLE: log_debug("Preset files say disable %s.", name); @@ -2904,50 +3040,50 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char if (r < 0) return r; - return query_presets(name, presets); + return query_presets(name, presets, NULL); } static int execute_preset( UnitFileScope scope, - UnitFileFlags flags, InstallContext *plus, InstallContext *minus, const LookupPaths *paths, + const char *config_path, char **files, UnitFilePresetMode mode, + bool force, UnitFileChange **changes, size_t *n_changes) { - const char *config_path; - bool force = !!(flags & UNIT_FILE_FORCE); - bool runtime = !!(flags & UNIT_FILE_RUNTIME); - int r = 0, q; + int r; assert(plus); assert(minus); assert(paths); + assert(config_path); if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) { _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; - q = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, changes, n_changes); - if (q < 0) - return q; + r = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, config_path, changes, n_changes); + if (r < 0) + return r; - FOREACH_STRING(config_path, paths->runtime_config, paths->persistent_config) { - q = remove_marked_symlinks(remove_symlinks_to, config_path, paths, false, changes, n_changes); - if (r == 0) - r = q; - } - } + r = remove_marked_symlinks(remove_symlinks_to, config_path, paths, false, changes, n_changes); + } else + r = 0; if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) { + int q; + /* Returns number of symlinks that where supposed to be installed. */ - q = install_context_apply(scope, plus, paths, - runtime ? paths->runtime_config : paths->persistent_config, - force, SEARCH_LOAD, changes, n_changes); - if (r == 0) - r = q; + q = install_context_apply(scope, plus, paths, config_path, force, SEARCH_LOAD, changes, n_changes); + if (r >= 0) { + if (q < 0) + r = q; + else + r += q; + } } return r; @@ -2964,6 +3100,7 @@ static int preset_prepare_one( size_t *n_changes) { _cleanup_(install_context_done) InstallContext tmp = {}; + _cleanup_strv_free_ char **instance_name_list = NULL; UnitFileInstallInfo *i; int r; @@ -2979,19 +3116,26 @@ static int preset_prepare_one( return 0; } - r = query_presets(name, presets); + r = query_presets(name, presets, &instance_name_list); if (r < 0) return r; if (r > 0) { - r = install_info_discover(scope, plus, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, - &i, changes, n_changes); - if (r < 0) - return r; + if (instance_name_list) { + char **s; + 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); + 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); + if (r < 0) + return r; + } - r = install_info_may_process(i, paths, 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); @@ -3011,6 +3155,7 @@ int unit_file_preset( _cleanup_(install_context_done) InstallContext plus = {}, minus = {}; _cleanup_(lookup_paths_free) LookupPaths paths = {}; _cleanup_(presets_freep) Presets presets = {}; + const char *config_path; char **i; int r; @@ -3022,6 +3167,10 @@ int unit_file_preset( if (r < 0) return r; + config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config; + if (!config_path) + return -ENXIO; + r = read_presets(scope, root_dir, &presets); if (r < 0) return r; @@ -3032,7 +3181,7 @@ int unit_file_preset( return r; } - return execute_preset(scope, flags, &plus, &minus, &paths, files, mode, changes, n_changes); + return execute_preset(scope, &plus, &minus, &paths, config_path, files, mode, !!(flags & UNIT_FILE_FORCE), changes, n_changes); } int unit_file_preset_all( @@ -3046,6 +3195,7 @@ int unit_file_preset_all( _cleanup_(install_context_done) InstallContext plus = {}, minus = {}; _cleanup_(lookup_paths_free) LookupPaths paths = {}; _cleanup_(presets_freep) Presets presets = {}; + const char *config_path = NULL; char **i; int r; @@ -3057,6 +3207,10 @@ int unit_file_preset_all( if (r < 0) return r; + config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config; + if (!config_path) + return -ENXIO; + r = read_presets(scope, root_dir, &presets); if (r < 0) return r; @@ -3074,6 +3228,7 @@ int unit_file_preset_all( } FOREACH_DIRENT(de, d, return -errno) { + if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY)) continue; @@ -3097,7 +3252,7 @@ int unit_file_preset_all( } } - return execute_preset(scope, flags, &plus, &minus, &paths, NULL, mode, changes, n_changes); + return execute_preset(scope, &plus, &minus, &paths, config_path, NULL, mode, !!(flags & UNIT_FILE_FORCE), changes, n_changes); } static void unit_file_list_free_one(UnitFileList *f) { |