From 1b8f03df53235124840695922b54168fa1eff381 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 22 Mar 2017 10:17:47 -0400 Subject: [PATCH] daemon: Add new write_deployments() function and bump_mtime() This is prep for livefs. We need to tweak the logic from what core libostree has in `ostree_sysroot_simple_write_deployment()`, and while we could land improved logic there, I think it makes sense to carry this here until we're confident enough in the logic to make it ABI. This does depend on a [new libostree API](https://github.com/ostreedev/ostree/pull/745) that allows writing deployments without doing cleanup. The `bump_mtime()` bit is also prep for livefs, carrying in this patch to avoid splitting things too much. --- src/daemon/rpmostree-sysroot-upgrader.c | 53 +++-------- src/daemon/rpmostreed-utils.c | 114 ++++++++++++++++++++++++ src/daemon/rpmostreed-utils.h | 12 +++ 3 files changed, 137 insertions(+), 42 deletions(-) diff --git a/src/daemon/rpmostree-sysroot-upgrader.c b/src/daemon/rpmostree-sysroot-upgrader.c index a82319dc31..2a3f46fe77 100644 --- a/src/daemon/rpmostree-sysroot-upgrader.c +++ b/src/daemon/rpmostree-sysroot-upgrader.c @@ -109,31 +109,6 @@ parse_origin_deployment (RpmOstreeSysrootUpgrader *self, return TRUE; } -/* This is like ostree_sysroot_get_merge_deployment() except we explicitly - * ignore the magical "booted" behavior. For rpm-ostree we're trying something - * different now where we are a bit more stateful and pick up changes from the - * pending root. This allows users to chain operations together naturally. - */ -static OstreeDeployment * -get_origin_merge_deployment (OstreeSysroot *self, - const char *osname) -{ - g_autoptr(GPtrArray) deployments = ostree_sysroot_get_deployments (self); - guint i; - - for (i = 0; i < deployments->len; i++) - { - OstreeDeployment *deployment = deployments->pdata[i]; - - if (strcmp (ostree_deployment_get_osname (deployment), osname) != 0) - continue; - - return g_object_ref (deployment); - } - - return NULL; -} - static gboolean rpmostree_sysroot_upgrader_initable_init (GInitable *initable, GCancellable *cancellable, @@ -169,7 +144,7 @@ rpmostree_sysroot_upgrader_initable_init (GInitable *initable, goto out; self->cfg_merge_deployment = ostree_sysroot_get_merge_deployment (self->sysroot, self->osname); - self->origin_merge_deployment = get_origin_merge_deployment (self->sysroot, self->osname); + self->origin_merge_deployment = rpmostreed_get_origin_merge_deployment (self->sysroot, self->osname); if (self->cfg_merge_deployment == NULL || self->origin_merge_deployment == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, @@ -1130,7 +1105,6 @@ rpmostree_sysroot_upgrader_deploy (RpmOstreeSysrootUpgrader *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; glnx_unref_object OstreeDeployment *new_deployment = NULL; const char *target_revision; g_autoptr(GKeyFile) origin = NULL; @@ -1141,7 +1115,7 @@ rpmostree_sysroot_upgrader_deploy (RpmOstreeSysrootUpgrader *self, g_hash_table_size (rpmostree_origin_get_local_packages (self->origin)) > 0) { if (!do_local_assembly (self, cancellable, error)) - goto out; + return FALSE; } else g_clear_pointer (&self->final_revision, g_free); @@ -1149,8 +1123,7 @@ rpmostree_sysroot_upgrader_deploy (RpmOstreeSysrootUpgrader *self, if (self->flags & RPMOSTREE_SYSROOT_UPGRADER_FLAGS_PKGOVERLAY_DRY_RUN) { /* we already printed the transaction in do_final_local_assembly() */ - ret = TRUE; - goto out; + return TRUE; } /* make sure we have a known target to deploy */ @@ -1164,7 +1137,7 @@ rpmostree_sysroot_upgrader_deploy (RpmOstreeSysrootUpgrader *self, NULL, &new_deployment, cancellable, error)) - goto out; + return FALSE; if (self->final_revision) { @@ -1174,22 +1147,18 @@ rpmostree_sysroot_upgrader_deploy (RpmOstreeSysrootUpgrader *self, if (!ostree_repo_set_ref_immediate (self->repo, NULL, RPMOSTREE_TMP_BASE_REF, self->base_revision, cancellable, error)) - goto out; + return FALSE; } - if (!ostree_sysroot_simple_write_deployment (self->sysroot, self->osname, - new_deployment, - self->cfg_merge_deployment, - OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NO_CLEAN, - cancellable, error)) - goto out; + if (!rpmostree_write_deployment (self->sysroot, new_deployment, + self->cfg_merge_deployment, FALSE, + cancellable, error)) + return FALSE; if (!rpmostree_sysroot_upgrader_cleanup (self->sysroot, self->repo, cancellable, error)) - goto out; + return FALSE; - ret = TRUE; - out: - return ret; + return TRUE; } GType diff --git a/src/daemon/rpmostreed-utils.c b/src/daemon/rpmostreed-utils.c index ecd26935d4..70b54923fc 100644 --- a/src/daemon/rpmostreed-utils.c +++ b/src/daemon/rpmostreed-utils.c @@ -23,6 +23,9 @@ #include "libglnx.h" #include +#include +#include +#include static void append_to_object_path (GString *str, @@ -214,6 +217,117 @@ rpmostreed_refspec_parse_partial (const gchar *new_provided_refspec, return ret; } +/* This is like ostree_sysroot_get_merge_deployment() except we explicitly + * ignore the magical "booted" behavior. For rpm-ostree we're trying something + * different now where we are a bit more stateful and pick up changes from the + * pending root. This allows users to chain operations together naturally. + */ +OstreeDeployment * +rpmostreed_get_origin_merge_deployment (OstreeSysroot *self, const char *osname) +{ + g_autoptr(GPtrArray) deployments = ostree_sysroot_get_deployments (self); + guint i; + + for (i = 0; i < deployments->len; i++) + { + OstreeDeployment *deployment = deployments->pdata[i]; + + if (strcmp (ostree_deployment_get_osname (deployment), osname) != 0) + continue; + + return g_object_ref (deployment); + } + + return NULL; +} + + +/* Copy of currently private _ostree_sysroot_bump_mtime() + * until we decide to either formalize that, or have a method + * to notify of changes to e.g. live replaced xattrs. + */ +gboolean +rpmostree_sysroot_bump_mtime (OstreeSysroot *sysroot, + GError **error) +{ + if (utimensat (ostree_sysroot_get_fd (sysroot), "ostree/deploy", NULL, 0) < 0) + { + glnx_set_prefix_error_from_errno (error, "%s", "futimens"); + return FALSE; + } + return TRUE; +} + +/* A version of ostree_sysroot_simple_write_deployment() but with + * a few changes: + * + * - There's just @pushing_rollback, which if true makes the deployment not-default + * as well as retaining the pending deployment + * - osname logic is based on new deployment + * - Fix insertion of deployment to be after booted (patch pending for ostree upstream) + */ +gboolean +rpmostree_write_deployment (OstreeSysroot *sysroot, + OstreeDeployment *new_deployment, + OstreeDeployment *merge_deployment, + gboolean pushing_rollback, + GCancellable *cancellable, + GError **error) +{ + OstreeDeployment *booted_deployment = NULL; + OstreeSysrootWriteDeploymentsOpts write_opts = { .do_postclean = FALSE }; + g_autoptr(GPtrArray) deployments = NULL; + g_autoptr(GPtrArray) new_deployments = g_ptr_array_new_with_free_func (g_object_unref); + const char *osname = ostree_deployment_get_osname (new_deployment); + /* Whether or not we added @new_deployment to the list yet */ + gboolean added_new = FALSE; + /* Keep track of whether we're looking at a deployment before or after the booted */ + gboolean before_booted = TRUE; + + deployments = ostree_sysroot_get_deployments (sysroot); + booted_deployment = ostree_sysroot_get_booted_deployment (sysroot); + + if (!pushing_rollback) + { + g_ptr_array_add (new_deployments, g_object_ref (new_deployment)); + added_new = TRUE; + } + + for (guint i = 0; i < deployments->len; i++) + { + OstreeDeployment *deployment = deployments->pdata[i]; + const gboolean osname_matches = (strcmp (ostree_deployment_get_osname (deployment), osname) == 0); + const gboolean is_booted = ostree_deployment_equal (deployment, booted_deployment); + const gboolean is_merge_or_booted = is_booted || + ostree_deployment_equal (deployment, merge_deployment); + const gboolean is_last = i == (deployments->len - 1); + + if (is_booted) + before_booted = FALSE; + + /* Retain deployment if: + * - The deployment is for another osname + * - We're pushing a rollback and this is a pending deployment + * - It's the merge or booted deployment + */ + if (!osname_matches || (pushing_rollback && before_booted) || is_merge_or_booted) + g_ptr_array_add (new_deployments, g_object_ref (deployment)); + + /* Insert new rollback right after the booted */ + if (!added_new && (!before_booted || is_last)) + { + g_ptr_array_add (new_deployments, g_object_ref (new_deployment)); + added_new = TRUE; + } + } + + if (!ostree_sysroot_write_deployments_with_options (sysroot, new_deployments, + &write_opts, cancellable, error)) + return FALSE; + + return TRUE; +} + void rpmostreed_reboot (GCancellable *cancellable, GError **error) { diff --git a/src/daemon/rpmostreed-utils.h b/src/daemon/rpmostreed-utils.h index 8a679fe388..f88c0a25ce 100644 --- a/src/daemon/rpmostreed-utils.h +++ b/src/daemon/rpmostreed-utils.h @@ -34,6 +34,18 @@ gboolean rpmostreed_refspec_parse_partial (const gchar *new_provided_refspec, const gchar *base_refspec, gchar **out_refspec, GError **error); + +OstreeDeployment *rpmostreed_get_origin_merge_deployment (OstreeSysroot *self, const char *osname); + +gboolean rpmostree_sysroot_bump_mtime (OstreeSysroot *self, GError **error); + +gboolean rpmostree_write_deployment (OstreeSysroot *sysroot, + OstreeDeployment *new_deployment, + OstreeDeployment *merge_deployment, + gboolean make_default, + GCancellable *cancellable, + GError **error); + void rpmostreed_reboot (GCancellable *cancellable, GError **error);