[ostree] admin: Rework /ostree/deploy to support multiple independent operating systems
- From: Colin Walters <walters src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [ostree] admin: Rework /ostree/deploy to support multiple independent operating systems
- Date: Fri, 21 Dec 2012 19:13:52 +0000 (UTC)
commit 3832544ac40b5bbfcee3621cc5ab096ac64e578d
Author: Colin Walters <walters verbum org>
Date: Wed Dec 19 17:52:46 2012 -0500
admin: Rework /ostree/deploy to support multiple independent operating systems
The real vision of OSTree is to "multiple versions of multiple
operating systems". Up until now, it's worked to install gnome-ostree
inside a host distribution, but several things don't work quite right
if you try to do completely different systems.
In the new model, there's the concept of an "osname" which encompasses
a few properties:
1) Its own /var
2) A set of trees deployed in /ostree/deploy/OSNAME/
3) Its own "current" and "previous" links.
Now it no longer really makes sense to boot with "ostree=current".
Instead, you specify e.g. "ostree=gnome/current".
This is an incompatible change to the deployment code - you will need
to run init-os gnome and redeploy.
All "ostree admin" subcommands now take an OSNAME argument.
Makefile-ostree.am | 8 +-
src/ostree/ostree-curl-fetcher.c | 204 ++++++++++++++++++++
src/ostree/ostree-curl-fetcher.h | 59 ++++++
src/ostree/ot-admin-builtin-deploy.c | 73 ++++----
src/ostree/ot-admin-builtin-diff.c | 17 ++-
src/ostree/ot-admin-builtin-install.c | 200 +++++++++++++++++++
src/ostree/ot-admin-builtin-os-init.c | 105 ++++++++++
src/ostree/ot-admin-builtin-prune.c | 21 ++-
src/ostree/ot-admin-builtin-pull-deploy.c | 91 +++-------
src/ostree/ot-admin-builtin-update-kernel.c | 19 ++-
...n-builtin-init.c => ot-admin-builtin-upgrade.c} | 32 +++-
src/ostree/ot-admin-builtins.h | 4 +-
src/ostree/ot-admin-functions.c | 53 +-----
src/ostree/ot-admin-functions.h | 2 +
src/ostree/ot-builtin-admin.c | 4 +-
src/switchroot/ostree-switch-root.c | 78 ++++----
16 files changed, 758 insertions(+), 212 deletions(-)
---
diff --git a/Makefile-ostree.am b/Makefile-ostree.am
index d4649c5..0066765 100644
--- a/Makefile-ostree.am
+++ b/Makefile-ostree.am
@@ -22,8 +22,10 @@ bin_PROGRAMS += ostree
endif
ostree_SOURCES = src/ostree/main.c \
- src/ostree/ot-builtins.h \
+ src/ostree/ostree-curl-fetcher.h \
+ src/ostree/ostree-curl-fetcher.c \
src/ostree/ot-builtin-admin.c \
+ src/ostree/ot-builtins.h \
src/ostree/ot-builtin-cat.c \
src/ostree/ot-builtin-config.c \
src/ostree/ot-builtin-checkout.c \
@@ -46,12 +48,14 @@ ostree_SOURCES = src/ostree/main.c \
# Admin subcommand
ostree_SOURCES += \
- src/ostree/ot-admin-builtin-init.c \
src/ostree/ot-admin-builtin-init-fs.c \
src/ostree/ot-admin-builtin-diff.c \
src/ostree/ot-admin-builtin-deploy.c \
src/ostree/ot-admin-builtin-prune.c \
src/ostree/ot-admin-builtin-pull-deploy.c \
+ src/ostree/ot-admin-builtin-os-init.c \
+ src/ostree/ot-admin-builtin-install.c \
+ src/ostree/ot-admin-builtin-upgrade.c \
src/ostree/ot-admin-builtin-update-kernel.c \
src/ostree/ot-admin-builtins.h \
src/ostree/ot-admin-functions.h \
diff --git a/src/ostree/ostree-curl-fetcher.c b/src/ostree/ostree-curl-fetcher.c
new file mode 100644
index 0000000..fbe96ab
--- /dev/null
+++ b/src/ostree/ostree-curl-fetcher.c
@@ -0,0 +1,204 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2011,2012 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.
+ *
+ * Author: Colin Walters <walters verbum org>
+ */
+
+#include "config.h"
+
+#include "ostree-curl-fetcher.h"
+#include "ostree.h"
+
+struct OstreeCurlFetcher
+{
+ GObject parent_instance;
+
+ GFile *tmpdir;
+
+ GSSubprocess *curl_proc;
+ GQueue *queue;
+};
+
+G_DEFINE_TYPE (OstreeCurlFetcher, ostree_curl_fetcher, G_TYPE_OBJECT)
+
+static void
+ostree_curl_fetcher_finalize (GObject *object)
+{
+ OstreeCurlFetcher *self;
+
+ self = OSTREE_CURL_FETCHER (object);
+
+ g_clear_object (&self->curl_proc);
+ g_queue_free (self->queue);
+
+ G_OBJECT_CLASS (ostree_curl_fetcher_parent_class)->finalize (object);
+}
+
+static void
+ostree_curl_fetcher_class_init (OstreeCurlFetcherClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = ostree_curl_fetcher_finalize;
+}
+
+static void
+ostree_curl_fetcher_init (OstreeCurlFetcher *self)
+{
+ self->queue = g_queue_new ();
+}
+
+OstreeCurlFetcher *
+ostree_curl_fetcher_new (GFile *tmpdir)
+{
+ OstreeCurlFetcher *self = (OstreeCurlFetcher*)g_object_new (OSTREE_TYPE_CURL_FETCHER, NULL);
+
+ self->tmpdir = g_object_ref (tmpdir);
+
+ return self;
+}
+
+typedef struct {
+ OstreeCurlFetcher *self;
+ gchar *uri;
+ GFile *tmpfile;
+ GCancellable *cancellable;
+ GSimpleAsyncResult *result;
+} OstreeCurlFetcherOp;
+
+static void
+fetcher_op_free (OstreeCurlFetcherOp *op)
+{
+ g_clear_object (&op->self);
+ g_free (op->uri);
+ g_clear_object (&op->tmpfile);
+ g_clear_object (&op->cancellable);
+ g_free (op);
+}
+
+static void
+maybe_fetch (OstreeCurlFetcher *self);
+
+static void
+on_curl_exited (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GSSubprocess *proc = GS_SUBPROCESS (object);
+ OstreeCurlFetcherOp *op = user_data;
+ GError *error = NULL;
+ int estatus;
+
+ if (!gs_subprocess_wait_finish (proc, result, &estatus, &error))
+ goto out;
+
+ if (!g_spawn_check_exit_status (estatus, &error))
+ goto out;
+
+ out:
+ if (error)
+ g_simple_async_result_take_error (op->result, error);
+
+ g_simple_async_result_complete (op->result);
+
+ g_clear_object (&op->self->curl_proc);
+
+ maybe_fetch (op->self);
+
+ g_object_unref (op->result);
+}
+
+static void
+maybe_fetch (OstreeCurlFetcher *self)
+{
+ OstreeCurlFetcherOp *op;
+ GError *error = NULL;
+ gs_unref_object GSSubprocessContext *context = NULL;
+
+ if (self->curl_proc != NULL
+ || g_queue_is_empty (self->queue))
+ return;
+
+ op = g_queue_pop_head (self->queue);
+
+ if (!ostree_create_temp_regular_file (self->tmpdir, NULL, NULL,
+ &op->tmpfile, NULL,
+ op->cancellable, &error))
+ goto out;
+
+ context = gs_subprocess_context_newv ("curl", op->uri, "-o",
+ gs_file_get_path_cached (op->tmpfile),
+ NULL);
+ g_assert (self->curl_proc == NULL);
+ self->curl_proc = gs_subprocess_new (context, op->cancellable, &error);
+ if (!self->curl_proc)
+ goto out;
+
+ gs_subprocess_wait (self->curl_proc, op->cancellable,
+ on_curl_exited, op);
+
+ out:
+ if (error)
+ {
+ g_simple_async_result_take_error (op->result, error);
+ g_simple_async_result_complete (op->result);
+ }
+}
+
+void
+ostree_curl_fetcher_request_uri_async (OstreeCurlFetcher *self,
+ const char *uri,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ OstreeCurlFetcherOp *op;
+
+ op = g_new0 (OstreeCurlFetcherOp, 1);
+ op->self = g_object_ref (self);
+ op->uri = g_strdup (uri);
+ op->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+ op->result = g_simple_async_result_new ((GObject*) self, callback, user_data,
+ ostree_curl_fetcher_request_uri_async);
+
+ g_queue_push_tail (self->queue, op);
+
+ g_simple_async_result_set_op_res_gpointer (op->result, op,
+ (GDestroyNotify) fetcher_op_free);
+
+ maybe_fetch (self);
+}
+
+GFile *
+ostree_curl_fetcher_request_uri_finish (OstreeCurlFetcher *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ OstreeCurlFetcherOp *op;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, (GObject*)self, ostree_curl_fetcher_request_uri_async), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ if (g_simple_async_result_propagate_error (simple, error))
+ return NULL;
+ op = g_simple_async_result_get_op_res_gpointer (simple);
+
+ return g_object_ref (op->tmpfile);
+}
diff --git a/src/ostree/ostree-curl-fetcher.h b/src/ostree/ostree-curl-fetcher.h
new file mode 100644
index 0000000..d7276aa
--- /dev/null
+++ b/src/ostree/ostree-curl-fetcher.h
@@ -0,0 +1,59 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef _OSTREE_CURL_FETCHER
+#define _OSTREE_CURL_FETCHER
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define OSTREE_TYPE_CURL_FETCHER (ostree_curl_fetcher_get_type ())
+#define OSTREE_CURL_FETCHER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OSTREE_TYPE_CURL_FETCHER, OstreeCurlFetcher))
+#define OSTREE_CURL_FETCHER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), OSTREE_TYPE_CURL_FETCHER, OstreeCurlFetcherClass))
+#define OSTREE_IS_CURL_FETCHER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSTREE_TYPE_CURL_FETCHER))
+#define OSTREE_IS_CURL_FETCHER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OSTREE_TYPE_CURL_FETCHER))
+#define OSTREE_CURL_FETCHER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OSTREE_TYPE_CURL_FETCHER, OstreeCurlFetcherClass))
+
+typedef struct OstreeCurlFetcherClass OstreeCurlFetcherClass;
+typedef struct OstreeCurlFetcher OstreeCurlFetcher;
+
+struct OstreeCurlFetcherClass
+{
+ GObjectClass parent_class;
+};
+
+GType ostree_curl_fetcher_get_type (void) G_GNUC_CONST;
+
+OstreeCurlFetcher *ostree_curl_fetcher_new (GFile *tmpdir);
+
+void ostree_curl_fetcher_request_uri_async (OstreeCurlFetcher *self,
+ const char *uri,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+GFile *ostree_curl_fetcher_request_uri_finish (OstreeCurlFetcher *self,
+ GAsyncResult *result,
+ GError **error);
+
+G_END_DECLS
+
+#endif
diff --git a/src/ostree/ot-admin-builtin-deploy.c b/src/ostree/ot-admin-builtin-deploy.c
index 7153d20..d870a99 100644
--- a/src/ostree/ot-admin-builtin-deploy.c
+++ b/src/ostree/ot-admin-builtin-deploy.c
@@ -31,6 +31,8 @@
typedef struct {
OstreeRepo *repo;
GFile *ostree_dir;
+ char *osname;
+ GFile *osname_dir;
} OtAdminDeploy;
static gboolean opt_no_kernel;
@@ -63,21 +65,18 @@ update_current (OtAdminDeploy *self,
{
gboolean ret = FALSE;
ot_lobj GFile *current_path = NULL;
- ot_lobj GFile *current_etc_path = NULL;
ot_lobj GFile *previous_path = NULL;
ot_lobj GFile *tmp_current_path = NULL;
- ot_lobj GFile *tmp_current_etc_path = NULL;
ot_lobj GFile *tmp_previous_path = NULL;
ot_lobj GFileInfo *previous_info = NULL;
ot_lfree char *relative_current = NULL;
ot_lfree char *relative_current_etc = NULL;
ot_lfree char *relative_previous = NULL;
- current_path = g_file_get_child (self->ostree_dir, "current");
- current_etc_path = g_file_get_child (self->ostree_dir, "current-etc");
- previous_path = g_file_get_child (self->ostree_dir, "previous");
+ current_path = g_file_get_child (self->osname_dir, "current");
+ previous_path = g_file_get_child (self->osname_dir, "previous");
- relative_current = g_file_get_relative_path (self->ostree_dir, deploy_target);
+ relative_current = g_file_get_relative_path (self->osname_dir, deploy_target);
g_assert (relative_current);
relative_current_etc = g_strconcat (relative_current, "-etc", NULL);
@@ -92,10 +91,10 @@ update_current (OtAdminDeploy *self,
return TRUE;
}
- tmp_previous_path = g_file_get_child (self->ostree_dir, "tmp-previous");
+ tmp_previous_path = g_file_get_child (self->osname_dir, "tmp-previous");
(void) gs_file_unlink (tmp_previous_path, NULL, NULL);
- relative_previous = g_file_get_relative_path (self->ostree_dir, current_deployment);
+ relative_previous = g_file_get_relative_path (self->osname_dir, current_deployment);
g_assert (relative_previous);
if (symlink (relative_previous, gs_file_get_path_cached (tmp_previous_path)) < 0)
{
@@ -104,7 +103,7 @@ update_current (OtAdminDeploy *self,
}
}
- tmp_current_path = g_file_get_child (self->ostree_dir, "tmp-current");
+ tmp_current_path = g_file_get_child (self->osname_dir, "tmp-current");
(void) gs_file_unlink (tmp_current_path, NULL, NULL);
if (symlink (relative_current, gs_file_get_path_cached (tmp_current_path)) < 0)
@@ -113,20 +112,9 @@ update_current (OtAdminDeploy *self,
goto out;
}
- tmp_current_etc_path = g_file_get_child (self->ostree_dir, "tmp-current-etc");
- (void) gs_file_unlink (tmp_current_etc_path, NULL, NULL);
- if (symlink (relative_current_etc, gs_file_get_path_cached (tmp_current_etc_path)) < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
-
if (!gs_file_rename (tmp_current_path, current_path,
cancellable, error))
goto out;
- if (!gs_file_rename (tmp_current_etc_path, current_etc_path,
- cancellable, error))
- goto out;
if (tmp_previous_path)
{
@@ -367,7 +355,7 @@ merge_etc_changes (OtAdminDeploy *self,
* deploy_tree:
*
* Look up @revision in the repository, and check it out in
- * OSTREE_DIR/deploy/DEPLOY_TARGET.
+ * OSTREE_DIR/deploy/OS/DEPLOY_TARGET.
*
* Merge configuration changes from the old deployment, if any.
*
@@ -383,9 +371,8 @@ deploy_tree (OtAdminDeploy *self,
GError **error)
{
gboolean ret = FALSE;
- const char *current_deployment_ref = "deployment/current";
- const char *previous_deployment_ref = "deployment/previous";
- ot_lobj GFile *deploy_dir = NULL;
+ gs_free char *current_deployment_ref = NULL;
+ gs_free char *previous_deployment_ref = NULL;
ot_lfree char *deploy_target_fullname = NULL;
ot_lfree char *deploy_target_fullname_tmp = NULL;
ot_lobj GFile *deploy_target_path = NULL;
@@ -410,7 +397,16 @@ deploy_tree (OtAdminDeploy *self,
if (!revision)
revision = deploy_target;
- deploy_dir = g_file_get_child (self->ostree_dir, "deploy");
+ current_deployment_ref = g_strdup_printf ("deployment/%s/current", self->osname);
+ previous_deployment_ref = g_strdup_printf ("deployment/%s/previous", self->osname);
+
+ if (!g_file_query_exists (self->osname_dir, cancellable))
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "No OS \"%s\" found in \"%s\"", self->osname,
+ gs_file_get_path_cached (self->osname_dir));
+ goto out;
+ }
if (!ostree_repo_resolve_rev (self->repo, revision, FALSE, &resolved_commit, error))
goto out;
@@ -426,17 +422,17 @@ deploy_tree (OtAdminDeploy *self,
goto out;
deploy_target_fullname = g_strconcat (deploy_target, "-", resolved_commit, NULL);
- deploy_target_path = g_file_resolve_relative_path (deploy_dir, deploy_target_fullname);
+ deploy_target_path = g_file_resolve_relative_path (self->osname_dir, deploy_target_fullname);
deploy_target_fullname_tmp = g_strconcat (deploy_target_fullname, ".tmp", NULL);
- deploy_target_path_tmp = g_file_resolve_relative_path (deploy_dir, deploy_target_fullname_tmp);
+ deploy_target_path_tmp = g_file_resolve_relative_path (self->osname_dir, deploy_target_fullname_tmp);
deploy_parent = g_file_get_parent (deploy_target_path);
if (!gs_file_ensure_directory (deploy_parent, TRUE, cancellable, error))
goto out;
deploy_target_etc_name = g_strconcat (deploy_target, "-", resolved_commit, "-etc", NULL);
- deploy_target_etc_path = g_file_resolve_relative_path (deploy_dir, deploy_target_etc_name);
+ deploy_target_etc_path = g_file_resolve_relative_path (self->osname_dir, deploy_target_etc_name);
/* Delete any previous temporary data */
if (!gs_shutil_rm_rf (deploy_target_path_tmp, cancellable, error))
@@ -470,7 +466,7 @@ deploy_tree (OtAdminDeploy *self,
goto out;
}
- if (!ot_admin_get_current_deployment (self->ostree_dir, &previous_deployment,
+ if (!ot_admin_get_current_deployment (self->ostree_dir, self->osname, &previous_deployment,
cancellable, error))
goto out;
if (previous_deployment)
@@ -588,6 +584,7 @@ do_update_kernel (OtAdminDeploy *self,
ot_ptrarray_add_many (args, "ostree", "admin",
"--ostree-dir", gs_file_get_path_cached (self->ostree_dir),
"update-kernel",
+ self->osname,
gs_file_get_path_cached (deploy_path), NULL);
if (opt_no_kernel)
g_ptr_array_add (args, "--modules-only");
@@ -618,22 +615,23 @@ ot_admin_builtin_deploy (int argc, char **argv, GFile *ostree_dir, GError **erro
gboolean ret = FALSE;
ot_lobj GFile *repo_path = NULL;
ot_lobj GFile *deploy_path = NULL;
+ const char *osname = NULL;
const char *deploy_target = NULL;
const char *revision = NULL;
__attribute__((unused)) GCancellable *cancellable = NULL;
memset (self, 0, sizeof (*self));
- context = g_option_context_new ("NAME [REVISION] - Check out revision NAME (or REVISION as NAME)");
+ context = g_option_context_new ("OSNAME TREENAME [REVISION] - In operating system OS, check out revision TREENAME (or REVISION as TREENAME)");
g_option_context_add_main_entries (context, options, NULL);
if (!g_option_context_parse (context, &argc, &argv, error))
goto out;
- if (argc < 2)
+ if (argc < 3)
{
- ot_util_usage_error (context, "NAME must be specified", error);
+ ot_util_usage_error (context, "OSNAME and TREENAME must be specified", error);
goto out;
}
@@ -647,10 +645,13 @@ ot_admin_builtin_deploy (int argc, char **argv, GFile *ostree_dir, GError **erro
if (!ostree_repo_check (self->repo, error))
goto out;
- deploy_target = argv[1];
- if (argc > 2)
- revision = argv[2];
+ osname = argv[1];
+ deploy_target = argv[2];
+ if (argc > 3)
+ revision = argv[3];
+ self->osname = g_strdup (osname);
+ self->osname_dir = ot_gfile_get_child_build_path (self->ostree_dir, "deploy", osname, NULL);
if (!deploy_tree (self, deploy_target, revision, &deploy_path,
cancellable, error))
goto out;
@@ -661,7 +662,9 @@ ot_admin_builtin_deploy (int argc, char **argv, GFile *ostree_dir, GError **erro
ret = TRUE;
out:
g_clear_object (&self->repo);
+ g_free (self->osname);
g_clear_object (&self->ostree_dir);
+ g_clear_object (&self->osname_dir);
if (context)
g_option_context_free (context);
return ret;
diff --git a/src/ostree/ot-admin-builtin-diff.c b/src/ostree/ot-admin-builtin-diff.c
index 7b9eb49..64c2bcc 100644
--- a/src/ostree/ot-admin-builtin-diff.c
+++ b/src/ostree/ot-admin-builtin-diff.c
@@ -37,6 +37,7 @@ ot_admin_builtin_diff (int argc, char **argv, GFile *ostree_dir, GError **error)
{
GOptionContext *context;
gboolean ret = FALSE;
+ const char *osname;
ot_lobj GFile *repo_path = NULL;
ot_lobj GFile *deployment = NULL;
ot_lobj GFile *deploy_parent = NULL;
@@ -47,7 +48,7 @@ ot_admin_builtin_diff (int argc, char **argv, GFile *ostree_dir, GError **error)
ot_lobj GFile *new_etc_path = NULL;
__attribute__((unused)) GCancellable *cancellable = NULL;
- context = g_option_context_new ("[NAME] - Diff configuration for revision NAME");
+ context = g_option_context_new ("OSNAME [REVISION] - Diff configuration for OSNAME");
g_option_context_add_main_entries (context, options, NULL);
@@ -56,9 +57,17 @@ ot_admin_builtin_diff (int argc, char **argv, GFile *ostree_dir, GError **error)
repo_path = g_file_get_child (ostree_dir, "repo");
- if (argc > 1)
+ if (argc < 2)
{
- deployment = ot_gfile_get_child_build_path (ostree_dir, "deploy", argv[1], NULL);
+ ot_util_usage_error (context, "OSNAME must be specified", error);
+ goto out;
+ }
+
+ osname = argv[1];
+
+ if (argc > 2)
+ {
+ deployment = ot_gfile_get_child_build_path (ostree_dir, "deploy", osname, argv[2], NULL);
if (!g_file_query_exists (deployment, NULL))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
@@ -68,7 +77,7 @@ ot_admin_builtin_diff (int argc, char **argv, GFile *ostree_dir, GError **error)
}
else
{
- if (!ot_admin_get_current_deployment (ostree_dir, &deployment,
+ if (!ot_admin_get_current_deployment (ostree_dir, osname, &deployment,
cancellable, error))
goto out;
}
diff --git a/src/ostree/ot-admin-builtin-install.c b/src/ostree/ot-admin-builtin-install.c
new file mode 100644
index 0000000..7e0cb45
--- /dev/null
+++ b/src/ostree/ot-admin-builtin-install.c
@@ -0,0 +1,200 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2012 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.
+ *
+ * Author: Colin Walters <walters verbum org>
+ */
+
+#include "config.h"
+
+#include "ot-admin-builtins.h"
+#include "ot-admin-functions.h"
+#include "ostree-curl-fetcher.h"
+#include "otutil.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <glib/gi18n.h>
+
+typedef struct {
+ GMainLoop *loop;
+ GFile *osconfig_path;
+} OtAdminBuiltinInstall;
+
+static GOptionEntry options[] = {
+ { NULL }
+};
+
+static void
+on_keyfile_retrieved (GObject *obj,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ OtAdminBuiltinInstall *self = user_data;
+ GError *error = NULL;
+
+ self->osconfig_path = ostree_curl_fetcher_request_uri_finish ((OstreeCurlFetcher*)obj, result, &error);
+ if (!self->osconfig_path)
+ goto out;
+
+ out:
+ if (error)
+ {
+ g_printerr ("%s\n", error->message);
+ exit (1);
+ }
+ g_main_loop_quit (self->loop);
+}
+
+gboolean
+ot_admin_builtin_install (int argc, char **argv, GFile *ostree_dir, GError **error)
+{
+ OtAdminBuiltinInstall self_data;
+ OtAdminBuiltinInstall *self = &self_data;
+ GOptionContext *context;
+ gboolean ret = FALSE;
+ const char *keyfile_arg = NULL;
+ const char *treename_arg = NULL;
+ ot_lobj GFile *deploy_dir = NULL;
+ ot_lobj GFile *osdir = NULL;
+ ot_lobj GFile *dest_osconfig_path = NULL;
+ gs_unref_ptrarray GPtrArray *subproc_args = NULL;
+ ot_lfree char *osname = NULL;
+ ot_lfree char *repoarg = NULL;
+ ot_lfree char *ostree_dir_arg = NULL;
+ ot_lfree char *tree_to_deploy = NULL;
+ GKeyFile *keyfile = NULL;
+ __attribute__((unused)) GCancellable *cancellable = NULL;
+
+ memset (self, 0, sizeof (*self));
+
+ context = g_option_context_new ("KEYFILE [TREE] - Initialize, download, and deploy operating system");
+ g_option_context_add_main_entries (context, options, NULL);
+
+ if (!g_option_context_parse (context, &argc, &argv, error))
+ goto out;
+
+ if (argc < 2)
+ {
+ ot_util_usage_error (context, "KEYFILE must be specified", error);
+ goto out;
+ }
+
+ self->loop = g_main_loop_new (NULL, TRUE);
+
+ keyfile_arg = argv[1];
+ if (argc > 2)
+ treename_arg = argv[2];
+
+ keyfile = g_key_file_new ();
+
+ if (g_str_has_prefix (keyfile_arg, "http://") || g_str_has_prefix (keyfile_arg, "https://"))
+ {
+ ot_lobj GFile *tmp = g_file_new_for_path (g_get_tmp_dir ());
+ ot_lobj OstreeCurlFetcher *fetcher = ostree_curl_fetcher_new (tmp);
+
+ g_print ("Fetching %s...\n", keyfile_arg);
+ ostree_curl_fetcher_request_uri_async (fetcher, keyfile_arg, cancellable,
+ on_keyfile_retrieved, self);
+
+ g_main_loop_run (self->loop);
+ }
+ else
+ {
+ self->osconfig_path = g_file_new_for_path (keyfile_arg);
+ }
+
+ if (!g_key_file_load_from_file (keyfile, gs_file_get_path_cached (self->osconfig_path), 0,
+ error))
+ goto out;
+
+ osname = g_key_file_get_string (keyfile, "os", "Name", error);
+
+ ostree_dir_arg = g_strconcat ("--ostree-dir=",
+ gs_file_get_path_cached (ostree_dir),
+ NULL);
+
+ if (!gs_subprocess_simple_run_sync (gs_file_get_path_cached (ostree_dir),
+ GS_SUBPROCESS_STREAM_DISPOSITION_NULL,
+ cancellable, error,
+ "ostree", "admin", ostree_dir_arg, "os-init", osname, NULL))
+ goto out;
+
+ if (treename_arg)
+ {
+ tree_to_deploy = g_strdup (treename_arg);
+ }
+ else
+ {
+ tree_to_deploy = g_key_file_get_string (keyfile, "os", "TreeDefault", error);
+ if (!tree_to_deploy)
+ goto out;
+ }
+
+ osdir = ot_gfile_get_child_build_path (ostree_dir, "deploy", osname, NULL);
+ dest_osconfig_path = ot_gfile_get_child_strconcat (osdir, osname, ".cfg", NULL);
+
+ if (!g_file_copy (self->osconfig_path, dest_osconfig_path, G_FILE_COPY_OVERWRITE | G_FILE_COPY_TARGET_DEFAULT_PERMS,
+ cancellable, NULL, NULL, error))
+ goto out;
+
+ if (!gs_file_unlink (self->osconfig_path, cancellable, error))
+ goto out;
+
+ repoarg = g_strconcat ("--repo=",
+ gs_file_get_path_cached (ostree_dir), "/repo",
+ NULL);
+
+ {
+ ot_lfree char *repourl = NULL;
+
+ repourl = g_key_file_get_string (keyfile, "os", "Repo", error);
+ if (!repourl)
+ goto out;
+
+ if (!gs_subprocess_simple_run_sync (gs_file_get_path_cached (ostree_dir),
+ GS_SUBPROCESS_STREAM_DISPOSITION_NULL,
+ cancellable, error,
+ "ostree", repoarg, "remote", "add",
+ osname, repourl, tree_to_deploy, NULL))
+ goto out;
+ }
+
+ if (!gs_subprocess_simple_run_sync (gs_file_get_path_cached (ostree_dir),
+ GS_SUBPROCESS_STREAM_DISPOSITION_NULL,
+ cancellable, error,
+ "ostree", "pull", repoarg, osname, NULL))
+ goto out;
+
+ if (!gs_subprocess_simple_run_sync (gs_file_get_path_cached (ostree_dir),
+ GS_SUBPROCESS_STREAM_DISPOSITION_NULL,
+ cancellable, error,
+ "ostree", "admin", ostree_dir_arg, "deploy", osname,
+ tree_to_deploy, NULL))
+ goto out;
+
+ ret = TRUE;
+ out:
+ if (self->loop)
+ g_main_loop_unref (self->loop);
+ g_clear_object (&self->osconfig_path);
+ g_clear_pointer (&keyfile, (GDestroyNotify) g_key_file_unref);
+ if (context)
+ g_option_context_free (context);
+ return ret;
+}
diff --git a/src/ostree/ot-admin-builtin-os-init.c b/src/ostree/ot-admin-builtin-os-init.c
new file mode 100644
index 0000000..3cd38aa
--- /dev/null
+++ b/src/ostree/ot-admin-builtin-os-init.c
@@ -0,0 +1,105 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2012 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.
+ *
+ * Author: Colin Walters <walters verbum org>
+ */
+
+#include "config.h"
+
+#include "ot-admin-builtins.h"
+#include "ot-admin-functions.h"
+#include "otutil.h"
+
+#include <glib/gi18n.h>
+
+static GOptionEntry options[] = {
+ { NULL }
+};
+
+gboolean
+ot_admin_builtin_os_init (int argc, char **argv, GFile *ostree_dir, GError **error)
+{
+ GOptionContext *context;
+ gboolean ret = FALSE;
+ const char *osname = NULL;
+ ot_lobj GFile *deploy_dir = NULL;
+ ot_lobj GFile *dir = NULL;
+ __attribute__((unused)) GCancellable *cancellable = NULL;
+
+ context = g_option_context_new ("OSNAME - Initialize empty state for given operating system");
+ g_option_context_add_main_entries (context, options, NULL);
+
+ if (!g_option_context_parse (context, &argc, &argv, error))
+ goto out;
+
+ if (!ot_admin_ensure_initialized (ostree_dir, cancellable, error))
+ goto out;
+
+ if (argc < 2)
+ {
+ ot_util_usage_error (context, "OSNAME must be specified", error);
+ goto out;
+ }
+
+ osname = argv[1];
+
+ deploy_dir = ot_gfile_get_child_build_path (ostree_dir, "deploy", osname, NULL);
+
+ /* Ensure core subdirectories of /var exist, since we need them for
+ * dracut generation, and the host will want them too.
+ */
+ g_clear_object (&dir);
+ dir = ot_gfile_get_child_build_path (deploy_dir, "var", "log", NULL);
+ if (!gs_file_ensure_directory (dir, TRUE, cancellable, error))
+ goto out;
+
+ g_clear_object (&dir);
+ dir = ot_gfile_get_child_build_path (deploy_dir, "var", "tmp", NULL);
+ if (!gs_file_ensure_directory (dir, TRUE, cancellable, error))
+ goto out;
+ if (chmod (gs_file_get_path_cached (dir), 01777) < 0)
+ {
+ ot_util_set_error_from_errno (error, errno);
+ goto out;
+ }
+
+ g_clear_object (&dir);
+ dir = ot_gfile_get_child_build_path (deploy_dir, "var", "lib", NULL);
+ if (!gs_file_ensure_directory (dir, TRUE, cancellable, error))
+ goto out;
+
+ g_clear_object (&dir);
+ dir = ot_gfile_get_child_build_path (deploy_dir, "var", "run", NULL);
+ if (!g_file_test (gs_file_get_path_cached (dir), G_FILE_TEST_IS_SYMLINK))
+ {
+ if (symlink ("../run", gs_file_get_path_cached (dir)) < 0)
+ {
+ ot_util_set_error_from_errno (error, errno);
+ goto out;
+ }
+ }
+
+ g_print ("%s initialized as OSTree root\n", gs_file_get_path_cached (deploy_dir));
+
+ ret = TRUE;
+ out:
+ if (context)
+ g_option_context_free (context);
+ return ret;
+}
diff --git a/src/ostree/ot-admin-builtin-prune.c b/src/ostree/ot-admin-builtin-prune.c
index 14ebee6..d2b2cc5 100644
--- a/src/ostree/ot-admin-builtin-prune.c
+++ b/src/ostree/ot-admin-builtin-prune.c
@@ -103,29 +103,38 @@ ot_admin_builtin_prune (int argc, char **argv, GFile *ostree_dir, GError **error
GOptionContext *context;
gboolean ret = FALSE;
guint i;
+ const char *osname;
ot_lobj GFile *repo_path = NULL;
+ ot_lobj GFile *deploy_dir = NULL;
ot_lobj GFile *current_deployment = NULL;
ot_lobj GFile *previous_deployment = NULL;
ot_lptrarray GPtrArray *deployments = NULL;
__attribute__((unused)) GCancellable *cancellable = NULL;
- context = g_option_context_new ("- Delete untagged deployments and repository objects");
+ context = g_option_context_new ("OSNAME - Delete untagged deployments and repository objects");
g_option_context_add_main_entries (context, options, NULL);
if (!g_option_context_parse (context, &argc, &argv, error))
goto out;
- if (!ot_admin_ensure_initialized (ostree_dir, cancellable, error))
- goto out;
+ if (argc < 2)
+ {
+ ot_util_usage_error (context, "OSNAME must be specified", error);
+ goto out;
+ }
+
+ osname = argv[1];
+
+ deploy_dir = ot_gfile_get_child_build_path (ostree_dir, "deploy", osname, NULL);
deployments = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
- if (!list_deployments (ostree_dir, deployments, cancellable, error))
+ if (!list_deployments (deploy_dir, deployments, cancellable, error))
goto out;
- if (!ot_admin_get_current_deployment (ostree_dir, ¤t_deployment,
+ if (!ot_admin_get_current_deployment (ostree_dir, osname, ¤t_deployment,
cancellable, error));
- if (!ot_admin_get_previous_deployment (ostree_dir, &previous_deployment,
+ if (!ot_admin_get_previous_deployment (ostree_dir, osname, &previous_deployment,
cancellable, error));
for (i = 0; i < deployments->len; i++)
diff --git a/src/ostree/ot-admin-builtin-pull-deploy.c b/src/ostree/ot-admin-builtin-pull-deploy.c
index 4c67f6b..47c675d 100644
--- a/src/ostree/ot-admin-builtin-pull-deploy.c
+++ b/src/ostree/ot-admin-builtin-pull-deploy.c
@@ -36,13 +36,13 @@ static GOptionEntry options[] = {
};
static char *
-parse_deploy_name_from_path (GFile *ostree_dir,
+parse_deploy_name_from_path (GFile *osdir,
GFile *path)
{
- ot_lobj GFile *deploy_dir = g_file_get_child (ostree_dir, "deploy");
- ot_lfree char *relpath = g_file_get_relative_path (deploy_dir, path);
+ ot_lfree char *relpath = g_file_get_relative_path (osdir, path);
const char *last_dash;
+ g_assert (relpath);
last_dash = strrchr (relpath, '-');
if (!last_dash)
g_error ("Failed to parse deployment name %s", relpath);
@@ -50,80 +50,37 @@ parse_deploy_name_from_path (GFile *ostree_dir,
return g_strndup (relpath, last_dash - relpath);
}
-static char *
-remote_name_from_path (GKeyFile *repo_config,
- const char *deploy_path)
-{
- const char *group_prefix = "remote \"";
- char **groups = NULL;
- char **group_iter = NULL;
- char *ret = NULL;
-
- groups = g_key_file_get_groups (repo_config, NULL);
- for (group_iter = groups; *group_iter; group_iter++)
- {
- const char *group = *group_iter;
- char **configured_branches = NULL;
- char **branch_iter = NULL;
- gboolean found = FALSE;
-
- if (!(g_str_has_prefix (group, group_prefix)
- && g_str_has_suffix (group, "\"")))
- continue;
-
- configured_branches = g_key_file_get_string_list (repo_config, group, "branches", NULL, NULL);
- if (!configured_branches)
- continue;
-
- for (branch_iter = configured_branches; *branch_iter; branch_iter++)
- {
- const char *branch = *branch_iter;
-
- if (!strcmp (branch, deploy_path))
- {
- found = TRUE;
- break;
- }
- }
-
- if (found)
- break;
- }
-
- if (*group_iter)
- {
- const char *group = *group_iter;
- size_t len;
- ret = g_strdup (group + strlen (group_prefix));
- len = strlen (ret);
- g_assert (len > 0 && ret[len-1] == '\"');
- ret[len-1] = '\0';
- }
- g_strfreev (groups);
- return ret;
-}
-
gboolean
ot_admin_builtin_pull_deploy (int argc, char **argv, GFile *ostree_dir, GError **error)
{
GOptionContext *context;
gboolean ret = FALSE;
+ const char *osname;
ot_lobj GFile *repo_path = NULL;
- ot_lobj OstreeRepo *repo = NULL;
ot_lobj GFile *current_deployment = NULL;
ot_lfree char *deploy_name = NULL;
+ ot_lobj GFile *deploy_dir = NULL;
+ ot_lobj GFile *os_dir = NULL;
ot_lfree char *remote_name = NULL;
ot_lptrarray GPtrArray *subproc_args = NULL;
__attribute__((unused)) GCancellable *cancellable = NULL;
- context = g_option_context_new (" - Upgrade and redeploy current tree");
+ context = g_option_context_new ("OSNAME - Upgrade and redeploy current tree");
g_option_context_add_main_entries (context, options, NULL);
if (!g_option_context_parse (context, &argc, &argv, error))
goto out;
- if (!ot_admin_get_current_deployment (ostree_dir, ¤t_deployment,
+ if (argc < 2)
+ {
+ ot_util_usage_error (context, "OSNAME must be specified", error);
+ goto out;
+ }
+
+ osname = argv[1];
+
+ if (!ot_admin_get_current_deployment (ostree_dir, osname, ¤t_deployment,
cancellable, error))
goto out;
@@ -134,15 +91,13 @@ ot_admin_builtin_pull_deploy (int argc, char **argv, GFile *ostree_dir, GError *
goto out;
}
- deploy_name = parse_deploy_name_from_path (ostree_dir, current_deployment);
+ deploy_dir = g_file_get_child (ostree_dir, "deploy");
+ os_dir = g_file_get_child (deploy_dir, osname);
+ g_print ("%s\n%s\n", gs_file_get_path_cached (os_dir),
+ gs_file_get_path_cached (current_deployment));
+ deploy_name = parse_deploy_name_from_path (os_dir, current_deployment);
repo_path = g_file_get_child (ostree_dir, "repo");
- repo = ostree_repo_new (repo_path);
- if (!ostree_repo_check (repo, error))
- goto out;
-
- remote_name = remote_name_from_path (ostree_repo_get_config (repo),
- deploy_name);
{
ot_lfree char *repo_arg = g_strconcat ("--repo=",
@@ -152,7 +107,7 @@ ot_admin_builtin_pull_deploy (int argc, char **argv, GFile *ostree_dir, GError *
if (!gs_subprocess_simple_run_sync (gs_file_get_path_cached (ostree_dir),
GS_SUBPROCESS_STREAM_DISPOSITION_NULL,
cancellable, error,
- "ostree", "pull", repo_arg, remote_name, NULL))
+ "ostree", "pull", repo_arg, osname, NULL))
goto out;
}
@@ -163,7 +118,7 @@ ot_admin_builtin_pull_deploy (int argc, char **argv, GFile *ostree_dir, GError *
if (!gs_subprocess_simple_run_sync (gs_file_get_path_cached (ostree_dir),
GS_SUBPROCESS_STREAM_DISPOSITION_NULL,
cancellable, error,
- "ostree", "admin", opt_ostree_dir_arg, "deploy",
+ "ostree", "admin", opt_ostree_dir_arg, "deploy", osname,
deploy_name, NULL))
goto out;
}
diff --git a/src/ostree/ot-admin-builtin-update-kernel.c b/src/ostree/ot-admin-builtin-update-kernel.c
index e0fc074..1fd9ac7 100644
--- a/src/ostree/ot-admin-builtin-update-kernel.c
+++ b/src/ostree/ot-admin-builtin-update-kernel.c
@@ -33,6 +33,7 @@ typedef struct {
const char *deploy_path;
GFile *kernel_path;
char *release;
+ char *osname;
} OtAdminUpdateKernel;
static gboolean opt_modules_only;
@@ -200,7 +201,8 @@ update_initramfs (OtAdminUpdateKernel *self,
cancellable, error))
goto out;
- ostree_vardir = g_file_get_child (self->ostree_dir, "var");
+ ostree_vardir = ot_gfile_get_child_build_path (self->ostree_dir, "deploy",
+ self->osname, "var", NULL);
if (opt_host_kernel)
ostree_moduledir = g_file_get_child (self->ostree_dir, "modules");
@@ -213,6 +215,7 @@ update_initramfs (OtAdminUpdateKernel *self,
if (!g_output_stream_close (tmp_log_out, cancellable, error))
goto out;
+ mkinitramfs_args = g_ptr_array_new ();
/* Note: the hardcoded /tmp path below is not actually a
* security flaw, because we've bind-mounted dracut's view
* of /tmp to the securely-created tmpdir above.
@@ -403,14 +406,22 @@ ot_admin_builtin_update_kernel (int argc, char **argv, GFile *ostree_dir, GError
memset (self, 0, sizeof (*self));
- context = g_option_context_new ("[OSTREE_REVISION - Update kernel and regenerate initial ramfs");
+ context = g_option_context_new ("OSNAME DEPLOY_PATH - Update kernel and regenerate initial ramfs");
g_option_context_add_main_entries (context, options, NULL);
if (!g_option_context_parse (context, &argc, &argv, error))
goto out;
- if (argc > 1)
- self->deploy_path = argv[1];
+ if (argc < 2)
+ {
+ ot_util_usage_error (context, "OSNAME must be specified", error);
+ goto out;
+ }
+
+ self->osname = g_strdup (argv[1]);
+
+ if (argc > 2)
+ self->deploy_path = argv[2];
else
self->deploy_path = "current";
diff --git a/src/ostree/ot-admin-builtin-init.c b/src/ostree/ot-admin-builtin-upgrade.c
similarity index 55%
rename from src/ostree/ot-admin-builtin-init.c
rename to src/ostree/ot-admin-builtin-upgrade.c
index 8774fd2..635ae1f 100644
--- a/src/ostree/ot-admin-builtin-init.c
+++ b/src/ostree/ot-admin-builtin-upgrade.c
@@ -26,6 +26,8 @@
#include "ot-admin-functions.h"
#include "otutil.h"
+#include <unistd.h>
+#include <stdlib.h>
#include <glib/gi18n.h>
static GOptionEntry options[] = {
@@ -33,23 +35,43 @@ static GOptionEntry options[] = {
};
gboolean
-ot_admin_builtin_init (int argc, char **argv, GFile *ostree_dir, GError **error)
+ot_admin_builtin_upgrade (int argc, char **argv, GFile *ostree_dir, GError **error)
{
GOptionContext *context;
gboolean ret = FALSE;
- ot_lobj GFile *dir = NULL;
+ const char *osname = NULL;
+ gs_free char *ostree_dir_arg = NULL;
__attribute__((unused)) GCancellable *cancellable = NULL;
- context = g_option_context_new ("- Initialize /ostree directory");
+ context = g_option_context_new ("OSNAME - pull, deploy, and prune");
g_option_context_add_main_entries (context, options, NULL);
if (!g_option_context_parse (context, &argc, &argv, error))
goto out;
- if (!ot_admin_ensure_initialized (ostree_dir, cancellable, error))
+ if (argc < 2)
+ {
+ ot_util_usage_error (context, "OSNAME must be specified", error);
+ goto out;
+ }
+
+ osname = argv[1];
+
+ ostree_dir_arg = g_strconcat ("--ostree-dir=",
+ gs_file_get_path_cached (ostree_dir),
+ NULL);
+
+ if (!gs_subprocess_simple_run_sync (gs_file_get_path_cached (ostree_dir),
+ GS_SUBPROCESS_STREAM_DISPOSITION_NULL,
+ cancellable, error,
+ "ostree", "admin", ostree_dir_arg, "pull-deploy", osname, NULL))
goto out;
- g_print ("%s initialized as OSTree root\n", gs_file_get_path_cached (ostree_dir));
+ if (!gs_subprocess_simple_run_sync (gs_file_get_path_cached (ostree_dir),
+ GS_SUBPROCESS_STREAM_DISPOSITION_NULL,
+ cancellable, error,
+ "ostree", "admin", ostree_dir_arg, "prune", osname, NULL))
+ goto out;
ret = TRUE;
out:
diff --git a/src/ostree/ot-admin-builtins.h b/src/ostree/ot-admin-builtins.h
index 6994c96..2d535f0 100644
--- a/src/ostree/ot-admin-builtins.h
+++ b/src/ostree/ot-admin-builtins.h
@@ -27,13 +27,15 @@
G_BEGIN_DECLS
-gboolean ot_admin_builtin_init (int argc, char **argv, GFile *ostree_dir, GError **error);
+gboolean ot_admin_builtin_os_init (int argc, char **argv, GFile *ostree_dir, GError **error);
+gboolean ot_admin_builtin_install (int argc, char **argv, GFile *ostree_dir, GError **error);
gboolean ot_admin_builtin_init_fs (int argc, char **argv, GFile *ostree_dir, GError **error);
gboolean ot_admin_builtin_deploy (int argc, char **argv, GFile *ostree_dir, GError **error);
gboolean ot_admin_builtin_prune (int argc, char **argv, GFile *ostree_dir, GError **error);
gboolean ot_admin_builtin_pull_deploy (int argc, char **argv, GFile *ostree_dir, GError **error);
gboolean ot_admin_builtin_diff (int argc, char **argv, GFile *ostree_dir, GError **error);
gboolean ot_admin_builtin_update_kernel (int argc, char **argv, GFile *ostree_dir, GError **error);
+gboolean ot_admin_builtin_upgrade (int argc, char **argv, GFile *ostree_dir, GError **error);
G_END_DECLS
diff --git a/src/ostree/ot-admin-functions.c b/src/ostree/ot-admin-functions.c
index 0336e80..7623062 100644
--- a/src/ostree/ot-admin-functions.c
+++ b/src/ostree/ot-admin-functions.c
@@ -45,11 +45,6 @@ ot_admin_ensure_initialized (GFile *ostree_dir,
goto out;
g_clear_object (&dir);
- dir = g_file_get_child (ostree_dir, "modules");
- if (!gs_file_ensure_directory (dir, TRUE, cancellable, error))
- goto out;
-
- g_clear_object (&dir);
dir = ot_gfile_get_child_build_path (ostree_dir, "repo", "objects", NULL);
if (!g_file_query_exists (dir, NULL))
{
@@ -65,40 +60,6 @@ ot_admin_ensure_initialized (GFile *ostree_dir,
}
}
- /* Ensure core subdirectories of /var exist, since we need them for
- * dracut generation, and the host will want them too.
- */
- g_clear_object (&dir);
- dir = ot_gfile_get_child_build_path (ostree_dir, "var", "log", NULL);
- if (!gs_file_ensure_directory (dir, TRUE, cancellable, error))
- goto out;
-
- g_clear_object (&dir);
- dir = ot_gfile_get_child_build_path (ostree_dir, "var", "tmp", NULL);
- if (!gs_file_ensure_directory (dir, TRUE, cancellable, error))
- goto out;
- if (chmod (gs_file_get_path_cached (dir), 01777) < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
-
- g_clear_object (&dir);
- dir = ot_gfile_get_child_build_path (ostree_dir, "var", "lib", NULL);
- if (!gs_file_ensure_directory (dir, TRUE, cancellable, error))
- goto out;
-
- g_clear_object (&dir);
- dir = ot_gfile_get_child_build_path (ostree_dir, "var", "run", NULL);
- if (!g_file_test (gs_file_get_path_cached (dir), G_FILE_TEST_IS_SYMLINK))
- {
- if (symlink ("../run", gs_file_get_path_cached (dir)) < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
- }
-
ret = TRUE;
out:
return ret;
@@ -183,13 +144,15 @@ query_symlink_target_allow_noent (GFile *path,
*/
gboolean
ot_admin_get_current_deployment (GFile *ostree_dir,
+ const char *osname,
GFile **out_deployment,
GCancellable *cancellable,
GError **error)
{
ot_lobj GFile *current_path = NULL;
- current_path = g_file_get_child (ostree_dir, "current");
+ current_path = ot_gfile_get_child_build_path (ostree_dir, "deploy", osname,
+ "current", NULL);
return query_symlink_target_allow_noent (current_path, out_deployment,
cancellable, error);
@@ -204,13 +167,15 @@ ot_admin_get_current_deployment (GFile *ostree_dir,
*/
gboolean
ot_admin_get_previous_deployment (GFile *ostree_dir,
- GFile **out_deployment,
- GCancellable *cancellable,
- GError **error)
+ const char *osname,
+ GFile **out_deployment,
+ GCancellable *cancellable,
+ GError **error)
{
ot_lobj GFile *previous_path = NULL;
- previous_path = g_file_get_child (ostree_dir, "previous");
+ previous_path = ot_gfile_get_child_build_path (ostree_dir, "deploy", osname,
+ "previous", NULL);
return query_symlink_target_allow_noent (previous_path, out_deployment,
cancellable, error);
diff --git a/src/ostree/ot-admin-functions.h b/src/ostree/ot-admin-functions.h
index af114aa..3c21ad1 100644
--- a/src/ostree/ot-admin-functions.h
+++ b/src/ostree/ot-admin-functions.h
@@ -32,10 +32,12 @@ gboolean ot_admin_ensure_initialized (GFile *ostree_dir,
GError **error);
gboolean ot_admin_get_current_deployment (GFile *ostree_dir,
+ const char *osname,
GFile **out_deployment,
GCancellable *cancellable,
GError **error);
gboolean ot_admin_get_previous_deployment (GFile *ostree_dir,
+ const char *osname,
GFile **out_deployment,
GCancellable *cancellable,
GError **error);
diff --git a/src/ostree/ot-builtin-admin.c b/src/ostree/ot-builtin-admin.c
index 2f2340e..e80ac03 100644
--- a/src/ostree/ot-builtin-admin.c
+++ b/src/ostree/ot-builtin-admin.c
@@ -43,9 +43,11 @@ typedef struct {
} OstreeAdminCommand;
static OstreeAdminCommand admin_subcommands[] = {
- { "init", ot_admin_builtin_init },
+ { "os-init", ot_admin_builtin_os_init },
{ "init-fs", ot_admin_builtin_init_fs },
{ "deploy", ot_admin_builtin_deploy },
+ { "install", ot_admin_builtin_install },
+ { "upgrade", ot_admin_builtin_upgrade },
{ "pull-deploy", ot_admin_builtin_pull_deploy },
{ "prune", ot_admin_builtin_prune },
{ "update-kernel", ot_admin_builtin_update_kernel },
diff --git a/src/switchroot/ostree-switch-root.c b/src/switchroot/ostree-switch-root.c
index 6330223..86c6855 100644
--- a/src/switchroot/ostree-switch-root.c
+++ b/src/switchroot/ostree-switch-root.c
@@ -153,17 +153,20 @@ main(int argc, char *argv[])
const char *initramfs_move_mounts[] = { "/dev", "/proc", "/sys", "/run", NULL };
const char *toproot_bind_mounts[] = { "/home", "/root", "/tmp", NULL };
const char *ostree_bind_mounts[] = { "/var", NULL };
- /* ostree_readonly_bind_mounts /lib/modules -> modules */
const char *readonly_bind_mounts[] = { "/bin", "/lib", "/sbin", "/usr",
NULL };
const char *root_mountpoint = NULL;
const char *ostree_target = NULL;
const char *ostree_subinit = NULL;
+ const char *p = NULL;
+ char *ostree_osname = NULL;
char ostree_target_path[PATH_MAX];
+ char *deploy_path = NULL;
char srcpath[PATH_MAX];
char destpath[PATH_MAX];
struct stat stbuf;
char **init_argv = NULL;
+ size_t len;
int initramfs_fd;
int i;
int before_init_argc = 0;
@@ -183,6 +186,14 @@ main(int argc, char *argv[])
ostree_subinit = argv[3];
before_init_argc++;
+ p = strchr (ostree_target, '/');
+ if (p == NULL)
+ {
+ fprintf (stderr, "Malformed OSTree target %s; expected OSNAME/TREENAME\n", ostree_target);
+ exit (1);
+ }
+ ostree_osname = strndup (ostree_target, p - ostree_target);
+
/* For now, we just remount the root filesystem read/write. This is
* kind of ugly, but to do this properly we'd basically have to have
* to be fully integrated into the init process.
@@ -193,7 +204,7 @@ main(int argc, char *argv[])
exit (1);
}
- snprintf (destpath, sizeof(destpath), "%s/ostree/%s",
+ snprintf (destpath, sizeof(destpath), "%s/ostree/deploy/%s",
root_mountpoint, ostree_target);
if (stat (destpath, &stbuf) < 0)
{
@@ -204,7 +215,7 @@ main(int argc, char *argv[])
for (i = 0; initramfs_move_mounts[i] != NULL; i++)
{
const char *path = initramfs_move_mounts[i];
- snprintf (destpath, sizeof(destpath), "%s/ostree/%s%s", root_mountpoint, ostree_target, path);
+ snprintf (destpath, sizeof(destpath), "%s/ostree/deploy/%s%s", root_mountpoint, ostree_target, path);
if (mount (path, destpath, NULL, MS_MOVE, NULL) < 0)
{
perrorv ("failed to move mount of %s to %s", path, destpath);
@@ -247,45 +258,38 @@ main(int argc, char *argv[])
* so we no longer refer to root_mountpoint.
*/
- snprintf (destpath, sizeof(destpath), "/ostree/%s", ostree_target);
+ snprintf (destpath, sizeof(destpath), "/ostree/deploy/%s", ostree_target);
fprintf (stderr, "Examining %s\n", destpath);
if (lstat (destpath, &stbuf) < 0)
{
perrorv ("Second stat of ostree root '%s' failed: ", destpath);
exit (1);
}
- if (S_ISLNK (stbuf.st_mode))
+ if (!S_ISLNK (stbuf.st_mode))
{
- if (readlink (destpath, ostree_target_path, PATH_MAX) < 0)
- {
- perrorv ("readlink(%s) failed: ", destpath);
- exit (1);
- }
- fprintf (stderr, "Resolved OSTree target to: %s\n", ostree_target_path);
+ fprintf (stderr, "OSTree target is not a symbolic link: %s\n", destpath);
+ exit (1);
}
- else
+ if (readlink (destpath, ostree_target_path, PATH_MAX) < 0)
{
- strncpy (ostree_target_path, ostree_target, PATH_MAX);
- fprintf (stderr, "OSTree target is: %s\n", ostree_target_path);
- }
-
- snprintf (destpath, sizeof(destpath), "/ostree/%s/sysroot", ostree_target_path);
- if (mount ("/", destpath, NULL, MS_BIND, NULL) < 0)
- {
- perrorv ("Failed to bind mount / to '%s'", destpath);
+ perrorv ("readlink(%s) failed: ", destpath);
exit (1);
}
+ len = strlen (ostree_target_path);
+ if (ostree_target_path[len-1] == '/')
+ ostree_target_path[len-1] = '\0';
+ fprintf (stderr, "Resolved OSTree target to: %s\n", ostree_target_path);
+ asprintf (&deploy_path, "/ostree/deploy/%s/%s", ostree_osname, ostree_target_path);
- snprintf (srcpath, sizeof(srcpath), "/ostree/%s-etc", ostree_target_path);
- snprintf (destpath, sizeof(destpath), "/ostree/%s/etc", ostree_target_path);
- if (mount (srcpath, destpath, NULL, MS_BIND, NULL) < 0)
+ snprintf (destpath, sizeof(destpath), "%s/sysroot", deploy_path);
+ if (mount ("/", destpath, NULL, MS_BIND, NULL) < 0)
{
- perrorv ("Failed to bind mount '%s' to '%s'", srcpath, destpath);
+ perrorv ("Failed to bind mount / to '%s'", destpath);
exit (1);
}
- snprintf (srcpath, sizeof(srcpath), "%s", "/ostree/var");
- snprintf (destpath, sizeof(destpath), "/ostree/%s/var", ostree_target_path);
+ snprintf (srcpath, sizeof(srcpath), "%s-etc", deploy_path);
+ snprintf (destpath, sizeof(destpath), "%s/etc", deploy_path);
if (mount (srcpath, destpath, NULL, MS_BIND, NULL) < 0)
{
perrorv ("Failed to bind mount '%s' to '%s'", srcpath, destpath);
@@ -294,7 +298,7 @@ main(int argc, char *argv[])
for (i = 0; toproot_bind_mounts[i] != NULL; i++)
{
- snprintf (destpath, sizeof(destpath), "/ostree/%s%s", ostree_target, toproot_bind_mounts[i]);
+ snprintf (destpath, sizeof(destpath), "%s%s", deploy_path, toproot_bind_mounts[i]);
if (mount (toproot_bind_mounts[i], destpath, NULL, MS_BIND & ~MS_RDONLY, NULL) < 0)
{
perrorv ("failed to bind mount (class:toproot) %s to %s", toproot_bind_mounts[i], destpath);
@@ -304,8 +308,8 @@ main(int argc, char *argv[])
for (i = 0; ostree_bind_mounts[i] != NULL; i++)
{
- snprintf (srcpath, sizeof(srcpath), "/ostree/%s", ostree_bind_mounts[i]);
- snprintf (destpath, sizeof(destpath), "/ostree/%s%s", ostree_target_path, ostree_bind_mounts[i]);
+ snprintf (srcpath, sizeof(srcpath), "/ostree/deploy/%s%s", ostree_osname, ostree_bind_mounts[i]);
+ snprintf (destpath, sizeof(destpath), "%s%s", deploy_path, ostree_bind_mounts[i]);
if (mount (srcpath, destpath, NULL, MS_MGC_VAL|MS_BIND, NULL) < 0)
{
perrorv ("failed to bind mount (class:bind) %s to %s", srcpath, destpath);
@@ -315,7 +319,7 @@ main(int argc, char *argv[])
for (i = 0; readonly_bind_mounts[i] != NULL; i++)
{
- snprintf (destpath, sizeof(destpath), "/ostree/%s%s", ostree_target_path, readonly_bind_mounts[i]);
+ snprintf (destpath, sizeof(destpath), "%s%s", deploy_path, readonly_bind_mounts[i]);
if (mount (destpath, destpath, NULL, MS_BIND, NULL) < 0)
{
perrorv ("failed to bind mount (class:readonly) %s", destpath);
@@ -328,19 +332,9 @@ main(int argc, char *argv[])
}
}
- /* This should come after we've bind mounted /lib */
- snprintf (srcpath, sizeof(srcpath), "/ostree/modules");
- snprintf (destpath, sizeof(destpath), "/ostree/%s/lib/modules", ostree_target_path);
- if (mount (srcpath, destpath, NULL, MS_MGC_VAL|MS_BIND, NULL) < 0)
- {
- perrorv ("failed to bind mount %s to %s", srcpath, destpath);
- exit (1);
- }
-
- snprintf (destpath, sizeof(destpath), "/ostree/%s", ostree_target_path);
- if (chroot (destpath) < 0)
+ if (chroot (deploy_path) < 0)
{
- perrorv ("failed to change root to '%s'", destpath);
+ perrorv ("failed to change root to '%s'", deploy_path);
exit (1);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]