summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2014-03-23 08:54:28 -0400
committerColin Walters <walters@verbum.org>2014-03-24 18:08:22 -0400
commit7baa600e237b326899de2899a9bc54a6b863943c (patch)
tree7f374dbfa6b10ec7fa19b140baf91189106bb321 /src
parentffb9d3467164c1e8ec126d1bf265148e1b2374ab (diff)
downloadostree-7baa600e237b326899de2899a9bc54a6b863943c.tar.gz
Add an OstreeSysrootUpgrader API
This moves some utility code from the ostree tool into the shared library, which will make it easier to consume by external tools.
Diffstat (limited to 'src')
-rw-r--r--src/libostree/ostree-sysroot-upgrader.c496
-rw-r--r--src/libostree/ostree-sysroot-upgrader.h71
-rw-r--r--src/libostree/ostree-types.h1
-rw-r--r--src/libostree/ostree.h1
-rw-r--r--src/ostree/ot-admin-builtin-switch.c141
-rw-r--r--src/ostree/ot-admin-builtin-upgrade.c119
-rw-r--r--src/ostree/ot-admin-functions.c60
-rw-r--r--src/ostree/ot-admin-functions.h11
8 files changed, 643 insertions, 257 deletions
diff --git a/src/libostree/ostree-sysroot-upgrader.c b/src/libostree/ostree-sysroot-upgrader.c
new file mode 100644
index 00000000..c565434f
--- /dev/null
+++ b/src/libostree/ostree-sysroot-upgrader.c
@@ -0,0 +1,496 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2014 Colin Walters <walters@verbum.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "otutil.h"
+#include "libgsystem.h"
+
+#include "ostree-sysroot-upgrader.h"
+
+/**
+ * SECTION:libostree-sysroot-upgrader
+ * @title: Simple upgrade class
+ * @short_description: Upgrade OSTree systems
+ *
+ * The #OstreeSysrootUpgrader class allows performing simple upgrade
+ * operations.
+ */
+typedef struct {
+ GObjectClass parent_class;
+} OstreeSysrootUpgraderClass;
+
+struct OstreeSysrootUpgrader {
+ GObject parent;
+
+ OstreeSysroot *sysroot;
+ char *osname;
+
+ OstreeDeployment *merge_deployment;
+ GKeyFile *origin;
+ char *origin_remote;
+ char *origin_ref;
+
+ char *new_revision;
+};
+
+enum {
+ PROP_0,
+
+ PROP_SYSROOT,
+ PROP_OSNAME
+};
+
+static void ostree_sysroot_upgrader_initable_iface_init (GInitableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (OstreeSysrootUpgrader, ostree_sysroot_upgrader, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, ostree_sysroot_upgrader_initable_iface_init))
+
+static gboolean
+parse_refspec (OstreeSysrootUpgrader *self,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ gs_free char *origin_refspec = NULL;
+
+ origin_refspec = g_key_file_get_string (self->origin, "origin", "refspec", NULL);
+ if (!origin_refspec)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "No origin/refspec in current deployment origin; cannot upgrade via ostree");
+ goto out;
+ }
+ g_clear_pointer (&self->origin_remote, g_free);
+ g_clear_pointer (&self->origin_ref, g_free);
+ if (!ostree_parse_refspec (origin_refspec,
+ &self->origin_remote,
+ &self->origin_ref,
+ error))
+ goto out;
+
+ ret = TRUE;
+ out:
+ return ret;
+}
+
+static gboolean
+ostree_sysroot_upgrader_initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ OstreeSysrootUpgrader *self = (OstreeSysrootUpgrader*)initable;
+ OstreeDeployment *booted_deployment =
+ ostree_sysroot_get_booted_deployment (self->sysroot);
+ gs_unref_object GFile *deployment_path = NULL;
+ gs_unref_object GFile *deployment_origin_path = NULL;
+
+ if (booted_deployment == NULL && self->osname == NULL)
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Not currently booted into an OSTree system and no OS specified");
+ goto out;
+ }
+
+ if (self->osname == NULL)
+ {
+ g_assert (booted_deployment);
+ self->osname = g_strdup (ostree_deployment_get_osname (booted_deployment));
+ }
+
+ self->merge_deployment = ostree_sysroot_get_merge_deployment (self->sysroot, self->osname);
+ if (self->merge_deployment == NULL)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "No previous deployment for OS '%s'", self->osname);
+ goto out;
+ }
+
+ deployment_path = ostree_sysroot_get_deployment_directory (self->sysroot, self->merge_deployment);
+ deployment_origin_path = ostree_sysroot_get_deployment_origin_path (deployment_path);
+
+ self->origin = ostree_deployment_get_origin (self->merge_deployment);
+ if (!self->origin)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "No origin known for deployment %s.%d",
+ ostree_deployment_get_csum (self->merge_deployment),
+ ostree_deployment_get_deployserial (self->merge_deployment));
+ goto out;
+ }
+
+ if (!parse_refspec (self, cancellable, error))
+ goto out;
+
+ ret = TRUE;
+ out:
+ return ret;
+}
+
+static void
+ostree_sysroot_upgrader_initable_iface_init (GInitableIface *iface)
+{
+ iface->init = ostree_sysroot_upgrader_initable_init;
+}
+
+static void
+ostree_sysroot_upgrader_finalize (GObject *object)
+{
+ OstreeSysrootUpgrader *self = OSTREE_SYSROOT_UPGRADER (object);
+
+ g_clear_object (&self->sysroot);
+ g_free (self->osname);
+
+ g_clear_object (&self->merge_deployment);
+ if (self->origin)
+ g_key_file_unref (self->origin);
+ g_free (self->origin_remote);
+ g_free (self->origin_ref);
+
+ G_OBJECT_CLASS (ostree_sysroot_upgrader_parent_class)->finalize (object);
+}
+
+static void
+ostree_sysroot_upgrader_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ OstreeSysrootUpgrader *self = OSTREE_SYSROOT_UPGRADER (object);
+
+ switch (prop_id)
+ {
+ case PROP_SYSROOT:
+ self->sysroot = g_value_dup_object (value);
+ break;
+ case PROP_OSNAME:
+ self->osname = g_value_dup_string (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+ostree_sysroot_upgrader_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ OstreeSysrootUpgrader *self = OSTREE_SYSROOT_UPGRADER (object);
+
+ switch (prop_id)
+ {
+ case PROP_SYSROOT:
+ g_value_set_object (value, self->sysroot);
+ break;
+ case PROP_OSNAME:
+ g_value_set_string (value, self->osname);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+ostree_sysroot_upgrader_constructed (GObject *object)
+{
+ OstreeSysrootUpgrader *self = OSTREE_SYSROOT_UPGRADER (object);
+
+ g_assert (self->sysroot != NULL);
+
+ G_OBJECT_CLASS (ostree_sysroot_upgrader_parent_class)->constructed (object);
+}
+
+static void
+ostree_sysroot_upgrader_class_init (OstreeSysrootUpgraderClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->constructed = ostree_sysroot_upgrader_constructed;
+ object_class->get_property = ostree_sysroot_upgrader_get_property;
+ object_class->set_property = ostree_sysroot_upgrader_set_property;
+ object_class->finalize = ostree_sysroot_upgrader_finalize;
+
+ g_object_class_install_property (object_class,
+ PROP_SYSROOT,
+ g_param_spec_object ("sysroot", "", "",
+ OSTREE_TYPE_SYSROOT,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (object_class,
+ PROP_OSNAME,
+ g_param_spec_string ("osname", "", "", NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+ostree_sysroot_upgrader_init (OstreeSysrootUpgrader *self)
+{
+}
+
+/**
+ * ostree_sysroot_upgrader_new:
+ * @sysroot: An #OstreeSysroot
+ *
+ * Returns: (transfer full): An upgrader
+ */
+OstreeSysrootUpgrader*
+ostree_sysroot_upgrader_new (OstreeSysroot *sysroot,
+ GCancellable *cancellable,
+ GError **error)
+{
+ return g_initable_new (OSTREE_TYPE_SYSROOT_UPGRADER, cancellable, error,
+ "sysroot", sysroot, NULL);
+}
+
+/**
+ * ostree_sysroot_upgrader_new_for_os:
+ * @sysroot: An #OstreeSysroot
+ * @osname: (allow-none): Operating system name
+ *
+ * Returns: (transfer full): An upgrader
+ */
+OstreeSysrootUpgrader*
+ostree_sysroot_upgrader_new_for_os (OstreeSysroot *sysroot,
+ const char *osname,
+ GCancellable *cancellable,
+ GError **error)
+{
+ return g_initable_new (OSTREE_TYPE_SYSROOT_UPGRADER, cancellable, error,
+ "sysroot", sysroot, "osname", osname, NULL);
+}
+
+/**
+ * ostree_sysroot_upgrader_get_origin:
+ * @self: Sysroot
+ *
+ * Returns: (transfer none): The origin file, or %NULL if unknown
+ */
+GKeyFile *
+ostree_sysroot_upgrader_get_origin (OstreeSysrootUpgrader *self)
+{
+ return self->origin;
+}
+
+/**
+ * ostree_sysroot_upgrader_set_origin:
+ * @self: Sysroot
+ * @origin: (allow-none): The new origin
+ * @cancellable: Cancellable
+ * @error: Error
+ *
+ * Replace the origin with @origin.
+ */
+gboolean
+ostree_sysroot_upgrader_set_origin (OstreeSysrootUpgrader *self,
+ GKeyFile *origin,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+
+ g_clear_pointer (&self->origin, g_key_file_unref);
+ if (origin)
+ {
+ self->origin = g_key_file_ref (origin);
+ if (!parse_refspec (self, cancellable, error))
+ goto out;
+ }
+
+ ret = TRUE;
+ out:
+ return ret;
+}
+
+/**
+ * ostree_sysroot_upgrader_check_timestamps:
+ * @repo: Repo
+ * @from_rev: From revision
+ * @to_rev: To revision
+ * @error: Error
+ *
+ * Check that the timestamp on @to_rev is equal to or newer than
+ * @from_rev. This protects systems against man-in-the-middle
+ * attackers which provide a client with an older commit.
+ */
+gboolean
+ostree_sysroot_upgrader_check_timestamps (OstreeRepo *repo,
+ const char *from_rev,
+ const char *to_rev,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ gs_unref_variant GVariant *old_commit = NULL;
+ gs_unref_variant GVariant *new_commit = NULL;
+
+ if (!ostree_repo_load_variant (repo,
+ OSTREE_OBJECT_TYPE_COMMIT,
+ from_rev,
+ &old_commit,
+ error))
+ goto out;
+
+ if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT,
+ to_rev, &new_commit,
+ error))
+ goto out;
+
+ if (ostree_commit_get_timestamp (old_commit) > ostree_commit_get_timestamp (new_commit))
+ {
+ GDateTime *old_ts = g_date_time_new_from_unix_utc (ostree_commit_get_timestamp (old_commit));
+ GDateTime *new_ts = g_date_time_new_from_unix_utc (ostree_commit_get_timestamp (new_commit));
+ gs_free char *old_ts_str = NULL;
+ gs_free char *new_ts_str = NULL;
+
+ g_assert (old_ts);
+ g_assert (new_ts);
+ old_ts_str = g_date_time_format (old_ts, "%c");
+ new_ts_str = g_date_time_format (new_ts, "%c");
+ g_date_time_unref (old_ts);
+ g_date_time_unref (new_ts);
+
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Upgrade target revision '%s' with timestamp '%s' is chronologically older than current revision '%s' with timestamp '%s'; use --allow-downgrade to permit",
+ to_rev, new_ts_str, from_rev, old_ts_str);
+ goto out;
+ }
+
+ ret = TRUE;
+ out:
+ return ret;
+}
+
+
+/**
+ * ostree_sysroot_upgrader_pull:
+ * @self: Upgrader
+ * @flags: Flags controlling pull behavior
+ * @upgrader_flags: Flags controlling upgrader behavior
+ * @progress: (allow-none): Progress
+ * @out_changed: (out): Whether or not the origin changed
+ * @cancellable: Cancellable
+ * @error: Error
+ *
+ * Perform a pull from the origin. First check if the ref has
+ * changed, if so download the linked objects, and store the updated
+ * ref locally. Then @out_changed will be %TRUE.
+ *
+ * If the origin remote is unchanged, @out_changed will be set to
+ * %FALSE.
+ */
+gboolean
+ostree_sysroot_upgrader_pull (OstreeSysrootUpgrader *self,
+ OstreeRepoPullFlags flags,
+ OstreeSysrootUpgraderPullFlags upgrader_flags,
+ OstreeAsyncProgress *progress,
+ gboolean *out_changed,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ gs_unref_object OstreeRepo *repo = NULL;
+ char *refs_to_fetch[] = { self->origin_ref, NULL };
+ gs_free char *from_revision = NULL;
+ gs_free char *new_revision = NULL;
+ gs_free char *origin_refspec = NULL;
+
+ if (!ostree_sysroot_get_repo (self->sysroot, &repo, cancellable, error))
+ goto out;
+
+ if (self->origin_remote)
+ origin_refspec = g_strconcat (self->origin_remote, ":", self->origin_ref, NULL);
+ else
+ origin_refspec = g_strdup (self->origin_ref);
+
+ if (!ostree_repo_resolve_rev (repo, origin_refspec, TRUE, &from_revision,
+ error))
+ goto out;
+
+ if (!ostree_repo_pull (repo, self->origin_remote, refs_to_fetch,
+ flags, progress,
+ cancellable, error))
+ goto out;
+
+ if (!ostree_repo_resolve_rev (repo, origin_refspec, FALSE, &self->new_revision,
+ error))
+ goto out;
+
+ if (g_strcmp0 (from_revision, self->new_revision) == 0)
+ {
+ *out_changed = FALSE;
+ }
+ else
+ {
+ *out_changed = TRUE;
+ if (from_revision)
+ {
+ if (!ostree_sysroot_upgrader_check_timestamps (repo, from_revision,
+ self->new_revision,
+ error))
+ goto out;
+ }
+ }
+
+ ret = TRUE;
+ out:
+ return ret;
+}
+
+/**
+ * ostree_sysroot_upgrader_deploy:
+ * @self: Self
+ * @cancellable: Cancellable
+ * @error: Error
+ *
+ * Write the new deployment to disk, perform a configuration merge
+ * with /etc, and update the bootloader configuration.
+ */
+gboolean
+ostree_sysroot_upgrader_deploy (OstreeSysrootUpgrader *self,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ gs_unref_object OstreeDeployment *new_deployment = NULL;
+
+ if (!ostree_sysroot_deploy_tree (self->sysroot, self->osname,
+ self->new_revision,
+ self->origin,
+ self->merge_deployment,
+ NULL,
+ &new_deployment,
+ cancellable, error))
+ goto out;
+
+ if (!ostree_sysroot_simple_write_deployment (self->sysroot, self->osname,
+ new_deployment,
+ self->merge_deployment,
+ 0,
+ cancellable, error))
+ goto out;
+
+ ret = TRUE;
+ out:
+ return ret;
+}
diff --git a/src/libostree/ostree-sysroot-upgrader.h b/src/libostree/ostree-sysroot-upgrader.h
new file mode 100644
index 00000000..79f36355
--- /dev/null
+++ b/src/libostree/ostree-sysroot-upgrader.h
@@ -0,0 +1,71 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2014 Colin Walters <walters@verbum.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#pragma once
+
+#include "ostree-sysroot.h"
+
+G_BEGIN_DECLS
+
+#define OSTREE_TYPE_SYSROOT_UPGRADER ostree_sysroot_upgrader_get_type()
+#define OSTREE_SYSROOT_UPGRADER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), OSTREE_TYPE_SYSROOT_UPGRADER, OstreeSysrootUpgrader))
+#define OSTREE_IS_SYSROOT_UPGRADER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OSTREE_TYPE_SYSROOT_UPGRADER))
+
+GType ostree_sysroot_upgrader_get_type (void);
+
+OstreeSysrootUpgrader *ostree_sysroot_upgrader_new (OstreeSysroot *sysroot,
+ GCancellable *cancellable,
+ GError **error);
+
+OstreeSysrootUpgrader *ostree_sysroot_upgrader_new_for_os (OstreeSysroot *sysroot,
+ const char *osname,
+ GCancellable *cancellable,
+ GError **error);
+
+GKeyFile *ostree_sysroot_upgrader_get_origin (OstreeSysrootUpgrader *self);
+gboolean ostree_sysroot_upgrader_set_origin (OstreeSysrootUpgrader *self, GKeyFile *origin,
+ GCancellable *cancellable, GError **error);
+
+gboolean ostree_sysroot_upgrader_check_timestamps (OstreeRepo *repo,
+ const char *from_rev,
+ const char *to_rev,
+ GError **error);
+
+typedef enum {
+ OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_NONE = 0,
+ OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER = (1 << 0)
+} OstreeSysrootUpgraderPullFlags;
+
+gboolean ostree_sysroot_upgrader_pull (OstreeSysrootUpgrader *self,
+ OstreeRepoPullFlags flags,
+ OstreeSysrootUpgraderPullFlags upgrader_flags,
+ OstreeAsyncProgress *progress,
+ gboolean *out_changed,
+ GCancellable *cancellable,
+ GError **error);
+
+gboolean ostree_sysroot_upgrader_deploy (OstreeSysrootUpgrader *self,
+ GCancellable *cancellable,
+ GError **error);
+
+G_END_DECLS
+
diff --git a/src/libostree/ostree-types.h b/src/libostree/ostree-types.h
index 8be12584..533d3b10 100644
--- a/src/libostree/ostree-types.h
+++ b/src/libostree/ostree-types.h
@@ -29,6 +29,7 @@ G_BEGIN_DECLS
typedef struct OstreeRepo OstreeRepo;
typedef struct OstreeSePolicy OstreeSePolicy;
typedef struct OstreeSysroot OstreeSysroot;
+typedef struct OstreeSysrootUpgrader OstreeSysrootUpgrader;
typedef struct OstreeMutableTree OstreeMutableTree;
typedef struct OstreeRepoFile OstreeRepoFile;
diff --git a/src/libostree/ostree.h b/src/libostree/ostree.h
index f1e74507..57b2ffd2 100644
--- a/src/libostree/ostree.h
+++ b/src/libostree/ostree.h
@@ -26,6 +26,7 @@
#include <ostree-mutable-tree.h>
#include <ostree-repo-file.h>
#include <ostree-sysroot.h>
+#include <ostree-sysroot-upgrader.h>
#include <ostree-deployment.h>
#include <ostree-bootconfig-parser.h>
#include <ostree-diff.h>
diff --git a/src/ostree/ot-admin-builtin-switch.c b/src/ostree/ot-admin-builtin-switch.c
index 1edd7f5d..d9d6ee03 100644
--- a/src/ostree/ot-admin-builtin-switch.c
+++ b/src/ostree/ot-admin-builtin-switch.c
@@ -46,14 +46,21 @@ ot_admin_builtin_switch (int argc, char **argv, OstreeSysroot *sysroot, GCancell
GOptionContext *context;
const char *new_ref = NULL;
gs_unref_object OstreeRepo *repo = NULL;
+ gs_free char *origin_refspec = NULL;
gs_free char *origin_remote = NULL;
gs_free char *origin_ref = NULL;
+ gs_free char *new_refspec = NULL;
gs_free char *new_revision = NULL;
gs_unref_object GFile *deployment_path = NULL;
gs_unref_object GFile *deployment_origin_path = NULL;
gs_unref_object OstreeDeployment *merge_deployment = NULL;
gs_unref_object OstreeDeployment *new_deployment = NULL;
- GKeyFile *origin;
+ gs_unref_object OstreeSysrootUpgrader *upgrader = NULL;
+ gs_unref_object OstreeAsyncProgress *progress = NULL;
+ gboolean changed;
+ GSConsole *console;
+ GKeyFile *old_origin;
+ GKeyFile *new_origin = NULL;
context = g_option_context_new ("REF - Construct new tree from current origin and deploy it, if it changed");
g_option_context_add_main_entries (context, options, NULL);
@@ -72,108 +79,74 @@ ot_admin_builtin_switch (int argc, char **argv, OstreeSysroot *sysroot, GCancell
if (!ostree_sysroot_load (sysroot, cancellable, error))
goto out;
- if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error))
+ upgrader = ostree_sysroot_upgrader_new_for_os (sysroot, opt_osname,
+ cancellable, error);
+ if (!upgrader)
goto out;
- if (!ot_admin_deploy_prepare (sysroot, opt_osname, &merge_deployment,
- &origin_remote, &origin_ref,
- &origin,
- cancellable, error))
+ old_origin = ostree_sysroot_upgrader_get_origin (upgrader);
+ origin_refspec = g_key_file_get_string (old_origin, "origin", "refspec", NULL);
+
+ if (!ostree_parse_refspec (origin_refspec, &origin_remote, &origin_ref, error))
goto out;
+
+ if (origin_remote)
+ new_refspec = g_strconcat (origin_remote, ":", new_ref, NULL);
+ else
+ new_refspec = g_strdup (new_ref);
- if (strcmp (origin_ref, new_ref) == 0)
+ if (strcmp (origin_refspec, new_refspec) == 0)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Old and new refs are equal: %s", new_ref);
+ "Old and new refs are equal: %s", new_refspec);
goto out;
}
- {
- gs_free char *new_refspec = NULL;
- if (origin_remote)
- new_refspec = g_strconcat (origin_remote, ":", new_ref, NULL);
- else
- new_refspec = g_strdup (new_ref);
- g_key_file_unref (origin);
- origin = ostree_sysroot_origin_new_from_refspec (sysroot, new_refspec);
- }
+ new_origin = ostree_sysroot_origin_new_from_refspec (sysroot, new_refspec);
+ if (!ostree_sysroot_upgrader_set_origin (upgrader, new_origin, cancellable, error))
+ goto out;
- if (origin_remote)
+ console = gs_console_get ();
+ if (console)
{
- OstreeRepoPullFlags pullflags = 0;
- char *refs_to_fetch[] = { (char*)new_ref, NULL };
- GSConsole *console;
- gs_unref_object OstreeAsyncProgress *progress = NULL;
-
- g_print ("Fetching remote %s ref %s\n", origin_remote, new_ref);
-
- console = gs_console_get ();
- if (console)
- {
- gs_console_begin_status_line (console, "", NULL, NULL);
- progress = ostree_async_progress_new_and_connect (ot_common_pull_progress, console);
- }
-
- if (!ostree_repo_pull (repo, origin_remote, refs_to_fetch, pullflags, progress,
- cancellable, error))
- goto out;
+ gs_console_begin_status_line (console, "", NULL, NULL);
+ progress = ostree_async_progress_new_and_connect (ot_common_pull_progress, console);
}
- if (!ostree_repo_resolve_rev (repo, new_ref, FALSE, &new_revision,
- error))
+ if (!ostree_sysroot_upgrader_pull (upgrader, 0, 0, progress, &changed,
+ cancellable, error))
goto out;
- if (TRUE)
- {
- gs_unref_object GFile *real_sysroot = g_file_new_for_path ("/");
+ if (!ostree_sysroot_upgrader_deploy (upgrader, cancellable, error))
+ goto out;
+
+ if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error))
+ goto out;
+
+ if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error))
+ goto out;
+
+ g_print ("Deleting ref '%s:%s'\n", origin_remote, origin_ref);
+ ostree_repo_transaction_set_ref (repo, origin_remote, origin_ref, NULL);
+
+ if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error))
+ goto out;
+
+ {
+ gs_unref_object GFile *real_sysroot = g_file_new_for_path ("/");
- /* Here we perform cleanup of any leftover data from previous
- * partial failures. This avoids having to call gs_shutil_rm_rf()
- * at random points throughout the process.
- *
- * TODO: Add /ostree/transaction file, and only do this cleanup if
- * we find it.
- */
- if (!ostree_sysroot_cleanup (sysroot, cancellable, error))
- {
- g_prefix_error (error, "Performing initial cleanup: ");
- goto out;
- }
-
- if (!ostree_sysroot_deploy_tree (sysroot,
- opt_osname, new_revision, origin,
- merge_deployment,
- NULL,
- &new_deployment,
- cancellable, error))
- goto out;
-
- if (!ostree_sysroot_simple_write_deployment (sysroot, opt_osname,
- new_deployment,
- merge_deployment,
- 0,
- cancellable, error))
- goto out;
-
- if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error))
- goto out;
-
- g_print ("Deleting ref '%s:%s'\n", origin_remote, origin_ref);
- ostree_repo_transaction_set_ref (repo, origin_remote, origin_ref, NULL);
-
- if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error))
- goto out;
-
- if (opt_reboot && g_file_equal (ostree_sysroot_get_path (sysroot), real_sysroot))
- {
- gs_subprocess_simple_run_sync (NULL, GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT,
- cancellable, error,
- "systemctl", "reboot", NULL);
- }
- }
+ if (opt_reboot && g_file_equal (ostree_sysroot_get_path (sysroot), real_sysroot))
+ {
+ gs_subprocess_simple_run_sync (NULL, GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT,
+ cancellable, error,
+ "systemctl", "reboot", NULL);
+ }
+ }
ret = TRUE;
out:
+ if (new_origin)
+ g_key_file_unref (new_origin);
if (context)
g_option_context_free (context);
return ret;
diff --git a/src/ostree/ot-admin-builtin-upgrade.c b/src/ostree/ot-admin-builtin-upgrade.c
index badaf2e2..f8527117 100644
--- a/src/ostree/ot-admin-builtin-upgrade.c
+++ b/src/ostree/ot-admin-builtin-upgrade.c
@@ -49,7 +49,7 @@ ot_admin_builtin_upgrade (int argc, char **argv, OstreeSysroot *sysroot, GCancel
{
gboolean ret = FALSE;
GOptionContext *context;
- gs_unref_object OstreeRepo *repo = NULL;
+ gs_unref_object OstreeSysrootUpgrader *upgrader = NULL;
gs_free char *origin_remote = NULL;
gs_free char *origin_ref = NULL;
gs_free char *origin_refspec = NULL;
@@ -58,7 +58,9 @@ ot_admin_builtin_upgrade (int argc, char **argv, OstreeSysroot *sysroot, GCancel
gs_unref_object GFile *deployment_origin_path = NULL;
gs_unref_object OstreeDeployment *merge_deployment = NULL;
gs_unref_object OstreeDeployment *new_deployment = NULL;
- GKeyFile *origin;
+ GSConsole *console;
+ gs_unref_object OstreeAsyncProgress *progress = NULL;
+ gboolean changed;
context = g_option_context_new ("Construct new tree from current origin and deploy it, if it changed");
g_option_context_add_main_entries (context, options, NULL);
@@ -69,118 +71,31 @@ ot_admin_builtin_upgrade (int argc, char **argv, OstreeSysroot *sysroot, GCancel
if (!ostree_sysroot_load (sysroot, cancellable, error))
goto out;
-
- if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error))
- goto out;
-
- if (!ot_admin_deploy_prepare (sysroot, opt_osname, &merge_deployment,
- &origin_remote, &origin_ref,
- &origin,
- cancellable, error))
+ upgrader = ostree_sysroot_upgrader_new_for_os (sysroot, opt_osname,
+ cancellable, error);
+ if (!upgrader)
goto out;
- if (origin_remote)
+ console = gs_console_get ();
+ if (console)
{
- OstreeRepoPullFlags pullflags = 0;
- char *refs_to_fetch[] = { origin_ref, NULL };
- GSConsole *console;
- gs_unref_object OstreeAsyncProgress *progress = NULL;
-
- g_print ("Fetching remote %s ref %s\n", origin_remote, origin_ref);
-
- console = gs_console_get ();
- if (console)
- {
- gs_console_begin_status_line (console, "", NULL, NULL);
- progress = ostree_async_progress_new_and_connect (ot_common_pull_progress, console);
- }
-
- if (!ostree_repo_pull (repo, origin_remote, refs_to_fetch, pullflags, progress,
- cancellable, error))
- goto out;
-
- origin_refspec = g_strconcat (origin_remote, ":", origin_ref, NULL);
+ gs_console_begin_status_line (console, "", NULL, NULL);
+ progress = ostree_async_progress_new_and_connect (ot_common_pull_progress, console);
}
- else
- origin_refspec = g_strdup (origin_ref);
-
- if (!ostree_repo_resolve_rev (repo, origin_refspec, FALSE, &new_revision,
- error))
+ if (!ostree_sysroot_upgrader_pull (upgrader, 0, 0, progress, &changed,
+ cancellable, error))
goto out;
-
- if (strcmp (ostree_deployment_get_csum (merge_deployment), new_revision) == 0)
+
+ if (!changed)
{
- g_print ("Refspec %s is unchanged\n", origin_refspec);
+ g_print ("No update available.\n");
}
else
{
gs_unref_object GFile *real_sysroot = g_file_new_for_path ("/");
- if (!opt_allow_downgrade)
- {
- const char *old_revision = ostree_deployment_get_csum (merge_deployment);
- gs_unref_variant GVariant *old_commit = NULL;
- gs_unref_variant GVariant *new_commit = NULL;
-
- if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT,
- old_revision,
- &old_commit,
- error))
- goto out;
-
- if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT,
- new_revision, &new_commit,
- error))
- goto out;
-
- if (ostree_commit_get_timestamp (old_commit) > ostree_commit_get_timestamp (new_commit))
- {
- GDateTime *old_ts = g_date_time_new_from_unix_utc (ostree_commit_get_timestamp (old_commit));
- GDateTime *new_ts = g_date_time_new_from_unix_utc (ostree_commit_get_timestamp (new_commit));
- gs_free char *old_ts_str = NULL;
- gs_free char *new_ts_str = NULL;
-
- g_assert (old_ts);
- g_assert (new_ts);
- old_ts_str = g_date_time_format (old_ts, "%c");
- new_ts_str = g_date_time_format (new_ts, "%c");
- g_date_time_unref (old_ts);
- g_date_time_unref (new_ts);
-
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Upgrade target revision '%s' with timestamp '%s' is chronologically older than current revision '%s' with timestamp '%s'; use --allow-downgrade to permit",
- new_revision, new_ts_str, old_revision, old_ts_str);
- goto out;
- }
- }
-
- /* Here we perform cleanup of any leftover data from previous
- * partial failures. This avoids having to call gs_shutil_rm_rf()
- * at random points throughout the process.
- *
- * TODO: Add /ostree/transaction file, and only do this cleanup if
- * we find it.
- */
- if (!ostree_sysroot_cleanup (sysroot, cancellable, error))
- {
- g_prefix_error (error, "Performing initial cleanup: ");
- goto out;
- }
-
- if (!ostree_sysroot_deploy_tree (sysroot,
- opt_osname, new_revision, origin,
- merge_deployment,
- NULL,
- &new_deployment,
- cancellable, error))
- goto out;
-
- if (!ostree_sysroot_simple_write_deployment (sysroot, opt_osname,
- new_deployment,
- merge_deployment,
- 0,
- cancellable, error))
+ if (!ostree_sysroot_upgrader_deploy (upgrader, cancellable, error))
goto out;
if (opt_reboot && g_file_equal (ostree_sysroot_get_path (sysroot), real_sysroot))
diff --git a/src/ostree/ot-admin-functions.c b/src/ostree/ot-admin-functions.c
index 198f3e48..34e5c6b2 100644
--- a/src/ostree/ot-admin-functions.c
+++ b/src/ostree/ot-admin-functions.c
@@ -48,63 +48,3 @@ ot_admin_require_booted_deployment_or_osname (OstreeSysroot *sysroot,
out:
return ret;
}
-
-gboolean
-ot_admin_deploy_prepare (OstreeSysroot *sysroot,
- const char *osname,
- OstreeDeployment **out_merge_deployment,
- char **out_origin_remote,
- char **out_origin_ref,
- GKeyFile **out_origin,
- GCancellable *cancellable,
- GError **error)
-{
- gboolean ret = FALSE;
- gs_free char *origin_refspec = NULL;
- gs_free char *origin_remote = NULL;
- gs_free char *origin_ref = NULL;
- gs_unref_object GFile *deployment_path = NULL;
- gs_unref_object GFile *deployment_origin_path = NULL;
- gs_unref_object OstreeDeployment *merge_deployment = NULL;
- GKeyFile *origin;
-
- if (!ot_admin_require_booted_deployment_or_osname (sysroot, osname,
- cancellable, error))
- goto out;
- merge_deployment = ostree_sysroot_get_merge_deployment (sysroot, osname);
- if (merge_deployment == NULL)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "No previous deployment for OS '%s'", osname);
- goto out;
- }
-
- deployment_path = ostree_sysroot_get_deployment_directory (sysroot, merge_deployment);
- deployment_origin_path = ostree_sysroot_get_deployment_origin_path (deployment_path);
-
- origin = ostree_deployment_get_origin (merge_deployment);
- if (!origin)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "No origin known for current deployment");
- goto out;
- }
- origin_refspec = g_key_file_get_string (origin, "origin", "refspec", NULL);
- if (!origin_refspec)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "No origin/refspec in current deployment origin; cannot upgrade via ostree");
- goto out;
- }
- if (!ostree_parse_refspec (origin_refspec, &origin_remote, &origin_ref, error))
- goto out;
-
- ret = TRUE;
- gs_transfer_out_value (out_merge_deployment, &merge_deployment);
- gs_transfer_out_value (out_origin_remote, &origin_remote);
- gs_transfer_out_value (out_origin_ref, &origin_ref);
- gs_transfer_out_value (out_origin, &origin);
- out:
- g_clear_pointer (&origin, g_key_file_unref);
- return ret;
-}
diff --git a/src/ostree/ot-admin-functions.h b/src/ostree/ot-admin-functions.h
index 8d903713..ab830369 100644
--- a/src/ostree/ot-admin-functions.h
+++ b/src/ostree/ot-admin-functions.h
@@ -32,16 +32,5 @@ ot_admin_require_booted_deployment_or_osname (OstreeSysroot *sysroot,
const char *osname,
GCancellable *cancellable,
GError **error);
-
-gboolean
-ot_admin_deploy_prepare (OstreeSysroot *sysroot,
- const char *osname,
- OstreeDeployment **merge_deployment,
- char **origin_remote,
- char **origin_ref,
- GKeyFile **out_origin,
- GCancellable *cancellable,
- GError **error);
-
G_END_DECLS