diff options
author | Alex Crawford <alex.crawford@coreos.com> | 2016-04-27 23:59:20 -0700 |
---|---|---|
committer | Alex Crawford <alex.crawford@coreos.com> | 2016-05-03 11:46:14 -0700 |
commit | 8965d9f8b93b467c8827201b8cd55a762e406801 (patch) | |
tree | 2058a5d5ec7d2069305261f6ce8ac57eab01443a /src/shared/install.c | |
parent | 622d37058487ce955337ca9d843d92a67cd6a609 (diff) |
install: cache the presets before evaluating
The previous implementation traversed the various config directories,
walking the preset files and parsing each line to determine if a service
should be enabled or disabled. It did this for every service which
resulted in many more file operations than neccessary.
This approach parses each of the preset entries into an array which is
then used to check if each service should be enabled or disabled.
Diffstat (limited to 'src/shared/install.c')
-rw-r--r-- | src/shared/install.c | 146 |
1 files changed, 121 insertions, 25 deletions
diff --git a/src/shared/install.c b/src/shared/install.c index 1ea7e4674f..d2799bf0df 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -66,6 +66,35 @@ typedef struct { OrderedHashmap *have_processed; } InstallContext; +typedef enum { + PRESET_UNKNOWN, + PRESET_ENABLE, + PRESET_DISABLE, +} PresetAction; + +typedef struct { + char *pattern; + PresetAction action; +} PresetRule; + +typedef struct { + PresetRule *rules; + size_t n_rules; +} Presets; + +static inline void presets_freep(Presets *p) { + size_t i; + + if (!p) + return; + + for (i = 0; i < p->n_rules; i++) + free(p->rules[i].pattern); + + free(p->rules); + p->n_rules = 0; +} + static int unit_file_lookup_state(UnitFileScope scope, const LookupPaths *paths, const char *name, UnitFileState *ret); static int in_search_path(const LookupPaths *p, const char *path) { @@ -2367,17 +2396,16 @@ int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char * return 1; } -int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) { +static int read_presets(UnitFileScope scope, const char *root_dir, Presets *presets) { + _cleanup_(presets_freep) Presets ps = {}; + size_t n_allocated = 0; _cleanup_strv_free_ char **files = NULL; char **p; int r; assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); - assert(name); - - if (!unit_name_is_valid(name, UNIT_NAME_ANY)) - return -EINVAL; + assert(presets); if (scope == UNIT_FILE_SYSTEM) r = conf_files_list(&files, ".preset", root_dir, @@ -2394,8 +2422,11 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char "/usr/local/lib/systemd/user-preset", "/usr/lib/systemd/user-preset", NULL); - else - return 1; /* Default is "enable" */ + else { + *presets = (Presets){}; + + return 0; + } if (r < 0) return r; @@ -2414,6 +2445,7 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char } FOREACH_LINE(line, f, return -errno) { + PresetRule rule = {}; const char *parameter; char *l; @@ -2427,21 +2459,37 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char parameter = first_word(l, "enable"); if (parameter) { - if (fnmatch(parameter, name, FNM_NOESCAPE) == 0) { - log_debug("Preset file says enable %s.", name); - return 1; - } + char *pattern; - continue; + pattern = strdup(parameter); + if (!pattern) + return -ENOMEM; + + rule = (PresetRule) { + .pattern = pattern, + .action = PRESET_ENABLE, + }; } parameter = first_word(l, "disable"); if (parameter) { - if (fnmatch(parameter, name, FNM_NOESCAPE) == 0) { - log_debug("Preset file says disable %s.", name); - return 0; - } + char *pattern; + pattern = strdup(parameter); + if (!pattern) + return -ENOMEM; + + rule = (PresetRule) { + .pattern = pattern, + .action = PRESET_DISABLE, + }; + } + + if (rule.action) { + if (!GREEDY_REALLOC(ps.rules, n_allocated, ps.n_rules + 1)) + return -ENOMEM; + + ps.rules[ps.n_rules++] = rule; continue; } @@ -2449,9 +2497,49 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char } } - /* Default is "enable" */ - log_debug("Preset file doesn't say anything about %s, enabling.", name); - return 1; + *presets = ps; + ps = (Presets){}; + + return 0; +} + +static int query_presets(const char *name, const Presets presets) { + PresetAction action = PRESET_UNKNOWN; + size_t i; + + 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) { + action = presets.rules[i].action; + break; + } + + switch (action) { + case PRESET_UNKNOWN: + 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); + return 1; + case PRESET_DISABLE: + log_debug("Preset files say disable %s.", name); + return 0; + default: + assert_not_reached("invalid preset action"); + } +} + +int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) { + _cleanup_(presets_freep) Presets presets = {}; + int r; + + r = read_presets(scope, root_dir, &presets); + if (r < 0) + return r; + + return query_presets(name, presets); } static int execute_preset( @@ -2507,6 +2595,7 @@ static int preset_prepare_one( LookupPaths *paths, UnitFilePresetMode mode, const char *name, + Presets presets, UnitFileChange **changes, unsigned *n_changes) { @@ -2517,7 +2606,7 @@ static int preset_prepare_one( install_info_find(minus, name)) return 0; - r = unit_file_query_preset(scope, paths->root_dir, name); + r = query_presets(name, presets); if (r < 0) return r; @@ -2547,6 +2636,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; @@ -2561,11 +2651,12 @@ int unit_file_preset( config_path = runtime ? paths.runtime_config : paths.persistent_config; - STRV_FOREACH(i, files) { - if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) - return -EINVAL; + r = read_presets(scope, root_dir, &presets); + if (r < 0) + return r; - r = preset_prepare_one(scope, &plus, &minus, &paths, mode, *i, changes, n_changes); + STRV_FOREACH(i, files) { + r = preset_prepare_one(scope, &plus, &minus, &paths, mode, *i, presets, changes, n_changes); if (r < 0) return r; } @@ -2584,6 +2675,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; @@ -2598,6 +2690,10 @@ int unit_file_preset_all( config_path = runtime ? paths.runtime_config : paths.persistent_config; + r = read_presets(scope, root_dir, &presets); + if (r < 0) + return r; + STRV_FOREACH(i, paths.search_path) { _cleanup_closedir_ DIR *d = NULL; struct dirent *de; @@ -2621,7 +2717,7 @@ int unit_file_preset_all( continue; /* we don't pass changes[] in, because we want to handle errors on our own */ - r = preset_prepare_one(scope, &plus, &minus, &paths, mode, de->d_name, NULL, 0); + r = preset_prepare_one(scope, &plus, &minus, &paths, mode, de->d_name, presets, NULL, 0); if (r == -ERFKILL) r = unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_MASKED, de->d_name, NULL); |