gboolean ot_admin_builtin_diff (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError **error) { GOptionContext *context; gboolean ret = FALSE; gs_unref_object OstreeDeployment *deployment = NULL; gs_unref_object GFile *deployment_dir = NULL; gs_unref_ptrarray GPtrArray *modified = NULL; gs_unref_ptrarray GPtrArray *removed = NULL; gs_unref_ptrarray GPtrArray *added = NULL; gs_unref_object GFile *orig_etc_path = NULL; gs_unref_object GFile *new_etc_path = NULL; context = g_option_context_new ("Diff current /etc configuration versus default"); g_option_context_add_main_entries (context, options, NULL); if (!g_option_context_parse (context, &argc, &argv, error)) goto out; if (!ostree_sysroot_load (sysroot, cancellable, error)) goto out; if (!ot_admin_require_booted_deployment_or_osname (sysroot, opt_osname, cancellable, error)) goto out; if (opt_osname != NULL) { 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); orig_etc_path = g_file_resolve_relative_path (deployment_dir, "usr/etc"); new_etc_path = g_file_resolve_relative_path (deployment_dir, "etc"); modified = g_ptr_array_new_with_free_func ((GDestroyNotify) ostree_diff_item_unref); removed = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); added = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); if (!ostree_diff_dirs (OSTREE_DIFF_FLAGS_IGNORE_XATTRS, orig_etc_path, new_etc_path, modified, removed, added, cancellable, error)) goto out; ostree_diff_print (orig_etc_path, new_etc_path, modified, removed, added); ret = TRUE; out: if (context) g_option_context_free (context); return ret; }
gint rpmostreed_rollback_deployment_index (const gchar *name, OstreeSysroot *ot_sysroot, GError **error) { g_autoptr(GPtrArray) deployments = NULL; glnx_unref_object OstreeDeployment *merge_deployment = NULL; gint index_to_prepend = -1; gint merge_index = -1; gint previous_index = -1; guint i; merge_deployment = ostree_sysroot_get_merge_deployment (ot_sysroot, name); if (merge_deployment == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "No deployments found for os %s", name); goto out; } deployments = ostree_sysroot_get_deployments (ot_sysroot); if (deployments->len < 2) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Found %u deployments, at least 2 required for rollback", deployments->len); goto out; } g_assert (merge_deployment != NULL); for (i = 0; i < deployments->len; i++) { if (deployments->pdata[i] == merge_deployment) merge_index = i; if (g_strcmp0 (ostree_deployment_get_osname (deployments->pdata[i]), name) == 0 && deployments->pdata[i] != merge_deployment && previous_index < 0) { previous_index = i; } } g_assert (merge_index < deployments->len); g_assert (deployments->pdata[merge_index] == merge_deployment); /* If merge deployment is not booted assume we are using it. */ if (merge_index == 0 && previous_index > 0) index_to_prepend = previous_index; else index_to_prepend = merge_index; out: return index_to_prepend; }
gboolean ot_admin_builtin_deploy (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; const char *refspec; GOptionContext *context; GKeyFile *origin = NULL; gs_unref_object OstreeRepo *repo = NULL; gs_unref_ptrarray GPtrArray *new_deployments = NULL; gs_unref_object OstreeDeployment *new_deployment = NULL; gs_unref_object OstreeDeployment *merge_deployment = NULL; gs_free char *revision = NULL; __attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL; context = g_option_context_new ("REFSPEC - Checkout revision REFSPEC as the new default deployment"); g_option_context_add_main_entries (context, options, NULL); if (!g_option_context_parse (context, &argc, &argv, error)) goto out; if (argc < 2) { ot_util_usage_error (context, "REF/REV must be specified", error); goto out; } refspec = argv[1]; if (!ostree_sysroot_load (sysroot, cancellable, error)) 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 (!ot_admin_require_booted_deployment_or_osname (sysroot, opt_osname, cancellable, error)) { g_prefix_error (error, "Looking for booted deployment: "); goto out; } if (opt_origin_path) { origin = g_key_file_new (); if (!g_key_file_load_from_file (origin, opt_origin_path, 0, error)) goto out; } else { origin = ostree_sysroot_origin_new_from_refspec (sysroot, refspec); } if (!ostree_repo_resolve_rev (repo, refspec, FALSE, &revision, error)) goto out; merge_deployment = ostree_sysroot_get_merge_deployment (sysroot, opt_osname); /* Here we perform cleanup of any leftover data from previous * partial failures. This avoids having to call gs_shutil_rm_rf() * at random points throughout the process. * * TODO: Add /ostree/transaction file, and only do this cleanup if * we find it. */ if (!ostree_sysroot_cleanup (sysroot, cancellable, error)) { g_prefix_error (error, "Performing initial cleanup: "); goto out; } kargs = _ostree_kernel_args_new (); /* If they want the current kernel's args, they very likely don't * want the ones from the merge. */ if (opt_kernel_proc_cmdline) { gs_unref_object GFile *proc_cmdline_path = g_file_new_for_path ("/proc/cmdline"); gs_free char *proc_cmdline = NULL; gsize proc_cmdline_len = 0; gs_strfreev char **proc_cmdline_args = NULL; if (!g_file_load_contents (proc_cmdline_path, cancellable, &proc_cmdline, &proc_cmdline_len, NULL, error)) goto out; g_strchomp (proc_cmdline); proc_cmdline_args = g_strsplit (proc_cmdline, " ", -1); _ostree_kernel_args_replace_argv (kargs, proc_cmdline_args); } else if (merge_deployment) { OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (merge_deployment); gs_strfreev char **previous_args = g_strsplit (ostree_bootconfig_parser_get (bootconfig, "options"), " ", -1); _ostree_kernel_args_replace_argv (kargs, previous_args); } if (opt_kernel_argv) { _ostree_kernel_args_replace_argv (kargs, opt_kernel_argv); } if (opt_kernel_argv_append) { _ostree_kernel_args_append_argv (kargs, opt_kernel_argv_append); } { gs_strfreev char **kargs_strv = _ostree_kernel_args_to_strv (kargs); if (!ostree_sysroot_deploy_tree (sysroot, opt_osname, revision, origin, merge_deployment, kargs_strv, &new_deployment, cancellable, error)) goto out; } if (!ostree_sysroot_simple_write_deployment (sysroot, opt_osname, new_deployment, merge_deployment, opt_retain ? OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN : 0, cancellable, error)) goto out; ret = TRUE; out: if (origin) g_key_file_unref (origin); if (context) g_option_context_free (context); return ret; }
static gboolean package_diff_transaction_execute (RpmostreedTransaction *transaction, GCancellable *cancellable, GError **error) { PackageDiffTransaction *self; OstreeSysroot *sysroot; glnx_unref_object RpmOstreeSysrootUpgrader *upgrader = NULL; glnx_unref_object OstreeAsyncProgress *progress = NULL; glnx_unref_object OstreeRepo *repo = NULL; glnx_unref_object OstreeDeployment *merge_deployment = NULL; g_autofree gchar *origin_description = NULL; RpmOstreeSysrootUpgraderFlags upgrader_flags = 0; gboolean upgrading = FALSE; gboolean changed = FALSE; gboolean ret = FALSE; self = (PackageDiffTransaction *) transaction; if (self->revision != NULL || self->refspec == NULL) upgrader_flags |= RPMOSTREE_SYSROOT_UPGRADER_FLAGS_ALLOW_OLDER; sysroot = rpmostreed_transaction_get_sysroot (transaction); upgrader = rpmostree_sysroot_upgrader_new (sysroot, self->osname, upgrader_flags, cancellable, error); if (upgrader == NULL) goto out; if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error)) goto out; merge_deployment = ostree_sysroot_get_merge_deployment (sysroot, self->osname); /* Determine if we're upgrading before we set the refspec. */ upgrading = (self->refspec == NULL && self->revision == NULL); if (self->refspec != NULL) { if (!change_upgrader_refspec (sysroot, upgrader, self->refspec, cancellable, NULL, NULL, error)) goto out; } else { self->refspec = g_strdup (rpmostree_sysroot_upgrader_get_refspec (upgrader)); if (!self->refspec) { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Booted deployment has no origin"); goto out; } } progress = ostree_async_progress_new (); rpmostreed_transaction_connect_download_progress (transaction, progress); rpmostreed_transaction_connect_signature_progress (transaction, repo); if (self->revision != NULL) { g_autofree char *checksum = NULL; g_autofree char *version = NULL; if (!rpmostreed_parse_revision (self->revision, &checksum, &version, error)) goto out; if (version != NULL) { rpmostreed_transaction_emit_message_printf (transaction, "Resolving version '%s'", version); if (!rpmostreed_repo_lookup_version (repo, self->refspec, version, progress, cancellable, &checksum, error)) goto out; } rpmostree_sysroot_upgrader_set_origin_override (upgrader, checksum); } else if (upgrading) { rpmostree_sysroot_upgrader_set_origin_override (upgrader, NULL); } origin_description = rpmostree_sysroot_upgrader_get_origin_description (upgrader); if (origin_description != NULL) rpmostreed_transaction_emit_message_printf (transaction, "Updating from: %s", origin_description); if (!rpmostree_sysroot_upgrader_pull (upgrader, "/usr/share/rpm", 0, progress, &changed, cancellable, error)) goto out; rpmostree_transaction_emit_progress_end (RPMOSTREE_TRANSACTION (transaction)); if (!changed) { if (upgrading) rpmostreed_transaction_emit_message_printf (transaction, "No upgrade available."); else rpmostreed_transaction_emit_message_printf (transaction, "No change."); } ret = TRUE; out: return ret; }