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:
parent
853b8397ac
commit
fabe5c0e5f
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)) { \
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user