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 0aaa1e45c37f4d5d70bc966a1e8faae6b7825c98..b4644fa75e7cd6b5c2d64c1f1f6ecfb3cb4776c2 100644 (file)
@@ -1287,8 +1287,11 @@ install-data-hook:
        $(MKDIR_P) -m 0755 \
                $(DESTDIR)$(tmpfilesdir) \
                $(DESTDIR)$(sysconfdir)/modules-load.d \
        $(MKDIR_P) -m 0755 \
                $(DESTDIR)$(tmpfilesdir) \
                $(DESTDIR)$(sysconfdir)/modules-load.d \
+               $(DESTDIR)$(prefix)/lib/modules-load.d \
                $(DESTDIR)$(sysconfdir)/sysctl.d \
                $(DESTDIR)$(sysconfdir)/sysctl.d \
+               $(DESTDIR)$(prefix)/lib/sysctl.d \
                $(DESTDIR)$(sysconfdir)/binfmt.d \
                $(DESTDIR)$(sysconfdir)/binfmt.d \
+               $(DESTDIR)$(prefix)/lib/binfmt.d \
                $(DESTDIR)$(systemshutdowndir) \
                $(DESTDIR)$(systemgeneratordir) \
                $(DESTDIR)$(usergeneratordir)
                $(DESTDIR)$(systemshutdowndir) \
                $(DESTDIR)$(systemgeneratordir) \
                $(DESTDIR)$(usergeneratordir)
index 64c27554e672bf9b609b944c254df06b2e36bd02..5a8803f661997e0d4ae0c2e344576d797697e125 100644 (file)
         </refnamediv>
 
         <refsynopsisdiv>
         </refnamediv>
 
         <refsynopsisdiv>
