[ostree] admin: Split up the monstrous ot-admin-functions.c



commit 1fa1443bae220581e43c7f0bfd978faa5ea5e331
Author: Colin Walters <walters verbum org>
Date:   Sun Jul 7 12:42:02 2013 -0400

    admin: Split up the monstrous ot-admin-functions.c
    
    Now util, cleanup, and functions.

 Makefile-ostree.am              |    2 +
 src/ostree/ot-admin-cleanup.c   |  400 +++++++++++++++++++++++++++++++++++
 src/ostree/ot-admin-deploy.c    |    2 +-
 src/ostree/ot-admin-functions.c |  442 +-------------------------------------
 src/ostree/ot-admin-functions.h |   14 ++-
 src/ostree/ot-admin-util.c      |   78 +++++++
 6 files changed, 506 insertions(+), 432 deletions(-)
---
diff --git a/Makefile-ostree.am b/Makefile-ostree.am
index cfbd456..13f967e 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 0000000..d647fa5
--- /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 a3fa0c3..707c8a1 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 89466f1..5ebeb9c 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 5a3c076..950d11e 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 0000000..871871f
--- /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;
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]