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

This commit is contained in:
Kay Sievers 2011-04-25 20:41:47 +02:00
parent 3a90ae0482
commit db1413d738
11 changed files with 222 additions and 169 deletions

View 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)

View File

@ -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>

View File

@ -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>

View 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>
@ -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>

View File

@ -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;
}

View 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;
}

View 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))

View File

@ -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) {

View 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;

View 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;
}

View 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