No functional change.
Note that this function will be modified in subsequent commits, and the API
will change.
#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"
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;
+}
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
+#include <stdbool.h>
+
#include "macro.h"
enum {
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);
}
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. */
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);
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)
}
}
- if (ferror(f)) {
- log_error_errno(errno, "Failed to read from file %s: %m", fn);
- if (r == 0)
- r = -EIO;
- }
-
return r;
}