Skip to content

Commit

Permalink
Merge pull request #3164 from cgwalters/prepare-root-device-inode
Browse files Browse the repository at this point in the history
Track deployment root/inode from prepare root
  • Loading branch information
cgwalters authored Feb 8, 2024
2 parents da89214 + 525a57d commit 61ed3bf
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 25 deletions.
5 changes: 3 additions & 2 deletions src/libostree/ostree-sysroot-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,9 @@ struct OstreeSysroot
/* The device/inode for / and /etc, used to detect booted deployment */
dev_t root_device;
ino_t root_inode;
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;
Expand Down
57 changes: 34 additions & 23 deletions src/libostree/ostree-sysroot.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -808,26 +809,35 @@ parse_deployment (OstreeSysroot *self, const char *boot_link, OstreeDeployment *
if (looking_for_booted_deployment)
{
struct stat stbuf;
struct stat etc_stbuf = {};
if (!glnx_fstat (deployment_dfd, &stbuf, error))
return FALSE;

/* 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
* dir is.
/* ostree-prepare-root records the (device, inode) pair of the underlying real deployment
* directory (before we might have mounted a composefs or overlayfs on top).
*
* Because this parser is operating outside the mounted namespace, we compare against
* that backing directory.
*/

if (!glnx_fstatat_allow_noent (deployment_dfd, "etc", &etc_stbuf, 0, 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_BACKING_ROOTDEVINO, "(tt)",
&expected_root_dev, &expected_root_inode))
{
g_debug ("Missing %s", OTCORE_RUN_BOOTED_KEY_BACKING_ROOTDEVINO);
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_BACKING_ROOTDEVINO);

/* A bit ugly, we're assigning to a sysroot-owned variable from deep in
* this parsing code. But eh, if something fails the sysroot state can't
* be relied on anyways.
*/
is_booted_deployment
= (stbuf.st_dev == self->root_device && stbuf.st_ino == self->root_inode)
|| (etc_stbuf.st_dev == self->etc_device && etc_stbuf.st_ino == self->etc_inode);
= stbuf.st_dev == expected_root_dev && stbuf.st_ino == expected_root_inode;
}

g_autoptr (OstreeDeployment) ret_deployment
Expand Down Expand Up @@ -1016,10 +1026,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))
Expand All @@ -1028,17 +1049,6 @@ ostree_sysroot_initialize (OstreeSysroot *self, GError **error)
self->root_inode = root_stbuf.st_ino;
}

{
struct stat etc_stbuf;
if (!glnx_fstatat_allow_noent (AT_FDCWD, "/etc", &etc_stbuf, 0, error))
return FALSE;
if (errno != ENOENT)
{
self->etc_device = etc_stbuf.st_dev;
self->etc_inode = etc_stbuf.st_ino;
}
}

struct stat self_stbuf;
if (!glnx_fstatat (AT_FDCWD, gs_file_get_path_cached (self->path), &self_stbuf, 0, error))
return FALSE;
Expand All @@ -1047,6 +1057,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;
}

Expand Down
2 changes: 2 additions & 0 deletions src/libotcore/otcore.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_BACKING_ROOTDEVINO "backing-root-device-inode"

#define OTCORE_RUN_BOOTED_KEY_TRANSIENT_ETC "transient-etc"
9 changes: 9 additions & 0 deletions src/switchroot/ostree-prepare-root.c
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,15 @@ main (int argc, char *argv[])
GVariantBuilder metadata_builder;
g_variant_builder_init (&metadata_builder, G_VARIANT_TYPE ("a{sv}"));

/* Record the underlying plain deployment directory (device,inode) pair
* so that it can be later checked by the sysroot code to figure out
* which deployment was booted.
*/
if (lstat (".", &stbuf) < 0)
err (EXIT_FAILURE, "lstat deploy_root");
g_variant_builder_add (&metadata_builder, "{sv}", OTCORE_RUN_BOOTED_KEY_BACKING_ROOTDEVINO,
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;

Expand Down

0 comments on commit 61ed3bf

Please sign in to comment.