diff --git a/src/ostree/ot-admin-builtin-prune.c b/src/ostree/ot-admin-builtin-prune.c index 2a3c42f6..4d600991 100644 --- a/src/ostree/ot-admin-builtin-prune.c +++ b/src/ostree/ot-admin-builtin-prune.c @@ -35,67 +35,6 @@ static GOptionEntry options[] = { { NULL } }; -static gboolean -list_deployments (GFile *from_dir, - GPtrArray *inout_deployments, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - GError *temp_error = NULL; - ot_lobj GFileEnumerator *dir_enum = NULL; - ot_lobj GFileInfo *file_info = NULL; - - dir_enum = g_file_enumerate_children (from_dir, OSTREE_GIO_FAST_QUERYINFO, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - NULL, error); - if (!dir_enum) - goto out; - - while ((file_info = g_file_enumerator_next_file (dir_enum, cancellable, error)) != NULL) - { - const char *name; - ot_lobj GFile *child = NULL; - ot_lobj GFile *possible_etc = NULL; - ot_lobj GFile *possible_usr = NULL; - - name = g_file_info_get_name (file_info); - - if (g_str_has_suffix (name, "-etc")) - goto next; - if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY) - goto next; - - child = g_file_get_child (from_dir, name); - - possible_etc = ot_gfile_get_child_strconcat (from_dir, name, "-etc", NULL); - /* Bit of a hack... */ - possible_usr = g_file_get_child (child, "usr"); - - if (g_file_query_exists (possible_etc, cancellable)) - g_ptr_array_add (inout_deployments, g_file_get_child (from_dir, name)); - else if (g_file_query_exists (possible_usr, cancellable)) - goto next; - else - { - if (!list_deployments (child, inout_deployments, - cancellable, error)) - goto out; - } - - next: - g_clear_object (&file_info); - } - if (temp_error != NULL) - { - g_propagate_error (error, temp_error); - goto out; - } - - ret = TRUE; - out: - return ret; -} gboolean ot_admin_builtin_prune (int argc, char **argv, OtAdminBuiltinOpts *admin_opts, GError **error) @@ -109,7 +48,9 @@ ot_admin_builtin_prune (int argc, char **argv, OtAdminBuiltinOpts *admin_opts, G ot_lobj GFile *deploy_dir = NULL; ot_lobj GFile *current_deployment = NULL; ot_lobj GFile *previous_deployment = NULL; + ot_lobj GFile *active_deployment = NULL; ot_lptrarray GPtrArray *deployments = NULL; + gs_free char *active_osname = NULL; __attribute__((unused)) GCancellable *cancellable = NULL; context = g_option_context_new ("OSNAME - Delete untagged deployments and repository objects"); @@ -127,16 +68,16 @@ ot_admin_builtin_prune (int argc, char **argv, OtAdminBuiltinOpts *admin_opts, G 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 (deploy_dir, deployments, cancellable, error)) + if (!ot_admin_list_deployments (ostree_dir, osname, &deployments, + cancellable, error)) goto out; if (!ot_admin_get_current_deployment (ostree_dir, osname, ¤t_deployment, cancellable, error)); if (!ot_admin_get_previous_deployment (ostree_dir, osname, &previous_deployment, cancellable, error)); + if (!ot_admin_get_active_deployment (ostree_dir, &active_osname, &active_deployment, + cancellable, error)); for (i = 0; i < deployments->len; i++) { @@ -145,7 +86,8 @@ ot_admin_builtin_prune (int argc, char **argv, OtAdminBuiltinOpts *admin_opts, G ot_lobj GFile *parent = NULL; if ((current_deployment && g_file_equal (deployment, current_deployment)) - || (previous_deployment && g_file_equal (deployment, previous_deployment))) + || (previous_deployment && g_file_equal (deployment, previous_deployment)) + || (active_deployment && g_file_equal (deployment, active_deployment))) continue; parent = g_file_get_parent (deployment); diff --git a/src/ostree/ot-admin-functions.c b/src/ostree/ot-admin-functions.c index 6cc4ff0f..c642ab84 100644 --- a/src/ostree/ot-admin-functions.c +++ b/src/ostree/ot-admin-functions.c @@ -181,6 +181,257 @@ ot_admin_get_previous_deployment (GFile *ostree_dir, cancellable, error); } +/* +static gboolean +ot_admin_list_osnames (GFile *ostree_dir, + GPtrArray **out_osnames, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + ot_lobj GFileEnumerator *dir_enum = NULL; + ot_lobj GFileInfo *file_info = NULL; + ot_lobj GFile *deploy_dir = NULL; + ot_lptrarray GPtrArray *ret_osnames = NULL; + GError *temp_error = NULL; + + deploy_dir = g_file_get_child (ostree_dir, "deploy"); + + dir_enum = g_file_enumerate_children (deploy_dir, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + NULL, error); + if (!dir_enum) + goto out; + + while ((file_info = g_file_enumerator_next_file (dir_enum, NULL, error)) != NULL) + { + if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY) + { + char *name = g_strdup (g_file_info_get_name (file_info)); + g_ptr_array_add (ret_osnames, name); + } + g_clear_object (&file_info); + } + + if (temp_error != NULL) + { + g_propagate_error (error, temp_error); + goto out; + } + + ret = TRUE; + ot_transfer_out_value (out_osnames, &ret_osnames); + out: + return ret; +} +*/ + +static gboolean +list_deployments_internal (GFile *from_dir, + GPtrArray *inout_deployments, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + GError *temp_error = NULL; + ot_lobj GFileEnumerator *dir_enum = NULL; + ot_lobj GFileInfo *file_info = NULL; + + dir_enum = g_file_enumerate_children (from_dir, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + NULL, error); + if (!dir_enum) + goto out; + + while ((file_info = g_file_enumerator_next_file (dir_enum, cancellable, error)) != NULL) + { + const char *name; + ot_lobj GFile *child = NULL; + ot_lobj GFile *possible_etc = NULL; + ot_lobj GFile *possible_usr = NULL; + + name = g_file_info_get_name (file_info); + + if (g_str_has_suffix (name, "-etc")) + goto next; + if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY) + goto next; + + child = g_file_get_child (from_dir, name); + + possible_etc = ot_gfile_get_child_strconcat (from_dir, name, "-etc", NULL); + /* Bit of a hack... */ + possible_usr = g_file_get_child (child, "usr"); + + if (g_file_query_exists (possible_etc, cancellable)) + g_ptr_array_add (inout_deployments, g_file_get_child (from_dir, name)); + else if (g_file_query_exists (possible_usr, cancellable)) + goto next; + else + { + if (!list_deployments_internal (child, inout_deployments, + cancellable, error)) + goto out; + } + + next: + g_clear_object (&file_info); + } + if (temp_error != NULL) + { + g_propagate_error (error, temp_error); + goto out; + } + + ret = TRUE; + out: + return ret; +} + +gboolean +ot_admin_list_deployments (GFile *ostree_dir, + const char *osname, + GPtrArray **out_deployments, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + ot_lobj GFileEnumerator *dir_enum = NULL; + ot_lobj GFileInfo *file_info = NULL; + ot_lobj GFile *osdir = NULL; + ot_lptrarray GPtrArray *ret_deployments = NULL; + + osdir = ot_gfile_get_child_build_path (ostree_dir, "deploy", osname, NULL); + ret_deployments = g_ptr_array_new_with_free_func (g_object_unref); + + if (!list_deployments_internal (osdir, ret_deployments, cancellable, error)) + goto out; + + ret = TRUE; + ot_transfer_out_value (out_deployments, &ret_deployments); + out: + return ret; +} + +static gboolean +ot_admin_get_booted_os (char **out_osname, + char **out_tree, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + gs_free char *ret_osname = NULL; + gs_free char *ret_tree = NULL; + gs_free char *cmdline_contents = NULL; + const char *iter; + gsize len; + + if (!g_file_get_contents ("/proc/cmdline", &cmdline_contents, &len, + error)) + goto out; + + iter = cmdline_contents; + do + { + const char *next = strchr (iter, ' '); + if (next) + next += 1; + if (g_str_has_prefix (iter, "ostree=")) + { + const char *slash = strchr (iter, '/'); + if (slash) + { + const char *start = iter + strlen ("ostree="); + ret_osname = g_strndup (start, slash - start); + if (next) + ret_tree = g_strndup (slash + 1, next - slash - 1); + else + ret_tree = g_strdup (slash + 1); + break; + } + } + iter = next; + } + while (iter != NULL); + + ret = TRUE; + out: + ot_transfer_out_value (out_osname, &ret_osname); + ot_transfer_out_value (out_tree, &ret_tree); + return ret; +} + +gboolean +ot_admin_get_active_deployment (GFile *ostree_dir, + char **out_osname, + GFile **out_deployment, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + ot_lptrarray GPtrArray *osnames = NULL; + ot_lptrarray GPtrArray *deployments = NULL; + gs_free char *ret_osname = NULL; + gs_unref_object GFile *ret_deployment = NULL; + + if (!ot_admin_get_booted_os (&ret_osname, NULL, cancellable, error)) + goto out; + + if (ret_osname != NULL) + { + gs_unref_object GFile *rootfs_path = NULL; + gs_unref_object GFileInfo *rootfs_info = NULL; + guint32 root_dev; + guint64 root_inode; + guint i; + + rootfs_path = g_file_new_for_path ("/"); + rootfs_info = g_file_query_info (rootfs_path, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); + if (!rootfs_info) + goto out; + + root_dev = g_file_info_get_attribute_uint32 (rootfs_info, "unix::device"); + root_inode = g_file_info_get_attribute_uint64 (rootfs_info, "unix::inode"); + + if (!ot_admin_list_deployments (ostree_dir, ret_osname, &deployments, + cancellable, error)) + goto out; + + for (i = 0; i < deployments->len; i++) + { + GFile *deployment = deployments->pdata[i]; + gs_unref_object GFileInfo *deployment_info = NULL; + guint32 deploy_dev; + guint64 deploy_inode; + + deployment_info = g_file_query_info (rootfs_path, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); + if (!deployment_info) + goto out; + + deploy_dev = g_file_info_get_attribute_uint32 (deployment_info, "unix::device"); + deploy_inode = g_file_info_get_attribute_uint64 (deployment_info, "unix::inode"); + + if (root_dev == deploy_dev && root_inode == deploy_inode) + { + ret_deployment = g_object_ref (deployment); + break; + } + } + + g_assert (ret_deployment != NULL); + } + + ret = TRUE; + ot_transfer_out_value (out_osname, &ret_osname); + ot_transfer_out_value (out_deployment, &ret_deployment); + out: + return ret; +} + gboolean ot_admin_get_default_ostree_dir (GFile **out_ostree_dir, GCancellable *cancellable, diff --git a/src/ostree/ot-admin-functions.h b/src/ostree/ot-admin-functions.h index c189b242..d74d768b 100644 --- a/src/ostree/ot-admin-functions.h +++ b/src/ostree/ot-admin-functions.h @@ -42,6 +42,18 @@ gboolean ot_admin_get_previous_deployment (GFile *ostree_dir, GCancellable *cancellable, GError **error); +gboolean ot_admin_list_deployments (GFile *ostree_dir, + const char *osname, + GPtrArray **out_deployments, + GCancellable *cancellable, + GError **error); + +gboolean ot_admin_get_active_deployment (GFile *ostree_dir, + char **out_osname, + GFile **out_deployment, + GCancellable *cancellable, + GError **error); + gboolean ot_admin_get_default_ostree_dir (GFile **out_ostree_dir, GCancellable *cancellable, GError **error);