]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sysctl: port parse_file() over conf_file_read()
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 5 Oct 2025 16:51:59 +0000 (01:51 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 5 Oct 2025 18:05:59 +0000 (03:05 +0900)
Then, systemd-sysctl can also support stdin and relative paths, like
systemd-sysusers and systemd-tmpfiles do.

man/systemd-sysctl.service.xml
src/sysctl/sysctl.c

index 720beed8eec23c43068ff205140b8132376b9d08..0702fa87ce41ded449fb40a4ff8fb936da6d7422 100644 (file)
     <para>When invoked with no arguments, <command>/usr/lib/systemd/systemd-sysctl</command> applies
     all directives from configuration files listed in
     <citerefentry><refentrytitle>sysctl.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
-    If one or more filenames are passed on the command line, only the directives in these files are
-    applied.</para>
+    When invoked with positional arguments, the configuration specified by the command line arguments is
+    executed. If the string <literal>-</literal> 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.</para>
 
     <para>In addition, <option>--prefix=</option> option may be used to limit which sysctl
     settings are applied.</para>
index 47990b4e6923414524fcc0cd129b07596c74ba1d..4e0c977c938869d2364c8ba8e9a26280cbd846a7 100644 (file)
@@ -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) {