mirror of
https://github.com/ostreedev/ostree.git
synced 2025-01-10 05:18:30 +03:00
sysroot: Rework how we find booted deployment
I was looking at this code in prep for "staging" deployments, and there are several cleanups to be made here. The first thing I noticed is that we look for the `ostree=` kernel argument, but the presence of that should be exactly equivalent to having `/run/ostree-booted` exist. We just added a member variable for that, so let's make use of it. Related to this, we were erroring out if we had the karg but didn't find a deployment. But this can happen if e.g. one is using `ostree admin --sysroot` from an ostree-booted system! It's actually a bit surprising no one has reported this so far; I guess in the end people are either using non-ostree systems or running from containers. Let's add a member variable `root_is_sysroot` that we can use to determine if we're looking at `/`. Then, our more precise "should find a booted deployment" state is when both `ostree_booted` and `root_is_sysroot` are TRUE. Next, rather than walking all of the deployments after parsing, we can inline the `fstatat()` while parsing. The mild ugly thing about this is assigning to the sysroot member variable while parsing, but I will likely clean that up later, just wanted to avoid rewriting everything in one go. Closes: #1497 Approved by: jlebon
This commit is contained in:
parent
bb9cc8912a
commit
5b3f79d4bb
@ -51,6 +51,10 @@ struct OstreeSysroot {
|
||||
|
||||
gboolean loaded;
|
||||
gboolean ostree_booted;
|
||||
gboolean root_is_sysroot; /* TRUE if sysroot_fd is pointed to rootfs "/" */
|
||||
/* The device/inode for /, used to detect booted deployment */
|
||||
dev_t root_device;
|
||||
ino_t root_inode;
|
||||
|
||||
gboolean is_physical; /* TRUE if we're pointed at physical storage root and not a deployment */
|
||||
GPtrArray *deployments;
|
||||
|
@ -37,13 +37,6 @@
|
||||
#include "ostree-bootloader-syslinux.h"
|
||||
#include "ostree-bootloader-grub2.h"
|
||||
|
||||
static gboolean
|
||||
find_booted_deployment (OstreeSysroot *self,
|
||||
GPtrArray *deployments,
|
||||
OstreeDeployment **out_deployment,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
/**
|
||||
* SECTION:ostree-sysroot
|
||||
* @title: Root partition mount point
|
||||
@ -642,6 +635,24 @@ parse_deployment (OstreeSysroot *self,
|
||||
&deployment_dfd, error))
|
||||
return FALSE;
|
||||
|
||||
/* See if this is the booted deployment */
|
||||
const gboolean looking_for_booted_deployment =
|
||||
(self->ostree_booted && self->root_is_sysroot &&
|
||||
!self->booted_deployment);
|
||||
gboolean is_booted_deployment = FALSE;
|
||||
if (looking_for_booted_deployment)
|
||||
{
|
||||
struct stat stbuf;
|
||||
if (!glnx_fstat (deployment_dfd, &stbuf, error))
|
||||
return FALSE;
|
||||
/* 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);
|
||||
}
|
||||
|
||||
g_autoptr(GKeyFile) origin = NULL;
|
||||
if (!parse_origin (self, deployment_dfd, deploy_basename, &origin,
|
||||
cancellable, error))
|
||||
@ -672,6 +683,8 @@ parse_deployment (OstreeSysroot *self,
|
||||
|
||||
g_debug ("Deployment %s.%d unlocked=%d", treecsum, deployserial, ret_deployment->unlocked);
|
||||
|
||||
if (is_booted_deployment)
|
||||
self->booted_deployment = g_object_ref (ret_deployment);
|
||||
if (out_deployment)
|
||||
*out_deployment = g_steal_pointer (&ret_deployment);
|
||||
return TRUE;
|
||||
@ -797,14 +810,30 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self,
|
||||
if (!ensure_repo (self, error))
|
||||
return FALSE;
|
||||
|
||||
/* If we didn't check already, see if we have the global ostree-booted flag;
|
||||
/* Gather some global state; first if we have the global ostree-booted flag;
|
||||
* we'll use it to sanity check that we found a booted deployment for example.
|
||||
* Second, we also find out whether sysroot == /.
|
||||
*/
|
||||
if (!self->loaded)
|
||||
{
|
||||
if (!glnx_fstatat_allow_noent (AT_FDCWD, "/run/ostree-booted", NULL, 0, error))
|
||||
return FALSE;
|
||||
self->ostree_booted = (errno == 0);
|
||||
|
||||
{ struct stat root_stbuf;
|
||||
if (!glnx_fstatat (AT_FDCWD, "/", &root_stbuf, 0, error))
|
||||
return FALSE;
|
||||
self->root_device = root_stbuf.st_dev;
|
||||
self->root_inode = root_stbuf.st_ino;
|
||||
}
|
||||
|
||||
struct stat self_stbuf;
|
||||
if (!glnx_fstat (self->sysroot_fd, &self_stbuf, error))
|
||||
return FALSE;
|
||||
|
||||
self->root_is_sysroot =
|
||||
(self->root_device == self_stbuf.st_dev &&
|
||||
self->root_inode == self_stbuf.st_ino);
|
||||
}
|
||||
|
||||
int bootversion = 0;
|
||||
@ -847,11 +876,19 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self,
|
||||
{
|
||||
OstreeBootconfigParser *config = boot_loader_configs->pdata[i];
|
||||
|
||||
/* Note this also sets self->booted_deployment */
|
||||
if (!list_deployments_process_one_boot_entry (self, config, deployments,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
{
|
||||
g_clear_object (&self->booted_deployment);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (self->ostree_booted && self->root_is_sysroot
|
||||
&& !self->booted_deployment)
|
||||
return glnx_throw (error, "Unexpected state: /run/ostree-booted found and in / sysroot but not in a booted deployment");
|
||||
|
||||
g_ptr_array_sort (deployments, compare_deployments_by_boot_loader_version_reversed);
|
||||
for (guint i = 0; i < deployments->len; i++)
|
||||
{
|
||||
@ -859,13 +896,6 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self,
|
||||
ostree_deployment_set_index (deployment, i);
|
||||
}
|
||||
|
||||
if (!find_booted_deployment (self, deployments, &self->booted_deployment,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
/* Sanity check; note the converse case is fine */
|
||||
if (self->booted_deployment && !self->ostree_booted)
|
||||
return glnx_throw (error, "Unexpected state: In a booted deployment but no /run/ostree-booted?");
|
||||
|
||||
/* Determine whether we're "physical" or not, the first time we initialize */
|
||||
if (!self->loaded)
|
||||
{
|
||||
@ -1104,84 +1134,6 @@ _ostree_sysroot_join_lines (GPtrArray *lines)
|
||||
return g_string_free (buf, FALSE);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_kernel_commandline (OstreeKernelArgs **out_args,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GFile) proc_cmdline = g_file_new_for_path ("/proc/cmdline");
|
||||
g_autofree char *contents = NULL;
|
||||
gsize len;
|
||||
|
||||
if (!g_file_load_contents (proc_cmdline, cancellable, &contents, &len, NULL,
|
||||
error))
|
||||
return FALSE;
|
||||
|
||||
g_strchomp (contents);
|
||||
*out_args = _ostree_kernel_args_from_string (contents);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
find_booted_deployment (OstreeSysroot *self,
|
||||
GPtrArray *deployments,
|
||||
OstreeDeployment **out_deployment,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
struct stat root_stbuf;
|
||||
struct stat self_stbuf;
|
||||
g_autoptr(OstreeDeployment) ret_deployment = NULL;
|
||||
|
||||
if (stat ("/", &root_stbuf) != 0)
|
||||
return glnx_throw_errno_prefix (error, "stat /");
|
||||
|
||||
if (!ensure_sysroot_fd (self, error))
|
||||
return FALSE;
|
||||
|
||||
if (fstat (self->sysroot_fd, &self_stbuf) != 0)
|
||||
return glnx_throw_errno_prefix (error, "fstat");
|
||||
|
||||
if (root_stbuf.st_dev == self_stbuf.st_dev &&
|
||||
root_stbuf.st_ino == self_stbuf.st_ino)
|
||||
{
|
||||
g_autoptr(OstreeKernelArgs) kernel_args = NULL;
|
||||
if (!parse_kernel_commandline (&kernel_args, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
const char *bootlink_arg = _ostree_kernel_args_get_last_value (kernel_args, "ostree");
|
||||
if (bootlink_arg)
|
||||
{
|
||||
for (guint i = 0; i < deployments->len; i++)
|
||||
{
|
||||
OstreeDeployment *deployment = deployments->pdata[i];
|
||||
g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment);
|
||||
struct stat stbuf;
|
||||
|
||||
if (fstatat (self->sysroot_fd, deployment_path, &stbuf, 0) != 0)
|
||||
return glnx_throw_errno_prefix (error, "fstatat");
|
||||
|
||||
if (stbuf.st_dev == root_stbuf.st_dev &&
|
||||
stbuf.st_ino == root_stbuf.st_ino)
|
||||
{
|
||||
ret_deployment = g_object_ref (deployment);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret_deployment == NULL)
|
||||
return glnx_throw (error, "Unexpected state: ostree= kernel argument found, but / is not a deployment root");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Not an ostree system */
|
||||
}
|
||||
}
|
||||
|
||||
ot_transfer_out_value (out_deployment, &ret_deployment);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_sysroot_query_deployments_for:
|
||||
* @self: Sysroot
|
||||
|
Loading…
Reference in New Issue
Block a user