From: Yu Watanabe Date: Sun, 5 Oct 2025 16:51:59 +0000 (+0900) Subject: sysctl: port parse_file() over conf_file_read() X-Git-Tag: v259-rc1~372^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=483de0e76b2a21cc12b9923a5f51e3974246b208;p=thirdparty%2Fsystemd.git sysctl: port parse_file() over conf_file_read() Then, systemd-sysctl can also support stdin and relative paths, like systemd-sysusers and systemd-tmpfiles do. --- diff --git a/man/systemd-sysctl.service.xml b/man/systemd-sysctl.service.xml index 720beed8eec..0702fa87ce4 100644 --- a/man/systemd-sysctl.service.xml +++ b/man/systemd-sysctl.service.xml @@ -42,8 +42,12 @@ When invoked with no arguments, /usr/lib/systemd/systemd-sysctl applies all directives from configuration files listed in sysctl.d5. - If one or more filenames are passed on the command line, only the directives in these files are - applied. + When invoked with positional arguments, the configuration specified by the command line arguments is + executed. If the string - is specified instead of a filename, the configuration is + read from standard input. If the argument is a file name (without any slashes), all configuration + directories are searched for a matching file and the file found that has the highest priority is + executed. If the argument is a path, that file is used directly without searching the configuration + directories for any other matching file. In addition, option may be used to limit which sysctl settings are applied. diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c index 47990b4e692..4e0c977c938 100644 --- a/src/sysctl/sysctl.c +++ b/src/sysctl/sysctl.c @@ -214,100 +214,79 @@ static int apply_all(OrderedHashmap *sysctl_options) { return r; } -static int parse_file(OrderedHashmap **sysctl_options, const char *path, bool ignore_enoent) { - _cleanup_fclose_ FILE *f = NULL; - _cleanup_free_ char *pp = NULL; - unsigned c = 0; +static int parse_line(const char *fname, unsigned line, const char *buffer, bool *invalid_config, void *userdata) { + OrderedHashmap **sysctl_options = ASSERT_PTR(userdata); + _cleanup_free_ char *k = NULL, *v = NULL; + bool ignore_failure = false; int r; - assert(path); - - r = search_and_fopen(path, "re", NULL, (const char**) CONF_PATHS_STRV("sysctl.d"), &f, &pp); - if (r < 0) { - if (ignore_enoent && r == -ENOENT) - return 0; + const char *eq = strchr(buffer, '='); + if (eq) { + if (buffer[0] == '-') { + ignore_failure = true; + buffer++; + } - return log_error_errno(r, "Failed to open file '%s', ignoring: %m", path); - } + k = strndup(buffer, eq - buffer); + if (!k) + return log_oom(); - log_debug("Parsing %s", pp); - for (;;) { - _cleanup_(option_freep) Option *new_option = NULL; - _cleanup_free_ char *l = NULL; - bool ignore_failure = false; - Option *existing; - char *value; - int k; + v = strdup(eq + 1); + if (!v) + return log_oom(); - k = read_stripped_line(f, LONG_LINE_MAX, &l); - if (k == 0) - break; - if (k < 0) - return log_error_errno(k, "Failed to read file '%s', ignoring: %m", pp); + } else { + if (buffer[0] == '-') + /* We have a "negative match" option. Let's continue with value==NULL. */ + buffer++; + else + return log_syntax(NULL, LOG_WARNING, fname, line, SYNTHETIC_ERRNO(EINVAL), + "Line is not an assignment, ignoring: %s", buffer); - c++; + k = strdup(buffer); + if (!k) + return log_oom(); + } - if (isempty(l)) - continue; - if (strchr(COMMENTS, l[0])) - continue; + const char *key = sysctl_normalize(strstrip(k)), *value = strstrip(v); - char *p = l; - value = strchr(p, '='); - if (value) { - if (p[0] == '-') { - ignore_failure = true; - p++; - } + /* We can't filter out globs at this point, we'll need to do that later. */ + if (!string_is_glob(key) && !test_prefix(key)) + return 0; - *value = 0; - value++; - value = strstrip(value); - - } else { - if (p[0] == '-') - /* We have a "negative match" option. Let's continue with value==NULL. */ - p++; - else { - log_syntax(NULL, LOG_WARNING, pp, c, 0, - "Line is not an assignment, ignoring: %s", p); - if (r == 0) - r = -EINVAL; - continue; - } + Option *existing = ordered_hashmap_get(*sysctl_options, key); + if (existing) { + if (streq_ptr(value, existing->value)) { + existing->ignore_failure = existing->ignore_failure || ignore_failure; + return 0; } - p = strstrip(p); - p = sysctl_normalize(p); - - /* We can't filter out globs at this point, we'll need to do that later. */ - if (!string_is_glob(p) && - !test_prefix(p)) - continue; - - existing = ordered_hashmap_get(*sysctl_options, p); - if (existing) { - if (streq_ptr(value, existing->value)) { - existing->ignore_failure = existing->ignore_failure || ignore_failure; - continue; - } - - log_debug("Overwriting earlier assignment of %s at '%s:%u'.", p, pp, c); - option_free(ordered_hashmap_remove(*sysctl_options, p)); - } + log_syntax(NULL, LOG_DEBUG, fname, line, 0, + "Overwriting earlier assignment of '%s'.", key); + option_free(ordered_hashmap_remove(*sysctl_options, key)); + } - new_option = option_new(p, value, ignore_failure); - if (!new_option) - return log_oom(); + _cleanup_(option_freep) Option *option = option_new(key, value, ignore_failure); + if (!option) + return log_oom(); - k = ordered_hashmap_ensure_put(sysctl_options, &option_hash_ops, new_option->key, new_option); - if (k < 0) - return log_error_errno(k, "Failed to add sysctl variable %s to hashmap: %m", p); + r = ordered_hashmap_ensure_put(sysctl_options, &option_hash_ops, option->key, option); + if (r < 0) + return log_error_errno(r, "Failed to add sysctl variable '%s' to hashmap: %m", key); - TAKE_PTR(new_option); - } + TAKE_PTR(option); + return 0; +} - return r; +static int parse_file(OrderedHashmap **sysctl_options, const char *path, bool ignore_enoent) { + return conf_file_read( + /* root = */ NULL, + (const char**) CONF_PATHS_STRV("sysctl.d"), + path, + parse_line, + sysctl_options, + ignore_enoent, + /* invalid_config = */ NULL); } static int read_credential_lines(OrderedHashmap **sysctl_options) {