+                <para><filename>/usr/lib/binfmt.d/*.conf</filename></para>
                 <para><filename>/etc/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
         </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
                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>
         </refsect1>
 
         <refsect1>
                 ignored. Note that this means you may not use ; and #
                 as delimiter in binary format rules.</para>
 
                 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>
         </refsect1>
 
         <refsect1>
index 34076916da26fe05fc29752ab6e5e8fb70725218..b2f15dc7b6f6966ca201839da0692cc5da3d6dee 100644 (file)
         </refnamediv>
 
         <refsynopsisdiv>
         </refnamediv>
 
         <refsynopsisdiv>
+                <para><filename>/usr/lib/modules-load.d/*.conf</filename></para>
                 <para><filename>/etc/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
         </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
                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>
 
                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>
         </refsect1>
 
         <refsect1>
index 8f336dc0dd6461696430e58a2ebd436c15c4319a..51afbfa77a158e86eddc5be629f48f82ee8702a6 100644 (file)
@@ -46,7 +46,9 @@
         </refnamediv>
 
         <refsynopsisdiv>
         </refnamediv>
 
         <refsynopsisdiv>
+                <para><filename>/usr/lib/sysctl.d/*.conf</filename></para>
                 <para><filename>/etc/sysctl.d/*.conf</filename></para>
                 <para><filename>/etc/sysctl.d/*.conf</filename></para>
+                <para><filename>/run/sysctl.d/*.conf</filename></para>
         </refsynopsisdiv>
 
         <refsect1>
         </refsynopsisdiv>
 
         <refsect1>
                 <para>Note that both / and . are accepted as
                 separators in sysctl variable names.</para>
 
                 <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>
         </refsect1>
 
         <refsect1>
index 6ebd212ee1dba318c14f9ccaf42682f7be345b1c..619f6e4aa781b37c1e36d4c6c4489dc68b2865f9 100644 (file)
 #include <string.h>
 #include <stdio.h>
 #include <limits.h>
 #include <string.h>
 #include <stdio.h>
 #include <limits.h>
+#include <stdarg.h>
 
 #include "log.h"
 
 #include "log.h"
+#include "hashmap.h"
+#include "strv.h"
 #include "util.h"
 
 static int delete_rule(const char *rule) {
 #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;
         }
 
                 return -errno;
         }
 
+        log_debug("apply: %s\n", path);
         while (!feof(f)) {
                 char l[LINE_MAX], *p;
                 int k;
         while (!feof(f)) {
                 char l[LINE_MAX], *p;
                 int k;
@@ -111,57 +115,6 @@ finish:
         return r;
 }
 
         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;
 
 int main(int argc, char *argv[]) {
         int r = 0;
 
@@ -174,14 +127,29 @@ int main(int argc, char *argv[]) {
         log_parse_environment();
         log_open();
 
         log_parse_environment();
         log_open();
 
-        if (argc > 1)
+        if (argc > 1) {
                 r = apply_file(argv[1], false);
                 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");
 
                 /* 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;
 }
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }
index 4b187057ec34f8af4d5de0fcb7bbdff8159438dc..53502576ad8b9773d08a528853ce7c27948c865c 100644 (file)
@@ -592,3 +592,21 @@ Hashmap *hashmap_copy(Hashmap *h) {
 
         return copy;
 }
 
         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 ac5a8ae0856cdc146b3ff3f4fce0521246d5b6a3..16ffbd392216e77a126ef1d8ef0d0877470c49b7 100644 (file)
@@ -76,6 +76,8 @@ void *hashmap_steal_first_key(Hashmap *h);
 void* hashmap_first(Hashmap *h);
 void* hashmap_last(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))
 
 #define HASHMAP_FOREACH(e, h, i) \
         for ((i) = ITERATOR_FIRST, (e) = hashmap_iterate((h), &(i), NULL); (e); (e) = hashmap_iterate((h), &(i), NULL))
 
index 3824b57de7649293e65793b5e0123a0bdade05d7..fac4511816011f7e6e65d089c223c5b07cbeeac4 100644 (file)
 #include "util.h"
 #include "strv.h"
 
 #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[]) {
 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 **arguments = NULL;
         unsigned n_arguments = 0, n_allocated = 0;
+        char **files, **fn;
 
         if (argc > 1) {
                 log_error("This program takes no argument.");
 
         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;
 
 
         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;
 
                 goto finish;
         }
 
         r = EXIT_SUCCESS;
 
-        for (i = 0; i < n; i++) {
-                int k;
-                char *fn;
+        STRV_FOREACH(fn, files) {
                 FILE *f;
 
                 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 (!f) {
-                        if (errno == ENOENT) {
-                                free(fn);
+                        if (errno == ENOENT)
                                 continue;
                                 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);
                         r = EXIT_FAILURE;
                         continue;
                 }
 
-                free(fn);
-
+                log_debug("apply: %s\n", *fn);
                 for (;;) {
                         char line[LINE_MAX], *l, *t;
 
                 for (;;) {
                         char line[LINE_MAX], *l, *t;
 
@@ -157,8 +123,7 @@ int main(int argc, char *argv[]) {
                 fclose(f);
         }
 
                 fclose(f);
         }
 
-        free(de);
-
+        strv_free(files);
 finish:
 
         if (n_arguments > 3) {
 finish:
 
         if (n_arguments > 3) {
index 15b6da79dc1d263fa83084672cda1b2fde9607c8..1d42e9378b7d060d4c1dcd912dc00b123144c33b 100644 (file)
@@ -27,6 +27,7 @@
 #include <limits.h>
 
 #include "log.h"
 #include <limits.h>
 
 #include "log.h"
+#include "strv.h"
 #include "util.h"
 
 #define PROC_SYS_PREFIX "/proc/sys/"
 #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;
         }
 
                 return -errno;
         }
 
+        log_debug("apply: %s\n", path);
         while (!feof(f)) {
                 char l[LINE_MAX], *p, *value;
                 int k;
         while (!feof(f)) {
                 char l[LINE_MAX], *p, *value;
                 int k;
@@ -119,57 +121,6 @@ finish:
         return r;
 }
 
         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;
 
 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 {
         if (argc > 1)
                 r = apply_file(argv[1], false);
         else {
-                int k;
+                char **files, **f;
 
                 r = apply_file("/etc/sysctl.conf", true);
 
 
                 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;
         }
 
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
index 5a076e6e34e7fefc51fdac0355ffbe4e29cfe106..5029896ef0635d507fcb9bc8e6e10dab537c81d3 100644 (file)
@@ -4528,3 +4528,97 @@ static const char *const signal_table[] = {
 };
 
 DEFINE_STRING_TABLE_LOOKUP(signal, int);
 };
 
 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 fcaeac4ab9da127622908edfb93112771b7d05f2..7fa488b0f57c0edb3e764e5a24eea8b9fe348a50 100644 (file)
@@ -441,4 +441,5 @@ int signal_from_string(const char *s);
 
 int signal_from_string_try_harder(const char *s);
 
 
 int signal_from_string_try_harder(const char *s);
 
+char **conf_files_list(const char *suffix, const char *dir, ...);
 #endif
 #endif