tmpfiles: split out helper to open and read a "config file"
No functional change. Note that this function will be modified in subsequent commits, and the API will change.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
+7
-59
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user