summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile-libostree-defines.am1
-rw-r--r--Makefile-libostree.am1
-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
10 files changed, 645 insertions, 257 deletions
diff --git a/Makefile-libostree-defines.am b/Makefile-libostree-defines.am
index 02037ed2..7f776e0a 100644
--- a/Makefile-libostree-defines.am
+++ b/Makefile-libostree-defines.am
@@ -29,6 +29,7 @@ libostree_public_headers = \
src/libostree/ostree-diff.h \
src/libostree/ostree-sepolicy.h \
src/libostree/ostree-sysroot.h \
+ src/libostree/ostree-sysroot-upgrader.h \
src/libostree/ostree-deployment.h \
src/libostree/ostree-bootconfig-parser.h \
$(NULL)
diff --git a/Makefile-libostree.am b/Makefile-libostree.am
index 04d03be6..988f1cbf 100644
--- a/Makefile-libostree.am
+++ b/Makefile-libostree.am
@@ -61,6 +61,7 @@ libostree_1_la_SOURCES = \
src/libostree/ostree-sysroot.c \
src/libostree/ostree-sysroot-cleanup.c \
src/libostree/ostree-sysroot-deploy.c \
+ src/libostree/ostree-sysroot-upgrader.c \
src/libostree/ostree-bootconfig-parser.c \
src/libostree/ostree-deployment.c \
src/libostree/ostree-bootloader.h \
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