Skip to content

Commit

Permalink
prepare-root: Introduce ostree/prepare-root.conf
Browse files Browse the repository at this point in the history
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`.
  • Loading branch information
cgwalters committed Jul 24, 2023
1 parent 4c0e5b1 commit dce8fdc
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 4 deletions.
17 changes: 17 additions & 0 deletions man/ostree-prepare-root.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down
5 changes: 5 additions & 0 deletions src/boot/dracut/module-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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" \
Expand Down
62 changes: 58 additions & 4 deletions src/switchroot/ostree-prepare-root.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,16 @@
#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"

Expand All @@ -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)
{
Expand All @@ -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 *
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand Down

0 comments on commit dce8fdc

Please sign in to comment.