]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
tmpfiles: split out helper to open and read a "config file"
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Sun, 3 Dec 2023 13:53:49 +0000 (14:53 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Fri, 9 Feb 2024 16:57:41 +0000 (17:57 +0100)
No functional change.

Note that this function will be modified in subsequent commits, and the API
will change.

src/basic/conf-files.c
src/basic/conf-files.h
src/tmpfiles/tmpfiles.c

index a56f82f8a3e8f309e592006ead319626598b13d4..d85d651525f1851c779285b862dc33ab0b1ac805 100644 (file)
@@ -9,7 +9,10 @@
 #include "conf-files.h"
 #include "constants.h"
 #include "dirent-util.h"
+#include "errno-util.h"
 #include "fd-util.h"
+#include "fileio.h"
+#include "glyph-util.h"
 #include "hashmap.h"
 #include "log.h"
 #include "macro.h"
@@ -372,3 +375,82 @@ int conf_files_list_dropins(
 
         return conf_files_list_strv(ret, ".conf", root, 0, (const char* const*) dropin_dirs);
 }
+
+/**
+ * Open and read a config file.
+ *
+ * The <fn> argument may be:
+ * - '-', meaning stdin.
+ * - a non-absolute path. In this case <config_dirs> are searched.
+ * - an absolute path. In this case <fn> is opened directly.
+ */
+int conf_file_read(
+                const char *root,
+                const char **config_dirs,
+                const char *fn,
+                parse_line_t parse_line,
+                void *userdata,
+                bool ignore_enoent,
+                bool *invalid_config) {
+
+        _cleanup_fclose_ FILE *_f = NULL;
+        _cleanup_free_ char *_fn = NULL;
+        unsigned v = 0;
+        FILE *f;
+        int r;
+
+        assert(fn);
+
+        if (streq(fn, "-")) {
+                f = stdin;
+                fn = "<stdin>";
+
+                log_debug("Reading config from stdin%s", special_glyph(SPECIAL_GLYPH_ELLIPSIS));
+
+        } else {
+                r = search_and_fopen(fn, "re", root, config_dirs, &_f, &_fn);
+                if (r == -ENOENT && ignore_enoent) {
+                        log_debug_errno(r, "Failed to open \"%s\", ignoring: %m", fn);
+                        return 0; /* No error, but nothing happened. */
+                }
+                if (r < 0)
+                        return log_error_errno(r, "Failed to read '%s': %m", fn);
+
+                f = _f;
+                fn = _fn;
+                log_debug("Reading config file \"%s\"%s", fn, special_glyph(SPECIAL_GLYPH_ELLIPSIS));
+        }
+
+        r = 1;  /* We entered the part where we may modify state. */
+
+        for (;;) {
+                _cleanup_free_ char *line = NULL;
+                bool invalid_line = false;
+                int k;
+
+                k = read_stripped_line(f, LONG_LINE_MAX, &line);
+                if (k < 0)
+                        return log_error_errno(k, "Failed to read '%s': %m", fn);
+                if (k == 0)
+                        break;
+
+                v++;
+
+                if (IN_SET(line[0], 0, '#'))
+                        continue;
+
+                k = parse_line(fn, v, line, &invalid_line, userdata);
+                if (k < 0 && invalid_line) {
+                        /* Allow reporting with a special code if the caller requested this. */
+                        if (invalid_config)
+                                *invalid_config = true;
+                } else
+                        /* The first error, if any, becomes our return value. */
+                        RET_GATHER(r, k);
+        }
+
+        if (ferror(f))
+                RET_GATHER(r, log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to read from file %s.", fn));
+
+        return r;
+}
index 566cc8fda4623f4c16bf6500583c75daa406f0ba..cf89ee62c68ac3badc2126bf225198af7ea8ca4c 100644 (file)
@@ -1,6 +1,8 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
+#include <stdbool.h>
+
 #include "macro.h"
 
 enum {
@@ -29,3 +31,19 @@ int conf_files_list_dropins(
                 const char *dropin_dirname,
                 const char *root,
                 const char * const *dirs);
+
+typedef int parse_line_t(
+                const char *fname,
+                unsigned line,
+                const char *buffer,
+                bool *invalid_config,
+                void *userdata);
+
+int conf_file_read(
+                const char *root,
+                const char **config_dirs,
+                const char *fn,
+                parse_line_t parse_line,
+                void *userdata,
+                bool ignore_enoent,
+                bool *invalid_config);
index 4e245e36681f69cfaa8cd96c9dc5a7012a650757..a2eb05c6a633c4c248cd806de8e028601a6fa759 100644 (file)
@@ -3463,12 +3463,13 @@ static bool is_duplicated_item(ItemArray *existing, const Item *i) {
 }
 
 static int parse_line(
-                Context *c,
                 const char *fname,
                 unsigned line,
                 const char *buffer,
-                bool *invalid_config) {
+                bool *invalid_config,
+                void *context) {
 
+        Context *c = ASSERT_PTR(context);
         _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
         _cleanup_(item_free_contents) Item i = {
                 /* The "age-by" argument considers all file timestamp types by default. */
@@ -3481,7 +3482,6 @@ static int parse_line(
         bool append_or_force = false, boot = false, allow_failure = false, try_replace = false,
                 unbase64 = false, from_cred = false, missing_user_or_group = false;
 
-        assert(c);
         assert(fname);
         assert(line >= 1);
         assert(buffer);
@@ -4225,62 +4225,16 @@ static int read_config_file(
                 bool ignore_enoent,
                 bool *invalid_config) {
 
-        _cleanup_fclose_ FILE *_f = NULL;
-        _cleanup_free_ char *pp = NULL;
-        unsigned v = 0;
-        FILE *f;
         ItemArray *ia;
         int r = 0;
 
         assert(c);
         assert(fn);
 
-        if (streq(fn, "-")) {
-                log_debug("Reading config from stdin%s", special_glyph(SPECIAL_GLYPH_ELLIPSIS));
-                fn = "<stdin>";
-                f = stdin;
-        } else {
-                r = search_and_fopen(fn, "re", arg_root, (const char**) config_dirs, &_f, &pp);
-                if (r < 0) {
-                        if (ignore_enoent && r == -ENOENT) {
-                                log_debug_errno(r, "Failed to open \"%s\", ignoring: %m", fn);
-                                return 0;
-                        }
-
-                        return log_error_errno(r, "Failed to open '%s': %m", fn);
-                }
-
-                log_debug("Reading config file \"%s\"%s", pp, special_glyph(SPECIAL_GLYPH_ELLIPSIS));
-                fn = pp;
-                f = _f;
-        }
-
-        for (;;) {
-                _cleanup_free_ char *line = NULL;
-                bool invalid_line = false;
-                int k;
-
-                k = read_stripped_line(f, LONG_LINE_MAX, &line);
-                if (k < 0)
-                        return log_error_errno(k, "Failed to read '%s': %m", fn);
-                if (k == 0)
-                        break;
-
-                v++;
-
-                if (IN_SET(line[0], 0, '#'))
-                        continue;
-
-                k = parse_line(c, fn, v, line, &invalid_line);
-                if (k < 0) {
-                        if (invalid_line)
-                                /* Allow reporting with a special code if the caller requested this */
-                                *invalid_config = true;
-                        else if (r == 0)
-                                /* The first error becomes our return value */
-                                r = k;
-                }
-        }
+        r = conf_file_read(arg_root, (const char**) config_dirs, fn,
+                           parse_line, c, ignore_enoent, invalid_config);
+        if (r <= 0)
+                return r;
 
         /* we have to determine age parameter for each entry of type X */
         ORDERED_HASHMAP_FOREACH(ia, c->globs)
@@ -4319,12 +4273,6 @@ static int read_config_file(
                         }
                 }
 
-        if (ferror(f)) {
-                log_error_errno(errno, "Failed to read from file %s: %m", fn);
-                if (r == 0)
-                        r = -EIO;
-        }
-
         return r;
 }