prepare-root: Introduce `ostree/prepare-root.conf`
authorColin Walters <walters@verbum.org>
Fri, 14 Jul 2023 18:31:58 +0000 (14:31 -0400)
committerColin Walters <walters@verbum.org>
Tue, 25 Jul 2023 13:15:09 +0000 (09:15 -0400)
Using the repository configuration for configuration of this
program was always a bit hacky.

But actually with composefs, we really must validate
the target root *before* we parse anything in it.

Let's add a config file for `ostree-prepare-root` that can live
in the initramfs, which will already have been verified.

In the future we'll also add configuration for composefs here.

We expect OS builders to drop this in `/usr/lib/ostree/prepare-root.conf`,
but system local configuration can live in `/etc`.

man/ostree-prepare-root.xml
src/boot/dracut/module-setup.sh
src/switchroot/ostree-prepare-root.c

index 8b42113a74ba95ef06972667d1a1dd98024104be..8726ccf18aedef2cae10634622271a25b5872592 100644 (file)
@@ -100,6 +100,23 @@ License along with this library. If not, see <https://www.gnu.org/licenses/>.
         </para>
     </refsect1>
 
+    <refsect1>
+        <title>Configuration</title>
+
+        <para>
+            The <literal>/usr/lib/ostree/prepare-root.conf</literal> (or <literal>/etc/ostree/prepare-root.conf</literal>) config file is parsed by <literal>ostree-prepare-root</literal>.  This file must
+            be present in the initramfs.  The default dracut module will copy it from the real root if present.
+        </para>
+
+        <variablelist>
+            <varlistentry>
+                <term><varname>sysroot.readonly</varname></term>
+                <listitem><para>A boolean value; the default is false.  If this is set to <literal>true</literal>, then the <literal>/sysroot</literal> mount point is mounted read-only.</para></listitem>
+          </varlistentry>
+        </variablelist>
+    </refsect1>
+
+
     <refsect1>
         <title>systemd</title>
 
index bedf584ec38b71c832a52efaf47de74855041b33..987e7697c7a1bf67730f54b41fb39d785d5da457 100755 (executable)
@@ -33,6 +33,11 @@ depends() {
 
 install() {
     dracut_install /usr/lib/ostree/ostree-prepare-root
+    for r in /usr/lib /etc; do
+        if test -f "$r/ostree/prepare-root.conf"; then
+            inst_simple "$r/ostree/prepare-root.conf"
+        fi
+    done
     inst_simple "${systemdsystemunitdir}/ostree-prepare-root.service"
     mkdir -p "${initdir}${systemdsystemconfdir}/initrd-root-fs.target.wants"
     ln_r "${systemdsystemunitdir}/ostree-prepare-root.service" \
index 5f35fc4345236eb40cde8f3dbaf535700b12f09b..dfac5481342888f8b8ebd4f57349e449c4c42fb2 100644 (file)
 #include <ostree-core.h>
 #include <ostree-repo-private.h>
 
+#include "ot-keyfile-utils.h"
 #include "otcore.h"
 
+// The path to the config file for this binary
+const char *config_roots[] = { "/usr/lib", "/etc" };
+#define PREPARE_ROOT_CONFIG_PATH "ostree/prepare-root.conf"
+
+#define SYSROOT_KEY "sysroot"
+#define READONLY_KEY "readonly"
+
 // The kernel argument we support to configure composefs.
 #define OT_COMPOSEFS_KARG "ot-composefs"
 
 
 #include "ostree-mount-util.h"
 
+// Load our config file; if it doesn't exist, we return an empty configuration.
+// NULL will be returned if we caught an error.
+static GKeyFile *
+load_config (GError **error)
+{
+  g_autoptr (GKeyFile) ret = g_key_file_new ();
+
+  for (guint i = 0; i < G_N_ELEMENTS (config_roots); i++)
+    {
+      glnx_autofd int fd = -1;
+      g_autofree char *path = g_build_filename (config_roots[i], PREPARE_ROOT_CONFIG_PATH, NULL);
+      if (!ot_openat_ignore_enoent (AT_FDCWD, path, &fd, error))
+        return NULL;
+      /* If the config file doesn't exist, that's OK */
+      if (fd == -1)
+        continue;
+
+      g_print ("Loading %s\n", path);
+
+      g_autofree char *buf = glnx_fd_readall_utf8 (fd, NULL, NULL, error);
+      if (!buf)
+        return NULL;
+      if (!g_key_file_load_from_data (ret, buf, -1, 0, error))
+        return NULL;
+    }
+
+  return g_steal_pointer (&ret);
+}
+
 static bool
 sysroot_is_configured_ro (const char *sysroot)
 {
@@ -103,7 +140,7 @@ sysroot_is_configured_ro (const char *sysroot)
       return false;
     }
 
-  return g_key_file_get_boolean (repo_config, "sysroot", "readonly", NULL);
+  return g_key_file_get_boolean (repo_config, SYSROOT_KEY, READONLY_KEY, NULL);
 }
 
 static inline char *
@@ -302,6 +339,15 @@ main (int argc, char *argv[])
     err (EXIT_FAILURE, "usage: ostree-prepare-root SYSROOT");
   root_arg = argv[1];
 
+  g_autoptr (GKeyFile) config = load_config (&error);
+  if (!config)
+    errx (EXIT_FAILURE, "Failed to parse config: %s", error->message);
+
+  gboolean sysroot_readonly = FALSE;
+  if (!ot_keyfile_get_boolean_with_default (config, SYSROOT_KEY, READONLY_KEY, FALSE,
+                                            &sysroot_readonly, &error))
+    errx (EXIT_FAILURE, "Failed to parse sysroot.readonly value: %s", error->message);
+
   /* This is the final target where we should prepare the rootfs.  The usual
    * case with systemd in the initramfs is that root_mountpoint = "/sysroot".
    * In the fastboot embedded case we're pid1 and will setup / ourself, and
@@ -317,10 +363,18 @@ main (int argc, char *argv[])
   if (mkdirat (AT_FDCWD, OTCORE_RUN_OSTREE_PRIVATE, 0) < 0)
     err (EXIT_FAILURE, "Failed to create %s", OTCORE_RUN_OSTREE_PRIVATE);
 
-  /* Query the repository configuration - this is an operating system builder
-   * choice.  More info: https://github.com/ostreedev/ostree/pull/1767
+  /* Fall back to querying the repository configuration in the target disk.
+   * This is an operating system builder choice.  More info:
+   * https://github.com/ostreedev/ostree/pull/1767
    */
-  const bool sysroot_readonly = sysroot_is_configured_ro (root_arg);
+  if (!sysroot_readonly)
+    {
+      sysroot_readonly = sysroot_is_configured_ro (root_arg);
+      // Encourage porting to the new config file
+      if (sysroot_readonly)
+        g_print ("Found legacy sysroot.readonly flag, not configured in %s\n",
+                 PREPARE_ROOT_CONFIG_PATH);
+    }
   const bool sysroot_currently_writable = !path_is_on_readonly_fs (root_arg);
   g_print ("sysroot.readonly configuration value: %d (fs writable: %d)\n", (int)sysroot_readonly,
            (int)sysroot_currently_writable);