summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2013-07-07 12:42:02 -0400
committerColin Walters <walters@verbum.org>2013-07-07 12:42:02 -0400
commit1fa1443bae220581e43c7f0bfd978faa5ea5e331 (patch)
treee749dc3ad0a28d61d953a033cdbff2586900d2b3
parent4b170d656c1b676929f5744448bafc250f3ad5dc (diff)
downloadostree-1fa1443bae220581e43c7f0bfd978faa5ea5e331.tar.gz
admin: Split up the monstrous ot-admin-functions.c
Now util, cleanup, and functions.
-rw-r--r--Makefile-ostree.am2
-rw-r--r--src/ostree/ot-admin-cleanup.c400
-rw-r--r--src/ostree/ot-admin-deploy.c2
-rw-r--r--src/ostree/ot-admin-functions.c442
-rw-r--r--src/ostree/ot-admin-functions.h14
-rw-r--r--src/ostree/ot-admin-util.c78
6 files changed, 506 insertions, 432 deletions
diff --git a/Makefile-ostree.am b/Makefile-ostree.am
index cfbd4569..13f967e9 100644
--- a/Makefile-ostree.am
+++ b/Makefile-ostree.am
@@ -62,6 +62,8 @@ ostree_SOURCES += \
src/ostree/ot-admin-builtin-run-triggers.c \
src/ostree/ot-admin-builtin-upgrade.c \
src/ostree/ot-admin-builtins.h \
+ src/ostree/ot-admin-cleanup.c \
+ src/ostree/ot-admin-util.c \
src/ostree/ot-admin-functions.h \
src/ostree/ot-admin-functions.c \
src/ostree/ot-admin-deploy.h \
diff --git a/src/ostree/ot-admin-cleanup.c b/src/ostree/ot-admin-cleanup.c
new file mode 100644
index 00000000..d647fa5e
--- /dev/null
+++ b/src/ostree/ot-admin-cleanup.c
@@ -0,0 +1,400 @@
+/* -*- 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>
+ */
+
+#define _GNU_SOURCE
+#include "config.h"
+
+#include "ot-admin-functions.h"
+#include "ot-deployment.h"
+#include "ot-config-parser.h"
+#include "otutil.h"
+#include "ostree-core.h"
+#include "ostree-prune.h"
+#include "libgsystem.h"
+
+static gboolean
+list_deployment_dirs_for_os (GFile *osdir,
+ GPtrArray *inout_deployments,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ const char *osname = gs_file_get_basename_cached (osdir);
+ gs_unref_object GFileEnumerator *dir_enum = NULL;
+ gs_unref_object GFile *osdeploy_dir = NULL;
+ GError *temp_error = NULL;
+
+ osdeploy_dir = g_file_get_child (osdir, "deploy");
+
+ dir_enum = g_file_enumerate_children (osdeploy_dir, OSTREE_GIO_FAST_QUERYINFO,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ NULL, &temp_error);
+ if (!dir_enum)
+ {
+ if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+ {
+ g_clear_error (&temp_error);
+ goto done;
+ }
+ else
+ {
+ g_propagate_error (error, temp_error);
+ goto out;
+ }
+ }
+
+ while (TRUE)
+ {
+ const char *name;
+ GFileInfo *file_info = NULL;
+ GFile *child = NULL;
+ gs_unref_object OtDeployment *deployment = NULL;
+ gs_free char *csum = NULL;
+ gint deployserial;
+
+ if (!gs_file_enumerator_iterate (dir_enum, &file_info, &child,
+ cancellable, error))
+ goto out;
+ if (file_info == NULL)
+ break;
+
+ name = g_file_info_get_name (file_info);
+
+ if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY)
+ continue;
+
+ if (!ot_admin_parse_deploy_path_name (name, &csum, &deployserial, error))
+ goto out;
+
+ deployment = ot_deployment_new (-1, osname, csum, deployserial, NULL, -1);
+ g_ptr_array_add (inout_deployments, g_object_ref (deployment));
+ }
+
+ done:
+ ret = TRUE;
+ out:
+ return ret;
+}
+static gboolean
+list_all_deployment_directories (GFile *sysroot,
+ GPtrArray **out_deployments,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ gs_unref_object GFileEnumerator *dir_enum = NULL;
+ gs_unref_object GFile *deploydir = NULL;
+ gs_unref_object GFile *osdir = NULL;
+ gs_unref_ptrarray GPtrArray *ret_deployments = NULL;
+ GError *temp_error = NULL;
+
+ deploydir = g_file_resolve_relative_path (sysroot, "ostree/deploy");
+
+ ret_deployments = g_ptr_array_new_with_free_func (g_object_unref);
+
+ dir_enum = g_file_enumerate_children (deploydir, 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);
+ goto done;
+ }
+ else
+ {
+ g_propagate_error (error, temp_error);
+ goto out;
+ }
+ }
+
+ while (TRUE)
+ {
+ GFileInfo *file_info = NULL;
+ GFile *child = NULL;
+
+ if (!gs_file_enumerator_iterate (dir_enum, &file_info, &child,
+ NULL, error))
+ goto out;
+ if (file_info == NULL)
+ break;
+
+ if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY)
+ continue;
+
+ if (!list_deployment_dirs_for_os (child, ret_deployments, cancellable, error))
+ goto out;
+ }
+
+ done:
+ ret = TRUE;
+ ot_transfer_out_value (out_deployments, &ret_deployments);
+ out:
+ return ret;
+}
+
+static gboolean
+cleanup_other_bootversions (GFile *sysroot,
+ int bootversion,
+ int subbootversion,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ int cleanup_bootversion;
+ int cleanup_subbootversion;
+ gs_free char *cleanup_boot_name = NULL;
+ gs_unref_object GFile *cleanup_boot_dir = NULL;
+
+ cleanup_bootversion = bootversion == 0 ? 1 : 0;
+ cleanup_subbootversion = subbootversion == 0 ? 1 : 0;
+
+ cleanup_boot_dir = ot_gfile_resolve_path_printf (sysroot, "boot/loader.%d", cleanup_bootversion);
+ if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error))
+ goto out;
+ g_clear_object (&cleanup_boot_dir);
+
+ cleanup_boot_dir = ot_gfile_resolve_path_printf (sysroot, "ostree/boot.%d", cleanup_bootversion);
+ if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error))
+ goto out;
+ g_clear_object (&cleanup_boot_dir);
+
+ cleanup_boot_dir = ot_gfile_resolve_path_printf (sysroot, "ostree/boot.%d.0", cleanup_bootversion);
+ if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error))
+ goto out;
+ g_clear_object (&cleanup_boot_dir);
+
+ cleanup_boot_dir = ot_gfile_resolve_path_printf (sysroot, "ostree/boot.%d.1", cleanup_bootversion);
+ if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error))
+ goto out;
+ g_clear_object (&cleanup_boot_dir);
+
+ cleanup_boot_dir = ot_gfile_resolve_path_printf (sysroot, "ostree/boot.%d.%d", bootversion,
+ cleanup_subbootversion);
+ if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error))
+ goto out;
+ g_clear_object (&cleanup_boot_dir);
+
+ ret = TRUE;
+ out:
+ return ret;
+}
+
+static gboolean
+cleanup_old_deployments (GFile *sysroot,
+ GPtrArray *deployments,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ guint32 root_device;
+ guint64 root_inode;
+ guint i;
+ gs_unref_object GFile *active_root = g_file_new_for_path ("/");
+ gs_unref_hashtable GHashTable *active_deployment_dirs = NULL;
+ gs_unref_ptrarray GPtrArray *all_deployment_dirs = NULL;
+
+ if (!ot_admin_util_get_devino (active_root, &root_device, &root_inode,
+ cancellable, error))
+ goto out;
+
+ active_deployment_dirs = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, NULL, g_object_unref);
+
+ for (i = 0; i < deployments->len; i++)
+ {
+ OtDeployment *deployment = deployments->pdata[i];
+ GFile *deployment_path = ot_admin_get_deployment_directory (sysroot, deployment);
+ /* Transfer ownership */
+ g_hash_table_insert (active_deployment_dirs, deployment_path, deployment_path);
+ }
+
+ if (!list_all_deployment_directories (sysroot, &all_deployment_dirs,
+ cancellable, error))
+ goto out;
+
+ for (i = 0; i < all_deployment_dirs->len; i++)
+ {
+ OtDeployment *deployment = all_deployment_dirs->pdata[i];
+ gs_unref_object GFile *deployment_path = ot_admin_get_deployment_directory (sysroot, deployment);
+ gs_unref_object GFile *origin_path = ot_admin_get_deployment_origin_path (deployment_path);
+ if (!g_hash_table_lookup (active_deployment_dirs, deployment_path))
+ {
+ guint32 device;
+ guint64 inode;
+
+ if (!ot_admin_util_get_devino (deployment_path, &device, &inode,
+ cancellable, error))
+ goto out;
+
+ /* This shouldn't happen, because higher levels should
+ * disallow having the booted deployment not in the active
+ * deployment list, but let's be extra safe. */
+ if (device == root_device && inode == root_inode)
+ continue;
+
+ g_print ("ostadmin: Deleting deployment %s\n", gs_file_get_path_cached (deployment_path));
+ if (!gs_shutil_rm_rf (deployment_path, cancellable, error))
+ goto out;
+ if (!gs_shutil_rm_rf (origin_path, cancellable, error))
+ goto out;
+ }
+ }
+
+ ret = TRUE;
+ out:
+ return ret;
+}
+
+static gboolean
+cleanup_ref_prefix (OstreeRepo *repo,
+ int bootversion,
+ int subbootversion,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ gs_free char *prefix = NULL;
+ gs_unref_hashtable GHashTable *refs = NULL;
+ GHashTableIter hashiter;
+ gpointer hashkey, hashvalue;
+
+ prefix = g_strdup_printf ("ostree/%d/%d", bootversion, subbootversion);
+
+ if (!ostree_repo_list_refs (repo, prefix, &refs, cancellable, error))
+ goto out;
+
+ g_hash_table_iter_init (&hashiter, refs);
+ while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue))
+ {
+ const char *suffix = hashkey;
+ gs_free char *ref = g_strconcat (prefix, "/", suffix, NULL);
+ if (!ostree_repo_write_refspec (repo, ref, NULL, error))
+ goto out;
+ }
+
+ ret = TRUE;
+ out:
+ return ret;
+}
+
+static gboolean
+generate_deployment_refs_and_prune (GFile *sysroot,
+ OstreeRepo *repo,
+ int bootversion,
+ int subbootversion,
+ GPtrArray *deployments,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ int cleanup_bootversion;
+ int cleanup_subbootversion;
+ guint i;
+ gint n_objects_total, n_objects_pruned;
+ guint64 freed_space;
+ gs_free char *cleanup_boot_name = NULL;
+ gs_unref_object GFile *cleanup_boot_dir = NULL;
+
+ cleanup_bootversion = (bootversion == 0) ? 1 : 0;
+ cleanup_subbootversion = (subbootversion == 0) ? 1 : 0;
+
+ if (!cleanup_ref_prefix (repo, cleanup_bootversion, 0,
+ cancellable, error))
+ goto out;
+
+ if (!cleanup_ref_prefix (repo, cleanup_bootversion, 1,
+ cancellable, error))
+ goto out;
+
+ if (!cleanup_ref_prefix (repo, bootversion, cleanup_subbootversion,
+ cancellable, error))
+ goto out;
+
+ for (i = 0; i < deployments->len; i++)
+ {
+ OtDeployment *deployment = deployments->pdata[i];
+ gs_free char *refname = g_strdup_printf ("ostree/%d/%d/%u",
+ bootversion, subbootversion,
+ i);
+ if (!ostree_repo_write_refspec (repo, refname, ot_deployment_get_csum (deployment),
+ error))
+ goto out;
+ }
+
+ if (!ostree_prune (repo, OSTREE_PRUNE_FLAGS_REFS_ONLY, 0,
+ &n_objects_total, &n_objects_pruned, &freed_space,
+ cancellable, error))
+ goto out;
+ if (freed_space > 0)
+ {
+ char *freed_space_str = g_format_size_full (freed_space, 0);
+ g_print ("Freed objects: %s\n", freed_space_str);
+ }
+
+ ret = TRUE;
+ out:
+ return ret;
+}
+
+gboolean
+ot_admin_cleanup (GFile *sysroot,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ gs_unref_ptrarray GPtrArray *deployments = NULL;
+ gs_unref_object OstreeRepo *repo = NULL;
+ int bootversion;
+ int subbootversion;
+
+ if (!ot_admin_list_deployments (sysroot, &bootversion, &deployments,
+ cancellable, error))
+ goto out;
+
+ if (!ot_admin_read_current_subbootversion (sysroot, bootversion, &subbootversion,
+ cancellable, error))
+ goto out;
+
+ if (!cleanup_other_bootversions (sysroot, bootversion, subbootversion,
+ cancellable, error))
+ goto out;
+
+ if (!cleanup_old_deployments (sysroot, deployments,
+ cancellable, error))
+ goto out;
+
+ if (deployments->len > 0)
+ {
+ if (!ot_admin_get_repo (sysroot, &repo, cancellable, error))
+ goto out;
+
+ if (!generate_deployment_refs_and_prune (sysroot, repo, bootversion,
+ subbootversion, deployments,
+ cancellable, error))
+ goto out;
+ }
+
+ ret = TRUE;
+ out:
+ return ret;
+}
diff --git a/src/ostree/ot-admin-deploy.c b/src/ostree/ot-admin-deploy.c
index a3fa0c33..707c8a1c 100644
--- a/src/ostree/ot-admin-deploy.c
+++ b/src/ostree/ot-admin-deploy.c
@@ -1148,7 +1148,7 @@ ot_admin_deploy (GFile *sysroot,
for (strviter = add_kernel_argv; *strviter; strviter++)
{
char *karg = g_strdup (*strviter);
- const char *val = ot_admin_split_keyeq (karg);
+ const char *val = ot_admin_util_split_keyeq (karg);
ot_ordered_hash_replace_key_take (ohash, karg, val);
}
diff --git a/src/ostree/ot-admin-functions.c b/src/ostree/ot-admin-functions.c
index 89466f19..5ebeb9c3 100644
--- a/src/ostree/ot-admin-functions.c
+++ b/src/ostree/ot-admin-functions.c
@@ -32,33 +32,6 @@
#include "ostree-prune.h"
#include "libgsystem.h"
-/*
- * Modify @arg which should be of the form key=value to make @arg just
- * contain key. Return a pointer to the start of value.
- */
-char *
-ot_admin_split_keyeq (char *arg)
-{
- char *eq;
-
- eq = strchr (arg, '=');
- if (eq)
- {
- /* Note key/val are in one malloc block,
- * so we don't free val...
- */
- *eq = '\0';
- return eq+1;
- }
- else
- {
- /* ...and this allows us to insert a constant
- * string.
- */
- return "";
- }
-}
-
OtOrderedHash *
ot_admin_parse_kernel_args (const char *options)
{
@@ -77,7 +50,7 @@ ot_admin_parse_kernel_args (const char *options)
char *arg = *iter;
char *val;
- val = ot_admin_split_keyeq (arg);
+ val = ot_admin_util_split_keyeq (arg);
g_ptr_array_add (ret->order, arg);
g_hash_table_insert (ret->table, arg, val);
@@ -228,11 +201,11 @@ parse_bootlink (const char *bootlink,
return ret;
}
-static gboolean
-parse_deploy_path_name (const char *name,
- char **out_csum,
- int *out_serial,
- GError **error)
+gboolean
+ot_admin_parse_deploy_path_name (const char *name,
+ char **out_csum,
+ int *out_serial,
+ GError **error)
{
gboolean ret = FALSE;
__attribute__((cleanup(match_info_cleanup))) GMatchInfo *match = NULL;
@@ -346,8 +319,8 @@ parse_deployment (GFile *sysroot,
&treebootserial_target, cancellable, error))
goto out;
- if (!parse_deploy_path_name (gs_file_get_basename_cached (treebootserial_target),
- &treecsum, &deployserial, error))
+ if (!ot_admin_parse_deploy_path_name (gs_file_get_basename_cached (treebootserial_target),
+ &treecsum, &deployserial, error))
goto out;
if (!parse_origin (sysroot, treebootserial_target, &origin,
@@ -387,28 +360,6 @@ parse_kernel_commandline (OtOrderedHash **out_args,
return ret;
}
-static gboolean
-get_devino (GFile *path,
- guint32 *out_device,
- guint64 *out_inode,
- GCancellable *cancellable,
- GError **error)
-{
- gboolean ret = FALSE;
- gs_unref_object GFileInfo *finfo = g_file_query_info (path, "unix::device,unix::inode",
- G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
- cancellable, error);
-
- if (!finfo)
- goto out;
-
- ret = TRUE;
- *out_device = g_file_info_get_attribute_uint32 (finfo, "unix::device");
- *out_inode = g_file_info_get_attribute_uint64 (finfo, "unix::inode");
- out:
- return ret;
-}
-
/**
* ot_admin_find_booted_deployment:
*
@@ -435,8 +386,8 @@ ot_admin_find_booted_deployment (GFile *target_sysroot,
guint32 root_device;
guint64 root_inode;
- if (!get_devino (active_root, &root_device, &root_inode,
- cancellable, error))
+ if (!ot_admin_util_get_devino (active_root, &root_device, &root_inode,
+ cancellable, error))
goto out;
if (!parse_kernel_commandline (&kernel_args, cancellable, error))
@@ -452,8 +403,8 @@ ot_admin_find_booted_deployment (GFile *target_sysroot,
guint32 device;
guint64 inode;
- if (!get_devino (deployment_path, &device, &inode,
- cancellable, error))
+ if (!ot_admin_util_get_devino (deployment_path, &device, &inode,
+ cancellable, error))
goto out;
if (device == root_device && inode == root_inode)
@@ -708,129 +659,6 @@ ot_admin_read_boot_loader_configs (GFile *sysroot,
return ret;
}
-static gboolean
-list_deployment_dirs_for_os (GFile *osdir,
- GPtrArray *inout_deployments,
- GCancellable *cancellable,
- GError **error)
-{
- gboolean ret = FALSE;
- const char *osname = gs_file_get_basename_cached (osdir);
- gs_unref_object GFileEnumerator *dir_enum = NULL;
- gs_unref_object GFile *osdeploy_dir = NULL;
- GError *temp_error = NULL;
-
- osdeploy_dir = g_file_get_child (osdir, "deploy");
-
- dir_enum = g_file_enumerate_children (osdeploy_dir, OSTREE_GIO_FAST_QUERYINFO,
- G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
- NULL, &temp_error);
- if (!dir_enum)
- {
- if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
- {
- g_clear_error (&temp_error);
- goto done;
- }
- else
- {
- g_propagate_error (error, temp_error);
- goto out;
- }
- }
-
- while (TRUE)
- {
- const char *name;
- GFileInfo *file_info = NULL;
- GFile *child = NULL;
- gs_unref_object OtDeployment *deployment = NULL;
- gs_free char *csum = NULL;
- gint deployserial;
-
- if (!gs_file_enumerator_iterate (dir_enum, &file_info, &child,
- cancellable, error))
- goto out;
- if (file_info == NULL)
- break;
-
- name = g_file_info_get_name (file_info);
-
- if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY)
- continue;
-
- if (!parse_deploy_path_name (name, &csum, &deployserial, error))
- goto out;
-
- deployment = ot_deployment_new (-1, osname, csum, deployserial, NULL, -1);
- g_ptr_array_add (inout_deployments, g_object_ref (deployment));
- }
-
- done:
- ret = TRUE;
- out:
- return ret;
-}
-
-static gboolean
-list_all_deployment_directories (GFile *sysroot,
- GPtrArray **out_deployments,
- GCancellable *cancellable,
- GError **error)
-{
- gboolean ret = FALSE;
- gs_unref_object GFileEnumerator *dir_enum = NULL;
- gs_unref_object GFile *deploydir = NULL;
- gs_unref_object GFile *osdir = NULL;
- gs_unref_ptrarray GPtrArray *ret_deployments = NULL;
- GError *temp_error = NULL;
-
- deploydir = g_file_resolve_relative_path (sysroot, "ostree/deploy");
-
- ret_deployments = g_ptr_array_new_with_free_func (g_object_unref);
-
- dir_enum = g_file_enumerate_children (deploydir, 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);
- goto done;
- }
- else
- {
- g_propagate_error (error, temp_error);
- goto out;
- }
- }
-
- while (TRUE)
- {
- GFileInfo *file_info = NULL;
- GFile *child = NULL;
-
- if (!gs_file_enumerator_iterate (dir_enum, &file_info, &child,
- NULL, error))
- goto out;
- if (file_info == NULL)
- break;
-
- if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY)
- continue;
-
- if (!list_deployment_dirs_for_os (child, ret_deployments, cancellable, error))
- goto out;
- }
-
- done:
- ret = TRUE;
- ot_transfer_out_value (out_deployments, &ret_deployments);
- out:
- return ret;
-}
-
static char *
get_ostree_kernel_arg_from_config (OtConfigParser *config)
{
@@ -982,252 +810,6 @@ ot_admin_get_deployment_directory (GFile *sysroot,
return g_file_resolve_relative_path (sysroot, path);
}
-static gboolean
-cleanup_other_bootversions (GFile *sysroot,
- int bootversion,
- int subbootversion,
- GCancellable *cancellable,
- GError **error)
-{
- gboolean ret = FALSE;
- int cleanup_bootversion;
- int cleanup_subbootversion;
- gs_free char *cleanup_boot_name = NULL;
- gs_unref_object GFile *cleanup_boot_dir = NULL;
-
- cleanup_bootversion = bootversion == 0 ? 1 : 0;
- cleanup_subbootversion = subbootversion == 0 ? 1 : 0;
-
- cleanup_boot_dir = ot_gfile_resolve_path_printf (sysroot, "boot/loader.%d", cleanup_bootversion);
- if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error))
- goto out;
- g_clear_object (&cleanup_boot_dir);
-
- cleanup_boot_dir = ot_gfile_resolve_path_printf (sysroot, "ostree/boot.%d", cleanup_bootversion);
- if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error))
- goto out;
- g_clear_object (&cleanup_boot_dir);
-
- cleanup_boot_dir = ot_gfile_resolve_path_printf (sysroot, "ostree/boot.%d.0", cleanup_bootversion);
- if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error))
- goto out;
- g_clear_object (&cleanup_boot_dir);
-
- cleanup_boot_dir = ot_gfile_resolve_path_printf (sysroot, "ostree/boot.%d.1", cleanup_bootversion);
- if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error))
- goto out;
- g_clear_object (&cleanup_boot_dir);
-
- cleanup_boot_dir = ot_gfile_resolve_path_printf (sysroot, "ostree/boot.%d.%d", bootversion,
- cleanup_subbootversion);
- if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error))
- goto out;
- g_clear_object (&cleanup_boot_dir);
-
- ret = TRUE;
- out:
- return ret;
-}
-
-static gboolean
-cleanup_old_deployments (GFile *sysroot,
- GPtrArray *deployments,
- GCancellable *cancellable,
- GError **error)
-{
- gboolean ret = FALSE;
- guint32 root_device;
- guint64 root_inode;
- guint i;
- gs_unref_object GFile *active_root = g_file_new_for_path ("/");
- gs_unref_hashtable GHashTable *active_deployment_dirs = NULL;
- gs_unref_ptrarray GPtrArray *all_deployment_dirs = NULL;
-
- if (!get_devino (active_root, &root_device, &root_inode,
- cancellable, error))
- goto out;
-
- active_deployment_dirs = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, NULL, g_object_unref);
-
- for (i = 0; i < deployments->len; i++)
- {
- OtDeployment *deployment = deployments->pdata[i];
- GFile *deployment_path = ot_admin_get_deployment_directory (sysroot, deployment);
- /* Transfer ownership */
- g_hash_table_insert (active_deployment_dirs, deployment_path, deployment_path);
- }
-
- if (!list_all_deployment_directories (sysroot, &all_deployment_dirs,
- cancellable, error))
- goto out;
-
- for (i = 0; i < all_deployment_dirs->len; i++)
- {
- OtDeployment *deployment = all_deployment_dirs->pdata[i];
- gs_unref_object GFile *deployment_path = ot_admin_get_deployment_directory (sysroot, deployment);
- gs_unref_object GFile *origin_path = ot_admin_get_deployment_origin_path (deployment_path);
- if (!g_hash_table_lookup (active_deployment_dirs, deployment_path))
- {
- guint32 device;
- guint64 inode;
-
- if (!get_devino (deployment_path, &device, &inode,
- cancellable, error))
- goto out;
-
- /* This shouldn't happen, because higher levels should
- * disallow having the booted deployment not in the active
- * deployment list, but let's be extra safe. */
- if (device == root_device && inode == root_inode)
- continue;
-
- g_print ("ostadmin: Deleting deployment %s\n", gs_file_get_path_cached (deployment_path));
- if (!gs_shutil_rm_rf (deployment_path, cancellable, error))
- goto out;
- if (!gs_shutil_rm_rf (origin_path, cancellable, error))
- goto out;
- }
- }
-
- ret = TRUE;
- out:
- return ret;
-}
-
-static gboolean
-cleanup_ref_prefix (OstreeRepo *repo,
- int bootversion,
- int subbootversion,
- GCancellable *cancellable,
- GError **error)
-{
- gboolean ret = FALSE;
- gs_free char *prefix = NULL;
- gs_unref_hashtable GHashTable *refs = NULL;
- GHashTableIter hashiter;
- gpointer hashkey, hashvalue;
-
- prefix = g_strdup_printf ("ostree/%d/%d", bootversion, subbootversion);
-
- if (!ostree_repo_list_refs (repo, prefix, &refs, cancellable, error))
- goto out;
-
- g_hash_table_iter_init (&hashiter, refs);
- while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue))
- {
- const char *suffix = hashkey;
- gs_free char *ref = g_strconcat (prefix, "/", suffix, NULL);
- if (!ostree_repo_write_refspec (repo, ref, NULL, error))
- goto out;
- }
-
- ret = TRUE;
- out:
- return ret;
-}
-
-static gboolean
-generate_deployment_refs_and_prune (GFile *sysroot,
- OstreeRepo *repo,
- int bootversion,
- int subbootversion,
- GPtrArray *deployments,
- GCancellable *cancellable,
- GError **error)
-{
- gboolean ret = FALSE;
- int cleanup_bootversion;
- int cleanup_subbootversion;
- guint i;
- gint n_objects_total, n_objects_pruned;
- guint64 freed_space;
- gs_free char *cleanup_boot_name = NULL;
- gs_unref_object GFile *cleanup_boot_dir = NULL;
-
- cleanup_bootversion = (bootversion == 0) ? 1 : 0;
- cleanup_subbootversion = (subbootversion == 0) ? 1 : 0;
-
- if (!cleanup_ref_prefix (repo, cleanup_bootversion, 0,
- cancellable, error))
- goto out;
-
- if (!cleanup_ref_prefix (repo, cleanup_bootversion, 1,
- cancellable, error))
- goto out;
-
- if (!cleanup_ref_prefix (repo, bootversion, cleanup_subbootversion,
- cancellable, error))
- goto out;
-
- for (i = 0; i < deployments->len; i++)
- {
- OtDeployment *deployment = deployments->pdata[i];
- gs_free char *refname = g_strdup_printf ("ostree/%d/%d/%u",
- bootversion, subbootversion,
- i);
- if (!ostree_repo_write_refspec (repo, refname, ot_deployment_get_csum (deployment),
- error))
- goto out;
- }
-
- if (!ostree_prune (repo, OSTREE_PRUNE_FLAGS_REFS_ONLY, 0,
- &n_objects_total, &n_objects_pruned, &freed_space,
- cancellable, error))
- goto out;
- if (freed_space > 0)
- {
- char *freed_space_str = g_format_size_full (freed_space, 0);
- g_print ("Freed objects: %s\n", freed_space_str);
- }
-
- ret = TRUE;
- out:
- return ret;
-}
-
-gboolean
-ot_admin_cleanup (GFile *sysroot,
- GCancellable *cancellable,
- GError **error)
-{
- gboolean ret = FALSE;
- gs_unref_ptrarray GPtrArray *deployments = NULL;
- gs_unref_object OstreeRepo *repo = NULL;
- int bootversion;
- int subbootversion;
-
- if (!ot_admin_list_deployments (sysroot, &bootversion, &deployments,
- cancellable, error))
- goto out;
-
- if (!ot_admin_read_current_subbootversion (sysroot, bootversion, &subbootversion,
- cancellable, error))
- goto out;
-
- if (!cleanup_other_bootversions (sysroot, bootversion, subbootversion,
- cancellable, error))
- goto out;
-
- if (!cleanup_old_deployments (sysroot, deployments,
- cancellable, error))
- goto out;
-
- if (deployments->len > 0)
- {
- if (!ot_admin_get_repo (sysroot, &repo, cancellable, error))
- goto out;
-
- if (!generate_deployment_refs_and_prune (sysroot, repo, bootversion,
- subbootversion, deployments,
- cancellable, error))
- goto out;
- }
-
- ret = TRUE;
- out:
- return ret;
-}
-
OtBootloader *
ot_admin_query_bootloader (GFile *sysroot)
{
diff --git a/src/ostree/ot-admin-functions.h b/src/ostree/ot-admin-functions.h
index 5a3c0763..950d11e7 100644
--- a/src/ostree/ot-admin-functions.h
+++ b/src/ostree/ot-admin-functions.h
@@ -31,6 +31,19 @@
G_BEGIN_DECLS
+char *ot_admin_util_split_keyeq (char *str);
+
+gboolean ot_admin_util_get_devino (GFile *path,
+ guint32 *out_device,
+ guint64 *out_inode,
+ GCancellable *cancellable,
+ GError **error);
+
+gboolean ot_admin_parse_deploy_path_name (const char *name,
+ char **out_csum,
+ int *out_serial,
+ GError **error);
+
gboolean ot_admin_ensure_initialized (GFile *ostree_dir,
GCancellable *cancellable,
GError **error);
@@ -40,7 +53,6 @@ gboolean ot_admin_check_os (GFile *sysroot,
GCancellable *cancellable,
GError **error);
-char *ot_admin_split_keyeq (char *str);
OtOrderedHash *ot_admin_parse_kernel_args (const char *options);
char * ot_admin_kernel_arg_string_serialize (OtOrderedHash *ohash);
diff --git a/src/ostree/ot-admin-util.c b/src/ostree/ot-admin-util.c
new file mode 100644
index 00000000..871871fd
--- /dev/null
+++ b/src/ostree/ot-admin-util.c
@@ -0,0 +1,78 @@
+/* -*- 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>
+ */
+
+#define _GNU_SOURCE
+#include "config.h"
+
+#include "ot-admin-functions.h"
+#include "otutil.h"
+#include "ostree-core.h"
+#include "libgsystem.h"
+
+/*
+ * Modify @arg which should be of the form key=value to make @arg just
+ * contain key. Return a pointer to the start of value.
+ */
+char *
+ot_admin_util_split_keyeq (char *arg)
+{
+ char *eq;
+
+ eq = strchr (arg, '=');
+ if (eq)
+ {
+ /* Note key/val are in one malloc block,
+ * so we don't free val...
+ */
+ *eq = '\0';
+ return eq+1;
+ }
+ else
+ {
+ /* ...and this allows us to insert a constant
+ * string.
+ */
+ return "";
+ }
+}
+
+gboolean
+ot_admin_util_get_devino (GFile *path,
+ guint32 *out_device,
+ guint64 *out_inode,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ gs_unref_object GFileInfo *finfo = g_file_query_info (path, "unix::device,unix::inode",
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ cancellable, error);
+
+ if (!finfo)
+ goto out;
+
+ ret = TRUE;
+ *out_device = g_file_info_get_attribute_uint32 (finfo, "unix::device");
+ *out_inode = g_file_info_get_attribute_uint64 (finfo, "unix::inode");
+ out:
+ return ret;
+}