1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-23 21:35:11 +03:00

binfmt,tmpfiles,modules-load,sysctl: rework the various early-boot services that work on .d/ directories

This unifies much of the logic behind them:

- All four will now ofllow the rule that the earlier file and earlier
  assignment in the .d/ directories wins. Before, sysctl was the only
  outlier, where the later setting always won.

- All four now support getopt() and --help on the command line.

- All four can now handle specification of configuration file names on
  the command line to apply. The tools will automatically find them, and
  apply them. Previously only tmpfiles could do that. This is useful for
  %post scripts in RPMs and suchlike.

- This fixes various error path issues in conf_files_list()
This commit is contained in:
Lennart Poettering 2013-02-11 23:48:36 +01:00
parent 853b8397ac
commit fabe5c0e5f
15 changed files with 518 additions and 292 deletions

View File

@ -92,7 +92,7 @@
alphabetical order, regardless in which of the
directories they reside, to guarantee that a specific
configuration file takes precedence over another file
with an alphabetically earlier name, if both files
with an alphabetically later name, if both files
contain the same variable setting.</para>
<para>If the administrator wants to disable a

View File

@ -26,6 +26,7 @@
#include <stdio.h>
#include <limits.h>
#include <stdarg.h>
#include <getopt.h>
#include "log.h"
#include "hashmap.h"
@ -33,28 +34,34 @@
#include "util.h"
#include "conf-files.h"
static const char conf_file_dirs[] =
"/etc/binfmt.d\0"
"/run/binfmt.d\0"
"/usr/local/lib/binfmt.d\0"
"/usr/lib/binfmt.d\0"
#ifdef HAVE_SPLIT_USR
"/lib/binfmt.d\0"
#endif
;
static int delete_rule(const char *rule) {
char *x, *fn = NULL, *e;
int r;
_cleanup_free_ char *x = NULL, *fn = NULL;
char *e;
assert(rule[0]);
if (!(x = strdup(rule)))
x = strdup(rule);
if (!x)
return log_oom();
e = strchrnul(x+1, x[0]);
*e = 0;
asprintf(&fn, "/proc/sys/fs/binfmt_misc/%s", x+1);
free(x);
fn = strappend("/proc/sys/fs/binfmt_misc/", x+1);
if (!fn)
return log_oom();
r = write_one_line_file(fn, "-1");
free(fn);
return r;
return write_one_line_file(fn, "-1");
}
static int apply_rule(const char *rule) {
@ -62,7 +69,8 @@ static int apply_rule(const char *rule) {
delete_rule(rule);
if ((r = write_one_line_file("/proc/sys/fs/binfmt_misc/register", rule)) < 0) {
r = write_one_line_file("/proc/sys/fs/binfmt_misc/register", rule);
if (r < 0) {
log_error("Failed to add binary format: %s", strerror(-r));
return r;
}
@ -71,21 +79,22 @@ static int apply_rule(const char *rule) {
}
static int apply_file(const char *path, bool ignore_enoent) {
FILE *f;
int r = 0;
_cleanup_fclose_ FILE *f = NULL;
int r;
assert(path);
if (!(f = fopen(path, "re"))) {
if (ignore_enoent && errno == ENOENT)
r = search_and_fopen_nulstr(path, "re", conf_file_dirs, &f);
if (r < 0) {
if (ignore_enoent && r == -ENOENT)
return 0;
log_error("Failed to open file '%s', ignoring: %m", path);
return -errno;
log_error("Failed to open file '%s', ignoring: %s", path, strerror(-r));
return r;
}
log_debug("apply: %s\n", path);
while (!feof(f)) {
for (;;) {
char l[LINE_MAX], *p;
int k;
@ -94,30 +103,71 @@ static int apply_file(const char *path, bool ignore_enoent) {
break;
log_error("Failed to read file '%s', ignoring: %m", path);
r = -errno;
goto finish;
return -errno;
}
p = strstrip(l);
if (!*p)
continue;
if (strchr(COMMENTS, *p))
continue;
if ((k = apply_rule(p)) < 0 && r == 0)
k = apply_rule(p);
if (k < 0 && r == 0)
r = k;
}
finish:
fclose(f);
return r;
}
static int help(void) {
printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
"Registers binary formats.\n\n"
" -h --help Show this help\n",
program_invocation_short_name);
return 0;
}
static int parse_argv(int argc, char *argv[]) {
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ NULL, 0, NULL, 0 }
};
int c;
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
switch (c) {
case 'h':
help();
return 0;
case '?':
return -EINVAL;
default:
log_error("Unknown option code %c", c);
return -EINVAL;
}
}
return 1;
}
int main(int argc, char *argv[]) {
int r = 0;
int r, k;
r = parse_argv(argc, argv);
if (r <= 0)
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
log_set_target(LOG_TARGET_AUTO);
log_parse_environment();
@ -125,28 +175,21 @@ int main(int argc, char *argv[]) {
umask(0022);
if (argc > 1) {
r = 0;
if (argc > optind) {
int i;
for (i = 1; i < argc; i++) {
int k;
for (i = optind; i < argc; i++) {
k = apply_file(argv[i], false);
if (k < 0 && r == 0)
r = k;
}
} else {
char **files, **f;
_cleanup_strv_free_ char **files = NULL;
char **f;
r = conf_files_list(&files, ".conf", NULL,
"/etc/binfmt.d",
"/run/binfmt.d",
"/usr/local/lib/binfmt.d",
"/usr/lib/binfmt.d",
#ifdef HAVE_SPLIT_USR
"/lib/binfmt.d",
#endif
NULL);
r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
if (r < 0) {
log_error("Failed to enumerate binfmt.d files: %s", strerror(-r));
goto finish;
@ -156,15 +199,12 @@ int main(int argc, char *argv[]) {
write_one_line_file("/proc/sys/fs/binfmt_misc/status", "-1");
STRV_FOREACH(f, files) {
int k;
k = apply_file(*f, true);
if (k < 0 && r == 0)
r = k;
}
strv_free(files);
}
finish:
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}

View File

@ -26,6 +26,7 @@
#include <sys/stat.h>
#include <limits.h>
#include <dirent.h>
#include <getopt.h>
#include <libkmod.h>
#include "log.h"
@ -36,6 +37,16 @@
static char **arg_proc_cmdline_modules = NULL;
static const char conf_file_dirs[] =
"/etc/modules-load.d\0"
"/run/modules-load.d\0"
"/usr/local/lib/modules-load.d\0"
"/usr/lib/modules-load.d\0"
#ifdef HAVE_SPLIT_USR
"/lib/modules-load.d\0"
#endif
;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
static void systemd_kmod_log(void *data, int priority, const char *file, int line,
@ -46,14 +57,14 @@ static void systemd_kmod_log(void *data, int priority, const char *file, int lin
#pragma GCC diagnostic pop
static int add_modules(const char *p) {
char **t, **k;
char **t;
_cleanup_strv_free_ char **k = NULL;
k = strv_split(p, ",");
if (!k)
return log_oom();
t = strv_merge(arg_proc_cmdline_modules, k);
strv_free(k);
if (!t)
return log_oom();
@ -162,15 +173,98 @@ static int load_module(struct kmod_ctx *ctx, const char *m) {
return r;
}
static int apply_file(struct kmod_ctx *ctx, const char *path, bool ignore_enoent) {
_cleanup_fclose_ FILE *f = NULL;
int r;
assert(ctx);
assert(path);
r = search_and_fopen_nulstr(path, "re", conf_file_dirs, &f);
if (r < 0) {
if (ignore_enoent && r == -ENOENT)
return 0;
log_error("Failed to open %s, ignoring: %s", path, strerror(-r));
return r;
}
log_debug("apply: %s\n", path);
for (;;) {
char line[LINE_MAX], *l;
int k;
if (!fgets(line, sizeof(line), f)) {
if (feof(f))
break;
log_error("Failed to read file '%s', ignoring: %m", path);
return -errno;
}
l = strstrip(line);
if (!*l)
continue;
if (strchr(COMMENTS, *l))
continue;
k = load_module(ctx, l);
if (k < 0 && r == 0)
r = k;
}
return r;
}
static int help(void) {
printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
"Loads statically configured kernel modules.\n\n"
" -h --help Show this help\n",
program_invocation_short_name);
return 0;
}
static int parse_argv(int argc, char *argv[]) {
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ NULL, 0, NULL, 0 }
};
int c;
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
switch (c) {
case 'h':
help();
return 0;
case '?':
return -EINVAL;
default:
log_error("Unknown option code %c", c);
return -EINVAL;
}
}
return 1;
}
int main(int argc, char *argv[]) {
int r = EXIT_FAILURE, k;
char **files = NULL, **fn, **i;
int r, k;
struct kmod_ctx *ctx;
if (argc > 1) {
log_error("This program takes no argument.");
return EXIT_FAILURE;
}
r = parse_argv(argc, argv);
if (r <= 0)
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
log_set_target(LOG_TARGET_AUTO);
log_parse_environment();
@ -190,70 +284,43 @@ int main(int argc, char *argv[]) {
kmod_load_resources(ctx);
kmod_set_log_fn(ctx, systemd_kmod_log, NULL);
r = EXIT_SUCCESS;
r = 0;
STRV_FOREACH(i, arg_proc_cmdline_modules) {
k = load_module(ctx, *i);
if (k < 0)
r = EXIT_FAILURE;
}
if (argc > optind) {
int i;
k = conf_files_list(&files, ".conf", NULL,
"/etc/modules-load.d",
"/run/modules-load.d",
"/usr/local/lib/modules-load.d",
"/usr/lib/modules-load.d",
#ifdef HAVE_SPLIT_USR
"/lib/modules-load.d",
#endif
NULL);
if (k < 0) {
log_error("Failed to enumerate modules-load.d files: %s", strerror(-k));
r = EXIT_FAILURE;
goto finish;
}
STRV_FOREACH(fn, files) {
FILE *f;
f = fopen(*fn, "re");
if (!f) {
if (errno == ENOENT)
continue;
log_error("Failed to open %s: %m", *fn);
r = EXIT_FAILURE;
continue;
for (i = optind; i < argc; i++) {
k = apply_file(ctx, argv[i], false);
if (k < 0 && r == 0)
r = k;
}
log_debug("apply: %s\n", *fn);
for (;;) {
char line[LINE_MAX], *l;
} else {
_cleanup_free_ char **files = NULL;
char **fn, **i;
if (!fgets(line, sizeof(line), f))
break;
l = strstrip(line);
if (*l == '#' || *l == 0)
continue;
k = load_module(ctx, l);
STRV_FOREACH(i, arg_proc_cmdline_modules) {
k = load_module(ctx, *i);
if (k < 0)
r = EXIT_FAILURE;
}
if (ferror(f)) {
log_error("Failed to read from file: %m");
r = EXIT_FAILURE;
r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
if (r < 0) {
log_error("Failed to enumerate modules-load.d files: %s", strerror(-r));
goto finish;
}
fclose(f);
STRV_FOREACH(fn, files) {
k = apply_file(ctx, *fn, true);
if (k < 0 && r == 0)
r = k;
}
}
finish:
strv_free(files);
kmod_unref(ctx);
strv_free(arg_proc_cmdline_modules);
return r;
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}

View File

@ -38,7 +38,7 @@
#include "conf-files.h"
static int files_add(Hashmap *h, const char *root, const char *path, const char *suffix) {
_cleanup_closedir_ DIR *dir;
_cleanup_closedir_ DIR *dir = NULL;
_cleanup_free_ char *dirpath = NULL;
if (asprintf(&dirpath, "%s%s", root ? root : "", path) < 0)
@ -55,11 +55,11 @@ static int files_add(Hashmap *h, const char *root, const char *path, const char
struct dirent *de;
union dirent_storage buf;
char *p;
int err;
int r;
err = readdir_r(dir, &buf.de, &de);
if (err != 0)
return err;
r = readdir_r(dir, &buf.de, &de);
if (r != 0)
return -r;
if (!de)
break;
@ -67,11 +67,19 @@ static int files_add(Hashmap *h, const char *root, const char *path, const char
if (!dirent_is_file_with_suffix(de, suffix))
continue;
if (asprintf(&p, "%s/%s", dirpath, de->d_name) < 0)
p = strjoin(dirpath, "/", de->d_name, NULL);
if (!p)
return -ENOMEM;
if (hashmap_put(h, path_get_file_name(p), p) <= 0) {
log_debug("Skip overridden file: %s.", p);
r = hashmap_put(h, path_get_file_name(p), p);
if (r == -EEXIST) {
log_debug("Skipping overridden file: %s.", p);
free(p);
} else if (r < 0) {
free(p);
return r;
} else if (r == 0) {
log_debug("Duplicate file %s", p);
free(p);
}
}
@ -87,64 +95,84 @@ static int base_cmp(const void *a, const void *b) {
return strcmp(path_get_file_name(s1), path_get_file_name(s2));
}
int conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char **dirs) {
Hashmap *fh = NULL;
char **files = NULL;
const char **p;
static int conf_files_list_strv_internal(char ***strv, const char *suffix, const char *root, char **dirs) {
Hashmap *fh;
char **files, **p;
int r;
assert(dirs);
assert(strv);
assert(suffix);
/* This alters the dirs string array */
if (!path_strv_canonicalize_uniq(dirs))
return -ENOMEM;
fh = hashmap_new(string_hash_func, string_compare_func);
if (!fh) {
r = -ENOMEM;
goto finish;
}
if (!fh)
return -ENOMEM;
STRV_FOREACH(p, dirs) {
r = files_add(fh, root, *p, suffix);
if (r < 0)
log_warning("Failed to search for files in %s: %s",
*p, strerror(-r));
if (r == -ENOMEM) {
hashmap_free_free(fh);
return r;
} else if (r < 0)
log_debug("Failed to search for files in %s: %s",
*p, strerror(-r));
}
files = hashmap_get_strv(fh);
if (files == NULL) {
log_error("Failed to compose list of files.");
r = -ENOMEM;
goto finish;
hashmap_free_free(fh);
return -ENOMEM;
}
qsort(files, hashmap_size(fh), sizeof(char *), base_cmp);
r = 0;
finish:
hashmap_free(fh);
qsort(files, hashmap_size(fh), sizeof(char *), base_cmp);
*strv = files;
return r;
hashmap_free(fh);
return 0;
}
int conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char **dirs) {
_cleanup_strv_free_ char **copy = NULL;
assert(strv);
assert(suffix);
copy = strv_copy((char**) dirs);
if (!copy)
return -ENOMEM;
return conf_files_list_strv_internal(strv, suffix, root, copy);
}
int conf_files_list(char ***strv, const char *suffix, const char *root, const char *dir, ...) {
char **dirs = NULL;
_cleanup_strv_free_ char **dirs = NULL;
va_list ap;
int r;
assert(strv);
assert(suffix);
va_start(ap, dir);
dirs = strv_new_ap(dir, ap);
va_end(ap);
if (!dirs) {
r = -ENOMEM;
goto finish;
}
if (!path_strv_canonicalize(dirs)) {
r = -ENOMEM;
goto finish;
}
strv_uniq(dirs);
if (!dirs)
return -ENOMEM;
r = conf_files_list_strv(strv, suffix, root, (const char **)dirs);
finish:
strv_free(dirs);
return r;
return conf_files_list_strv_internal(strv, suffix, root, dirs);
}
int conf_files_list_nulstr(char ***strv, const char *suffix, const char *root, const char *d) {
_cleanup_strv_free_ char **dirs = NULL;
assert(strv);
assert(suffix);
dirs = strv_split_nulstr(d);
if (!dirs)
return -ENOMEM;
return conf_files_list_strv_internal(strv, suffix, root, dirs);
}

View File

@ -27,5 +27,6 @@
int conf_files_list(char ***strv, const char *suffix, const char *root, const char *dir, ...);
int conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char **dirs);
int conf_files_list_nulstr(char ***strv, const char *suffix, const char *root, const char *dirs);
#endif

View File

@ -309,6 +309,17 @@ void hashmap_free_free(Hashmap *h) {
hashmap_free(h);
}
void hashmap_free_free_free(Hashmap *h) {
/* Free the hashmap and all data and key objects in it */
if (!h)
return;
hashmap_clear_free_free(h);
hashmap_free(h);
}
void hashmap_clear(Hashmap *h) {
if (!h)
return;
@ -327,6 +338,22 @@ void hashmap_clear_free(Hashmap *h) {
free(p);
}
void hashmap_clear_free_free(Hashmap *h) {
if (!h)
return;
while (h->iterate_list_head) {
void *a, *b;
a = h->iterate_list_head->value;
b = (void*) h->iterate_list_head->key;
remove_entry(h, h->iterate_list_head);
free(a);
free(b);
}
}
static struct hashmap_entry *hash_scan(Hashmap *h, unsigned hash, const void *key) {
struct hashmap_entry *e;
assert(h);

View File

@ -50,6 +50,7 @@ int uint64_compare_func(const void *a, const void *b);
Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func);
void hashmap_free(Hashmap *h);
void hashmap_free_free(Hashmap *h);
void hashmap_free_free_free(Hashmap *h);
Hashmap *hashmap_copy(Hashmap *h);
int hashmap_ensure_allocated(Hashmap **h, hash_func_t hash_func, compare_func_t compare_func);
@ -77,6 +78,7 @@ void *hashmap_iterate_skip(Hashmap *h, const void *key, Iterator *i);
void hashmap_clear(Hashmap *h);
void hashmap_clear_free(Hashmap *h);
void hashmap_clear_free_free(Hashmap *h);
void *hashmap_steal_first(Hashmap *h);
void *hashmap_steal_first_key(Hashmap *h);

View File

@ -215,6 +215,16 @@ char **path_strv_canonicalize(char **l) {
return l;
}
char **path_strv_canonicalize_uniq(char **l) {
if (strv_isempty(l))
return l;
if (!path_strv_canonicalize(l))
return NULL;
return strv_uniq(l);
}
char *path_kill_slashes(char *path) {
char *f, *t;
bool slash = false;

View File

@ -37,6 +37,7 @@ bool path_equal(const char *a, const char *b);
char **path_strv_make_absolute_cwd(char **l);
char **path_strv_canonicalize(char **l);
char **path_strv_canonicalize_uniq(char **l);
int path_is_mount_point(const char *path, bool allow_symlink);
int path_is_read_only_fs(const char *path);

View File

@ -504,6 +504,22 @@ char **strv_parse_nulstr(const char *s, size_t l) {
return v;
}
char **strv_split_nulstr(const char *s) {
const char *i;
char **r = NULL;
NULSTR_FOREACH(i, s)
if (strv_extend(&r, i) < 0) {
strv_free(r);
return NULL;
}
if (!r)
return strv_new(NULL, NULL);
return r;
}
bool strv_overlap(char **a, char **b) {
char **i, **j;

View File

@ -62,6 +62,7 @@ char **strv_split_quoted(const char *s) _malloc_;
char *strv_join(char **l, const char *separator) _malloc_;
char **strv_parse_nulstr(const char *s, size_t l);
char **strv_split_nulstr(const char *s);
bool strv_overlap(char **a, char **b);

View File

@ -5909,3 +5909,82 @@ int on_ac_power(void) {
return found_online || !found_offline;
}
static int search_and_fopen_internal(const char *path, const char *mode, char **search, FILE **_f) {
char **i;
assert(path);
assert(mode);
assert(_f);
if (!path_strv_canonicalize_uniq(search))
return -ENOMEM;
STRV_FOREACH(i, search) {
_cleanup_free_ char *p = NULL;
FILE *f;
p = strjoin(*i, "/", path, NULL);
if (!p)
return -ENOMEM;
f = fopen(p, mode);
if (f) {
*_f = f;
return 0;
}
if (errno != ENOENT)
return -errno;
}
return -ENOENT;
}
int search_and_fopen(const char *path, const char *mode, const char **search, FILE **_f) {
_cleanup_strv_free_ char **copy = NULL;
assert(path);
assert(mode);
assert(_f);
if (path_is_absolute(path)) {
FILE *f;
f = fopen(path, mode);
if (f) {
*_f = f;
return 0;
}
return -errno;
}
copy = strv_copy((char**) search);
if (!copy)
return -ENOMEM;
return search_and_fopen_internal(path, mode, copy, _f);
}
int search_and_fopen_nulstr(const char *path, const char *mode, const char *search, FILE **_f) {
_cleanup_strv_free_ char **s = NULL;
if (path_is_absolute(path)) {
FILE *f;
f = fopen(path, mode);
if (f) {
*_f = f;
return 0;
}
return -errno;
}
s = strv_split_nulstr(search);
if (!s)
return -ENOMEM;
return search_and_fopen_internal(path, mode, s, _f);
}

View File

@ -568,6 +568,9 @@ char *strip_tab_ansi(char **p, size_t *l);
int on_ac_power(void);
int search_and_fopen(const char *path, const char *mode, const char **search, FILE **_f);
int search_and_fopen_nulstr(const char *path, const char *mode, const char *search, FILE **_f);
#define FOREACH_LINE(f, line, on_error) \
for (char line[LINE_MAX]; !feof(f); ) \
if (!fgets(line, sizeof(line), f)) { \

View File

@ -35,28 +35,42 @@
#include "path-util.h"
#include "conf-files.h"
#define PROC_SYS_PREFIX "/proc/sys/"
static char **arg_prefixes = NULL;
static char **arg_prefixes;
static Hashmap *sysctl_options;
static const char conf_file_dirs[] =
"/etc/sysctl.d\0"
"/run/sysctl.d\0"
"/usr/local/lib/sysctl.d\0"
"/usr/lib/sysctl.d\0"
#ifdef HAVE_SPLIT_USR
"/lib/sysctl.d\0"
#endif
;
static char *normalize_sysctl(char *s) {
char *n;
for (n = s; *n; n++)
if (*n == '.')
*n = '/';
return s;
}
static int apply_sysctl(const char *property, const char *value) {
char *p, *n;
_cleanup_free_ char *p = NULL;
char *n;
int r = 0, k;
log_debug("Setting '%s' to '%s'", property, value);
p = new(char, sizeof(PROC_SYS_PREFIX) + strlen(property));
p = new(char, sizeof("/proc/sys/") + strlen(property));
if (!p)
return log_oom();
n = stpcpy(p, PROC_SYS_PREFIX);
n = stpcpy(p, "/proc/sys/");
strcpy(n, property);
for (; *n; n++)
if (*n == '.')
*n = '/';
if (!strv_isempty(arg_prefixes)) {
char **i;
bool good = false;
@ -69,14 +83,12 @@ static int apply_sysctl(const char *property, const char *value) {
if (!good) {
log_debug("Skipping %s", p);
free(p);
return 0;
}
}
k = write_one_line_file(p, value);
if (k < 0) {
log_full(k == -ENOENT ? LOG_DEBUG : LOG_WARNING,
"Failed to write '%s' to '%s': %s", value, p, strerror(-k));
@ -84,16 +96,16 @@ static int apply_sysctl(const char *property, const char *value) {
r = k;
}
free(p);
return r;
}
static int apply_all(void) {
static int apply_all(Hashmap *sysctl_options) {
int r = 0;
char *property, *value;
Iterator i;
assert(sysctl_options);
HASHMAP_FOREACH_KEY(value, property, sysctl_options, i) {
int k;
@ -104,36 +116,35 @@ static int apply_all(void) {
return r;
}
static int parse_file(const char *path, bool ignore_enoent) {
FILE *f;
int r = 0;
static int parse_file(Hashmap *sysctl_options, const char *path, bool ignore_enoent) {
_cleanup_fclose_ FILE *f = NULL;
int r;
assert(path);
f = fopen(path, "re");
if (!f) {
if (ignore_enoent && errno == ENOENT)
r = search_and_fopen_nulstr(path, "re", conf_file_dirs, &f);
if (r < 0) {
if (ignore_enoent && errno == -ENOENT)
return 0;
log_error("Failed to open file '%s', ignoring: %m", path);
return -errno;
log_error("Failed to open file '%s', ignoring: %s", path, strerror(-r));
return r;
}
log_debug("parse: %s\n", path);
while (!feof(f)) {
char l[LINE_MAX], *p, *value, *new_value, *property;
char l[LINE_MAX], *p, *value, *new_value, *property, *existing;
int k;
if (!fgets(l, sizeof(l), f)) {
if (feof(f))
break;
log_error("Failed to read file '%s', ignoring: %m", path);
r = -errno;
goto finish;
return -errno;
}
p = strstrip(l);
if (!*p)
continue;
@ -152,40 +163,36 @@ static int parse_file(const char *path, bool ignore_enoent) {
*value = 0;
value++;
property = strdup(strstrip(p));
if (!property) {
r = log_oom();
goto finish;
p = normalize_sysctl(strstrip(p));
value = strstrip(value);
existing = hashmap_get(sysctl_options, p);
if (existing) {
if (!streq(value, existing))
log_warning("Two ore more conflicting assignments of %s, ignoring.", property);
continue;
}
new_value = strdup(strstrip(value));
property = strdup(p);
if (!property)
return log_oom();
new_value = strdup(value);
if (!new_value) {
free(property);
r = log_oom();
goto finish;
return log_oom();
}
r = hashmap_put(sysctl_options, property, new_value);
if (r < 0) {
if (r == -EEXIST) {
/* ignore this "error" to avoid returning it
* for the function when this is the last key
* in the file being parsed. */
r = 0;
log_debug("Skipping previously assigned sysctl variable %s", property);
} else
log_error("Failed to add sysctl variable %s to hashmap: %s", property, strerror(-r));
k = hashmap_put(sysctl_options, property, new_value);
if (k < 0) {
log_error("Failed to add sysctl variable %s to hashmap: %s", property, strerror(-r));
free(property);
free(new_value);
if (r != 0)
goto finish;
return k;
}
}
finish:
fclose(f);
return r;
}
@ -257,8 +264,7 @@ static int parse_argv(int argc, char *argv[]) {
int main(int argc, char *argv[]) {
int r = 0, k;
char *property, *value;
Iterator it;
Hashmap *sysctl_options;
r = parse_argv(argc, argv);
if (r <= 0)
@ -282,54 +288,35 @@ int main(int argc, char *argv[]) {
int i;
for (i = optind; i < argc; i++) {
k = parse_file(argv[i], false);
if (k < 0)
k = parse_file(sysctl_options, argv[i], false);
if (k < 0 && r == 0)
r = k;
}
} else {
char **files, **f;
_cleanup_strv_free_ char **files = NULL;
char **f;
r = conf_files_list(&files, ".conf", NULL,
"/etc/sysctl.d",
"/run/sysctl.d",
"/usr/local/lib/sysctl.d",
"/usr/lib/sysctl.d",
#ifdef HAVE_SPLIT_USR
"/lib/sysctl.d",
#endif
NULL);
r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
if (r < 0) {
log_error("Failed to enumerate sysctl.d files: %s", strerror(-r));
goto finish;
}
/* We parse the files in decreasing order of precedence.
* parse_file() will skip keys that were already assigned. */
r = parse_file(sysctl_options, "/etc/sysctl.conf", true);
r = parse_file("/etc/sysctl.conf", true);
f = files + strv_length(files) - 1;
STRV_FOREACH_BACKWARDS(f, files) {
k = parse_file(*f, true);
if (k < 0)
STRV_FOREACH(f, files) {
k = parse_file(sysctl_options, *f, true);
if (k < 0 && r == 0)
r = k;
}
strv_free(files);
}
k = apply_all();
if (k < 0)
k = apply_all(sysctl_options);
if (k < 0 && r == 0)
r = k;
finish:
HASHMAP_FOREACH_KEY(value, property, sysctl_options, it) {
hashmap_remove(sysctl_options, property);
free(property);
free(value);
}
hashmap_free(sysctl_options);
hashmap_free_free_free(sysctl_options);
strv_free(arg_prefixes);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;

View File

@ -106,16 +106,15 @@ static bool arg_remove = false;
static const char *arg_prefix = NULL;
static const char * const conf_file_dirs[] = {
"/etc/tmpfiles.d",
"/run/tmpfiles.d",
"/usr/local/lib/tmpfiles.d",
"/usr/lib/tmpfiles.d",
static const char conf_file_dirs[] =
"/etc/tmpfiles.d\0"
"/run/tmpfiles.d\0"
"/usr/local/lib/tmpfiles.d\0"
"/usr/lib/tmpfiles.d\0"
#ifdef HAVE_SPLIT_USR
"/lib/tmpfiles.d",
"/lib/tmpfiles.d\0"
#endif
NULL
};
;
#define MAX_DEPTH 256
@ -1289,20 +1288,19 @@ static int parse_argv(int argc, char *argv[]) {
static int read_config_file(const char *fn, bool ignore_enoent) {
FILE *f;
unsigned v = 0;
int r = 0;
int r;
Iterator iterator;
Item *i;
assert(fn);
f = fopen(fn, "re");
if (!f) {
if (ignore_enoent && errno == ENOENT)
r = search_and_fopen_nulstr(fn, "re", conf_file_dirs, &f);
if (r < 0) {
if (ignore_enoent && r == -ENOENT)
return 0;
log_error("Failed to open %s: %m", fn);
return -errno;
log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
return r;
}
log_debug("apply: %s\n", fn);
@ -1363,32 +1361,8 @@ static int read_config_file(const char *fn, bool ignore_enoent) {
return r;
}
static char *resolve_fragment(const char *fragment, const char **search_paths) {
const char **p;
char *resolved_path;
if (is_path(fragment))
return strdup(fragment);
STRV_FOREACH(p, search_paths) {
resolved_path = strjoin(*p, "/", fragment, NULL);
if (resolved_path == NULL) {
log_oom();
return NULL;
}
if (access(resolved_path, F_OK) == 0)
return resolved_path;
free(resolved_path);
}
errno = ENOENT;
return NULL;
}
int main(int argc, char *argv[]) {
int r;
int r, k;
Item *i;
Iterator iterator;
@ -1408,46 +1382,36 @@ int main(int argc, char *argv[]) {
globs = hashmap_new(string_hash_func, string_compare_func);
if (!items || !globs) {
log_oom();
r = EXIT_FAILURE;
r = log_oom();
goto finish;
}
r = EXIT_SUCCESS;
r = 0;
if (optind < argc) {
int j;
for (j = optind; j < argc; j++) {
char *fragment;
fragment = resolve_fragment(argv[j], (const char **)conf_file_dirs);
if (!fragment) {
log_error("Failed to find a %s file: %m", argv[j]);
r = EXIT_FAILURE;
goto finish;
}
if (read_config_file(fragment, false) < 0)
r = EXIT_FAILURE;
free(fragment);
k = read_config_file(argv[j], false);
if (k < 0 && r == 0)
r = k;
}
} else {
char **files, **f;
_cleanup_strv_free_ char **files = NULL;
char **f;
r = conf_files_list_strv(&files, ".conf", NULL, (const char **)conf_file_dirs);
r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
if (r < 0) {
log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
r = EXIT_FAILURE;
goto finish;
}
STRV_FOREACH(f, files) {
if (read_config_file(*f, true) < 0)
r = EXIT_FAILURE;
k = read_config_file(*f, true);
if (k < 0 && r == 0)
r = k;
}
strv_free(files);
}
HASHMAP_FOREACH(i, globs, iterator)
@ -1470,5 +1434,5 @@ finish:
label_finish();
return r;
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}