diff --git a/doc/ostree-sections.txt b/doc/ostree-sections.txt index 9bcedce4..aaecbb48 100644 --- a/doc/ostree-sections.txt +++ b/doc/ostree-sections.txt @@ -140,16 +140,17 @@ ostree_sysroot_get_type ostree_sysroot_new ostree_sysroot_new_default ostree_sysroot_get_path +ostree_sysroot_load ostree_sysroot_ensure_initialized -ostree_sysroot_read_current_subbootversion -ostree_sysroot_list_deployments +ostree_sysroot_get_bootversion +ostree_sysroot_get_subbootversion +ostree_sysroot_get_deployments +ostree_sysroot_get_booted_deployment ostree_sysroot_get_deployment_directory ostree_sysroot_get_deployment_origin_path ostree_sysroot_cleanup ostree_sysroot_get_repo -ostree_sysroot_find_booted_deployment -ostree_sysroot_require_deployment_or_osname ostree_sysroot_write_deployments -ostree_sysroot_deploy +ostree_sysroot_deploy_one_tree ostree_sysroot_get_merge_deployment diff --git a/src/libostree/ostree-sysroot-cleanup.c b/src/libostree/ostree-sysroot-cleanup.c index fbad0b25..186c6cb2 100644 --- a/src/libostree/ostree-sysroot-cleanup.c +++ b/src/libostree/ostree-sysroot-cleanup.c @@ -242,8 +242,6 @@ list_all_boot_directories (OstreeSysroot *self, static gboolean cleanup_other_bootversions (OstreeSysroot *self, - int bootversion, - int subbootversion, GCancellable *cancellable, GError **error) { @@ -252,8 +250,8 @@ cleanup_other_bootversions (OstreeSysroot *self, int cleanup_subbootversion; gs_unref_object GFile *cleanup_boot_dir = NULL; - cleanup_bootversion = bootversion == 0 ? 1 : 0; - cleanup_subbootversion = subbootversion == 0 ? 1 : 0; + cleanup_bootversion = self->bootversion == 0 ? 1 : 0; + cleanup_subbootversion = self->subbootversion == 0 ? 1 : 0; cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "boot/loader.%d", cleanup_bootversion); if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error)) @@ -275,7 +273,7 @@ cleanup_other_bootversions (OstreeSysroot *self, goto out; g_clear_object (&cleanup_boot_dir); - cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d.%d", bootversion, + cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d.%d", self->bootversion, cleanup_subbootversion); if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error)) goto out; @@ -288,7 +286,6 @@ cleanup_other_bootversions (OstreeSysroot *self, static gboolean cleanup_old_deployments (OstreeSysroot *self, - GPtrArray *deployments, GCancellable *cancellable, GError **error) { @@ -309,9 +306,9 @@ cleanup_old_deployments (OstreeSysroot *self, active_deployment_dirs = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, NULL, g_object_unref); active_boot_checksums = g_hash_table_new_full (g_str_hash, (GEqualFunc)g_str_equal, g_free, NULL); - for (i = 0; i < deployments->len; i++) + for (i = 0; i < self->deployments->len; i++) { - OstreeDeployment *deployment = deployments->pdata[i]; + OstreeDeployment *deployment = self->deployments->pdata[i]; GFile *deployment_path = ostree_sysroot_get_deployment_directory (self, deployment); char *bootcsum = g_strdup (ostree_deployment_get_bootcsum (deployment)); /* Transfer ownership */ @@ -494,34 +491,23 @@ ostree_sysroot_cleanup (OstreeSysroot *self, GError **error) { gboolean ret = FALSE; - gs_unref_ptrarray GPtrArray *deployments = NULL; gs_unref_object OstreeRepo *repo = NULL; - int bootversion; - int subbootversion; - if (!ostree_sysroot_list_deployments (self, &bootversion, &deployments, - cancellable, error)) + g_return_val_if_fail (self->loaded, FALSE); + + if (!cleanup_other_bootversions (self, cancellable, error)) goto out; - if (!ostree_sysroot_read_current_subbootversion (self, bootversion, &subbootversion, - cancellable, error)) + if (!cleanup_old_deployments (self, cancellable, error)) goto out; - if (!cleanup_other_bootversions (self, bootversion, subbootversion, - cancellable, error)) - goto out; - - if (!cleanup_old_deployments (self, deployments, - cancellable, error)) - goto out; - - if (deployments->len > 0) + if (self->deployments->len > 0) { if (!ostree_sysroot_get_repo (self, &repo, cancellable, error)) goto out; - if (!generate_deployment_refs_and_prune (self, repo, bootversion, - subbootversion, deployments, + if (!generate_deployment_refs_and_prune (self, repo, self->bootversion, + self->subbootversion, self->deployments, cancellable, error)) goto out; } diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c index c295bebb..cc8f542c 100644 --- a/src/libostree/ostree-sysroot-deploy.c +++ b/src/libostree/ostree-sysroot-deploy.c @@ -507,8 +507,7 @@ compute_new_deployment_list (int current_bootversion, gboolean retain, const char *revision, const char *bootcsum, - GPtrArray **out_new_deployments, - int *out_new_bootversion) + GPtrArray **out_new_deployments) { guint i; int new_index; @@ -518,10 +517,6 @@ compute_new_deployment_list (int current_bootversion, gs_unref_ptrarray GPtrArray *matching_deployments_by_bootserial = NULL; OstreeDeployment *deployment_to_delete = NULL; gs_unref_ptrarray GPtrArray *ret_new_deployments = NULL; - gboolean requires_new_bootversion; - - if (osname == NULL) - osname = ostree_deployment_get_osname (booted_deployment); /* First, compute the serial for this deployment; we look * for other ones in this os with the same checksum. @@ -566,13 +561,6 @@ compute_new_deployment_list (int current_bootversion, } } - /* We need to update the bootloader only if the deployment we're - * removing uses a different kernel. - */ - requires_new_bootversion = - (deployment_to_delete == NULL) || - (strcmp (ostree_deployment_get_bootcsum (deployment_to_delete), bootcsum) != 0); - ret_new_deployments = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref); new_deployment = ostree_deployment_new (0, osname, revision, new_deployserial, @@ -606,11 +594,6 @@ compute_new_deployment_list (int current_bootversion, *out_new_deployments = ret_new_deployments; ret_new_deployments = NULL; - g_assert (current_bootversion == 0 || current_bootversion == 1); - if (requires_new_bootversion) - *out_new_bootversion = (current_bootversion == 0) ? 1 : 0; - else - *out_new_bootversion = current_bootversion; } static GHashTable * @@ -707,29 +690,34 @@ full_system_sync (GCancellable *cancellable, } static gboolean -swap_bootlinks (OstreeSysroot *sysroot, - int current_bootversion, +swap_bootlinks (OstreeSysroot *self, + int bootversion, GPtrArray *new_deployments, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; guint i; - int old_subbootversion, new_subbootversion; - gs_unref_object GFile *ostree_dir = g_file_get_child (ostree_sysroot_get_path (sysroot), "ostree"); - gs_free char *ostree_bootdir_name = g_strdup_printf ("boot.%d", current_bootversion); + int old_subbootversion; + int new_subbootversion; + gs_unref_object GFile *ostree_dir = g_file_get_child (self->path, "ostree"); + gs_free char *ostree_bootdir_name = g_strdup_printf ("boot.%d", bootversion); gs_unref_object GFile *ostree_bootdir = g_file_resolve_relative_path (ostree_dir, ostree_bootdir_name); gs_free char *ostree_subbootdir_name = NULL; gs_unref_object GFile *ostree_subbootdir = NULL; - if (!ostree_sysroot_read_current_subbootversion (sysroot, current_bootversion, - &old_subbootversion, - cancellable, error)) - goto out; + if (bootversion != self->bootversion) + { + if (!_ostree_sysroot_read_current_subbootversion (self, bootversion, &old_subbootversion, + cancellable, error)) + goto out; + } + else + old_subbootversion = self->subbootversion; new_subbootversion = old_subbootversion == 0 ? 1 : 0; - ostree_subbootdir_name = g_strdup_printf ("boot.%d.%d", current_bootversion, new_subbootversion); + ostree_subbootdir_name = g_strdup_printf ("boot.%d.%d", bootversion, new_subbootversion); ostree_subbootdir = g_file_resolve_relative_path (ostree_dir, ostree_subbootdir_name); if (!gs_file_ensure_directory (ostree_subbootdir, TRUE, cancellable, error)) @@ -982,38 +970,91 @@ swap_bootloader (OstreeSysroot *sysroot, return ret; } +static GHashTable * +bootcsum_counts_for_deployment_list (GPtrArray *deployments) +{ + guint i; + GHashTable *ret = + g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL); + + for (i = 0; i < deployments->len; i++) + { + OstreeDeployment *deployment = deployments->pdata[i]; + const char *bootcsum = ostree_deployment_get_bootcsum (deployment); + gpointer orig_key; + gpointer countp; + + if (!g_hash_table_lookup_extended (ret, bootcsum, &orig_key, &countp)) + { + g_hash_table_insert (ret, (char*)bootcsum, GUINT_TO_POINTER (0)); + } + else + { + guint count = GPOINTER_TO_UINT (countp); + g_hash_table_replace (ret, (char*)bootcsum, GUINT_TO_POINTER (count + 1)); + } + } + return ret; +} + /** * ostree_sysroot_write_deployments: * @self: Sysroot - * @current_bootversion: 0 or 1 for active boot version - * @new_bootversion: 0 or 1 for new bootversion * @new_deployments: (element-type OstreeDeployment): List of new deployments * @cancellable: Cancellable * @error: Error * - * Complete the deployment of @new_deployments by updating either the - * bootloader configuration (if @current_bootversion and the new - * version @new_bootversion differ), or swapping the bootlinks if - * they're the same. + * Assuming @new_deployments have already been deployed in place on + * disk, atomically update bootloader configuration. */ gboolean ostree_sysroot_write_deployments (OstreeSysroot *self, - int current_bootversion, - int new_bootversion, GPtrArray *new_deployments, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; guint i; + gboolean requires_new_bootversion = FALSE; gs_unref_object OstreeBootloader *bootloader = _ostree_sysroot_query_bootloader (self); + /* Determine whether or not we need to touch the bootloader + * configuration. If we have an equal number of deployments and + * more strongly an equal number of deployments per bootcsum, then + * we can just swap the subbootversion bootlinks. + */ + if (new_deployments->len != self->deployments->len) + requires_new_bootversion = TRUE; + else + { + GHashTableIter hashiter; + gpointer hkey, hvalue; + gs_unref_hashtable GHashTable *orig_bootcsum_to_count + = bootcsum_counts_for_deployment_list (self->deployments); + gs_unref_hashtable GHashTable *new_bootcsum_to_count + = bootcsum_counts_for_deployment_list (new_deployments); + + g_hash_table_iter_init (&hashiter, orig_bootcsum_to_count); + while (g_hash_table_iter_next (&hashiter, &hkey, &hvalue)) + { + guint orig_count = GPOINTER_TO_UINT (hvalue); + gpointer new_countp = g_hash_table_lookup (new_bootcsum_to_count, hkey); + guint new_count = GPOINTER_TO_UINT (new_countp); + + if (orig_count != new_count) + { + requires_new_bootversion = TRUE; + break; + } + } + } + if (bootloader) g_print ("Detected bootloader: %s\n", _ostree_bootloader_get_name (bootloader)); else g_print ("Detected bootloader: (unknown)\n"); - if (current_bootversion == new_bootversion) + if (!requires_new_bootversion) { if (!full_system_sync (cancellable, error)) { @@ -1021,7 +1062,7 @@ ostree_sysroot_write_deployments (OstreeSysroot *self, goto out; } - if (!swap_bootlinks (self, current_bootversion, + if (!swap_bootlinks (self, self->bootversion, new_deployments, cancellable, error)) { @@ -1031,6 +1072,7 @@ ostree_sysroot_write_deployments (OstreeSysroot *self, } else { + int new_bootversion = self->bootversion ? 0 : 1; for (i = 0; i < new_deployments->len; i++) { OstreeDeployment *deployment = new_deployments->pdata[i]; @@ -1059,12 +1101,12 @@ ostree_sysroot_write_deployments (OstreeSysroot *self, if (bootloader && !_ostree_bootloader_write_config (bootloader, new_bootversion, cancellable, error)) - { - g_prefix_error (error, "Bootloader write config: "); - goto out; - } + { + g_prefix_error (error, "Bootloader write config: "); + goto out; + } - if (!swap_bootloader (self, current_bootversion, new_bootversion, + if (!swap_bootloader (self, self->bootversion, new_bootversion, cancellable, error)) { g_prefix_error (error, "Final bootloader swap: "); @@ -1072,25 +1114,25 @@ ostree_sysroot_write_deployments (OstreeSysroot *self, } } + /* Now reload from disk */ + if (!ostree_sysroot_load (self, cancellable, error)) + goto out; + ret = TRUE; out: return ret; } /** - * ostree_sysroot_deploy: - * @current_bootversion: Active bootversion - * @current_deployments: (element-type OstreeDeployment): Active deployments + * ostree_sysroot_deploy_one_tree: + * @self: Sysroot * @osname: (allow-none): osname to use for merge deployment * @revision: Checksum to add * @origin: (allow-none): Origin to use for upgrades * @add_kernel_argv: (allow-none): Append these arguments to kernel configuration * @retain: If %TRUE, then do not delete earlier deployment - * @booted_deployment: (allow-none): Retain this deployment * @provided_merge_deployment: (allow-none): Use this deployment for merge path * @out_new_deployment: (out): The new deployment path - * @out_new_bootversion: (out): The new bootversion - * @out_new_deployments: (out) (element-type OstreeDeployment): Full list of new deployments * @cancellable: Cancellable * @error: Error * @@ -1098,21 +1140,16 @@ ostree_sysroot_write_deployments (OstreeSysroot *self, * then an earlier deployment will be garbage collected. */ gboolean -ostree_sysroot_deploy (OstreeSysroot *self, - int current_bootversion, - GPtrArray *current_deployments, - const char *osname, - const char *revision, - GKeyFile *origin, - char **add_kernel_argv, - gboolean retain, - OstreeDeployment *booted_deployment, - OstreeDeployment *provided_merge_deployment, - OstreeDeployment **out_new_deployment, - int *out_new_bootversion, - GPtrArray **out_new_deployments, - GCancellable *cancellable, - GError **error) +ostree_sysroot_deploy_one_tree (OstreeSysroot *self, + const char *osname, + const char *revision, + GKeyFile *origin, + char **add_kernel_argv, + gboolean retain, + OstreeDeployment *provided_merge_deployment, + OstreeDeployment **out_new_deployment, + GCancellable *cancellable, + GError **error) { gboolean ret = FALSE; OstreeDeployment *new_deployment; @@ -1125,7 +1162,11 @@ ostree_sysroot_deploy (OstreeSysroot *self, gs_free char *new_bootcsum = NULL; gs_unref_object OstreeBootconfigParser *bootconfig = NULL; gs_unref_ptrarray GPtrArray *new_deployments = NULL; - int new_bootversion; + + g_return_val_if_fail (osname != NULL || self->booted_deployment != NULL, FALSE); + + if (osname == NULL) + osname = ostree_deployment_get_osname (self->booted_deployment); if (!ostree_sysroot_get_repo (self, &repo, cancellable, error)) goto out; @@ -1168,20 +1209,18 @@ ostree_sysroot_deploy (OstreeSysroot *self, if (provided_merge_deployment != NULL) merge_deployment = g_object_ref (provided_merge_deployment); else - merge_deployment = ostree_sysroot_get_merge_deployment (current_deployments, osname, - booted_deployment); + merge_deployment = ostree_sysroot_get_merge_deployment (self, osname); - compute_new_deployment_list (current_bootversion, - current_deployments, osname, - booted_deployment, merge_deployment, + compute_new_deployment_list (self->bootversion, + self->deployments, osname, + self->booted_deployment, merge_deployment, retain, revision, new_bootcsum, - &new_deployments, - &new_bootversion); + &new_deployments); new_deployment = g_object_ref (new_deployments->pdata[0]); ostree_deployment_set_origin (new_deployment, origin); - print_deployment_diff (current_deployments, new_deployments); + print_deployment_diff (self->deployments, new_deployments); /* Check out the userspace tree onto the filesystem */ if (!checkout_deployment_tree (self, repo, new_deployment, &new_deployment_path, @@ -1238,8 +1277,7 @@ ostree_sysroot_deploy (OstreeSysroot *self, ostree_bootconfig_parser_set (bootconfig, "options", new_options); } - if (!ostree_sysroot_write_deployments (self, current_bootversion, new_bootversion, - new_deployments, cancellable, error)) + if (!ostree_sysroot_write_deployments (self, new_deployments, cancellable, error)) goto out; g_print ("Transaction complete, performing cleanup\n"); @@ -1269,8 +1307,6 @@ ostree_sysroot_deploy (OstreeSysroot *self, ret = TRUE; ot_transfer_out_value (out_new_deployment, &new_deployment); - *out_new_bootversion = new_bootversion; - ot_transfer_out_value (out_new_deployments, &new_deployments) out: return ret; } diff --git a/src/libostree/ostree-sysroot-private.h b/src/libostree/ostree-sysroot-private.h index f51b2bb8..682c3894 100644 --- a/src/libostree/ostree-sysroot-private.h +++ b/src/libostree/ostree-sysroot-private.h @@ -30,6 +30,13 @@ struct OstreeSysroot { GFile *path; int sysroot_fd; + + gboolean loaded; + + GPtrArray *deployments; + int bootversion; + int subbootversion; + OstreeDeployment *booted_deployment; }; gboolean @@ -39,6 +46,13 @@ _ostree_sysroot_read_boot_loader_configs (OstreeSysroot *self, GCancellable *cancellable, GError **error); +gboolean +_ostree_sysroot_read_current_subbootversion (OstreeSysroot *self, + int bootversion, + int *out_subbootversion, + GCancellable *cancellable, + GError **error); + gboolean _ostree_sysroot_parse_deploy_path_name (const char *name, char **out_csum, diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c index e7bc34f4..01d16172 100644 --- a/src/libostree/ostree-sysroot.c +++ b/src/libostree/ostree-sysroot.c @@ -27,6 +27,12 @@ #include "ostree-bootloader-uboot.h" #include "ostree-bootloader-syslinux.h" +static gboolean +find_booted_deployment (OstreeSysroot *self, + OstreeDeployment **out_deployment, + GCancellable *cancellable, + GError **error); + /** * SECTION:libostree-sysroot * @title: Root partition mount point @@ -193,7 +199,9 @@ _ostree_sysroot_get_devino (GFile *path, /** * ostree_sysroot_ensure_initialized: - * @self: + * @self: Sysroot + * @cancellable: Cancellable + * @error: Error * * Ensure that @self is set up as a valid rootfs, by creating * /ostree/repo, among other things. @@ -275,23 +283,12 @@ _ostree_sysroot_parse_deploy_path_name (const char *name, return ret; } - -/** - * ostree_sysroot_read_current_subbootversion: - * @self: Sysroot - * @bootversion: Current boot version - * @out_subbootversion: (out): The active subbootversion - * @cancellable: Cancellable - * @error: Error - * - * Determine the active subbootversion. - */ gboolean -ostree_sysroot_read_current_subbootversion (OstreeSysroot *self, - int bootversion, - int *out_subbootversion, - GCancellable *cancellable, - GError **error) +_ostree_sysroot_read_current_subbootversion (OstreeSysroot *self, + int bootversion, + int *out_subbootversion, + GCancellable *cancellable, + GError **error) { gboolean ret = FALSE; gs_unref_object GFile *ostree_dir = g_file_get_child (self->path, "ostree"); @@ -664,62 +661,117 @@ compare_deployments_by_boot_loader_version_reversed (gconstpointer a_pp, else return 1; } + /** - * ostree_sysroot_list_deployments: - * @sysroot: Sysroot - * @out_current_bootversion: (out): Current bootversion - * @out_deployments: (out) (element-type OstreeDeployment): Deployment list + * ostree_sysroot_load: + * @self: Sysroot * @cancellable: Cancellable * @error: Error * - * Enumerate all deployments, in the boot order. Also returns the - * active bootversion. + * Load deployment list, bootversion, and subbootversion from the + * rootfs @self. */ gboolean -ostree_sysroot_list_deployments (OstreeSysroot *self, - int *out_current_bootversion, - GPtrArray **out_deployments, - GCancellable *cancellable, - GError **error) +ostree_sysroot_load (OstreeSysroot *self, + GCancellable *cancellable, + GError **error) { gboolean ret = FALSE; - gs_unref_ptrarray GPtrArray *boot_loader_configs = NULL; - gs_unref_ptrarray GPtrArray *ret_deployments = NULL; guint i; - int bootversion = -1; + int bootversion; + int subbootversion; + gs_unref_ptrarray GPtrArray *boot_loader_configs = NULL; + gs_unref_ptrarray GPtrArray *deployments = NULL; + + g_clear_pointer (&self->deployments, g_ptr_array_unref); + g_clear_pointer (&self->booted_deployment, g_object_unref); + self->bootversion = -1; + self->subbootversion = -1; if (!read_current_bootversion (self, &bootversion, cancellable, error)) goto out; + if (!_ostree_sysroot_read_current_subbootversion (self, bootversion, &subbootversion, + cancellable, error)) + goto out; + if (!_ostree_sysroot_read_boot_loader_configs (self, bootversion, &boot_loader_configs, cancellable, error)) goto out; - ret_deployments = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref); + deployments = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref); for (i = 0; i < boot_loader_configs->len; i++) { OstreeBootconfigParser *config = boot_loader_configs->pdata[i]; - if (!list_deployments_process_one_boot_entry (self, config, ret_deployments, + if (!list_deployments_process_one_boot_entry (self, config, deployments, cancellable, error)) goto out; } - g_ptr_array_sort (ret_deployments, compare_deployments_by_boot_loader_version_reversed); - for (i = 0; i < ret_deployments->len; i++) + g_ptr_array_sort (deployments, compare_deployments_by_boot_loader_version_reversed); + for (i = 0; i < deployments->len; i++) { - OstreeDeployment *deployment = ret_deployments->pdata[i]; + OstreeDeployment *deployment = deployments->pdata[i]; ostree_deployment_set_index (deployment, i); } + if (!find_booted_deployment (self, &self->booted_deployment, + cancellable, error)) + goto out; + + self->bootversion = bootversion; + self->subbootversion = subbootversion; + self->deployments = deployments; + deployments = NULL; /* Transfer ownership */ + self->loaded = TRUE; + ret = TRUE; - *out_current_bootversion = bootversion; - gs_transfer_out_value (out_deployments, &ret_deployments); out: return ret; } +int +ostree_sysroot_get_bootversion (OstreeSysroot *self) +{ + return self->bootversion; +} + +int +ostree_sysroot_get_subbootversion (OstreeSysroot *self) +{ + return self->subbootversion; +} + +/** + * ostree_sysroot_get_booted_deployment: + * @self: Sysroot + * + * Returns: (transfer none): The currently booted deployment, or %NULL if none + */ +OstreeDeployment * +ostree_sysroot_get_booted_deployment (OstreeSysroot *self) +{ + return self->booted_deployment; +} + +/** + * ostree_sysroot_get_deployments: + * @self: Sysroot + * + * Returns: (element-type OstreeDeployment) (transfer full): Ordered list of deployments + */ +GPtrArray * +ostree_sysroot_get_deployments (OstreeSysroot *self) +{ + GPtrArray *copy = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref); + guint i; + for (i = 0; i < self->deployments->len; i++) + g_ptr_array_add (copy, g_object_ref (self->deployments->pdata[i])); + return copy; +} + /** * ostree_sysroot_get_deployment_directory: * @self: Sysroot @@ -740,8 +792,7 @@ ostree_sysroot_get_deployment_directory (OstreeSysroot *self, /** * ostree_sysroot_get_deployment_origin_path: - * @self: Sysroot - * @deployment: A deployment + * @deployment_path: A deployment path * * Returns: (transfer full): Path to deployment origin file */ @@ -754,7 +805,6 @@ ostree_sysroot_get_deployment_origin_path (GFile *deployment_path) gs_file_get_path_cached (deployment_path)); } - /** * ostree_sysroot_get_repo: * @self: Sysroot @@ -784,7 +834,6 @@ ostree_sysroot_get_repo (OstreeSysroot *self, return ret; } - /** * ostree_sysroot_query_bootloader: * @sysroot: Sysroot @@ -852,32 +901,19 @@ parse_kernel_commandline (OstreeOrderedHash **out_args, return ret; } -/** - * ostree_sysroot_find_booted_deployment: - * @target_sysroot: Root directory - * @deployments: (element-type OstreeDeployment): Loaded deployments - * @out_deployment: (out): The currently booted deployment - * @cancellable: - * @error: - * - * If the system is currently booted into a deployment in - * @deployments, set @out_deployment. Note that if @target_sysroot is - * not equal to "/", @out_deployment will always be set to %NULL. - */ -gboolean -ostree_sysroot_find_booted_deployment (OstreeSysroot *self, - GPtrArray *deployments, - OstreeDeployment **out_deployment, - GCancellable *cancellable, - GError **error) +static gboolean +find_booted_deployment (OstreeSysroot *self, + OstreeDeployment **out_deployment, + GCancellable *cancellable, + GError **error) { gboolean ret = FALSE; gs_unref_object GFile *active_root = g_file_new_for_path ("/"); - gs_unref_object OstreeSysroot *active_deployment_root = ostree_sysroot_new_default (); gs_unref_object OstreeDeployment *ret_deployment = NULL; if (g_file_equal (active_root, self->path)) { + gs_unref_object OstreeSysroot *active_deployment_root = ostree_sysroot_new_default (); guint i; const char *bootlink_arg; __attribute__((cleanup(_ostree_ordered_hash_cleanup))) OstreeOrderedHash *kernel_args = NULL; @@ -894,9 +930,9 @@ ostree_sysroot_find_booted_deployment (OstreeSysroot *self, bootlink_arg = g_hash_table_lookup (kernel_args->table, "ostree"); if (bootlink_arg) { - for (i = 0; i < deployments->len; i++) + for (i = 0; i < self->deployments->len; i++) { - OstreeDeployment *deployment = deployments->pdata[i]; + OstreeDeployment *deployment = self->deployments->pdata[i]; gs_unref_object GFile *deployment_path = ostree_sysroot_get_deployment_directory (active_deployment_root, deployment); guint32 device; guint64 inode; @@ -930,34 +966,6 @@ ostree_sysroot_find_booted_deployment (OstreeSysroot *self, return ret; } -gboolean -ostree_sysroot_require_deployment_or_osname (OstreeSysroot *sysroot, - GPtrArray *deployments, - const char *osname, - OstreeDeployment **out_deployment, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - gs_unref_object OstreeDeployment *ret_deployment = NULL; - - if (!ostree_sysroot_find_booted_deployment (sysroot, deployments, &ret_deployment, - cancellable, error)) - goto out; - - if (ret_deployment == NULL && osname == NULL) - { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Not currently booted into an OSTree system and no --os= argument given"); - goto out; - } - - ret = TRUE; - ot_transfer_out_value (out_deployment, &ret_deployment); - out: - return ret; -} - OstreeOrderedHash * _ostree_sysroot_parse_kernel_args (const char *options) { @@ -1040,27 +1048,34 @@ _ostree_sysroot_kernel_arg_string_serialize (OstreeOrderedHash *ohash) return g_string_free (buf, FALSE); } +/** + * ostree_sysroot_get_merge_deployment: + * @self: Sysroot + * @osname: (allow-none): Operating system group + * + * Find the deployment to use as a configuration merge source; this is + * the first one in the current deployment list which matches osname. + */ OstreeDeployment * -ostree_sysroot_get_merge_deployment (GPtrArray *deployments, - const char *osname, - OstreeDeployment *booted_deployment) +ostree_sysroot_get_merge_deployment (OstreeSysroot *self, + const char *osname) { - g_return_val_if_fail (osname != NULL || booted_deployment != NULL, NULL); + g_return_val_if_fail (osname != NULL || self->booted_deployment != NULL, NULL); if (osname == NULL) - osname = ostree_deployment_get_osname (booted_deployment); + osname = ostree_deployment_get_osname (self->booted_deployment); - if (booted_deployment && - g_strcmp0 (ostree_deployment_get_osname (booted_deployment), osname) == 0) + if (self->booted_deployment && + g_strcmp0 (ostree_deployment_get_osname (self->booted_deployment), osname) == 0) { - return g_object_ref (booted_deployment); + return g_object_ref (self->booted_deployment); } else { guint i; - for (i = 0; i < deployments->len; i++) + for (i = 0; i < self->deployments->len; i++) { - OstreeDeployment *deployment = deployments->pdata[i]; + OstreeDeployment *deployment = self->deployments->pdata[i]; if (strcmp (ostree_deployment_get_osname (deployment), osname) != 0) continue; diff --git a/src/libostree/ostree-sysroot.h b/src/libostree/ostree-sysroot.h index 9ae1fe8e..8ff9cfd5 100644 --- a/src/libostree/ostree-sysroot.h +++ b/src/libostree/ostree-sysroot.h @@ -40,21 +40,18 @@ OstreeSysroot* ostree_sysroot_new_default (void); GFile *ostree_sysroot_get_path (OstreeSysroot *self); +gboolean ostree_sysroot_load (OstreeSysroot *self, + GCancellable *cancellable, + GError **error); + gboolean ostree_sysroot_ensure_initialized (OstreeSysroot *self, GCancellable *cancellable, GError **error); -gboolean ostree_sysroot_read_current_subbootversion (OstreeSysroot *self, - int bootversion, - int *out_subbootversion, - GCancellable *cancellable, - GError **error); - -gboolean ostree_sysroot_list_deployments (OstreeSysroot *self, - int *out_bootversion, - GPtrArray **out_deployments, - GCancellable *cancellable, - GError **error); +int ostree_sysroot_get_bootversion (OstreeSysroot *self); +int ostree_sysroot_get_subbootversion (OstreeSysroot *self); +GPtrArray *ostree_sysroot_get_deployments (OstreeSysroot *self); +OstreeDeployment *ostree_sysroot_get_booted_deployment (OstreeSysroot *self); GFile *ostree_sysroot_get_deployment_directory (OstreeSysroot *self, OstreeDeployment *deployment); @@ -70,47 +67,24 @@ gboolean ostree_sysroot_get_repo (OstreeSysroot *self, GCancellable *cancellable, GError **error); - -gboolean ostree_sysroot_find_booted_deployment (OstreeSysroot *sysroot, - GPtrArray *deployments, - OstreeDeployment **out_deployment, - GCancellable *cancellable, - GError **error); - -gboolean ostree_sysroot_require_deployment_or_osname (OstreeSysroot *sysroot, - GPtrArray *deployment_list, - const char *osname, - OstreeDeployment **out_deployment, - GCancellable *cancellable, - GError **error); - gboolean ostree_sysroot_write_deployments (OstreeSysroot *self, - int current_bootversion, - int new_bootversion, GPtrArray *new_deployments, GCancellable *cancellable, GError **error); -gboolean ostree_sysroot_deploy (OstreeSysroot *self, - int current_bootversion, - GPtrArray *current_deployments, - const char *osname, - const char *revision, - GKeyFile *origin, - char **add_kernel_argv, - gboolean retain, - OstreeDeployment *booted_deployment, - OstreeDeployment *merge_deployment, - OstreeDeployment **out_new_deployment, - int *out_new_bootversion, - GPtrArray **out_new_deployments, - GCancellable *cancellable, - GError **error); +gboolean ostree_sysroot_deploy_one_tree (OstreeSysroot *self, + const char *osname, + const char *revision, + GKeyFile *origin, + char **add_kernel_argv, + gboolean retain, + OstreeDeployment *provided_merge_deployment, + OstreeDeployment **out_new_deployment, + GCancellable *cancellable, + GError **error); - -OstreeDeployment *ostree_sysroot_get_merge_deployment (GPtrArray *deployment_list, - const char *osname, - OstreeDeployment *booted_deployment); +OstreeDeployment *ostree_sysroot_get_merge_deployment (OstreeSysroot *self, + const char *osname); G_END_DECLS diff --git a/src/ostree/ot-admin-builtin-cleanup.c b/src/ostree/ot-admin-builtin-cleanup.c index db9c6673..015dfe7a 100644 --- a/src/ostree/ot-admin-builtin-cleanup.c +++ b/src/ostree/ot-admin-builtin-cleanup.c @@ -46,6 +46,9 @@ ot_admin_builtin_cleanup (int argc, char **argv, OstreeSysroot *sysroot, GCancel if (!g_option_context_parse (context, &argc, &argv, error)) goto out; + if (!ostree_sysroot_load (sysroot, cancellable, error)) + goto out; + if (!ostree_sysroot_cleanup (sysroot, cancellable, error)) goto out; diff --git a/src/ostree/ot-admin-builtin-deploy.c b/src/ostree/ot-admin-builtin-deploy.c index 6e5cc601..9761f864 100644 --- a/src/ostree/ot-admin-builtin-deploy.c +++ b/src/ostree/ot-admin-builtin-deploy.c @@ -51,13 +51,9 @@ ot_admin_builtin_deploy (int argc, char **argv, OstreeSysroot *sysroot, GCancell const char *refspec; GOptionContext *context; GKeyFile *origin = NULL; - int current_bootversion; - int new_bootversion; gs_unref_object OstreeRepo *repo = NULL; - gs_unref_ptrarray GPtrArray *current_deployments = NULL; gs_unref_ptrarray GPtrArray *new_deployments = NULL; gs_unref_object OstreeDeployment *new_deployment = NULL; - gs_unref_object OstreeDeployment *booted_deployment = NULL; gs_free char *revision = NULL; context = g_option_context_new ("REFSPEC - Checkout revision REFSPEC as the new default deployment"); @@ -75,23 +71,17 @@ ot_admin_builtin_deploy (int argc, char **argv, OstreeSysroot *sysroot, GCancell refspec = argv[1]; - if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error)) + if (!ostree_sysroot_load (sysroot, cancellable, error)) goto out; - if (!ostree_sysroot_list_deployments (sysroot, ¤t_bootversion, ¤t_deployments, - cancellable, error)) - { - g_prefix_error (error, "While listing deployments: "); - goto out; - } + if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error)) + goto out; /* Find the currently booted deployment, if any; we will ensure it * is present in the new deployment list. */ - if (!ostree_sysroot_require_deployment_or_osname (sysroot, current_deployments, - opt_osname, - &booted_deployment, - cancellable, error)) + if (!ot_admin_require_booted_deployment_or_osname (sysroot, opt_osname, + cancellable, error)) { g_prefix_error (error, "Looking for booted deployment: "); goto out; @@ -112,12 +102,12 @@ ot_admin_builtin_deploy (int argc, char **argv, OstreeSysroot *sysroot, GCancell if (!ostree_repo_resolve_rev (repo, refspec, FALSE, &revision, error)) goto out; - if (!ostree_sysroot_deploy (sysroot, current_bootversion, current_deployments, - opt_osname, revision, origin, - opt_kernel_argv, opt_retain, - booted_deployment, NULL, - &new_deployment, &new_bootversion, &new_deployments, - cancellable, error)) + if (!ostree_sysroot_deploy_one_tree (sysroot, + opt_osname, revision, origin, + opt_kernel_argv, opt_retain, + NULL, + &new_deployment, + cancellable, error)) goto out; ret = TRUE; diff --git a/src/ostree/ot-admin-builtin-diff.c b/src/ostree/ot-admin-builtin-diff.c index 8c543928..7497e1a5 100644 --- a/src/ostree/ot-admin-builtin-diff.c +++ b/src/ostree/ot-admin-builtin-diff.c @@ -46,10 +46,8 @@ ot_admin_builtin_diff (int argc, char **argv, OstreeSysroot *sysroot, GCancellab gs_unref_ptrarray GPtrArray *modified = NULL; gs_unref_ptrarray GPtrArray *removed = NULL; gs_unref_ptrarray GPtrArray *added = NULL; - gs_unref_ptrarray GPtrArray *deployments = NULL; gs_unref_object GFile *orig_etc_path = NULL; gs_unref_object GFile *new_etc_path = NULL; - int bootversion; context = g_option_context_new ("Diff current /etc configuration versus default"); @@ -58,27 +56,24 @@ ot_admin_builtin_diff (int argc, char **argv, OstreeSysroot *sysroot, GCancellab if (!g_option_context_parse (context, &argc, &argv, error)) goto out; - if (!ostree_sysroot_list_deployments (sysroot, &bootversion, &deployments, - cancellable, error)) - { - g_prefix_error (error, "While listing deployments: "); - goto out; - } - - if (!ostree_sysroot_require_deployment_or_osname (sysroot, deployments, - opt_osname, &deployment, - cancellable, error)) + if (!ostree_sysroot_load (sysroot, cancellable, error)) goto out; - if (deployment != NULL) - opt_osname = (char*)ostree_deployment_get_osname (deployment); - if (deployment == NULL) - deployment = ostree_sysroot_get_merge_deployment (deployments, opt_osname, deployment); - if (deployment == NULL) + + if (!ot_admin_require_booted_deployment_or_osname (sysroot, opt_osname, + cancellable, error)) + goto out; + if (opt_osname != NULL) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, - "No deployment for OS '%s'", opt_osname); - goto out; + deployment = ostree_sysroot_get_merge_deployment (sysroot, opt_osname); + if (deployment == NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "No deployment for OS '%s'", opt_osname); + goto out; + } } + else + deployment = g_object_ref (ostree_sysroot_get_booted_deployment (sysroot)); deployment_dir = ostree_sysroot_get_deployment_directory (sysroot, deployment); diff --git a/src/ostree/ot-admin-builtin-status.c b/src/ostree/ot-admin-builtin-status.c index c561eaf0..1f7801f5 100644 --- a/src/ostree/ot-admin-builtin-status.c +++ b/src/ostree/ot-admin-builtin-status.c @@ -38,8 +38,7 @@ ot_admin_builtin_status (int argc, char **argv, OstreeSysroot *sysroot, GCancell { GOptionContext *context; gboolean ret = FALSE; - int bootversion; - gs_unref_object OstreeDeployment *booted_deployment = NULL; + OstreeDeployment *booted_deployment = NULL; gs_unref_ptrarray GPtrArray *deployments = NULL; guint i; @@ -50,31 +49,18 @@ ot_admin_builtin_status (int argc, char **argv, OstreeSysroot *sysroot, GCancell if (!g_option_context_parse (context, &argc, &argv, error)) goto out; - if (!ostree_sysroot_list_deployments (sysroot, &bootversion, &deployments, - cancellable, error)) - { - g_prefix_error (error, "While listing deployments: "); - goto out; - } - - if (!ostree_sysroot_find_booted_deployment (sysroot, deployments, - &booted_deployment, - cancellable, error)) + if (!ostree_sysroot_load (sysroot, cancellable, error)) goto out; + deployments = ostree_sysroot_get_deployments (sysroot); + booted_deployment = ostree_sysroot_get_booted_deployment (sysroot); + if (deployments->len == 0) { g_print ("No deployments.\n"); } else { - int subbootversion; - - if (!ostree_sysroot_read_current_subbootversion (sysroot, bootversion, - &subbootversion, - cancellable, error)) - goto out; - for (i = 0; i < deployments->len; i++) { OstreeDeployment *deployment = deployments->pdata[i]; diff --git a/src/ostree/ot-admin-builtin-undeploy.c b/src/ostree/ot-admin-builtin-undeploy.c index 1de2a6c2..055209db 100644 --- a/src/ostree/ot-admin-builtin-undeploy.c +++ b/src/ostree/ot-admin-builtin-undeploy.c @@ -38,7 +38,6 @@ ot_admin_builtin_undeploy (int argc, char **argv, OstreeSysroot *sysroot, GCance GOptionContext *context; const char *deploy_index_str; int deploy_index; - int current_bootversion; gs_unref_ptrarray GPtrArray *current_deployments = NULL; gs_unref_object OstreeDeployment *booted_deployment = NULL; gs_unref_object OstreeDeployment *target_deployment = NULL; @@ -56,20 +55,13 @@ ot_admin_builtin_undeploy (int argc, char **argv, OstreeSysroot *sysroot, GCance goto out; } + if (!ostree_sysroot_load (sysroot, cancellable, error)) + goto out; + current_deployments = ostree_sysroot_get_deployments (sysroot); + deploy_index_str = argv[1]; deploy_index = atoi (deploy_index_str); - if (!ostree_sysroot_list_deployments (sysroot, ¤t_bootversion, ¤t_deployments, - cancellable, error)) - { - g_prefix_error (error, "While listing deployments: "); - goto out; - } - - if (!ostree_sysroot_find_booted_deployment (sysroot, current_deployments, &booted_deployment, - cancellable, error)) - goto out; - if (deploy_index < 0) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, @@ -84,7 +76,7 @@ ot_admin_builtin_undeploy (int argc, char **argv, OstreeSysroot *sysroot, GCance } target_deployment = g_object_ref (current_deployments->pdata[deploy_index]); - if (target_deployment == booted_deployment) + if (target_deployment == ostree_sysroot_get_booted_deployment (sysroot)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "Cannot undeploy currently booted deployment %i", deploy_index); @@ -93,8 +85,7 @@ ot_admin_builtin_undeploy (int argc, char **argv, OstreeSysroot *sysroot, GCance g_ptr_array_remove_index (current_deployments, deploy_index); - if (!ostree_sysroot_write_deployments (sysroot, current_bootversion, - current_bootversion ? 0 : 1, current_deployments, + if (!ostree_sysroot_write_deployments (sysroot, current_deployments, cancellable, error)) goto out; diff --git a/src/ostree/ot-admin-builtin-upgrade.c b/src/ostree/ot-admin-builtin-upgrade.c index 563b14be..045d1329 100644 --- a/src/ostree/ot-admin-builtin-upgrade.c +++ b/src/ostree/ot-admin-builtin-upgrade.c @@ -53,13 +53,8 @@ ot_admin_builtin_upgrade (int argc, char **argv, OstreeSysroot *sysroot, GCancel gs_free char *new_revision = NULL; gs_unref_object GFile *deployment_path = NULL; gs_unref_object GFile *deployment_origin_path = NULL; - gs_unref_object OstreeDeployment *booted_deployment = NULL; gs_unref_object OstreeDeployment *merge_deployment = NULL; - gs_unref_ptrarray GPtrArray *current_deployments = NULL; - gs_unref_ptrarray GPtrArray *new_deployments = NULL; gs_unref_object OstreeDeployment *new_deployment = NULL; - int current_bootversion; - int new_bootversion; GKeyFile *origin; context = g_option_context_new ("Construct new tree from current origin and deploy it, if it changed"); @@ -68,23 +63,15 @@ ot_admin_builtin_upgrade (int argc, char **argv, OstreeSysroot *sysroot, GCancel if (!g_option_context_parse (context, &argc, &argv, error)) goto out; - if (!ostree_sysroot_list_deployments (sysroot, ¤t_bootversion, - ¤t_deployments, - cancellable, error)) - { - g_prefix_error (error, "While listing deployments: "); - goto out; - } + if (!ostree_sysroot_load (sysroot, cancellable, error)) + goto out; - if (!ostree_sysroot_require_deployment_or_osname (sysroot, current_deployments, - opt_osname, - &booted_deployment, - cancellable, error)) + if (!ot_admin_require_booted_deployment_or_osname (sysroot, opt_osname, + cancellable, error)) goto out; if (!opt_osname) - opt_osname = (char*)ostree_deployment_get_osname (booted_deployment); - merge_deployment = ostree_sysroot_get_merge_deployment (current_deployments, opt_osname, - booted_deployment); + opt_osname = (char*)ostree_deployment_get_osname (ostree_sysroot_get_booted_deployment (sysroot)); + merge_deployment = ostree_sysroot_get_merge_deployment (sysroot, opt_osname); deployment_path = ostree_sysroot_get_deployment_directory (sysroot, merge_deployment); deployment_origin_path = ostree_sysroot_get_deployment_origin_path (deployment_path); @@ -131,13 +118,12 @@ ot_admin_builtin_upgrade (int argc, char **argv, OstreeSysroot *sysroot, GCancel else { gs_unref_object GFile *real_sysroot = g_file_new_for_path ("/"); - if (!ostree_sysroot_deploy (sysroot, - current_bootversion, current_deployments, - opt_osname, new_revision, origin, - NULL, FALSE, - booted_deployment, merge_deployment, - &new_deployment, &new_bootversion, &new_deployments, - cancellable, error)) + if (!ostree_sysroot_deploy_one_tree (sysroot, + opt_osname, new_revision, origin, + NULL, FALSE, + merge_deployment, + &new_deployment, + cancellable, error)) goto out; if (opt_reboot && g_file_equal (ostree_sysroot_get_path (sysroot), real_sysroot)) diff --git a/src/ostree/ot-admin-functions.c b/src/ostree/ot-admin-functions.c index c72c15b5..90f3a4ec 100644 --- a/src/ostree/ot-admin-functions.c +++ b/src/ostree/ot-admin-functions.c @@ -34,3 +34,25 @@ ot_origin_new_from_refspec (const char *refspec) g_key_file_set_string (ret, "origin", "refspec", refspec); return ret; } + +gboolean +ot_admin_require_booted_deployment_or_osname (OstreeSysroot *sysroot, + const char *osname, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + OstreeDeployment *booted_deployment = + ostree_sysroot_get_booted_deployment (sysroot); + + if (booted_deployment == NULL && osname == NULL) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Not currently booted into an OSTree system and no --os= argument given"); + goto out; + } + + ret = TRUE; + out: + return ret; +} diff --git a/src/ostree/ot-admin-functions.h b/src/ostree/ot-admin-functions.h index 189974f6..8b9758d6 100644 --- a/src/ostree/ot-admin-functions.h +++ b/src/ostree/ot-admin-functions.h @@ -29,5 +29,11 @@ G_BEGIN_DECLS GKeyFile *ot_origin_new_from_refspec (const char *refspec); +gboolean +ot_admin_require_booted_deployment_or_osname (OstreeSysroot *sysroot, + const char *osname, + GCancellable *cancellable, + GError **error); + G_END_DECLS