]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
shared/conf-parser: add function which implements the standard config file set
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 21 Feb 2024 21:31:41 +0000 (22:31 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 7 Mar 2024 18:14:36 +0000 (19:14 +0100)
Also allow config_parse_many() to be called for config files without
sections. The test uses such a file.

src/shared/conf-parser.c
src/shared/conf-parser.h
src/test/test-conf-parser.c

index b1bc6c8a9503ff4ba99fe2577281bb3c476f22a6..3e3e19b67fc18d10adff19ad35953b2ad9a3b3e6 100644 (file)
@@ -662,7 +662,6 @@ int config_parse_many(
 
         assert(conf_file_dirs);
         assert(dropin_dirname);
-        assert(sections);
         assert(table);
 
         r = conf_files_list_dropins(&files, dropin_dirname, root, conf_file_dirs);
@@ -679,6 +678,50 @@ int config_parse_many(
         return 0;
 }
 
+int config_parse_standard_file_with_dropins_full(
+                const char *root,
+                const char *main_file,    /* A path like "systemd/frobnicator.conf" */
+                const char *sections,
+                ConfigItemLookup lookup,
+                const void *table,
+                ConfigParseFlags flags,
+                void *userdata,
+                Hashmap **ret_stats_by_path,
+                char ***ret_dropin_files) {
+
+        const char* const *conf_paths = (const char* const*) CONF_PATHS_STRV("");
+        _cleanup_strv_free_ char **configs = NULL;
+        int r;
+
+        /* Build the list of main config files */
+        r = strv_extend_strv_biconcat(&configs, root, conf_paths, main_file);
+        if (r < 0) {
+                if (flags & CONFIG_PARSE_WARN)
+                        log_oom();
+                return r;
+        }
+
+        _cleanup_free_ char *dropin_dirname = strjoin(main_file, ".d");
+        if (!dropin_dirname) {
+                if (flags & CONFIG_PARSE_WARN)
+                        log_oom();
+                return -ENOMEM;
+        }
+
+        return config_parse_many(
+                        (const char* const*) configs,
+                        conf_paths,
+                        dropin_dirname,
+                        root,
+                        sections,
+                        lookup,
+                        table,
+                        flags,
+                        userdata,
+                        ret_stats_by_path,
+                        ret_dropin_files);
+}
+
 static int dropins_get_stats_by_path(
                 const char* conf_file,
                 const char* const* conf_file_dirs,
index 9d08cbd6770b00e488413819a241a349c94ace99..d3c65bbf92f937895da96d8df5c9ab8230797003 100644 (file)
@@ -114,6 +114,17 @@ int config_parse_many(
                 Hashmap **ret_stats_by_path,  /* possibly NULL */
                 char ***ret_drop_in_files);   /* possibly NULL */
 
+int config_parse_standard_file_with_dropins_full(
+                const char *root,
+                const char *main_file,        /* A path like "systemd/frobnicator.conf" */
+                const char *sections,
+                ConfigItemLookup lookup,
+                const void *table,
+                ConfigParseFlags flags,
+                void *userdata,
+                Hashmap **ret_stats_by_path,  /* possibly NULL */
+                char ***ret_dropin_files);    /* possibly NULL */
+
 int config_get_stats_by_path(
                 const char *suffix,
                 const char *root,
index 0acb4131b5928d175d6794eeb6e88a91e35759ee..d0d7419eaaf546627a6299d65babb55e38203cfa 100644 (file)
@@ -3,8 +3,10 @@
 #include "conf-parser.h"
 #include "fd-util.h"
 #include "fs-util.h"
+#include "fileio.h"
 #include "log.h"
 #include "macro.h"
+#include "mkdir.h"
 #include "string-util.h"
 #include "strv.h"
 #include "tests.h"
@@ -390,4 +392,102 @@ TEST(config_parse) {
                 test_config_parse_one(i, config_file[i]);
 }
 
+TEST(config_parse_standard_file_with_dropins_full) {
+        _cleanup_(rmdir_and_freep) char *root = NULL;
+        _cleanup_close_ int rfd = -EBADF;
+        int r;
+
+        assert_se(mkdtemp_malloc(NULL, &root) >= 0);
+        assert_se(mkdir_p_root(root, "/etc/kernel/install.conf.d", UID_INVALID, GID_INVALID, 0755, NULL));
+        assert_se(mkdir_p_root(root, "/run/kernel/install.conf.d", UID_INVALID, GID_INVALID, 0755, NULL));
+        assert_se(mkdir_p_root(root, "/usr/lib/kernel/install.conf.d", UID_INVALID, GID_INVALID, 0755, NULL));
+        assert_se(mkdir_p_root(root, "/usr/local/lib/kernel/install.conf.d", UID_INVALID, GID_INVALID, 0755, NULL));
+
+        rfd = open(root, O_CLOEXEC|O_DIRECTORY);
+        assert_se(rfd >= 0);
+
+        assert_se(write_string_file_at(rfd, "usr/lib/kernel/install.conf",         /* this one is ignored */
+                                       "A=!!!", WRITE_STRING_FILE_CREATE) == 0);
+        assert_se(write_string_file_at(rfd, "usr/local/lib/kernel/install.conf",
+                                       "A=aaa", WRITE_STRING_FILE_CREATE) == 0);
+        assert_se(write_string_file_at(rfd, "usr/local/lib/kernel/install.conf.d/drop1.conf",
+                                       "B=bbb", WRITE_STRING_FILE_CREATE) == 0);
+        assert_se(write_string_file_at(rfd, "usr/local/lib/kernel/install.conf.d/drop2.conf",
+                                       "C=c1", WRITE_STRING_FILE_CREATE) == 0);
+        assert_se(write_string_file_at(rfd, "usr/lib/kernel/install.conf.d/drop2.conf",   /* this one is ignored */
+                                       "C=c2", WRITE_STRING_FILE_CREATE) == 0);
+        assert_se(write_string_file_at(rfd, "run/kernel/install.conf.d/drop3.conf",
+                                       "D=ddd", WRITE_STRING_FILE_CREATE) == 0);
+        assert_se(write_string_file_at(rfd, "etc/kernel/install.conf.d/drop4.conf",
+                                       "E=eee", WRITE_STRING_FILE_CREATE) == 0);
+
+        _cleanup_free_ char *A = NULL, *B = NULL, *C = NULL, *D = NULL, *E = NULL, *F = NULL;
+        _cleanup_strv_free_ char **dropins = NULL;
+
+        const ConfigTableItem items[] = {
+                { NULL, "A",  config_parse_string,   0, &A},
+                { NULL, "B",  config_parse_string,   0, &B},
+                { NULL, "C",  config_parse_string,   0, &C},
+                { NULL, "D",  config_parse_string,   0, &D},
+                { NULL, "E",  config_parse_string,   0, &E},
+                { NULL, "F",  config_parse_string,   0, &F},
+                {}
+        };
+
+        r = config_parse_standard_file_with_dropins_full(
+                        root, "kernel/install.conf",
+                        /* sections= */ NULL,
+                        config_item_table_lookup, items,
+                        CONFIG_PARSE_WARN,
+                        /* userdata= */ NULL,
+                        /* ret_stats_by_path= */ NULL,
+                        /* ret_dropin_files= */ &dropins);
+        assert_se(r >= 0);
+        assert_se(streq_ptr(A, "aaa"));
+        assert_se(streq_ptr(B, "bbb"));
+        assert_se(streq_ptr(C, "c1"));
+        assert_se(streq_ptr(D, "ddd"));
+        assert_se(streq_ptr(E, "eee"));
+        assert_se(streq_ptr(F, NULL));
+
+        A = mfree(A);
+        B = mfree(B);
+        C = mfree(C);
+        D = mfree(D);
+        E = mfree(E);
+
+        assert_se(strv_length(dropins) == 4);
+
+        /* Make sure that we follow symlinks */
+        assert_se(mkdir_p_root(root, "/etc/kernel/install2.conf.d", UID_INVALID, GID_INVALID, 0755, NULL));
+        assert_se(mkdir_p_root(root, "/run/kernel/install2.conf.d", UID_INVALID, GID_INVALID, 0755, NULL));
+        assert_se(mkdir_p_root(root, "/usr/lib/kernel/install2.conf.d", UID_INVALID, GID_INVALID, 0755, NULL));
+        assert_se(mkdir_p_root(root, "/usr/local/lib/kernel/install2.conf.d", UID_INVALID, GID_INVALID, 0755, NULL));
+
+        /* (Those symlinks are only useful relative to <root>. */
+        assert_se(symlinkat("/usr/lib/kernel/install.conf", rfd, "usr/lib/kernel/install2.conf") == 0);
+        assert_se(symlinkat("/usr/local/lib/kernel/install.conf", rfd, "usr/local/lib/kernel/install2.conf") == 0);
+        assert_se(symlinkat("/usr/local/lib/kernel/install.conf.d/drop1.conf", rfd, "usr/local/lib/kernel/install2.conf.d/drop1.conf") == 0);
+        assert_se(symlinkat("/usr/local/lib/kernel/install.conf.d/drop2.conf", rfd, "usr/local/lib/kernel/install2.conf.d/drop2.conf") == 0);
+        assert_se(symlinkat("/usr/lib/kernel/install.conf.d/drop2.conf", rfd, "usr/lib/kernel/install2.conf.d/drop2.conf") == 0);
+        assert_se(symlinkat("/run/kernel/install.conf.d/drop3.conf", rfd, "run/kernel/install2.conf.d/drop3.conf") == 0);
+        assert_se(symlinkat("/etc/kernel/install.conf.d/drop4.conf", rfd, "etc/kernel/install2.conf.d/drop4.conf") == 0);
+
+        r = config_parse_standard_file_with_dropins_full(
+                        root, "kernel/install2.conf",
+                        /* sections= */ NULL,
+                        config_item_table_lookup, items,
+                        CONFIG_PARSE_WARN,
+                        /* userdata= */ NULL,
+                        /* ret_stats_by_path= */ NULL,
+                        /* ret_dropin_files= */ NULL);
+        assert_se(r >= 0);
+        assert_se(streq_ptr(A, "aaa"));
+        assert_se(streq_ptr(B, "bbb"));
+        assert_se(streq_ptr(C, "c1"));
+        assert_se(streq_ptr(D, "ddd"));
+        assert_se(streq_ptr(E, "eee"));
+        assert_se(streq_ptr(F, NULL));
+}
+
 DEFINE_TEST_MAIN(LOG_INFO);