From dce8fdc517c9225f0373769f303432202e38e67d Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Fri, 14 Jul 2023 14:31:58 -0400 Subject: [PATCH] prepare-root: Introduce `ostree/prepare-root.conf` 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 | 17 ++++++++ src/boot/dracut/module-setup.sh | 5 +++ src/switchroot/ostree-prepare-root.c | 62 ++++++++++++++++++++++++++-- 3 files changed, 80 insertions(+), 4 deletions(-) diff --git a/man/ostree-prepare-root.xml b/man/ostree-prepare-root.xml index 8b42113a74..8726ccf18a 100644 --- a/man/ostree-prepare-root.xml +++ b/man/ostree-prepare-root.xml @@ -100,6 +100,23 @@ License along with this library. If not, see . + + Configuration + + + The /usr/lib/ostree/prepare-root.conf (or /etc/ostree/prepare-root.conf) config file is parsed by ostree-prepare-root. This file must + be present in the initramfs. The default dracut module will copy it from the real root if present. + + + + + sysroot.readonly + A boolean value; the default is false. If this is set to true, then the /sysroot mount point is mounted read-only. + + + + + systemd diff --git a/src/boot/dracut/module-setup.sh b/src/boot/dracut/module-setup.sh index bedf584ec3..987e7697c7 100755 --- a/src/boot/dracut/module-setup.sh +++ b/src/boot/dracut/module-setup.sh @@ -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" \ diff --git a/src/switchroot/ostree-prepare-root.c b/src/switchroot/ostree-prepare-root.c index 0f84ed1c3b..30baa9869d 100644 --- a/src/switchroot/ostree-prepare-root.c +++ b/src/switchroot/ostree-prepare-root.c @@ -73,8 +73,16 @@ #include #include +#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" @@ -91,6 +99,35 @@ #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 @@ -312,10 +358,18 @@ main (int argc, char *argv[]) err (EXIT_FAILURE, "realpath(\"%s\")", root_arg); char *deploy_path = resolve_deploy_path (root_mountpoint); - /* 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);