[ostree/wip/etc-writable] [wip] Make /ostree/etc a writable mount
- From: Colin Walters <walters src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [ostree/wip/etc-writable] [wip] Make /ostree/etc a writable mount
- Date: Thu, 9 Aug 2012 19:40:26 +0000 (UTC)
commit a97014319a46deb41f37abd098a70b364f2ba04d
Author: Colin Walters <walters verbum org>
Date: Fri Jun 22 18:41:59 2012 -0400
[wip] Make /ostree/etc a writable mount
src/libotutil/ot-gio-utils.c | 62 +++++
src/libotutil/ot-gio-utils.h | 8 +
src/ostadmin/ot-admin-builtin-deploy.c | 415 ++++++++++++++++++++++++++++++--
src/ostadmin/ot-admin-builtin-init.c | 6 +
src/ostree/ot-builtin-checkout.c | 156 +-----------
src/switchroot/ostree-switch-root.c | 4 +-
6 files changed, 480 insertions(+), 171 deletions(-)
---
diff --git a/src/libotutil/ot-gio-utils.c b/src/libotutil/ot-gio-utils.c
index e31e47b..c1ad083 100644
--- a/src/libotutil/ot-gio-utils.c
+++ b/src/libotutil/ot-gio-utils.c
@@ -485,3 +485,65 @@ ot_gio_shutil_cp_al_or_fallback (GFile *src,
return ret;
}
+gboolean
+ot_gio_shutil_rm_rf (GFile *path,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ ot_lobj GFileEnumerator *dir_enum = NULL;
+ ot_lobj GFileInfo *file_info = NULL;
+ GError *temp_error = NULL;
+
+ dir_enum = g_file_enumerate_children (path, OSTREE_GIO_FAST_QUERYINFO,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ cancellable, &temp_error);
+ if (!dir_enum)
+ {
+ if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+ {
+ g_clear_error (&temp_error);
+ ret = TRUE;
+ }
+ else
+ g_propagate_error (error, temp_error);
+
+ goto out;
+ }
+
+ while ((file_info = g_file_enumerator_next_file (dir_enum, cancellable, &temp_error)) != NULL)
+ {
+ ot_lobj GFile *subpath = NULL;
+ GFileType type;
+ const char *name;
+
+ type = g_file_info_get_attribute_uint32 (file_info, "standard::type");
+ name = g_file_info_get_attribute_byte_string (file_info, "standard::name");
+
+ subpath = g_file_get_child (path, name);
+
+ if (type == G_FILE_TYPE_DIRECTORY)
+ {
+ if (!ot_gio_shutil_rm_rf (subpath, cancellable, error))
+ goto out;
+ }
+ else
+ {
+ if (!ot_gfile_unlink (subpath, cancellable, error))
+ goto out;
+ }
+ g_clear_object (&file_info);
+ }
+ if (temp_error)
+ {
+ g_propagate_error (error, temp_error);
+ goto out;
+ }
+
+ if (!g_file_delete (path, cancellable, error))
+ goto out;
+
+ ret = TRUE;
+ out:
+ return ret;
+}
diff --git a/src/libotutil/ot-gio-utils.h b/src/libotutil/ot-gio-utils.h
index 5855a97..4b282e2 100644
--- a/src/libotutil/ot-gio-utils.h
+++ b/src/libotutil/ot-gio-utils.h
@@ -51,6 +51,11 @@ gboolean ot_gfile_rename (GFile *src,
GCancellable *cancellable,
GError **error);
+gboolean ot_gfile_hardlink (GFile *src,
+ GFile *dest,
+ GCancellable *cancellable,
+ GError **error);
+
gboolean ot_gfile_unlink (GFile *path,
GCancellable *cancellable,
GError **error);
@@ -101,6 +106,9 @@ gboolean ot_gio_shutil_cp_al_or_fallback (GFile *src,
GCancellable *cancellable,
GError **error);
+gboolean ot_gio_shutil_rm_rf (GFile *path,
+ GCancellable *cancellable,
+ GError **error);
G_END_DECLS
diff --git a/src/ostadmin/ot-admin-builtin-deploy.c b/src/ostadmin/ot-admin-builtin-deploy.c
index e35eeec..b3daac6 100644
--- a/src/ostadmin/ot-admin-builtin-deploy.c
+++ b/src/ostadmin/ot-admin-builtin-deploy.c
@@ -307,38 +307,401 @@ update_current (const char *deploy_target,
}
static gboolean
-do_checkout (OtAdminDeploy *self,
+atomic_symlink_swap (GFile *dest,
+ const char *target,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ ot_lobj GFile *parent = NULL;
+ ot_lfree char *tmp_name = NULL;
+ ot_lobj GFile *tmp_link = NULL;
+
+ parent = g_file_get_parent (dest);
+ /* HACK - should use randomly generated temporary target name */
+ tmp_name = g_strconcat (ot_gfile_get_basename_cached (dest),
+ "-tmplink", NULL);
+ tmp_link = g_file_get_child (parent, tmp_name);
+ /* Ensure it doesn't exist; shouldn't be racing with anything
+ else */
+ (void) ot_gfile_unlink (tmp_link, NULL, NULL);
+ if (symlink (target, ot_gfile_get_path_cached (tmp_link)) < 0)
+ {
+ ot_util_set_error_from_errno (error, errno);
+ goto out;
+ }
+ if (!ot_gfile_rename (tmp_link, dest, cancellable, error))
+ goto out;
+
+ ret = TRUE;
+ out:
+ return ret;
+}
+
+static gboolean
+parse_commit_from_symlink (GFile *symlink,
+ char **out_commit,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ const char *target;
+ const char *last_dash;
+ const char *checksum;
+ ot_lobj GFileInfo *file_info = NULL;
+ ot_lfree char *ret_commit = NULL;
+
+ file_info = g_file_query_info (symlink, OSTREE_GIO_FAST_QUERYINFO,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ cancellable, error);
+ if (!file_info)
+ goto out;
+
+ target = g_file_info_get_symlink_target (file_info);
+ if (target == NULL)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Not a symbolic link");
+ goto out;
+ }
+
+ last_dash = strrchr (target, '-');
+ if (last_dash == NULL)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Invalid existing symlink target; no trailing dash");
+ goto out;
+ }
+ checksum = last_dash + 1;
+
+ if (!ostree_validate_structureof_checksum_string (checksum, error))
+ goto out;
+
+ ret_commit = g_strdup (checksum);
+
+ ret = TRUE;
+ ot_transfer_out_value (out_commit, &ret_commit);
+ out:
+ return ret;
+}
+
+typedef struct {
+ GError **error;
+ gboolean caught_error;
+
+ GMainLoop *loop;
+} ProcessOneCheckoutData;
+
+static void
+on_checkout_complete (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ ProcessOneCheckoutData *data = user_data;
+ GError *local_error = NULL;
+
+ if (!ostree_repo_checkout_tree_finish ((OstreeRepo*)object, result,
+ &local_error))
+ goto out;
+
+ out:
+ if (local_error)
+ {
+ data->caught_error = TRUE;
+ g_propagate_error (data->error, local_error);
+ }
+ g_main_loop_quit (data->loop);
+}
+
+static gboolean
+clone_dir (GFile *src,
+ GFile *dest,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ ot_lobj GFileInfo *src_info = NULL;
+ ot_lvariant GVariant *xattrs = NULL;
+
+ src_info = g_file_query_info (src, OSTREE_GIO_FAST_QUERYINFO,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ cancellable, error);
+ if (!src_info)
+ goto out;
+
+ if (!ostree_get_xattrs_for_file (src, &xattrs, cancellable, error))
+ goto out;
+
+ if (!ostree_create_file_from_input (dest, src_info, xattrs, NULL,
+ cancellable, error))
+ goto out;
+
+ ret = TRUE;
+ out:
+ return ret;
+}
+
+static gboolean
+merge_directory_recurse (GFile *src,
+ GFile *dest,
+ guint *out_n_created,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ GError *temp_error = NULL;
+ ot_lobj GFileEnumerator *src_enum = NULL;
+ ot_lobj GFileInfo *file_info = NULL;
+
+ src_enum = g_file_enumerate_children (src, OSTREE_GIO_FAST_QUERYINFO,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ cancellable, error);
+ if (!src_enum)
+ goto out;
+
+ file_info = g_file_query_info (dest, OSTREE_GIO_FAST_QUERYINFO,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ cancellable, &temp_error);
+ if (file_info == NULL)
+ {
+ ot_lvariant GVariant *xattrs = NULL;
+
+ if (!g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+ {
+ g_propagate_error (error, temp_error);
+ goto out;
+ }
+
+ g_clear_error (&temp_error);
+
+ if (!clone_dir (src, dest, cancellable, error))
+ goto out;
+ }
+ else if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Can't overwrite non-directory '%s' with directory",
+ ot_gfile_get_path_cached (src));
+ goto out;
+ }
+ else
+ g_clear_object (&file_info);
+
+ while ((file_info = g_file_enumerator_next_file (src_enum, cancellable, &temp_error)) != NULL)
+ {
+ GError *target_info_error = NULL;
+ ot_lobj GFile *child = NULL;
+ ot_lobj GFile *target = NULL;
+ ot_lobj GFileInfo *target_info = NULL;
+
+ child = g_file_get_child (src, g_file_info_get_name (file_info));
+ target = g_file_get_child (dest, g_file_info_get_name (file_info));
+
+ target_info = g_file_query_info (target, OSTREE_GIO_FAST_QUERYINFO,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ cancellable, &target_info_error);
+ if (!target_info)
+ {
+ if (!g_error_matches (target_info_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+ {
+ g_propagate_error (error, target_info_error);
+ goto out;
+ }
+ g_clear_error (&target_info_error);
+ }
+ else
+ continue;
+
+ if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY)
+ {
+ if (!merge_directory_recurse (child, target, out_n_created,
+ cancellable, error))
+ goto out;
+ }
+ else
+ {
+ if (!g_file_copy (child, target, G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_ALL_METADATA,
+ NULL, NULL, cancellable, error))
+ goto out;
+ (*out_n_created)++;
+ }
+
+ g_clear_object (&file_info);
+ }
+ if (temp_error)
+ {
+ g_propagate_error (error, temp_error);
+ goto out;
+ }
+
+ ret = TRUE;
+ out:
+ return ret;
+}
+
+static gboolean
+merge_etc_from_temp_tree (OtAdminDeploy *self,
+ GFile *tmp_tree,
+ guint *out_n_created,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ ot_lobj GFile *ostree_etc = NULL;
+ ot_lobj GFile *tmp_etc = NULL;
+
+ tmp_etc = g_file_get_child (tmp_tree, "etc");
+ ostree_etc = g_file_new_for_path ("/ostree/etc");
+
+ if (!merge_directory_recurse (tmp_etc, ostree_etc, out_n_created,
+ cancellable, error))
+ goto out;
+
+ ret = TRUE;
+ out:
+ return ret;
+}
+
+static gboolean
+deploy_tree (OtAdminDeploy *self,
const char *deploy_target,
const char *revision,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
- ot_lobj GFile *deploy_path = NULL;
- ot_lobj GFile *deploy_parent = NULL;
- ot_lfree char *tree_ref = NULL;
- ot_lfree char *repo_path = NULL;
- ot_lfree char *repo_arg = NULL;
- ot_lptrarray GPtrArray *checkout_args = NULL;
-
- repo_path = g_build_filename (opt_ostree_dir, "repo", NULL);
- repo_arg = g_strconcat ("--repo=", repo_path, NULL);
-
- deploy_path = ot_gfile_from_build_path (opt_ostree_dir, deploy_target, NULL);
- deploy_parent = g_file_get_parent (deploy_path);
- if (!ot_gfile_ensure_directory (deploy_parent, TRUE, error))
+ ot_lfree char *deploy_target_basename = NULL;
+ ot_lfree char *deploy_target_dirname = NULL;
+ ot_lfree char *deploy_target_tmp = NULL;
+ ot_lobj GFile *deploy_target_path = NULL;
+ ot_lobj GFile *checkout_target = NULL;
+ ot_lobj GFile *checkout_target_tmp = NULL;
+ ot_lobj GFile *checkout_parent = NULL;
+ ot_lobj OstreeRepoFile *root = NULL;
+ ot_lobj GFileInfo *file_info = NULL;
+ ot_lfree char *checkout_target_name = NULL;
+ ot_lfree char *checkout_target_tmp_name = NULL;
+ ot_lfree char *resolved_commit = NULL;
+ ot_lfree char *existing_commit = NULL;
+ GError *temp_error = NULL;
+ gboolean skip_checkout;
+
+ if (!revision)
+ revision = deploy_target;
+
+ if (!ostree_repo_resolve_rev (self->repo, revision, FALSE, &resolved_commit, error))
goto out;
- checkout_args = g_ptr_array_new ();
- ot_ptrarray_add_many (checkout_args, "ostree", repo_arg,
- "checkout", "--atomic-retarget", revision ? revision : deploy_target,
- ot_gfile_get_path_cached (deploy_path), NULL);
- g_ptr_array_add (checkout_args, NULL);
+ root = (OstreeRepoFile*)ostree_repo_file_new_root (self->repo, resolved_commit);
+ if (!ostree_repo_file_ensure_resolved (root, error))
+ goto out;
- if (!ot_spawn_sync_checked (opt_ostree_dir, (char**)checkout_args->pdata, NULL, G_SPAWN_SEARCH_PATH,
- NULL, NULL, NULL, NULL, error))
+ file_info = g_file_query_info ((GFile*)root, OSTREE_GIO_FAST_QUERYINFO,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ cancellable, error);
+ if (!file_info)
goto out;
+ deploy_target_path = ot_gfile_from_build_path (opt_ostree_dir, deploy_target, NULL);
+ deploy_target_basename = g_path_get_basename (deploy_target);
+ checkout_target_name = g_strconcat (deploy_target_basename, "-", resolved_commit, NULL);
+
+ {
+ const char *last_slash = strrchr (deploy_target, '/');
+ if (last_slash)
+ {
+ deploy_target_dirname = g_strndup (deploy_target, last_slash - deploy_target);
+ checkout_target = ot_gfile_from_build_path (opt_ostree_dir, deploy_target_dirname, checkout_target_name, NULL);
+ }
+ else
+ {
+ checkout_target = ot_gfile_from_build_path (opt_ostree_dir, checkout_target_name, NULL);
+ }
+ }
+
+ checkout_target_tmp_name = g_strconcat (ot_gfile_get_path_cached (checkout_target), ".tmp", NULL);
+ checkout_target_tmp = g_file_new_for_path (checkout_target_tmp_name);
+
+ checkout_parent = g_file_get_parent (checkout_target);
+ if (!ot_gfile_ensure_directory (checkout_parent, TRUE, error))
+ goto out;
+
+ /* Delete any previous temporary data */
+ if (!ot_gio_shutil_rm_rf (checkout_target_tmp, cancellable, error))
+ goto out;
+
+ if (!parse_commit_from_symlink (deploy_target_path, &existing_commit,
+ cancellable, &temp_error))
+ {
+ if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+ {
+ g_print ("ostadmin: No previous deployment of %s\n", deploy_target);
+ skip_checkout = FALSE;
+ g_clear_error (&temp_error);
+ }
+ else
+ {
+ g_propagate_error (error, temp_error);
+ goto out;
+ }
+ }
+ else
+ {
+ skip_checkout = strcmp (existing_commit, resolved_commit) == 0;
+ if (skip_checkout)
+ g_print ("ostadmin: Deployment of %s already points to %s\n", deploy_target,
+ resolved_commit);
+ }
+
+ if (!skip_checkout)
+ {
+ ProcessOneCheckoutData checkout_data;
+ guint n_new_etc_files = 0;
+
+ g_print ("ostadmin: Targeting deployment %s to %s\n", deploy_target,
+ resolved_commit);
+
+ memset (&checkout_data, 0, sizeof (checkout_data));
+ checkout_data.loop = g_main_loop_new (NULL, TRUE);
+ checkout_data.error = error;
+
+ ostree_repo_checkout_tree_async (self->repo, 0, 0, checkout_target_tmp, root,
+ file_info, cancellable,
+ on_checkout_complete, &checkout_data);
+
+ g_main_loop_run (checkout_data.loop);
+
+ g_main_loop_unref (checkout_data.loop);
+
+ if (checkout_data.caught_error)
+ goto out;
+
+ if (!ostree_run_triggers_in_root (checkout_target_tmp, cancellable, error))
+ goto out;
+
+ if (!merge_etc_from_temp_tree (self, checkout_target_tmp, &n_new_etc_files,
+ cancellable, error))
+ goto out;
+
+ g_print ("ostadmin: %lu new /etc files\n", (gulong)n_new_etc_files);
+
+ /* Blow away an existing tree if any; should be quite fast, and
+ * will help people using ostadmin to recover from disk corruption (hopefully).
+ */
+ if (!ot_gio_shutil_rm_rf (checkout_target, cancellable, error))
+ goto out;
+
+ if (!ot_gfile_rename (checkout_target_tmp, checkout_target,
+ cancellable, error))
+ goto out;
+ }
+
+ if (!atomic_symlink_swap (deploy_target_path, checkout_target_name,
+ cancellable, error))
+ goto out;
+
+ g_print ("ostadmin: Successfully deployed %s\n", deploy_target);
+
ret = TRUE;
out:
return ret;
@@ -351,6 +714,7 @@ ot_admin_builtin_deploy (int argc, char **argv, GError **error)
OtAdminDeploy self_data;
OtAdminDeploy *self = &self_data;
gboolean ret = FALSE;
+ ot_lobj GFile *repo_path = NULL;
const char *deploy_target = NULL;
const char *revision = NULL;
struct utsname utsname;
@@ -363,6 +727,7 @@ ot_admin_builtin_deploy (int argc, char **argv, GError **error)
memset (self, 0, sizeof (*self));
context = g_option_context_new ("NAME [REVISION] - Check out revision NAME (or REVISION as NAME)");
+
g_option_context_add_main_entries (context, options, NULL);
if (!g_option_context_parse (context, &argc, &argv, error))
@@ -373,12 +738,17 @@ ot_admin_builtin_deploy (int argc, char **argv, GError **error)
ot_util_usage_error (context, "NAME must be specified", error);
goto out;
}
+
+ repo_path = ot_gfile_from_build_path (opt_ostree_dir, "repo", NULL);
+ self->repo = ostree_repo_new (repo_path);
+ if (!ostree_repo_check (self->repo, error))
+ goto out;
deploy_target = argv[2];
if (argc > 3)
revision = argv[3];
- if (!do_checkout (self, deploy_target, revision, cancellable, error))
+ if (!deploy_tree (self, deploy_target, revision, cancellable, error))
goto out;
(void) uname (&utsname);
@@ -412,6 +782,7 @@ ot_admin_builtin_deploy (int argc, char **argv, GError **error)
ret = TRUE;
out:
+ g_clear_object (&self->repo);
if (context)
g_option_context_free (context);
return ret;
diff --git a/src/ostadmin/ot-admin-builtin-init.c b/src/ostadmin/ot-admin-builtin-init.c
index fdf61d6..3980972 100644
--- a/src/ostadmin/ot-admin-builtin-init.c
+++ b/src/ostadmin/ot-admin-builtin-init.c
@@ -63,6 +63,12 @@ ot_admin_builtin_init (int argc, char **argv, GError **error)
}
}
+ /* Create /ostree/etc */
+ g_clear_object (&dir);
+ dir = g_file_new_for_path ("/ostree/etc");
+ if (!ot_gfile_ensure_directory (dir, TRUE, error))
+ goto out;
+
/* Ensure a few subdirectories of /var exist, since we need them for
dracut generation */
g_clear_object (&dir);
diff --git a/src/ostree/ot-builtin-checkout.c b/src/ostree/ot-builtin-checkout.c
index 12a8f39..58f9239 100644
--- a/src/ostree/ot-builtin-checkout.c
+++ b/src/ostree/ot-builtin-checkout.c
@@ -30,7 +30,6 @@
#include <glib/gi18n.h>
static gboolean opt_user_mode;
-static gboolean opt_atomic_retarget;
static gboolean opt_no_triggers;
static char *opt_subpath;
static gboolean opt_union;
@@ -41,89 +40,12 @@ static GOptionEntry options[] = {
{ "user-mode", 'U', 0, G_OPTION_ARG_NONE, &opt_user_mode, "Do not change file ownership or initialize extended attributes", NULL },
{ "subpath", 0, 0, G_OPTION_ARG_STRING, &opt_subpath, "Checkout sub-directory PATH", "PATH" },
{ "union", 0, 0, G_OPTION_ARG_NONE, &opt_union, "Keep existing directories, overwrite existing files", NULL },
- { "atomic-retarget", 0, 0, G_OPTION_ARG_NONE, &opt_atomic_retarget, "Make a symbolic link for destination, suffix with checksum", NULL },
{ "no-triggers", 0, 0, G_OPTION_ARG_NONE, &opt_no_triggers, "Don't run triggers", NULL },
{ "from-stdin", 0, 0, G_OPTION_ARG_NONE, &opt_from_stdin, "Process many checkouts from standard input", NULL },
{ "from-file", 0, 0, G_OPTION_ARG_STRING, &opt_from_file, "Process many checkouts from input file", NULL },
{ NULL }
};
-static gboolean
-atomic_symlink_swap (GFile *dest,
- const char *target,
- GCancellable *cancellable,
- GError **error)
-{
- gboolean ret = FALSE;
- ot_lobj GFile *parent = NULL;
- ot_lfree char *tmp_name = NULL;
- ot_lobj GFile *tmp_link = NULL;
-
- parent = g_file_get_parent (dest);
- /* HACK - should use randomly generated temporary target name */
- tmp_name = g_strconcat (ot_gfile_get_basename_cached (dest),
- "-tmplink", NULL);
- tmp_link = g_file_get_child (parent, tmp_name);
- if (symlink (target, ot_gfile_get_path_cached (tmp_link)) < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
- if (!ot_gfile_rename (tmp_link, dest, cancellable, error))
- goto out;
-
- ret = TRUE;
- out:
- return ret;
-}
-
-static gboolean
-parse_commit_from_symlink (GFile *symlink,
- char **out_commit,
- GCancellable *cancellable,
- GError **error)
-{
- gboolean ret = FALSE;
- const char *target;
- const char *last_dash;
- const char *checksum;
- ot_lobj GFileInfo *file_info = NULL;
- ot_lfree char *ret_commit = NULL;
-
- file_info = g_file_query_info (symlink, OSTREE_GIO_FAST_QUERYINFO,
- G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
- cancellable, error);
- if (!file_info)
- goto out;
-
- target = g_file_info_get_symlink_target (file_info);
- if (target == NULL)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Not a symbolic link");
- goto out;
- }
-
- last_dash = strrchr (target, '-');
- if (last_dash == NULL)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Invalid existing symlink target; no trailing dash");
- goto out;
- }
- checksum = last_dash + 1;
-
- if (!ostree_validate_structureof_checksum_string (checksum, error))
- goto out;
-
- ret_commit = g_strdup (checksum);
-
- ret = TRUE;
- ot_transfer_out_value (out_commit, &ret_commit);
- out:
- return ret;
-}
-
typedef struct {
gboolean caught_error;
GError **error;
@@ -286,11 +208,9 @@ ostree_builtin_checkout (int argc, char **argv, GFile *repo_path, GError **error
gboolean ret = FALSE;
const char *commit;
const char *destination;
- gboolean skip_checkout;
ot_lobj OstreeRepo *repo = NULL;
ot_lfree char *existing_commit = NULL;
ot_lfree char *resolved_commit = NULL;
- ot_lfree char *suffixed_destination = NULL;
ot_lfree char *tmp_destination = NULL;
ot_lobj GFileInfo *symlink_file_info = NULL;
ot_lobj GFile *checkout_target = NULL;
@@ -319,13 +239,6 @@ ostree_builtin_checkout (int argc, char **argv, GFile *repo_path, GError **error
if (opt_from_stdin || opt_from_file)
{
- if (opt_atomic_retarget)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "--atomic-retarget may not be used with --from-stdin or --from-file");
- goto out;
- }
-
destination = argv[1];
checkout_target = g_file_new_for_path (destination);
@@ -349,69 +262,18 @@ ostree_builtin_checkout (int argc, char **argv, GFile *repo_path, GError **error
if (!ostree_repo_resolve_rev (repo, commit, FALSE, &resolved_commit, error))
goto out;
- if (opt_atomic_retarget)
- {
- GError *temp_error = NULL;
-
- suffixed_destination = g_strconcat (destination, "-", resolved_commit, NULL);
- checkout_target = g_file_new_for_path (suffixed_destination);
- tmp_destination = g_strconcat (suffixed_destination, ".tmp", NULL);
- checkout_target_tmp = g_file_new_for_path (tmp_destination);
- symlink_target = g_file_new_for_path (destination);
-
- if (!parse_commit_from_symlink (symlink_target, &existing_commit,
- cancellable, &temp_error))
- {
- if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
- {
- skip_checkout = FALSE;
- g_clear_error (&temp_error);
- }
- else
- {
- g_propagate_error (error, temp_error);
- goto out;
- }
- }
- else
- {
- skip_checkout = strcmp (existing_commit, resolved_commit) == 0;
- }
- }
- else
- {
- checkout_target = g_file_new_for_path (destination);
- skip_checkout = FALSE;
- }
+ checkout_target = g_file_new_for_path (destination);
- if (skip_checkout)
- {
- g_print ("ostree-checkout: Rev %s is already checked out as %s\n", commit, resolved_commit);
- }
- else
+ if (!process_one_checkout (repo, resolved_commit, opt_subpath,
+ checkout_target_tmp ? checkout_target_tmp : checkout_target,
+ cancellable, error))
+ goto out;
+
+ if (!opt_no_triggers)
{
- if (!process_one_checkout (repo, resolved_commit, opt_subpath,
- checkout_target_tmp ? checkout_target_tmp : checkout_target,
- cancellable, error))
+ if (!ostree_run_triggers_in_root (checkout_target_tmp ? checkout_target_tmp : checkout_target,
+ cancellable, error))
goto out;
-
- if (!opt_no_triggers)
- {
- if (!ostree_run_triggers_in_root (checkout_target_tmp ? checkout_target_tmp : checkout_target,
- cancellable, error))
- goto out;
- }
-
- if (opt_atomic_retarget)
- {
- if (!ot_gfile_rename (checkout_target_tmp, checkout_target, cancellable, error))
- goto out;
- if (!atomic_symlink_swap (symlink_target,
- ot_gfile_get_basename_cached (checkout_target),
- cancellable, error))
- goto out;
- g_print ("ostree-checkout: Rev %s checked out as %s\n", commit, resolved_commit);
- }
}
}
diff --git a/src/switchroot/ostree-switch-root.c b/src/switchroot/ostree-switch-root.c
index ff16b16..f0bf49b 100644
--- a/src/switchroot/ostree-switch-root.c
+++ b/src/switchroot/ostree-switch-root.c
@@ -152,9 +152,9 @@ 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 };
+ const char *ostree_bind_mounts[] = { "/var", "/etc", NULL };
/* ostree_readonly_bind_mounts /lib/modules -> modules */
- const char *readonly_bind_mounts[] = { "/bin", "/etc", "/lib", "/sbin", "/usr",
+ const char *readonly_bind_mounts[] = { "/bin", "/lib", "/sbin", "/usr",
NULL };
const char *root_mountpoint = NULL;
const char *ostree_target = NULL;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]