kernel-install: support full set of config files and drop-ins
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 21 Feb 2024 12:41:57 +0000 (13:41 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 7 Mar 2024 18:14:36 +0000 (19:14 +0100)
This brings the handling of config for kernel-install in line with most of
systemd, i.e. we search the set of paths for the main config file, and the full
set of drop-in paths for drop-ins.

This mirrors what 07f5e35fe7967c824a87f18a3a1d3c22e5be70f5 did for udev.conf.
That change worked out fine, so I hope this one will too.

The update in the man page is minimal. I think we should split out a separate
page for the config file later on.

One motivating use case is to allow a drop-in to be created for temporary
config overrides and then removed after the operation is done.

man/kernel-install.xml
src/kernel-install/kernel-install.c
src/kernel-install/test-kernel-install.sh

index 519829579fa9d36ee3f8dae8b6266a159732b2f0..168776b4d36c7faa49e364f928c2ce56ff1faaac 100644 (file)
 
       <para><varname>$KERNEL_INSTALL_CONF_ROOT</varname> can be set to override the location of the
       configuration files read by <command>kernel-install</command>. When set,
-      <filename>install.conf</filename>, <filename>entry-token</filename>, and other files will be
-      read from this directory.</para>
+      <filename>install.conf</filename>, <filename>entry-token</filename>, and other files will be read from
+      this directory only. Note that this path is relative to the host, and in particular <emphasis>symlinks
+      in this directory are resolved relative to the host</emphasis>, even if
+      <option>--root=<replaceable>root</replaceable></option> is used. This means that it is generally
+      <emphasis>not</emphasis> correct to use this variable to specify a directory underneath
+      <replaceable>root</replaceable> if symlinks are used there.</para>
 
       <para><varname>$KERNEL_INSTALL_PLUGINS</varname> can be set to override the list of plugins executed by
       <command>kernel-install</command>. The argument is a whitespace-separated list of paths.
       </varlistentry>
       <varlistentry>
         <term><filename>/etc/kernel/install.conf</filename></term>
+        <term><filename>/run/kernel/install.conf</filename></term>
+        <term><filename>/usr/local/lib/kernel/install.conf</filename></term>
         <term><filename>/usr/lib/kernel/install.conf</filename></term>
+        <term><filename>/etc/kernel/install.conf.d/*.conf</filename></term>
+        <term><filename>/run/kernel/install.conf.d/*.conf</filename></term>
+        <term><filename>/usr/local/lib/kernel/install.conf.d/*.conf</filename></term>
+        <term><filename>/usr/lib/kernel/install.conf.d/*.conf</filename></term>
         <listitem>
           <para>Configuration file with options for <command>kernel-install</command>, as a series of
           <varname>KEY=</varname><replaceable>VALUE</replaceable> assignments, compatible with shell syntax,
           following the same rules as described in
           <citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry>. The
           first of the files that is found will be used. <varname>$KERNEL_INSTALL_CONF_ROOT</varname> may be
-          used to override the search path; see below for details.</para>
+          used to override the search path; see below for details. Drop-in files may also be used
+          to extend the configuration with overrides, see
+          <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+          </para>
 
           <para>Currently, the following keys are supported:
           <varname>MACHINE_ID=</varname>,
index aa81af70d08f95d06550a4b393bb57c6d93c3f4c..af44ab911b0328cf0dc6f43c1c67c71ee4fd5464 100644 (file)
@@ -431,64 +431,59 @@ static int context_load_environment(Context *c) {
         return 0;
 }
 
-static int context_load_install_conf_one(Context *c, const char *path) {
-        _cleanup_fclose_ FILE *f = NULL;
-        _cleanup_free_ char
-                *conf = NULL, *machine_id = NULL, *boot_root = NULL, *layout = NULL,
-                *initrd_generator = NULL, *uki_generator = NULL;
+static int context_load_install_conf(Context *c) {
+        _cleanup_free_ char *machine_id = NULL, *boot_root = NULL, *layout = NULL,
+                            *initrd_generator = NULL, *uki_generator = NULL;
+        const ConfigTableItem items[] = {
+                { NULL, "MACHINE_ID",       config_parse_string, 0, &machine_id       },
+                { NULL, "BOOT_ROOT",        config_parse_string, 0, &boot_root        },
+                { NULL, "layout",           config_parse_string, 0, &layout           },
+                { NULL, "initrd_generator", config_parse_string, 0, &initrd_generator },
+                { NULL, "uki_generator",    config_parse_string, 0, &uki_generator    },
+                {}
+        };
         int r;
 
         assert(c);
-        assert(path);
 
-        conf = path_join(path, "install.conf");
-        if (!conf)
-                return log_oom();
-
-        r = chase_and_fopenat_unlocked(c->rfd, conf, CHASE_AT_RESOLVE_IN_ROOT, "re", NULL, &f);
-        if (r == -ENOENT)
-                return 0;
-        if (r < 0)
-                return log_error_errno(r, "Failed to chase %s: %m", conf);
+        if (c->conf_root) {
+                _cleanup_free_ char *conf = NULL;
 
-        log_debug("Loading %s…", conf);
+                conf = path_join(c->conf_root, "install.conf");
+                if (!conf)
+                        return log_oom();
 
-        r = parse_env_file(f, conf,
-                           "MACHINE_ID",       &machine_id,
-                           "BOOT_ROOT",        &boot_root,
-                           "layout",           &layout,
-                           "initrd_generator", &initrd_generator,
-                           "uki_generator",    &uki_generator);
+                r = config_parse_many(
+                                STRV_MAKE_CONST(conf),
+                                STRV_MAKE_CONST(c->conf_root),
+                                "install.conf.d",
+                                /* root= */ NULL, /* $KERNEL_INSTALL_CONF_ROOT and --root are independent */
+                                /* sections= */ NULL,
+                                config_item_table_lookup, items,
+                                CONFIG_PARSE_WARN,
+                                /* userdata = */ NULL,
+                                /* ret_stats_by_path= */ NULL,
+                                /* ret_dropin_files= */ NULL);
+        } else
+                r = config_parse_standard_file_with_dropins_full(
+                                arg_root,
+                                "kernel/install.conf",
+                                /* sections= */ NULL,
+                                config_item_table_lookup, items,
+                                CONFIG_PARSE_WARN,
+                                /* userdata = */ NULL,
+                                /* ret_stats_by_path= */ NULL,
+                                /* ret_dropin_files= */ NULL);
         if (r < 0)
