diff options
-rw-r--r-- | man/sysctl.d.xml | 2 | ||||
-rw-r--r-- | src/binfmt/binfmt.c | 130 | ||||
-rw-r--r-- | src/modules-load/modules-load.c | 181 | ||||
-rw-r--r-- | src/shared/conf-files.c | 112 | ||||
-rw-r--r-- | src/shared/conf-files.h | 1 | ||||
-rw-r--r-- | src/shared/hashmap.c | 27 | ||||
-rw-r--r-- | src/shared/hashmap.h | 2 | ||||
-rw-r--r-- | src/shared/path-util.c | 10 | ||||
-rw-r--r-- | src/shared/path-util.h | 1 | ||||
-rw-r--r-- | src/shared/strv.c | 16 | ||||
-rw-r--r-- | src/shared/strv.h | 1 | ||||
-rw-r--r-- | src/shared/util.c | 79 | ||||
-rw-r--r-- | src/shared/util.h | 3 | ||||
-rw-r--r-- | src/sysctl/sysctl.c | 153 | ||||
-rw-r--r-- | src/tmpfiles/tmpfiles.c | 88 |
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; } |