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.
This commit is contained in:
Colin Walters 2012-12-19 17:52:46 -05:00
parent 16d312e82f
commit 3832544ac4
16 changed files with 758 additions and 212 deletions

View File

@ -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 \

View File

@ -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);
}

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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))
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, &current_deployment,
if (!ot_admin_get_current_deployment (ostree_dir, osname, &current_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++)

View File

@ -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, &current_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, &current_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;
}

View File

@ -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";

View File

@ -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:

View File

@ -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

View File

@ -44,11 +44,6 @@ ot_admin_ensure_initialized (GFile *ostree_dir,
if (!gs_file_ensure_directory (dir, TRUE, cancellable, error))
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,
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);

View File

@ -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);

View File

@ -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 },

View File

@ -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))
{
fprintf (stderr, "OSTree target is not a symbolic link: %s\n", destpath);
exit (1);
}
if (readlink (destpath, ostree_target_path, PATH_MAX) < 0)
{
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);
}
else
{
strncpy (ostree_target_path, ostree_target, PATH_MAX);
fprintf (stderr, "OSTree target is: %s\n", ostree_target_path);
}
asprintf (&deploy_path, "/ostree/deploy/%s/%s", ostree_osname, ostree_target_path);
snprintf (destpath, sizeof(destpath), "/ostree/%s/sysroot", ostree_target_path);
snprintf (destpath, sizeof(destpath), "%s/sysroot", deploy_path);
if (mount ("/", destpath, NULL, MS_BIND, NULL) < 0)
{
perrorv ("Failed to bind mount / to '%s'", destpath);
exit (1);
}
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)
{
perrorv ("Failed to bind mount '%s' to '%s'", srcpath, 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)
if (chroot (deploy_path) < 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)
{
perrorv ("failed to change root to '%s'", destpath);
perrorv ("failed to change root to '%s'", deploy_path);
exit (1);
}