chiark / gitweb /
sysctl.d, binfmt.d, modules-load.d: switch to stacked config dirs in /lib, /etc,...
authorKay Sievers <kay.sievers@vrfy.org>
Mon, 25 Apr 2011 18:41:47 +0000 (20:41 +0200)
committerKay Sievers <kay.sievers@vrfy.org>
Mon, 25 Apr 2011 18:41:47 +0000 (20:41 +0200)
Makefile.am
man/binfmt.d.xml
man/modules-load.d.xml
man/sysctl.d.xml
src/binfmt.c
src/hashmap.c
src/hashmap.h
src/modules-load.c
src/sysctl.c
src/util.c
src/util.h

index 0aaa1e4..b4644fa 100644 (file)
@@ -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)
index 64c2755..5a8803f 100644 (file)
         </refnamediv>
 
         <refsynopsisdiv>
+                <para><filename>/usr/lib/binfmt.d/*.conf</filename></para>
                 <para><filename>/etc/binfmt.d/*.conf</filename></para>
+                <para><filename>/run/binfmt.d/*.conf</filename></para>
         </refsynopsisdiv>
 
         <refsect1>
                 <title>Description</title>
 
                <para><command>systemd</command> uses
-               <filename>/etc/binfmt.d/</filename> 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
-               <filename>/etc/binfmt.d/&lt;program&gt;.conf</filename>.</para>
-
-
+               <filename>&lt;program&gt;.conf</filename>.</para>
         </refsect1>
 
         <refsect1>
                 ignored. Note that this means you may not use ; and #
                 as delimiter in binary format rules.</para>
 
-                <para>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.</para>
-
+                <para>Files in <filename>/etc/</filename> overwrite
+                files with the same name in <filename>/usr/lib/</filename>.
+                Files in <filename>/run</filename> overwrite files with
+                the same name in <filename>/etc/</filename> and
+                <filename>/usr/lib/</filename>. Packages should install their
+                configuration files in <filename>/usr/lib/</filename>, files
+                in <filename>/etc/</filename> 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.</para>
         </refsect1>
 
         <refsect1>
index 3407691..b2f15dc 100644 (file)
         </refnamediv>
 
         <refsynopsisdiv>
+                <para><filename>/usr/lib/modules-load.d/*.conf</filename></para>
                 <para><filename>/etc/modules-load.d/*.conf</filename></para>
+                <para><filename>/run/modules-load.d/*.conf</filename></para>
         </refsynopsisdiv>
 
         <refsect1>
                 <title>Description</title>
 
                <para><command>systemd</command> uses
-               <filename>/etc/modules-load.d/</filename> 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
                <filename>/etc/modules-load.d/&lt;program&gt;.conf</filename>. Note
                newlines. Empty lines and lines whose first
                non-whitespace character is # or ; are ignored.</para>
 
+                <para>Files in <filename>/etc/</filename> overwrite
+                files with the same name in <filename>/usr/lib/</filename>.
+                Files in <filename>/run</filename> overwrite files with
+                the same name in <filename>/etc/</filename> and
+                <filename>/usr/lib/</filename>. Packages should install their
+                configuration files in <filename>/usr/lib/</filename>, files
+                in <filename>/etc/</filename> 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.</para>
         </refsect1>
 
         <refsect1>
index 8f336dc..51afbfa 100644 (file)
@@ -46,7 +46,9 @@
         </refnamediv>
 
         <refsynopsisdiv>
+                <para><filename>/usr/lib/sysctl.d/*.conf</filename></para>
                 <para><filename>/etc/sysctl.d/*.conf</filename></para>
+                <para><filename>/run/sysctl.d/*.conf</filename></para>
         </refsynopsisdiv>
 
         <refsect1>
                 <para>Note that both / and . are accepted as
                 separators in sysctl variable names.</para>
 
+                <para>Files in <filename>/etc/</filename> overwrite
+                files with the same name in <filename>/usr/lib/</filename>.
+                Files in <filename>/run</filename> overwrite files with
+                the same name in <filename>/etc/</filename> and
+                <filename>/usr/lib/</filename>. Packages should install their
+                configuration files in <filename>/usr/lib/</filename>, files
+                in <filename>/etc/</filename> 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.</para>
         </refsect1>
 
         <refsect1>
index 6ebd212..619f6e4 100644 (file)
 #include <string.h>
 #include <stdio.h>
 #include <limits.h>
+#include <stdarg.h>
 
 #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;
 }
index 4b18705..5350257 100644 (file)
@@ -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;
+}
index ac5a8ae..16ffbd3 100644 (file)
@@ -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))
 
index 3824b57..fac4511 100644 (file)
 #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) {
index 15b6da7..1d42e93 100644 (file)
@@ -27,6 +27,7 @@
 #include <limits.h>
 
 #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;
index 5a076e6..5029896 100644 (file)
@@ -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;
+}
index fcaeac4..7fa488b 100644 (file)
@@ -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