mirror of
https://github.com/ostreedev/ostree.git
synced 2024-12-22 17:35:55 +03:00
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:
parent
16d312e82f
commit
3832544ac4
@ -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 \
|
||||
|
204
src/ostree/ostree-curl-fetcher.c
Normal file
204
src/ostree/ostree-curl-fetcher.c
Normal 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);
|
||||
}
|
59
src/ostree/ostree-curl-fetcher.h
Normal file
59
src/ostree/ostree-curl-fetcher.h
Normal 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
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
200
src/ostree/ot-admin-builtin-install.c
Normal file
200
src/ostree/ot-admin-builtin-install.c
Normal 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;
|
||||
}
|
105
src/ostree/ot-admin-builtin-os-init.c
Normal file
105
src/ostree/ot-admin-builtin-os-init.c
Normal 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;
|
||||
}
|
@ -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++)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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";
|
||||
|
||||
|
@ -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:
|
@ -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
|
||||
|
||||
|
@ -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,
|
||||
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);
|
||||
|
@ -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);
|
||||
|
@ -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 },
|
||||
|
@ -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);
|
||||
perrorv ("readlink(%s) failed: ", destpath);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
snprintf (destpath, sizeof(destpath), "/ostree/%s/sysroot", ostree_target_path);
|
||||
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 (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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user