diff options
author | Colin Walters <walters@verbum.org> | 2018-03-12 13:55:51 -0500 |
---|---|---|
committer | Atomic Bot <atomic-devel@projectatomic.io> | 2018-03-15 17:43:19 +0000 |
commit | 5b3f79d4bb7dc80f4bc750a9e8911709646a5523 (patch) | |
tree | 363c8ea98cd9ac7fecc1996d4de59f8103200dd4 /src/libostree/ostree-sysroot.c | |
parent | bb9cc8912a0208a1b383ddbd24ecde6c7453e730 (diff) | |
download | ostree-5b3f79d4bb7dc80f4bc750a9e8911709646a5523.tar.gz |
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
Diffstat (limited to 'src/libostree/ostree-sysroot.c')
-rw-r--r-- | src/libostree/ostree-sysroot.c | 140 |
1 files changed, 46 insertions, 94 deletions
diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c index 3294e83d..1cf7779a 100644 --- a/src/libostree/ostree-sysroot.c +++ b/src/libostree/ostree-sysroot.c @@ -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 |