Commit db1413d7 authored by Kay Sievers's avatar Kay Sievers

sysctl.d, binfmt.d, modules-load.d: switch to stacked config dirs in /lib, /etc, /run

parent 3a90ae04
......@@ -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)
......
......@@ -46,20 +46,20 @@
</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>
......@@ -75,11 +75,19 @@
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>
......
......@@ -46,14 +46,16 @@
</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
......@@ -72,6 +74,19 @@
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>
......
......@@ -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>
......@@ -71,6 +73,19 @@
<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>
......
......@@ -25,8 +25,11 @@
#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;
}
......@@ -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;
}
......@@ -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))
......
......@@ -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) {
......
......@@ -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;
......
......@@ -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;
}
......@@ -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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment