From 0b16f02d9ef4bff82298807e5e906ce59b758cb7 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Thu, 8 Feb 2024 10:13:57 -0500 Subject: [PATCH] WIP: Track deployment root/inode from prepare root --- src/libostree/ostree-sysroot-private.h | 3 +++ src/libostree/ostree-sysroot.c | 32 +++++++++++++++++++++++--- src/libotcore/otcore.h | 2 ++ src/switchroot/ostree-prepare-root.c | 5 ++++ 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/libostree/ostree-sysroot-private.h b/src/libostree/ostree-sysroot-private.h index 5cbeae0ecb..f111efaa9c 100644 --- a/src/libostree/ostree-sysroot-private.h +++ b/src/libostree/ostree-sysroot-private.h @@ -77,6 +77,9 @@ struct OstreeSysroot dev_t etc_device; ino_t etc_inode; + // The parsed data from /run/ostree + GVariantDict *run_ostree_metadata; + gboolean is_physical; /* TRUE if we're pointed at physical storage root and not a deployment */ GPtrArray *deployments; int bootversion; diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c index 5bcae1c79a..defcbd7579 100644 --- a/src/libostree/ostree-sysroot.c +++ b/src/libostree/ostree-sysroot.c @@ -83,6 +83,7 @@ ostree_sysroot_finalize (GObject *object) g_clear_object (&self->path); g_clear_object (&self->repo); + g_clear_pointer (&self->run_ostree_metadata, g_variant_dict_unref); g_clear_pointer (&self->deployments, g_ptr_array_unref); g_clear_object (&self->booted_deployment); g_clear_object (&self->staged_deployment); @@ -812,6 +813,19 @@ parse_deployment (OstreeSysroot *self, const char *boot_link, OstreeDeployment * if (!glnx_fstat (deployment_dfd, &stbuf, error)) return FALSE; + g_assert (self->run_ostree_metadata); + guint64 expected_root_dev = 0; + guint64 expected_root_inode = 0; + if (!g_variant_dict_lookup (self->run_ostree_metadata, OTCORE_RUN_BOOTED_KEY_ROOTDEV, "(tt)", + &expected_root_dev, &expected_root_inode)) + { + g_debug ("Missing %s", OTCORE_RUN_BOOTED_KEY_ROOTDEV); + expected_root_dev = (guint64)self->root_device; + expected_root_inode = (guint64)self->root_inode; + } + else + g_debug ("Target rootdev key %s found", OTCORE_RUN_BOOTED_KEY_ROOTDEV); + /* We look for either the root or the etc subdir of the * deployment. We need to do this, because when using composefs, * the root is not a bind mount of the deploy dir, but the etc @@ -826,7 +840,7 @@ parse_deployment (OstreeSysroot *self, const char *boot_link, OstreeDeployment * * be relied on anyways. */ is_booted_deployment - = (stbuf.st_dev == self->root_device && stbuf.st_ino == self->root_inode) + = (stbuf.st_dev == expected_root_dev && stbuf.st_ino == expected_root_inode) || (etc_stbuf.st_dev == self->etc_device && etc_stbuf.st_ino == self->etc_inode); } @@ -1016,10 +1030,21 @@ ostree_sysroot_initialize (OstreeSysroot *self, GError **error) * we'll use it to sanity check that we found a booted deployment for example. * Second, we also find out whether sysroot == /. */ - if (!glnx_fstatat_allow_noent (AT_FDCWD, OSTREE_PATH_BOOTED, NULL, 0, error)) + glnx_autofd int booted_state_fd = -1; + if (!ot_openat_ignore_enoent (AT_FDCWD, OSTREE_PATH_BOOTED, &booted_state_fd, error)) return FALSE; - const gboolean ostree_booted = (errno == 0); + const gboolean ostree_booted = booted_state_fd != -1; + + if (booted_state_fd != -1) + { + g_autoptr (GVariant) ostree_run_metadata_v = NULL; + if (!ot_variant_read_fd (booted_state_fd, 0, G_VARIANT_TYPE_VARDICT, TRUE, + &ostree_run_metadata_v, error)) + return glnx_prefix_error (error, "failed to read %s", OTCORE_RUN_BOOTED); + self->run_ostree_metadata = g_variant_dict_new (ostree_run_metadata_v); + } + // Gather the root device/inode { struct stat root_stbuf; if (!glnx_fstatat (AT_FDCWD, "/", &root_stbuf, 0, error)) @@ -1047,6 +1072,7 @@ ostree_sysroot_initialize (OstreeSysroot *self, GError **error) = (self->root_device == self_stbuf.st_dev && self->root_inode == self_stbuf.st_ino); self->root_is_ostree_booted = (ostree_booted && root_is_sysroot); + g_debug ("root_is_ostree_booted: %d", self->root_is_ostree_booted); self->loadstate = OSTREE_SYSROOT_LOAD_STATE_INIT; } diff --git a/src/libotcore/otcore.h b/src/libotcore/otcore.h index 1fe4be015e..18f5590828 100644 --- a/src/libotcore/otcore.h +++ b/src/libotcore/otcore.h @@ -82,5 +82,7 @@ GKeyFile *otcore_load_config (int rootfs, const char *filename, GError **error); #define OTCORE_RUN_BOOTED_KEY_ROOT_TRANSIENT "root.transient" // This key will be present if the sysroot-ro flag was found #define OTCORE_RUN_BOOTED_KEY_SYSROOT_RO "sysroot-ro" +// Always holds the (device, inode) pair of the booted deployment +#define OTCORE_RUN_BOOTED_KEY_ROOTDEV "root-device-inode" #define OTCORE_RUN_BOOTED_KEY_TRANSIENT_ETC "transient-etc" diff --git a/src/switchroot/ostree-prepare-root.c b/src/switchroot/ostree-prepare-root.c index bde698b00e..bcbdb73e72 100644 --- a/src/switchroot/ostree-prepare-root.c +++ b/src/switchroot/ostree-prepare-root.c @@ -430,6 +430,11 @@ main (int argc, char *argv[]) GVariantBuilder metadata_builder; g_variant_builder_init (&metadata_builder, G_VARIANT_TYPE ("a{sv}")); + if (lstat (".", &stbuf) < 0) + err (EXIT_FAILURE, "lstat deploy_root"); + g_variant_builder_add (&metadata_builder, "{sv}", OTCORE_RUN_BOOTED_KEY_ROOTDEV, + g_variant_new ("(tt)", (guint64)stbuf.st_dev, (guint64)stbuf.st_ino)); + // Tracks if we did successfully enable it at runtime bool using_composefs = false;