systemd/0001-conf-parser-introduce-early-drop-ins.patch
Dominique Leuenberger 0e2ab45d5e Accepting request 964674 from Base:System
- spec: cope with %{_modprobedir} being /lib/modprobe.d on SLE

- Add 1000-Revert-getty-Pass-tty-to-use-by-agetty-via-stdin.patch
  A temporary workaround until bsc#1197178 is resolved.

- Import commit 8ef8dfd5401ba18caec59e54a05af9f2e0d7ac65 (merge of v250.4)
  For a complete list of changes, visit:
  ca89b1d1fd...8ef8dfd540

- Import commit ca89b1d1fd1ae86cc1e763d2d01ec2806f3a4d3a
  37b683c832 journal: preserve acls when rotating user journals with NOCOW attribute set
  d043fabebc journal: when copying journal file to undo NOCOW flag, go via fd
  78c2766689 journal-file: explicitly handle file systems that do not support hole punching
  7ecfb4b098 journal-file: fix error handling of pread() in journald_file_punch_holes()
  c4946a412c journal-file: don't use pread() when determining where to append, use mmap as before
  d3fbd20628 journal: various fixes to journal_file_read_object()
  5897a8e8d4 shared: Handle filesystems that don't support hole punching in COPY_HOLES
  27746408e2 journal: Truncate file instead of punching hole in final object
  59b6130030 shared: Ensure COPY_HOLES copies trailing holes
  ac9ccba73f journal: stat journal file after truncating
  0257283444 journal: Copy holes when archiving BTRFS journal files
  26c2a9952d shared: Copy holes in sparse files in copy_bytes_full()
  6c7191dece copy: fix wrong argument passed to S_ISREG() in copy_file_fd_full()
  af0a43024d udev: 60-persistent-storage-tape.rules: handle duplicate device ID (bsc#1195529)

- Update Supplements to new format in baselibs.conf
- Fix libsystemd-shared exclusion in baselibs.conf
- Exclude new cryptsetup libraries in baselibs.conf

- systemd.spec: minor simplification by assuming that %{bootstrap} is always

OBS-URL: https://build.opensuse.org/request/show/964674
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/systemd?expand=0&rev=354
2022-03-28 14:58:41 +00:00

342 lines
14 KiB
Diff

From 079a6f89f9e42517cd14b488320b6302746bcf9b Mon Sep 17 00:00:00 2001
From: Franck Bui <fbui@suse.com>
Date: Fri, 22 Jan 2021 14:57:08 +0100
Subject: [PATCH 01/11] conf-parser: introduce 'early' drop-ins
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
As formerly known as "downstream conf file drop-ins should never override main
user conf file".
Previously all drop-ins, including those shipped by downstream, shipped in
/usr, could override user's main configuration file (located in /etc) because
the main file was always parsed first.
This was problematic for downstreams because their customization should never
override the users one in general. Therefore the only way to make this logic
usable was by teaching users to never use the main conf files and to put all
theirs settings in drop-ins with a higher priority than the one downsteam would
use. However customizing the defaults through the main conf file is something
very well established since a long time hence this is not something
conceivable.
This patch reworks the way we parse configuration files by introducing "early"
conf files (idea from Zbigniew Jędrzejewski-Szmek), which always have a
priority lower than the main config file and hence other conf file drop-ins
too.
Early conf files can be located in any locations where regular conf snippets
can be installed and are sorted between them using the same sorting rules that
apply to other conf files. A conf file is considered as an early one if its
filename is prefixed with "__" (double underscore).
Hence for example, drop-in "/usr/lib/systemd/logind.conf.d/__99-foo.conf" will
always be parsed before:
/etc/systemd/logind.conf
/etc/systemd/logind.conf.d/00-foo.conf
/usr/lib/systemd/logind.conf.d/00-foo.conf
This change isn't backwards-compatible, but the '__' prefix is something that
is unlikely used. Hence the risk should be very low.
Unfortunately upstream is not seing this problem as a serious one and accept
that vendors' configuration files can take precedence over the main
configuration files (placed in /etc). See the following links for the
related discussions:
https://github.com/systemd/systemd/issues/2121 (initial issue report)
https://github.com/systemd/systemd/pull/17161 (first attempt to solve this issue)
https://github.com/systemd/systemd/pull/18347 (introduction of early drop-in)
Since SUSE heavily relies on drop-ins to customize some of the upstream default
settings, there was no other choice than to diverge from upstream in this
regard.
But it should be noted that these early drop-ins are strictly reserved for SUSE
own purpose only. IOW users should never use them and early drop-ins should
never be created in /etc but only in /usr. We reserve the right to change or
drop this feature at any time.
Fixes: #2121
---
src/shared/conf-parser.c | 48 +++++++++--
src/test/test-conf-parser.c | 154 ++++++++++++++++++++++++++++++++++++
2 files changed, 197 insertions(+), 5 deletions(-)
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c
index 1e1967d7ea..eb81732dfa 100644
--- a/src/shared/conf-parser.c
+++ b/src/shared/conf-parser.c
@@ -464,6 +464,7 @@ static int hashmap_put_stats_by_path(Hashmap **stats_by_path, const char *path,
static int config_parse_many_files(
const char* const* conf_files,
+ char **early_files,
char **files,
const char *sections,
ConfigItemLookup lookup,
@@ -481,6 +482,12 @@ static int config_parse_many_files(
stats_by_path = hashmap_new(&path_hash_ops_free_free);
if (!stats_by_path)
return -ENOMEM;
+ }
+
+ STRV_FOREACH(fn, early_files) {
+ r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata, &st);
+ if (r < 0)
+ return r;
}
/* First read the first found main config file. */
@@ -521,6 +528,28 @@ static int config_parse_many_files(
return 0;
}
+static int config_parse_split_conf_files(char **files, char ***early_files, char ***late_files) {
+ char **f;
+
+ assert(files);
+ assert(early_files);
+ assert(late_files);
+
+ STRV_FOREACH(f, files) {
+ char ***s, *p;
+
+ p = strdup(*f);
+ if (!p)
+ return log_oom();
+
+ s = startswith(basename(*f), "__") ? early_files : late_files;
+ if (strv_push(s, p) < 0)
+ return log_oom();
+ }
+
+ return 0;
+}
+
/* Parse each config file in the directories specified as nulstr. */
int config_parse_many_nulstr(
const char *conf_file,
@@ -532,15 +561,19 @@ int config_parse_many_nulstr(
void *userdata,
Hashmap **ret_stats_by_path) {
- _cleanup_strv_free_ char **files = NULL;
+ _cleanup_strv_free_ char **files = NULL, **early_files = NULL, **late_files = NULL;
int r;
r = conf_files_list_nulstr(&files, ".conf", NULL, 0, conf_file_dirs);
if (r < 0)
return r;
- return config_parse_many_files(STRV_MAKE_CONST(conf_file),
- files, sections, lookup, table, flags, userdata,
+ r = config_parse_split_conf_files(files, &early_files, &late_files);
+ if (r < 0)
+ return r;
+
+ return config_parse_many_files(STRV_MAKE_CONST(conf_file), early_files, late_files,
+ sections, lookup, table, flags, userdata,
ret_stats_by_path);
}
@@ -556,8 +589,8 @@ int config_parse_many(
void *userdata,
Hashmap **ret_stats_by_path) {
+ _cleanup_strv_free_ char **files = NULL, **early_files = NULL, **late_files = NULL;
_cleanup_strv_free_ char **dropin_dirs = NULL;
- _cleanup_strv_free_ char **files = NULL;
const char *suffix;
int r;
@@ -570,7 +603,12 @@ int config_parse_many(
if (r < 0)
return r;
- return config_parse_many_files(conf_files, files, sections, lookup, table, flags, userdata, ret_stats_by_path);
+ r = config_parse_split_conf_files(files, &early_files, &late_files);
+ if (r < 0)
+ return r;
+
+ return config_parse_many_files(conf_files, early_files, late_files,
+ sections, lookup, table, flags, userdata, ret_stats_by_path);
}
#define DEFINE_PARSER(type, vartype, conv_func) \
diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c
index e61932ab16..de408272f0 100644
--- a/src/test/test-conf-parser.c
+++ b/src/test/test-conf-parser.c
@@ -5,6 +5,9 @@
#include "fs-util.h"
#include "log.h"
#include "macro.h"
+#include "mkdir.h"
+#include "path-util.h"
+#include "rm-rf.h"
#include "string-util.h"
#include "strv.h"
#include "tests.h"
@@ -391,4 +394,155 @@ TEST(config_parse) {
test_config_parse_one(i, config_file[i]);
}
+static void setup_conf_files(const char *root, bool is_main, char **conf_files, char ***ret_conf_dirs) {
+ char **path;
+
+ /* If 'is_main' is true then 'conf_files' should only contain an entry
+ * for the main conf file. */
+ if (is_main)
+ assert_se(strv_length(conf_files) <= 1);
+
+ STRV_FOREACH(path, conf_files) {
+ _cleanup_free_ char *abspath = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+
+ abspath = path_join(root, *path);
+ assert_se(abspath);
+
+ (void) mkdir_parents(abspath, 0755);
+
+ f = fopen(abspath, "w");
+ assert_se(f);
+ fprintf(f,
+ "[Section]\n"
+ "name=%s\n",
+ *path);
+
+ if (!is_main)
+ fprintf(f,
+ "%s=%s\n",
+ startswith(basename(*path), "__") ? "early" : "late",
+ *path);
+
+ if (ret_conf_dirs) {
+ char *d;
+
+ assert_se((d = dirname_malloc(abspath)));
+ assert_se(strv_push(ret_conf_dirs, d) == 0);
+ }
+ }
+
+ if (ret_conf_dirs) {
+ strv_uniq(*ret_conf_dirs);
+ strv_sort(*ret_conf_dirs);
+ }
+}
+
+static void test_config_parse_many_nulstr_one(bool nulstr, const char *main, char **conf_files,
+ const char *name, const char *early, const char *late) {
+
+ _cleanup_free_ char *parsed_name = NULL, *parsed_early = NULL, *parsed_late = NULL;
+ _cleanup_strv_free_ char **conf_dirs = NULL;
+ _cleanup_free_ char *conf_dirs_nulstr = NULL;
+ char *conf_file;
+ char *tmp_dir;
+ size_t size;
+ int r;
+
+ const ConfigTableItem items[] = {
+ { "Section", "name", config_parse_string, 0, &parsed_name},
+ { "Section", "late", config_parse_string, 0, &parsed_late},
+ { "Section", "early", config_parse_string, 0, &parsed_early},
+ };
+
+ tmp_dir = strdupa("/tmp/test-conf-parser-XXXXXX");
+ assert_se(mkdtemp(tmp_dir));
+
+ setup_conf_files(tmp_dir, true, STRV_MAKE(main), NULL);
+ setup_conf_files(tmp_dir, false, conf_files, &conf_dirs);
+
+ conf_file = main ? strjoina(tmp_dir, "/", main) : NULL;
+
+ if (nulstr) {
+ r = strv_make_nulstr(conf_dirs, &conf_dirs_nulstr, &size);
+ assert_se(r == 0);
+
+ r = config_parse_many_nulstr(conf_file, conf_dirs_nulstr,
+ "Section\0",
+ config_item_table_lookup, items,
+ CONFIG_PARSE_WARN,
+ NULL,
+ NULL);
+ } else {
+ r = config_parse_many(STRV_MAKE_CONST(conf_file),
+ (const char * const*) conf_dirs, "",
+ "Section\0",
+ config_item_table_lookup, items,
+ CONFIG_PARSE_WARN,
+ NULL,
+ NULL);
+ }
+
+ assert_se(r == 0);
+ assert_se((!name && !parsed_name) || streq(name, parsed_name));
+ assert_se((!late && !parsed_late) || streq(late, parsed_late));
+ assert_se((!early && !parsed_early) || streq(early, parsed_early));
+
+ assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
+}
+
+static void test_config_parse_many_nulstr(bool nulstr) {
+ log_info("== %s%s ==", __func__, nulstr ? "_nulstr" : "");
+
+ test_config_parse_many_nulstr_one(nulstr, NULL, NULL, NULL, NULL, NULL);
+
+ test_config_parse_many_nulstr_one(nulstr,
+ "dir/main.conf", NULL,
+ "dir/main.conf", NULL, NULL);
+
+ test_config_parse_many_nulstr_one(nulstr,
+ NULL, STRV_MAKE("dir1/50-foo.conf"),
+ "dir1/50-foo.conf", NULL, "dir1/50-foo.conf");
+
+ test_config_parse_many_nulstr_one(nulstr,
+ NULL, STRV_MAKE("dir1/__50-foo.conf"),
+ "dir1/__50-foo.conf", "dir1/__50-foo.conf", NULL);
+
+ test_config_parse_many_nulstr_one(nulstr,
+ NULL, STRV_MAKE("dir1/10-foo.conf", "dir1/50-bar.conf"),
+ "dir1/50-bar.conf", NULL, "dir1/50-bar.conf");
+
+ test_config_parse_many_nulstr_one(nulstr,
+ NULL, STRV_MAKE("dir1/50-foo.conf", "dir2/10-bar.conf"),
+ "dir1/50-foo.conf", NULL, "dir1/50-foo.conf");
+
+ test_config_parse_many_nulstr_one(nulstr,
+ NULL, STRV_MAKE("dir1/10-foo.conf", "dir2/10-foo.conf"),
+ "dir1/10-foo.conf", NULL, "dir1/10-foo.conf");
+
+ /* Early conf files should never override the main one whatever their
+ * priority/location. */
+ test_config_parse_many_nulstr_one(nulstr,
+ "dir/10-main.conf",
+ STRV_MAKE("dir1/__10-foo.conf", "dir2/__99-foo.conf"),
+ "dir/10-main.conf", "dir2/__99-foo.conf", NULL);
+
+ /* Late conf files always take precendence over the early conf files
+ * and the main one. */
+ test_config_parse_many_nulstr_one(nulstr,
+ "dir/50-main.conf", STRV_MAKE("dir1/10-foo.conf"),
+ "dir1/10-foo.conf", NULL, "dir1/10-foo.conf");
+
+ test_config_parse_many_nulstr_one(nulstr,
+ "dir/10-main.conf",
+ STRV_MAKE("dir1/__10-foo.conf", "dir2/__99-foo.conf",
+ "dir2/10-foo.conf"),
+ "dir2/10-foo.conf", "dir2/__99-foo.conf", "dir2/10-foo.conf");
+}
+
+TEST(config_parse_many) {
+ test_config_parse_many_nulstr(true);
+ test_config_parse_many_nulstr(false);
+}
+
DEFINE_TEST_MAIN(LOG_INFO);
--
2.34.1