-                return log_error_errno(r, "Failed to parse '%s': %m", conf);
-
-        (void) context_set_machine_id(c, machine_id, conf);
-        (void) context_set_boot_root(c, boot_root, conf);
-        (void) context_set_layout(c, layout, conf);
-        (void) context_set_initrd_generator(c, initrd_generator, conf);
-        (void) context_set_uki_generator(c, uki_generator, conf);
-
-        log_debug("Loaded %s.", conf);
-        return 1;
-}
-
-static int context_load_install_conf(Context *c) {
-        int r;
-
-        assert(c);
+                return r == -ENOENT ? 0 : r;
 
-        if (c->conf_root) {
-                r = context_load_install_conf_one(c, c->conf_root);
-                if (r != 0)
-                        return r;
-        }
-
-        FOREACH_STRING(p, "/etc/kernel", "/usr/lib/kernel") {
-                r = context_load_install_conf_one(c, p);
-                if (r != 0)
-                        return r;
-        }
+        (void) context_set_machine_id(c, machine_id, "config");
+        (void) context_set_boot_root(c, boot_root, "config");
+        (void) context_set_layout(c, layout, "config");
+        (void) context_set_initrd_generator(c, initrd_generator, "config");
+        (void) context_set_uki_generator(c, uki_generator, "config");
 
+        log_debug("Loaded config.");
         return 0;
 }
 
index 338d8119578aec2818cd712a55c57836d2ee349e..0e419798782e827d30953393454d2109f7691923 100755 (executable)
@@ -125,7 +125,8 @@ grep -qE 'initrd' "$BOOT_ROOT/the-token/1.1.1/initrd"
 
 # Install UKI
 if [ -f "$ukify" ]; then
-    cat >>"$D/sources/install.conf" <<EOF
+    mkdir "$D/sources/install.conf.d"
+    cat >>"$D/sources/install.conf.d/override.conf" <<EOF
 layout=uki
 uki_generator=ukify
 EOF
@@ -146,6 +147,8 @@ EOF
     "$ukify" inspect "$uki" | grep -qE '^.initrd'
     "$ukify" inspect "$uki" | grep -qE '^.linux'
     "$ukify" inspect "$uki" | grep -qE '^.dtb'
+
+    rm "$D/sources/install.conf.d/override.conf"
 fi
 
 # Test bootctl