From db1413d7380acacc4e50faf801ca0d401da89764 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Mon, 25 Apr 2011 20:41:47 +0200 Subject: [PATCH] sysctl.d, binfmt.d, modules-load.d: switch to stacked config dirs in /lib, /etc, /run --- Makefile.am | 3 ++ man/binfmt.d.xml | 26 ++++++++---- man/modules-load.d.xml | 17 +++++++- man/sysctl.d.xml | 15 +++++++ src/binfmt.c | 78 +++++++++++------------------------ src/hashmap.c | 18 ++++++++ src/hashmap.h | 2 + src/modules-load.c | 65 +++++++---------------------- src/sysctl.c | 72 ++++++++------------------------ src/util.c | 94 ++++++++++++++++++++++++++++++++++++++++++ src/util.h | 1 + 11 files changed, 222 insertions(+), 169 deletions(-) diff --git a/Makefile.am b/Makefile.am index 0aaa1e45..b4644fa7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1287,8 +1287,11 @@ install-data-hook: $(MKDIR_P) -m 0755 \ $(DESTDIR)$(tmpfilesdir) \ $(DESTDIR)$(sysconfdir)/modules-load.d \ + $(DESTDIR)$(prefix)/lib/modules-load.d \ $(DESTDIR)$(sysconfdir)/sysctl.d \ + $(DESTDIR)$(prefix)/lib/sysctl.d \ $(DESTDIR)$(sysconfdir)/binfmt.d \ + $(DESTDIR)$(prefix)/lib/binfmt.d \ $(DESTDIR)$(systemshutdowndir) \ $(DESTDIR)$(systemgeneratordir) \ $(DESTDIR)$(usergeneratordir) diff --git a/man/binfmt.d.xml b/man/binfmt.d.xml index 64c27554..5a8803f6 100644 --- a/man/binfmt.d.xml +++ b/man/binfmt.d.xml @@ -46,20 +46,20 @@ + /usr/lib/binfmt.d/*.conf /etc/binfmt.d/*.conf + /run/binfmt.d/*.conf Description systemd uses - /etc/binfmt.d/ to configure + files from the above directories to configure additional binary formats to register during boot in the kernel. Each configuration file is named in the style of - /etc/binfmt.d/<program>.conf. - - + <program>.conf. @@ -75,11 +75,19 @@ ignored. Note that this means you may not use ; and # as delimiter in binary format rules. - Configuration files are loaded in alphabetical - order. To ensure that a specific rule takes precedence - over another place it in a file with an alphabetically - later name. - + Files in /etc/ overwrite + files with the same name in /usr/lib/. + Files in /run overwrite files with + the same name in /etc/ and + /usr/lib/. Packages should install their + configuration files in /usr/lib/, files + in /etc/ are reserved for the local + administration, which possibly decides to overwrite the + configurations installed from packages. All files are sorted + by filename in alphabetical order, regardless in which of the + directories they reside, to ensure that a specific + configuration file takes precedence over another file with + an alphabetically later name. diff --git a/man/modules-load.d.xml b/man/modules-load.d.xml index 34076916..b2f15dc7 100644 --- a/man/modules-load.d.xml +++ b/man/modules-load.d.xml @@ -46,14 +46,16 @@ + /usr/lib/modules-load.d/*.conf /etc/modules-load.d/*.conf + /run/modules-load.d/*.conf Description systemd uses - /etc/modules-load.d/ to configure + files from the above directories to configure kernel modules to load during boot in a static list. Each configuration file is named in the style of /etc/modules-load.d/<program>.conf. Note @@ -72,6 +74,19 @@ newlines. Empty lines and lines whose first non-whitespace character is # or ; are ignored. + Files in /etc/ overwrite + files with the same name in /usr/lib/. + Files in /run overwrite files with + the same name in /etc/ and + /usr/lib/. Packages should install their + configuration files in /usr/lib/, files + in /etc/ are reserved for the local + administration, which possibly decides to overwrite the + configurations installed from packages. All files are sorted + by filename in alphabetical order, regardless in which of the + directories they reside, to ensure that a specific + configuration file takes precedence over another file with + an alphabetically later name. diff --git a/man/sysctl.d.xml b/man/sysctl.d.xml index 8f336dc0..51afbfa7 100644 --- a/man/sysctl.d.xml +++ b/man/sysctl.d.xml @@ -46,7 +46,9 @@ + /usr/lib/sysctl.d/*.conf /etc/sysctl.d/*.conf + /run/sysctl.d/*.conf @@ -71,6 +73,19 @@ Note that both / and . are accepted as separators in sysctl variable names. + Files in /etc/ overwrite + files with the same name in /usr/lib/. + Files in /run overwrite files with + the same name in /etc/ and + /usr/lib/. Packages should install their + configuration files in /usr/lib/, files + in /etc/ are reserved for the local + administration, which possibly decides to overwrite the + configurations installed from packages. All files are sorted + by filename in alphabetical order, regardless in which of the + directories they reside, to ensure that a specific + configuration file takes precedence over another file with + an alphabetically later name. diff --git a/src/binfmt.c b/src/binfmt.c index 6ebd212e..619f6e4a 100644 --- a/src/binfmt.c +++ b/src/binfmt.c @@ -25,8 +25,11 @@ #include #include #include +#include #include "log.h" +#include "hashmap.h" +#include "strv.h" #include "util.h" static int delete_rule(const char *rule) { @@ -80,6 +83,7 @@ static int apply_file(const char *path, bool ignore_enoent) { return -errno; } + log_debug("apply: %s\n", path); while (!feof(f)) { char l[LINE_MAX], *p; int k; @@ -111,57 +115,6 @@ finish: return r; } -static int scandir_filter(const struct dirent *d) { - assert(d); - - if (ignore_file(d->d_name)) - return 0; - - if (d->d_type != DT_REG && - d->d_type != DT_LNK && - d->d_type != DT_UNKNOWN) - return 0; - - return endswith(d->d_name, ".conf"); -} - -static int apply_tree(const char *path) { - struct dirent **de = NULL; - int n, i, r = 0; - - if ((n = scandir(path, &de, scandir_filter, alphasort)) < 0) { - - if (errno == ENOENT) - return 0; - - log_error("Failed to enumerate %s files: %m", path); - return -errno; - } - - for (i = 0; i < n; i++) { - char *fn; - int k; - - k = asprintf(&fn, "%s/%s", path, de[i]->d_name); - free(de[i]); - - if (k < 0) { - log_error("Failed to allocate file name."); - - if (r == 0) - r = -ENOMEM; - continue; - } - - if ((k = apply_file(fn, true)) < 0 && r == 0) - r = k; - } - - free(de); - - return r; -} - int main(int argc, char *argv[]) { int r = 0; @@ -174,14 +127,29 @@ int main(int argc, char *argv[]) { log_parse_environment(); log_open(); - if (argc > 1) + if (argc > 1) { r = apply_file(argv[1], false); - else { + } else { + char **files, **f; + /* Flush out all rules */ write_one_line_file("/proc/sys/fs/binfmt_misc/status", "-1"); - r = apply_tree("/etc/binfmt.d"); - } + files = conf_files_list(".conf", + "/run/binfmt.d", + "/etc/binfmt.d", + "/usr/lib/binfmt.d", + NULL); + STRV_FOREACH(f, files) { + int k; + + k = apply_file(*f, true); + if (k < 0 && r == 0) + r = k; + } + + strv_free(files); + } return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/hashmap.c b/src/hashmap.c index 4b187057..53502576 100644 --- a/src/hashmap.c +++ b/src/hashmap.c @@ -592,3 +592,21 @@ Hashmap *hashmap_copy(Hashmap *h) { return copy; } + +char **hashmap_get_strv(Hashmap *h) { + char **sv; + Iterator it; + char *path; + int n; + + sv = malloc((h->n_entries+1) * sizeof(char *)); + if (sv == NULL) + return NULL; + + n = 0; + HASHMAP_FOREACH(path, h, it) + sv[n++] = path; + sv[n] = NULL; + + return sv; +} diff --git a/src/hashmap.h b/src/hashmap.h index ac5a8ae0..16ffbd39 100644 --- a/src/hashmap.h +++ b/src/hashmap.h @@ -76,6 +76,8 @@ void *hashmap_steal_first_key(Hashmap *h); void* hashmap_first(Hashmap *h); void* hashmap_last(Hashmap *h); +char **hashmap_get_strv(Hashmap *h); + #define HASHMAP_FOREACH(e, h, i) \ for ((i) = ITERATOR_FIRST, (e) = hashmap_iterate((h), &(i), NULL); (e); (e) = hashmap_iterate((h), &(i), NULL)) diff --git a/src/modules-load.c b/src/modules-load.c index 3824b57d..fac45118 100644 --- a/src/modules-load.c +++ b/src/modules-load.c @@ -31,30 +31,11 @@ #include "util.h" #include "strv.h" -/* This reads all module names listed in /etc/modules-load.d/?*.conf and - * loads them into the kernel. This follows roughly Debian's way to - * handle modules, but uses a directory of fragments instead of a - * single /etc/modules file. */ - -static int scandir_filter(const struct dirent *d) { - assert(d); - - if (ignore_file(d->d_name)) - return 0; - - if (d->d_type != DT_REG && - d->d_type != DT_LNK && - d->d_type != DT_UNKNOWN) - return 0; - - return endswith(d->d_name, ".conf"); -} - int main(int argc, char *argv[]) { - struct dirent **de = NULL; - int r = EXIT_FAILURE, n, i; + int r = EXIT_FAILURE; char **arguments = NULL; unsigned n_arguments = 0, n_allocated = 0; + char **files, **fn; if (argc > 1) { log_error("This program takes no argument."); @@ -72,48 +53,33 @@ int main(int argc, char *argv[]) { n_arguments = n_allocated = 3; - if ((n = scandir("/etc/modules-load.d/", &de, scandir_filter, alphasort)) < 0) { - - if (errno == ENOENT) - r = EXIT_SUCCESS; - else - log_error("Failed to enumerate /etc/modules-load.d/ files: %m"); - + files = conf_files_list(".conf", + "/run/modules-load.d", + "/etc/modules-load.d", + "/usr/lib/modules-load.d", + NULL); + if (files == NULL) { + log_error("Failed to enumerate modules-load.d files: %m"); goto finish; } r = EXIT_SUCCESS; - for (i = 0; i < n; i++) { - int k; - char *fn; + STRV_FOREACH(fn, files) { FILE *f; - k = asprintf(&fn, "/etc/modules-load.d/%s", de[i]->d_name); - free(de[i]); - - if (k < 0) { - log_error("Failed to allocate file name."); - r = EXIT_FAILURE; - continue; - } - - f = fopen(fn, "re"); - + f = fopen(*fn, "re"); if (!f) { - if (errno == ENOENT) { - free(fn); + if (errno == ENOENT) continue; - } - log_error("Failed to open %s: %m", fn); + log_error("Failed to open %s: %m", *fn); free(fn); r = EXIT_FAILURE; continue; } - free(fn); - + log_debug("apply: %s\n", *fn); for (;;) { char line[LINE_MAX], *l, *t; @@ -157,8 +123,7 @@ int main(int argc, char *argv[]) { fclose(f); } - free(de); - + strv_free(files); finish: if (n_arguments > 3) { diff --git a/src/sysctl.c b/src/sysctl.c index 15b6da79..1d42e937 100644 --- a/src/sysctl.c +++ b/src/sysctl.c @@ -27,6 +27,7 @@ #include #include "log.h" +#include "strv.h" #include "util.h" #define PROC_SYS_PREFIX "/proc/sys/" @@ -77,6 +78,7 @@ static int apply_file(const char *path, bool ignore_enoent) { return -errno; } + log_debug("apply: %s\n", path); while (!feof(f)) { char l[LINE_MAX], *p, *value; int k; @@ -119,57 +121,6 @@ finish: return r; } -static int scandir_filter(const struct dirent *d) { - assert(d); - - if (ignore_file(d->d_name)) - return 0; - - if (d->d_type != DT_REG && - d->d_type != DT_LNK && - d->d_type != DT_UNKNOWN) - return 0; - - return endswith(d->d_name, ".conf"); -} - -static int apply_tree(const char *path) { - struct dirent **de = NULL; - int n, i, r = 0; - - if ((n = scandir(path, &de, scandir_filter, alphasort)) < 0) { - - if (errno == ENOENT) - return 0; - - log_error("Failed to enumerate %s files: %m", path); - return -errno; - } - - for (i = 0; i < n; i++) { - char *fn; - int k; - - k = asprintf(&fn, "%s/%s", path, de[i]->d_name); - free(de[i]); - - if (k < 0) { - log_error("Failed to allocate file name."); - - if (r == 0) - r = -ENOMEM; - continue; - } - - if ((k = apply_file(fn, true)) < 0 && r == 0) - r = k; - } - - free(de); - - return r; -} - int main(int argc, char *argv[]) { int r = 0; @@ -185,12 +136,25 @@ int main(int argc, char *argv[]) { if (argc > 1) r = apply_file(argv[1], false); else { - int k; + char **files, **f; r = apply_file("/etc/sysctl.conf", true); - if ((k = apply_tree("/etc/sysctl.d")) < 0 && r == 0) - r = k; + files = conf_files_list(".conf", + "/run/sysctl.d", + "/etc/sysctl.d", + "/usr/lib/sysctl.d", + NULL); + + STRV_FOREACH(f, files) { + int k; + + k = apply_file(*f, true); + if (k < 0 && r == 0) + r = k; + } + + strv_free(files); } return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; diff --git a/src/util.c b/src/util.c index 5a076e6e..5029896e 100644 --- a/src/util.c +++ b/src/util.c @@ -4528,3 +4528,97 @@ static const char *const signal_table[] = { }; DEFINE_STRING_TABLE_LOOKUP(signal, int); + +static int file_is_conf(const struct dirent *d, const char *suffix) { + assert(d); + + if (ignore_file(d->d_name)) + return 0; + + if (d->d_type != DT_REG && + d->d_type != DT_LNK && + d->d_type != DT_UNKNOWN) + return 0; + + return endswith(d->d_name, suffix); +} + +static int files_add(Hashmap *h, const char *path, const char *suffix) { + DIR *dir; + struct dirent *de; + int r = 0; + + dir = opendir(path); + if (!dir) { + if (errno == ENOENT) + return 0; + return -errno; + } + + for (de = readdir(dir); de; de = readdir(dir)) { + char *f; + const char *base; + + if (!file_is_conf(de, suffix)) + continue; + + if (asprintf(&f, "%s/%s", path, de->d_name) < 0) { + r = -ENOMEM; + goto finish; + } + + log_debug("found: %s\n", f); + base = f + strlen(path) + 1; + if (hashmap_put(h, base, f) <= 0) + free(f); + } + +finish: + closedir(dir); + return r; +} + +static int base_cmp(const void *a, const void *b) { + const char *s1, *s2; + + s1 = *(char * const *)a; + s2 = *(char * const *)b; + return strcmp(file_name_from_path(s1), file_name_from_path(s2)); +} + +char **conf_files_list(const char *suffix, const char *dir, ...) { + Hashmap *fh; + char **files = NULL; + va_list ap; + int e = 0; + + fh = hashmap_new(string_hash_func, string_compare_func); + if (!fh) { + e = ENOMEM; + goto finish; + } + + va_start(ap, dir); + while (dir) { + if (files_add(fh, dir, suffix) < 0) { + log_error("Failed to search for files."); + e = EINVAL; + goto finish; + } + dir = va_arg(ap, const char *); + } + va_end(ap); + + files = hashmap_get_strv(fh); + if (files == NULL) { + log_error("Failed to compose list of files."); + e = ENOMEM; + goto finish; + } + + qsort(files, hashmap_size(fh), sizeof(char *), base_cmp); +finish: + hashmap_free(fh); + errno = e; + return files; +} diff --git a/src/util.h b/src/util.h index fcaeac4a..7fa488b0 100644 --- a/src/util.h +++ b/src/util.h @@ -441,4 +441,5 @@ int signal_from_string(const char *s); int signal_from_string_try_harder(const char *s); +char **conf_files_list(const char *suffix, const char *dir, ...); #endif -- 2.39.5