$(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)
</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/<program>.conf</filename>.</para>
-
-
+ <filename><program>.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>
</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/<program>.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>
</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>
#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) {
return -errno;
}
+ log_debug("apply: %s\n", path);
while (!feof(f)) {
char l[LINE_MAX], *p;
int k;
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;
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;
}
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;
+}
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))
#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.");
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;
fclose(f);
}
- free(de);
-
+ strv_free(files);
finish:
if (n_arguments > 3) {
#include <limits.h>
#include "log.h"
+#include "strv.h"
#include "util.h"
#define PROC_SYS_PREFIX "/proc/sys/"
return -errno;
}
+ log_debug("apply: %s\n", path);
while (!feof(f)) {
char l[LINE_MAX], *p, *value;
int k;
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;
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;
};
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;
+}
int signal_from_string_try_harder(const char *s);
+char **conf_files_list(const char *suffix, const char *dir, ...);
#endif