summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/sysctl.d.xml2
-rw-r--r--src/binfmt/binfmt.c130
-rw-r--r--src/modules-load/modules-load.c181
-rw-r--r--src/shared/conf-files.c112
-rw-r--r--src/shared/conf-files.h1
-rw-r--r--src/shared/hashmap.c27
-rw-r--r--src/shared/hashmap.h2
-rw-r--r--src/shared/path-util.c10
-rw-r--r--src/shared/path-util.h1
-rw-r--r--src/shared/strv.c16
-rw-r--r--src/shared/strv.h1
-rw-r--r--src/shared/util.c79
-rw-r--r--src/shared/util.h3
-rw-r--r--src/sysctl/sysctl.c153
-rw-r--r--src/tmpfiles/tmpfiles.c88
15 files changed, 516 insertions, 290 deletions
diff --git a/man/sysctl.d.xml b/man/sysctl.d.xml
index 69aac8cab7..0ef5545163 100644
--- a/man/sysctl.d.xml
+++ b/man/sysctl.d.xml
@@ -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
diff --git a/src/binfmt/binfmt.c b/src/binfmt/binfmt.c
index 296607d6a2..f8c97b5ca5 100644
--- a/src/binfmt/binfmt.c
+++ b/src/binfmt/binfmt.c
@@ -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) {
- int i;
+ r = 0;
- for (i = 1; i < argc; i++) {
- int k;
+ if (argc > optind) {
+ int i;
+ 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;
}
diff --git a/src/modules-load/modules-load.c b/src/modules-load/modules-load.c
index 936aaed8e4..88b1261494 100644
--- a/src/modules-load/modules-load.c
+++ b/src/modules-load/modules-load.c
@@ -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;
- }
-
- 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;
+ if (argc > optind) {
+ int i;
- 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;
-
- if (!fgets(line, sizeof(line), f))
- break;
+ } else {
+ _cleanup_free_ char **files = NULL;
+ char **fn, **i;
- 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;
}
diff --git a/src/shared/conf-files.c b/src/shared/conf-files.c
index 5bbd2388d3..296e605761 100644
--- a/src/shared/conf-files.c
+++ b/src/shared/conf-files.c
@@ -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;
+ *strv = files;
-finish:
hashmap_free(fh);
- *strv = files;
- return r;
+ 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;
+
+ return conf_files_list_strv_internal(strv, suffix, root, dirs);
+}
- r = conf_files_list_strv(strv, suffix, root, (const char **)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;
-finish:
- strv_free(dirs);
- return r;
+ return conf_files_list_strv_internal(strv, suffix, root, dirs);
}
diff --git a/src/shared/conf-files.h b/src/shared/conf-files.h
index 4d7941f4cb..28588e6f03 100644
--- a/src/shared/conf-files.h
+++ b/src/shared/conf-files.h
@@ -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
diff --git a/src/shared/hashmap.c b/src/shared/hashmap.c
index a2c728d642..9f7db34397 100644
--- a/src/shared/hashmap.c
+++ b/src/shared/hashmap.c
@@ -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);
diff --git a/src/shared/hashmap.h b/src/shared/hashmap.h
index 6fd71cf519..26bd03096d 100644
--- a/src/shared/hashmap.h
+++ b/src/shared/hashmap.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);
diff --git a/src/shared/path-util.c b/src/shared/path-util.c
index 52ce65de6d..0b50ea646a 100644
--- a/src/shared/path-util.c
+++ b/src/shared/path-util.c
@@ -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;
diff --git a/src/shared/path-util.h b/src/shared/path-util.h
index e37ab9350b..ff523943dc 100644
--- a/src/shared/path-util.h
+++ b/src/shared/path-util.h
@@ -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);
diff --git a/src/shared/strv.c b/src/shared/strv.c
index ee0b71ece0..ec25755289 100644
--- a/src/shared/strv.c
+++ b/src/shared/strv.c
@@ -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;
diff --git a/src/shared/strv.h b/src/shared/strv.h
index d28625bd2f..b3802a7a3f 100644
--- a/src/shared/strv.h
+++ b/src/shared/strv.h
@@ -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);
diff --git a/src/shared/util.c b/src/shared/util.c
index 29cb9f1e8d..24f9e7ee58 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -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);
+}
diff --git a/src/shared/util.h b/src/shared/util.h
index d926b01919..cd13457528 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -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)) { \
diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c
index f5ef89b385..f59a858323 100644
--- a/src/sysctl/sysctl.c
+++ b/src/sysctl/sysctl.c
@@ -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;
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 96adbff42e..6b3f70e071 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -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;
}