daemon: Make parts of cli use the daemon
This commit is contained in:
parent
0114507865
commit
f525730187
@ -31,6 +31,8 @@ rpm_ostree_SOURCES = src/app/main.c \
|
||||
src/app/rpmostree-db-builtin-diff.c \
|
||||
src/app/rpmostree-db-builtin-list.c \
|
||||
src/app/rpmostree-db-builtin-version.c \
|
||||
src/app/rpmostree-dbus-helpers.c \
|
||||
src/app/rpmostree-dbus-helpers.h \
|
||||
src/app/rpmostree-libbuiltin.c \
|
||||
src/app/rpmostree-libbuiltin.h \
|
||||
$(NULL)
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <glib-unix.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
@ -124,17 +125,28 @@ rpmostree_print_gpg_verify_result (OstreeGpgVerifyResult *result)
|
||||
g_string_free (buffer, TRUE);
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
on_sigint (gpointer user_data)
|
||||
{
|
||||
GCancellable *cancellable = user_data;
|
||||
g_debug ("Caught signal. Canceling");
|
||||
g_cancellable_cancel (cancellable);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char **argv)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GCancellable *cancellable = NULL;
|
||||
GCancellable *cancellable = g_cancellable_new ();
|
||||
RpmOstreeCommand *command;
|
||||
int in, out;
|
||||
const char *command_name = NULL;
|
||||
gs_free char *prgname = NULL;
|
||||
|
||||
|
||||
/* avoid gvfs (http://bugzilla.gnome.org/show_bug.cgi?id=526454) */
|
||||
g_setenv ("GIO_USE_VFS", "local", TRUE);
|
||||
g_set_prgname (argv[0]);
|
||||
@ -169,6 +181,10 @@ main (int argc,
|
||||
|
||||
argc = out;
|
||||
|
||||
g_unix_signal_add (SIGINT, on_sigint, cancellable);
|
||||
g_unix_signal_add (SIGTERM, on_sigint, cancellable);
|
||||
g_unix_signal_add (SIGHUP, on_sigint, cancellable);
|
||||
|
||||
/* Keep the "rpm" command working for backward-compatibility. */
|
||||
if (g_strcmp0 (command_name, "rpm") == 0)
|
||||
command_name = "db";
|
||||
@ -228,6 +244,7 @@ main (int argc,
|
||||
prefix = "\x1b[31m\x1b[1m"; /* red, bold */
|
||||
suffix = "\x1b[22m\x1b[0m"; /* bold off, color reset */
|
||||
}
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_printerr ("%serror: %s%s\n", prefix, suffix, error->message);
|
||||
g_error_free (error);
|
||||
return 1;
|
||||
|
@ -26,18 +26,37 @@
|
||||
#include "rpmostree-builtins.h"
|
||||
#include "rpmostree-util.h"
|
||||
#include "rpmostree-libbuiltin.h"
|
||||
#include "rpmostree-dbus-helpers.h"
|
||||
|
||||
#include "libgsystem.h"
|
||||
#include <libglnx.h>
|
||||
|
||||
static char *opt_sysroot = "/";
|
||||
static char *opt_osname;
|
||||
static gboolean opt_reboot;
|
||||
static gboolean opt_skip_purge;
|
||||
static gboolean opt_force_peer;
|
||||
|
||||
static GOptionEntry option_entries[] = {
|
||||
{ "sysroot", 0, 0, G_OPTION_ARG_STRING, &opt_sysroot, "Use system root SYSROOT (default: /)", "SYSROOT" },
|
||||
{ "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Operate on provided OSNAME", "OSNAME" },
|
||||
{ "reboot", 'r', 0, G_OPTION_ARG_NONE, &opt_reboot, "Initiate a reboot after rebase is finished", NULL },
|
||||
{ "skip-purge", 0, 0, G_OPTION_ARG_NONE, &opt_skip_purge, "Keep previous refspec after rebase", NULL },
|
||||
{ "peer", 0, 0, G_OPTION_ARG_NONE, &opt_force_peer, "Force a peer to peer connection instead of using the system message bus", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static GVariant *
|
||||
get_args_variant (void)
|
||||
{
|
||||
GVariantDict dict;
|
||||
|
||||
g_variant_dict_init (&dict, NULL);
|
||||
g_variant_dict_insert (&dict, "skip-purge", "b", opt_skip_purge);
|
||||
|
||||
return g_variant_dict_end (&dict);
|
||||
}
|
||||
|
||||
gboolean
|
||||
rpmostree_builtin_rebase (int argc,
|
||||
char **argv,
|
||||
@ -45,129 +64,73 @@ rpmostree_builtin_rebase (int argc,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GOptionContext *context = g_option_context_new ("REFSPEC - Switch to a different tree");
|
||||
gboolean is_peer = FALSE;
|
||||
const char *new_provided_refspec;
|
||||
gs_unref_object OstreeSysroot *sysroot = NULL;
|
||||
gs_unref_object OstreeRepo *repo = NULL;
|
||||
gs_free char *origin_refspec = NULL;
|
||||
gs_free char *origin_remote = NULL;
|
||||
gs_free char *origin_ref = NULL;
|
||||
gs_free char *new_remote = NULL;
|
||||
gs_free char *new_ref = NULL;
|
||||
gs_free char *new_refspec = NULL;
|
||||
gs_unref_object GFile *sysroot_path = NULL;
|
||||
gs_unref_object OstreeSysrootUpgrader *upgrader = NULL;
|
||||
gs_unref_object OstreeAsyncProgress *progress = NULL;
|
||||
gboolean changed;
|
||||
GSConsole *console = NULL;
|
||||
gs_unref_keyfile GKeyFile *old_origin = NULL;
|
||||
gs_unref_keyfile GKeyFile *new_origin = NULL;
|
||||
|
||||
|
||||
/* forced blank for now */
|
||||
const char *packages[] = { NULL };
|
||||
|
||||
GOptionContext *context = g_option_context_new ("REFSPEC - Switch to a different tree");
|
||||
glnx_unref_object GDBusConnection *connection = NULL;
|
||||
glnx_unref_object RPMOSTreeOS *os_proxy = NULL;
|
||||
glnx_unref_object RPMOSTreeSysroot *sysroot_proxy = NULL;
|
||||
g_autofree char *transaction_object_path = NULL;
|
||||
|
||||
if (!rpmostree_option_context_parse (context, option_entries, &argc, &argv, error))
|
||||
goto out;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"REFSPEC must be specified");
|
||||
goto out;
|
||||
}
|
||||
if (!rpmostree_load_connection_and_sysroot (opt_sysroot,
|
||||
opt_force_peer,
|
||||
cancellable,
|
||||
&connection,
|
||||
&sysroot_proxy,
|
||||
&is_peer,
|
||||
error))
|
||||
goto out;
|
||||
|
||||
if (!rpmostree_load_os_proxy (sysroot_proxy, opt_osname, is_peer,
|
||||
cancellable, &os_proxy, error))
|
||||
goto out;
|
||||
|
||||
new_provided_refspec = argv[1];
|
||||
|
||||
sysroot_path = g_file_new_for_path (opt_sysroot);
|
||||
sysroot = ostree_sysroot_new (sysroot_path);
|
||||
if (!ostree_sysroot_load (sysroot, cancellable, error))
|
||||
if (!rpmostree_os_call_rebase_sync (os_proxy,
|
||||
get_args_variant (),
|
||||
new_provided_refspec,
|
||||
packages,
|
||||
&transaction_object_path,
|
||||
cancellable,
|
||||
error))
|
||||
goto out;
|
||||
|
||||
upgrader = ostree_sysroot_upgrader_new_for_os_with_flags (sysroot, opt_osname,
|
||||
OSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED,
|
||||
cancellable, error);
|
||||
if (!upgrader)
|
||||
if (!rpmostree_transaction_get_response_sync (connection,
|
||||
transaction_object_path,
|
||||
cancellable,
|
||||
error))
|
||||
goto out;
|
||||
|
||||
old_origin = ostree_sysroot_upgrader_get_origin (upgrader);
|
||||
origin_refspec = g_key_file_get_string (old_origin, "origin", "refspec", NULL);
|
||||
|
||||
if (!ostree_parse_refspec (origin_refspec, &origin_remote, &origin_ref, error))
|
||||
goto out;
|
||||
|
||||
/* Allow just switching remotes */
|
||||
if (g_str_has_suffix (new_provided_refspec, ":"))
|
||||
if (!opt_reboot)
|
||||
{
|
||||
new_remote = g_strdup (new_provided_refspec);
|
||||
new_remote[strlen(new_remote)-1] = '\0';
|
||||
new_ref = g_strdup (origin_ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ostree_parse_refspec (new_provided_refspec, &new_remote, &new_ref, error))
|
||||
// by request, doing this without dbus
|
||||
if (!rpmostree_print_treepkg_diff_from_sysroot_path (opt_sysroot,
|
||||
cancellable,
|
||||
error))
|
||||
goto out;
|
||||
|
||||
g_print ("Run \"systemctl reboot\" to start a reboot\n");
|
||||
}
|
||||
|
||||
if (!new_remote)
|
||||
new_refspec = g_strconcat (origin_remote, ":", new_ref, NULL);
|
||||
else
|
||||
new_refspec = g_strconcat (new_remote, ":", new_ref, NULL);
|
||||
|
||||
if (strcmp (origin_refspec, new_refspec) == 0)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Old and new refs are equal: %s", new_refspec);
|
||||
goto out;
|
||||
gs_subprocess_simple_run_sync (NULL, GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT,
|
||||
cancellable, error,
|
||||
"systemctl", "reboot", NULL);
|
||||
}
|
||||
|
||||
new_origin = ostree_sysroot_origin_new_from_refspec (sysroot, new_refspec);
|
||||
if (!ostree_sysroot_upgrader_set_origin (upgrader, new_origin, cancellable, error))
|
||||
goto out;
|
||||
|
||||
console = gs_console_get ();
|
||||
if (console)
|
||||
{
|
||||
gs_console_begin_status_line (console, "", NULL, NULL);
|
||||
progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, console);
|
||||
}
|
||||
|
||||
/* Always allow older...there's not going to be a chronological
|
||||
* relationship necessarily.
|
||||
*/
|
||||
if (!ostree_sysroot_upgrader_pull (upgrader, 0,
|
||||
OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER,
|
||||
progress, &changed,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (console)
|
||||
{
|
||||
if (!gs_console_end_status_line (console, cancellable, error))
|
||||
{
|
||||
console = NULL;
|
||||
goto out;
|
||||
}
|
||||
console = NULL;
|
||||
}
|
||||
|
||||
if (!ostree_sysroot_upgrader_deploy (upgrader, cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error))
|
||||
goto out;
|
||||
|
||||
g_print ("Deleting ref '%s:%s'\n", origin_remote, origin_ref);
|
||||
ostree_repo_transaction_set_ref (repo, origin_remote, origin_ref, NULL);
|
||||
|
||||
if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (!rpmostree_print_treepkg_diff (sysroot, cancellable, error))
|
||||
goto out;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (console)
|
||||
(void) gs_console_end_status_line (console, NULL, NULL);
|
||||
|
||||
out:
|
||||
if (is_peer)
|
||||
rpmostree_cleanup_peer ();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -25,15 +25,19 @@
|
||||
|
||||
#include "rpmostree-builtins.h"
|
||||
#include "rpmostree-libbuiltin.h"
|
||||
#include "rpmostree-dbus-helpers.h"
|
||||
|
||||
#include "libgsystem.h"
|
||||
#include <libglnx.h>
|
||||
|
||||
static char *opt_sysroot = "/";
|
||||
static gboolean opt_reboot;
|
||||
static gboolean opt_force_peer;
|
||||
|
||||
static GOptionEntry option_entries[] = {
|
||||
{ "sysroot", 0, 0, G_OPTION_ARG_STRING, &opt_sysroot, "Use system root SYSROOT (default: /)", "SYSROOT" },
|
||||
{ "reboot", 'r', 0, G_OPTION_ARG_NONE, &opt_reboot, "Initiate a reboot after rollback is prepared", NULL },
|
||||
{ "peer", 0, 0, G_OPTION_ARG_NONE, &opt_force_peer, "Force a peer to peer connection instead of using the system message bus", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@ -44,101 +48,64 @@ rpmostree_builtin_rollback (int argc,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
gboolean is_peer = FALSE;
|
||||
|
||||
GOptionContext *context = g_option_context_new ("- Revert to the previously booted tree");
|
||||
gs_unref_object GFile *sysroot_path = NULL;
|
||||
gs_unref_object OstreeSysroot *sysroot = NULL;
|
||||
gs_free char *origin_description = NULL;
|
||||
gs_unref_ptrarray GPtrArray *deployments = NULL;
|
||||
gs_unref_ptrarray GPtrArray *new_deployments =
|
||||
g_ptr_array_new_with_free_func (g_object_unref);
|
||||
OstreeDeployment *booted_deployment = NULL;
|
||||
guint i;
|
||||
guint booted_index;
|
||||
guint index_to_prepend;
|
||||
|
||||
glnx_unref_object GDBusConnection *connection = NULL;
|
||||
glnx_unref_object RPMOSTreeOS *os_proxy = NULL;
|
||||
glnx_unref_object RPMOSTreeSysroot *sysroot_proxy = NULL;
|
||||
g_autofree char *transaction_object_path = NULL;
|
||||
|
||||
if (!rpmostree_option_context_parse (context, option_entries, &argc, &argv, error))
|
||||
goto out;
|
||||
|
||||
sysroot_path = g_file_new_for_path (opt_sysroot);
|
||||
sysroot = ostree_sysroot_new (sysroot_path);
|
||||
if (!ostree_sysroot_load (sysroot, cancellable, error))
|
||||
if (!rpmostree_load_connection_and_sysroot (opt_sysroot,
|
||||
opt_force_peer,
|
||||
cancellable,
|
||||
&connection,
|
||||
&sysroot_proxy,
|
||||
&is_peer,
|
||||
error))
|
||||
goto out;
|
||||
|
||||
booted_deployment = ostree_sysroot_get_booted_deployment (sysroot);
|
||||
if (booted_deployment == NULL)
|
||||
{
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Not currently booted into an OSTree system");
|
||||
goto out;
|
||||
}
|
||||
|
||||
deployments = ostree_sysroot_get_deployments (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 (booted_deployment != NULL);
|
||||
for (booted_index = 0; booted_index < deployments->len; booted_index++)
|
||||
{
|
||||
if (deployments->pdata[booted_index] == booted_deployment)
|
||||
break;
|
||||
}
|
||||
g_assert (booted_index < deployments->len);
|
||||
g_assert (deployments->pdata[booted_index] == booted_deployment);
|
||||
|
||||
if (booted_index != 0)
|
||||
{
|
||||
/* There is an earlier deployment, let's assume we want to just
|
||||
* insert the current one in front.
|
||||
*/
|
||||
|
||||
/*
|
||||
What this does is, if we're NOT in the default boot index, it plans to prepend
|
||||
our current index (1, since we can't have more than two trees) so that it becomes index 0
|
||||
(default) and the current default becomes index 1
|
||||
*/
|
||||
index_to_prepend = booted_index;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We're booted into the first, let's roll back to the previous */
|
||||
index_to_prepend = 1;
|
||||
}
|
||||
|
||||
g_ptr_array_add (new_deployments, g_object_ref (deployments->pdata[index_to_prepend]));
|
||||
for (i = 0; i < deployments->len; i++)
|
||||
{
|
||||
if (i == index_to_prepend)
|
||||
continue;
|
||||
g_ptr_array_add (new_deployments, g_object_ref (deployments->pdata[i]));
|
||||
}
|
||||
|
||||
g_print ("Moving '%s.%d' to be first deployment\n",
|
||||
ostree_deployment_get_csum (deployments->pdata[index_to_prepend]),
|
||||
ostree_deployment_get_deployserial (deployments->pdata[index_to_prepend]));
|
||||
|
||||
if (!ostree_sysroot_write_deployments (sysroot, new_deployments, cancellable,
|
||||
error))
|
||||
if (!rpmostree_load_os_proxy (sysroot_proxy, NULL, is_peer,
|
||||
cancellable, &os_proxy, error))
|
||||
goto out;
|
||||
|
||||
if (opt_reboot)
|
||||
gs_subprocess_simple_run_sync (NULL, GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT,
|
||||
cancellable, error,
|
||||
"systemctl", "reboot", NULL);
|
||||
else
|
||||
if (!rpmostree_os_call_rollback_sync (os_proxy,
|
||||
&transaction_object_path,
|
||||
cancellable,
|
||||
error))
|
||||
goto out;
|
||||
|
||||
if (!rpmostree_transaction_get_response_sync (connection,
|
||||
transaction_object_path,
|
||||
cancellable,
|
||||
error))
|
||||
goto out;
|
||||
|
||||
if (!opt_reboot)
|
||||
{
|
||||
if (!rpmostree_print_treepkg_diff (sysroot, cancellable, error))
|
||||
// by request, doing this without dbus
|
||||
if (!rpmostree_print_treepkg_diff_from_sysroot_path (opt_sysroot,
|
||||
cancellable,
|
||||
error))
|
||||
goto out;
|
||||
|
||||
g_print ("Successfully reset deployment order; run \"systemctl reboot\" to start a reboot\n");
|
||||
g_print ("Run \"systemctl reboot\" to start a reboot\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
gs_subprocess_simple_run_sync (NULL, GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT,
|
||||
cancellable, error,
|
||||
"systemctl", "reboot", NULL);
|
||||
}
|
||||
|
||||
if (opt_reboot)
|
||||
ret = TRUE;
|
||||
out:
|
||||
|
||||
out:
|
||||
if (is_peer)
|
||||
rpmostree_cleanup_peer ();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -24,19 +24,22 @@
|
||||
#include <glib-unix.h>
|
||||
|
||||
#include "rpmostree-builtins.h"
|
||||
#include "rpmostree-dbus-helpers.h"
|
||||
|
||||
#include "libgsystem.h"
|
||||
#include <libglnx.h>
|
||||
|
||||
static char *opt_sysroot = "/";
|
||||
static gboolean opt_pretty;
|
||||
static gboolean opt_force_peer;
|
||||
|
||||
static GOptionEntry option_entries[] = {
|
||||
{ "sysroot", 0, 0, G_OPTION_ARG_STRING, &opt_sysroot, "Use system root SYSROOT (default: /)", "SYSROOT" },
|
||||
{ "pretty", 'p', 0, G_OPTION_ARG_NONE, &opt_pretty, "Display status in formatted rows", NULL },
|
||||
{ "peer", 0, 0, G_OPTION_ARG_NONE, &opt_force_peer, "Force a peer to peer connection instead of using the system message bus", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
static void
|
||||
printchar (char *s, int n)
|
||||
{
|
||||
int i;
|
||||
@ -45,66 +48,16 @@ printchar (char *s, int n)
|
||||
g_print ("\n");
|
||||
}
|
||||
|
||||
/* FIXME: This is a copy of ot_admin_checksum_version */
|
||||
static char *
|
||||
checksum_version (GVariant *checksum)
|
||||
{
|
||||
gs_unref_variant GVariant *metadata = NULL;
|
||||
const char *ret = NULL;
|
||||
|
||||
metadata = g_variant_get_child_value (checksum, 0);
|
||||
|
||||
if (!g_variant_lookup (metadata, "version", "&s", &ret))
|
||||
return NULL;
|
||||
|
||||
return g_strdup (ret);
|
||||
}
|
||||
|
||||
static char *
|
||||
version_of_commit (OstreeRepo *repo, const char *checksum)
|
||||
{
|
||||
gs_unref_variant GVariant *variant = NULL;
|
||||
|
||||
/* Shouldn't fail, but if it does, we ignore it */
|
||||
if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, checksum,
|
||||
&variant, NULL))
|
||||
goto out;
|
||||
|
||||
return checksum_version (variant);
|
||||
out:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
deployment_get_gpg_verify (OstreeDeployment *deployment,
|
||||
OstreeRepo *repo)
|
||||
{
|
||||
/* XXX Something like this could be added to the OstreeDeployment
|
||||
* API in libostree if the OstreeRepo parameter is acceptable. */
|
||||
|
||||
GKeyFile *origin;
|
||||
gs_free char *refspec = NULL;
|
||||
gs_free char *remote = NULL;
|
||||
gboolean gpg_verify = FALSE;
|
||||
|
||||
origin = ostree_deployment_get_origin (deployment);
|
||||
|
||||
if (origin == NULL)
|
||||
goto out;
|
||||
|
||||
refspec = g_key_file_get_string (origin, "origin", "refspec", NULL);
|
||||
|
||||
if (refspec == NULL)
|
||||
goto out;
|
||||
|
||||
if (!ostree_parse_refspec (refspec, &remote, NULL, NULL))
|
||||
goto out;
|
||||
|
||||
(void) ostree_repo_remote_get_gpg_verify (repo, remote, &gpg_verify, NULL);
|
||||
|
||||
out:
|
||||
return gpg_verify;
|
||||
}
|
||||
enum {
|
||||
ID,
|
||||
OSNAME,
|
||||
SERIAL,
|
||||
CHECKSUM,
|
||||
VERSION,
|
||||
TIMESTAMP,
|
||||
ORIGIN,
|
||||
SIGNATURES
|
||||
};
|
||||
|
||||
gboolean
|
||||
rpmostree_builtin_status (int argc,
|
||||
@ -113,65 +66,78 @@ rpmostree_builtin_status (int argc,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
gs_unref_object GFile *sysroot_path = NULL;
|
||||
gs_unref_object OstreeSysroot *sysroot = NULL;
|
||||
gs_unref_object OstreeRepo *repo = NULL;
|
||||
gs_unref_ptrarray GPtrArray *deployments = NULL; // list of all depoyments
|
||||
OstreeDeployment *booted_deployment = NULL; // current booted deployment
|
||||
gboolean is_peer = FALSE;
|
||||
GOptionContext *context = g_option_context_new ("- Get the version of the booted system");
|
||||
glnx_unref_object GDBusConnection *connection = NULL;
|
||||
glnx_unref_object RPMOSTreeOS *os_proxy = NULL;
|
||||
glnx_unref_object RPMOSTreeSysroot *sysroot_proxy = NULL;
|
||||
g_autoptr (GVariant) booted_deployment = NULL;
|
||||
g_autoptr (GVariant) deployments = NULL;
|
||||
g_autoptr (GVariant) booted_signatures = NULL;
|
||||
gchar *booted_id = NULL; // borrowed
|
||||
|
||||
const guint CSUM_DISP_LEN = 10; // number of checksum characters to display
|
||||
guint i, j;
|
||||
guint i, n;
|
||||
guint max_timestamp_len = 19; // length of timestamp "YYYY-MM-DD HH:MM:SS"
|
||||
guint max_id_len = CSUM_DISP_LEN; // length of checksum ID
|
||||
guint max_osname_len = 0; // maximum length of osname - determined in conde
|
||||
guint max_refspec_len = 0; // maximum length of refspec - determined in code
|
||||
guint max_version_len = 0; // maximum length of version - determined in code
|
||||
guint buffer = 5; // minimum space between end of one entry and new column
|
||||
gs_free char *booted_csum = NULL;
|
||||
|
||||
|
||||
if (!rpmostree_option_context_parse (context, option_entries, &argc, &argv, error))
|
||||
goto out;
|
||||
|
||||
sysroot_path = g_file_new_for_path (opt_sysroot);
|
||||
sysroot = ostree_sysroot_new (sysroot_path);
|
||||
if (!ostree_sysroot_load (sysroot, cancellable, error))
|
||||
if (!rpmostree_load_connection_and_sysroot (opt_sysroot,
|
||||
opt_force_peer,
|
||||
cancellable,
|
||||
&connection,
|
||||
&sysroot_proxy,
|
||||
&is_peer,
|
||||
error))
|
||||
goto out;
|
||||
|
||||
if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error))
|
||||
if (!rpmostree_load_os_proxy (sysroot_proxy, NULL, is_peer,
|
||||
cancellable, &os_proxy, error))
|
||||
goto out;
|
||||
|
||||
booted_deployment = ostree_sysroot_get_booted_deployment (sysroot);
|
||||
deployments = ostree_sysroot_get_deployments (sysroot);
|
||||
|
||||
/* find lengths for use in column output */
|
||||
if(!opt_pretty)
|
||||
booted_deployment = rpmostree_os_dup_booted_deployment (os_proxy);
|
||||
if (booted_deployment)
|
||||
{
|
||||
/* find max lengths of osname and refspec */
|
||||
for (j = 0; j < deployments->len; j++)
|
||||
g_variant_get_child (booted_deployment, ID, "&s", &booted_id);
|
||||
booted_signatures = g_variant_get_child_value (booted_deployment, SIGNATURES);
|
||||
}
|
||||
|
||||
deployments = rpmostree_sysroot_dup_deployments (sysroot_proxy);
|
||||
if (deployments)
|
||||
n = g_variant_n_children (deployments);
|
||||
else
|
||||
n = 0;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
/* find lengths for use in column output */
|
||||
if (!opt_pretty)
|
||||
{
|
||||
const char *csum = ostree_deployment_get_csum (deployments->pdata[j]);
|
||||
GKeyFile *origin;
|
||||
gs_free char *origin_refspec = NULL;
|
||||
OstreeDeployment *deployment = deployments->pdata[j];
|
||||
gs_free char *version_string = NULL;
|
||||
g_autoptr (GVariant) v = NULL;
|
||||
gchar *origin_refspec = NULL; // borrowed
|
||||
gchar *os_name = NULL; // borrowed
|
||||
gchar *version_string = NULL; // borrowed
|
||||
|
||||
max_osname_len = MAX (max_osname_len, strlen (ostree_deployment_get_osname (deployment)));
|
||||
v = g_variant_get_child_value (deployments, i);
|
||||
g_variant_get_child (v, OSNAME, "&s", &os_name);
|
||||
g_variant_get_child (v, VERSION, "&s", &version_string);
|
||||
g_variant_get_child (v, ORIGIN, "&s", &origin_refspec);
|
||||
|
||||
origin = ostree_deployment_get_origin (deployment);
|
||||
if (!origin)
|
||||
origin_refspec = "none";
|
||||
else
|
||||
{
|
||||
origin_refspec = g_key_file_get_string (origin, "origin", "refspec", NULL);
|
||||
if (!origin_refspec)
|
||||
origin_refspec = g_strdup ("<unknown origin type>");
|
||||
}
|
||||
max_osname_len = MAX (max_osname_len, strlen (os_name));
|
||||
max_refspec_len = MAX (max_refspec_len, strlen (origin_refspec));
|
||||
|
||||
version_string = version_of_commit (repo, csum);
|
||||
if (version_string)
|
||||
max_version_len = MAX (max_version_len, strlen (version_string));
|
||||
max_version_len = MAX (max_version_len, strlen (version_string));
|
||||
}
|
||||
}
|
||||
|
||||
if (!opt_pretty)
|
||||
{
|
||||
/* print column headers */
|
||||
g_print (" %-*s", max_timestamp_len+buffer,"TIMESTAMP (UTC)");
|
||||
if (max_version_len)
|
||||
@ -186,59 +152,45 @@ rpmostree_builtin_status (int argc,
|
||||
printchar ("=", 60);
|
||||
|
||||
/* print entries for each deployment */
|
||||
for (i=0; i<deployments->len; i++)
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
gs_unref_variant GVariant *commit = NULL;
|
||||
const char *csum = ostree_deployment_get_csum (deployments->pdata[i]);
|
||||
OstreeDeployment *deployment = deployments->pdata[i];
|
||||
GKeyFile *origin;
|
||||
gs_free char *origin_refspec = NULL;
|
||||
GDateTime *timestamp = NULL;
|
||||
gs_free char *timestamp_string = NULL;
|
||||
char *truncated_csum = NULL;
|
||||
gs_free char *version_string = NULL;
|
||||
g_autofree char *timestamp_string = NULL;
|
||||
g_autofree gchar *truncated_csum = NULL;
|
||||
g_autoptr (GVariant) v = NULL;
|
||||
g_autoptr (GVariant) signatures = NULL;
|
||||
|
||||
/* get commit for timestamp */
|
||||
if (!ostree_repo_load_variant (repo,
|
||||
OSTREE_OBJECT_TYPE_COMMIT,
|
||||
csum,
|
||||
&commit,
|
||||
error))
|
||||
goto out;
|
||||
gchar *id = NULL; // borrowed
|
||||
gchar *origin_refspec = NULL; // borrowed
|
||||
gchar *os_name = NULL; // borrowed
|
||||
gchar *version_string = NULL; // borrowed
|
||||
gchar *checksum = NULL; // borrowed
|
||||
|
||||
/* format timestamp*/
|
||||
timestamp = g_date_time_new_from_unix_utc (ostree_commit_get_timestamp (commit));
|
||||
gint64 t;
|
||||
gint serial;
|
||||
gboolean is_booted = FALSE;
|
||||
|
||||
v = g_variant_get_child_value (deployments, i);
|
||||
g_variant_get (v, "(&s&si&s&st&sav)",
|
||||
&id, &os_name, &serial,
|
||||
&checksum, &version_string,
|
||||
&t, &origin_refspec, NULL);
|
||||
signatures = g_variant_get_child_value (v, SIGNATURES);
|
||||
is_booted = g_strcmp0 (booted_id, id) == 0;
|
||||
|
||||
timestamp = g_date_time_new_from_unix_utc (t);
|
||||
g_assert (timestamp);
|
||||
timestamp_string = g_date_time_format (timestamp, "%Y-%m-%d %T");
|
||||
g_date_time_unref (timestamp);
|
||||
version_string = checksum_version (commit);
|
||||
|
||||
/* get origin refspec */
|
||||
origin = ostree_deployment_get_origin (deployment);
|
||||
if (!origin)
|
||||
origin_refspec = g_strdup ("none");
|
||||
else
|
||||
{
|
||||
origin_refspec = g_key_file_get_string (origin, "origin", "refspec", NULL);
|
||||
if (!origin_refspec)
|
||||
origin_refspec = g_strdup ("<unknown origin type>");
|
||||
}
|
||||
|
||||
/* truncate checksum */
|
||||
truncated_csum = g_strndup (csum, CSUM_DISP_LEN);
|
||||
truncated_csum = g_strndup (checksum, CSUM_DISP_LEN);
|
||||
|
||||
/* print deployment info column */
|
||||
if (!opt_pretty)
|
||||
{
|
||||
if (deployment == booted_deployment)
|
||||
{
|
||||
/* Stash this for printing signatures later. */
|
||||
if (deployment_get_gpg_verify (deployment, repo))
|
||||
booted_csum = g_strdup (csum);
|
||||
}
|
||||
|
||||
g_print ("%c %-*s",
|
||||
deployment == booted_deployment ? '*' : ' ',
|
||||
is_booted ? '*' : ' ',
|
||||
max_timestamp_len+buffer, timestamp_string);
|
||||
|
||||
if (max_version_len)
|
||||
@ -246,73 +198,39 @@ rpmostree_builtin_status (int argc,
|
||||
max_version_len+buffer, version_string ? version_string : "");
|
||||
g_print ("%-*s%-*s%-*s\n",
|
||||
max_id_len+buffer, truncated_csum,
|
||||
max_osname_len+buffer, ostree_deployment_get_osname (deployment),
|
||||
max_osname_len+buffer, os_name,
|
||||
max_refspec_len+buffer, origin_refspec);
|
||||
}
|
||||
|
||||
/* print "pretty" row info */
|
||||
else
|
||||
{
|
||||
gs_unref_object OstreeGpgVerifyResult *result = NULL;
|
||||
guint n_sigs;
|
||||
guint tab = 11;
|
||||
char *title = NULL;
|
||||
GError *local_error = NULL;
|
||||
|
||||
if (i==0)
|
||||
title = "DEFAULT ON BOOT";
|
||||
else if (deployment == booted_deployment ||
|
||||
deployments->len <= 2)
|
||||
else if (is_booted || n <= 2)
|
||||
title = "NON-DEFAULT ROLLBACK TARGET";
|
||||
else
|
||||
title = "NON-DEFAULT DEPLOYMENT";
|
||||
g_print (" %c %s\n",
|
||||
deployment == booted_deployment ? '*' : ' ',
|
||||
is_booted ? '*' : ' ',
|
||||
title);
|
||||
|
||||
printchar ("-", 40);
|
||||
if (version_string)
|
||||
g_print (" %-*s%-*s\n", tab, "version", tab, version_string);
|
||||
|
||||
g_print (" %-*s%-*s\n %-*s%-*s.%d\n %-*s%-*s\n %-*s%-*s\n",
|
||||
tab, "timestamp", tab, timestamp_string,
|
||||
tab, "id", tab, csum, ostree_deployment_get_deployserial (deployment),
|
||||
tab, "osname", tab, ostree_deployment_get_osname (deployment),
|
||||
tab, "id", tab, checksum, serial,
|
||||
tab, "osname", tab, os_name,
|
||||
tab, "refspec", tab, origin_refspec);
|
||||
|
||||
if (deployment_get_gpg_verify (deployment, repo))
|
||||
{
|
||||
result = ostree_repo_verify_commit_ext (repo, csum, NULL, NULL,
|
||||
cancellable, &local_error);
|
||||
|
||||
/* NOT_FOUND just means the commit is not signed. */
|
||||
if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
||||
{
|
||||
g_clear_error (&local_error);
|
||||
}
|
||||
else if (local_error != NULL)
|
||||
{
|
||||
g_propagate_error (error, local_error);
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
GString *sigs_buffer;
|
||||
guint n_sigs, ii;
|
||||
|
||||
n_sigs = ostree_gpg_verify_result_count_all (result);
|
||||
|
||||
sigs_buffer = g_string_sized_new (256);
|
||||
|
||||
for (ii = 0; ii < n_sigs; ii++)
|
||||
{
|
||||
g_string_append_c (sigs_buffer, '\n');
|
||||
ostree_gpg_verify_result_describe (result, ii, sigs_buffer, " GPG: ",
|
||||
OSTREE_GPG_SIGNATURE_FORMAT_DEFAULT);
|
||||
}
|
||||
|
||||
g_print ("%s", sigs_buffer->str);
|
||||
g_string_free (sigs_buffer, TRUE);
|
||||
}
|
||||
}
|
||||
n_sigs = g_variant_n_children (signatures);
|
||||
if (n_sigs > 0)
|
||||
rpmostree_print_signatures (signatures, " GPG: ");
|
||||
|
||||
printchar ("=", 60);
|
||||
}
|
||||
@ -321,50 +239,23 @@ rpmostree_builtin_status (int argc,
|
||||
/* Print any signatures for the booted deployment, but only in NON-pretty
|
||||
* mode. We save this for the end to preserve the tabular formatting for
|
||||
* deployments. */
|
||||
if (booted_csum != NULL)
|
||||
if (!opt_pretty && booted_signatures != NULL)
|
||||
{
|
||||
gs_unref_object OstreeGpgVerifyResult *result = NULL;
|
||||
GError *local_error = NULL;
|
||||
|
||||
result = ostree_repo_verify_commit_ext (repo, booted_csum, NULL, NULL,
|
||||
cancellable, &local_error);
|
||||
|
||||
/* NOT_FOUND just means the commit is not signed. */
|
||||
if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
||||
guint n_sigs = g_variant_n_children (booted_signatures);
|
||||
if (n_sigs > 0)
|
||||
{
|
||||
g_clear_error (&local_error);
|
||||
}
|
||||
else if (local_error != NULL)
|
||||
{
|
||||
g_propagate_error (error, local_error);
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
GString *sigs_buffer;
|
||||
guint n_sigs, ii;
|
||||
|
||||
n_sigs = ostree_gpg_verify_result_count_all (result);
|
||||
|
||||
/* XXX If we ever add internationalization, use ngettext() here. */
|
||||
g_print ("\nGPG: Found %u signature%s on the booted deployment (*):\n",
|
||||
n_sigs, n_sigs == 1 ? "" : "s");
|
||||
|
||||
sigs_buffer = g_string_sized_new (256);
|
||||
|
||||
for (ii = 0; ii < n_sigs; ii++)
|
||||
{
|
||||
g_string_append_c (sigs_buffer, '\n');
|
||||
ostree_gpg_verify_result_describe (result, ii, sigs_buffer, " ",
|
||||
OSTREE_GPG_SIGNATURE_FORMAT_DEFAULT);
|
||||
}
|
||||
|
||||
g_print ("%s", sigs_buffer->str);
|
||||
g_string_free (sigs_buffer, TRUE);
|
||||
rpmostree_print_signatures (booted_signatures, " ");
|
||||
}
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
|
||||
out:
|
||||
if (is_peer)
|
||||
rpmostree_cleanup_peer ();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -27,15 +27,17 @@
|
||||
#include "rpmostree-builtins.h"
|
||||
#include "rpmostree-libbuiltin.h"
|
||||
#include "rpmostree-rpm-util.h"
|
||||
#include "rpm-ostreed-generated.h"
|
||||
#include "rpmostree-dbus-helpers.h"
|
||||
|
||||
#include "libgsystem.h"
|
||||
#include <libglnx.h>
|
||||
|
||||
static char *opt_sysroot = "/";
|
||||
static char *opt_osname;
|
||||
static gboolean opt_reboot;
|
||||
static gboolean opt_allow_downgrade;
|
||||
static gboolean opt_check_diff;
|
||||
static gboolean opt_force_peer;
|
||||
|
||||
static GOptionEntry option_entries[] = {
|
||||
{ "sysroot", 0, 0, G_OPTION_ARG_STRING, &opt_sysroot, "Use system root SYSROOT (default: /)", "SYSROOT" },
|
||||
@ -43,322 +45,28 @@ static GOptionEntry option_entries[] = {
|
||||
{ "reboot", 'r', 0, G_OPTION_ARG_NONE, &opt_reboot, "Initiate a reboot after an upgrade is prepared", NULL },
|
||||
{ "allow-downgrade", 0, 0, G_OPTION_ARG_NONE, &opt_allow_downgrade, "Permit deployment of chronologically older trees", NULL },
|
||||
{ "check-diff", 0, 0, G_OPTION_ARG_NONE, &opt_check_diff, "Check for upgrades and print package diff only", NULL },
|
||||
{ "peer", 0, 0, G_OPTION_ARG_NONE, &opt_force_peer, "Force a peer to peer connection instead of using the system message bus", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
#define DBUS_NAME "org.projectatomic.rpmostree1"
|
||||
#define BASE_DBUS_PATH "/org/projectatomic/rpmostree1"
|
||||
static GVariant *
|
||||
get_args_variant (void)
|
||||
{
|
||||
GVariantDict dict;
|
||||
|
||||
g_variant_dict_init (&dict, NULL);
|
||||
g_variant_dict_insert (&dict, "allow-downgrade", "b", opt_allow_downgrade);
|
||||
|
||||
return g_variant_dict_end (&dict);
|
||||
}
|
||||
|
||||
static void
|
||||
gpg_verify_result_cb (OstreeRepo *repo,
|
||||
const char *checksum,
|
||||
OstreeGpgVerifyResult *result,
|
||||
GSConsole *console)
|
||||
default_changed_callback (GObject *object,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
/* Temporarily place the GSConsole stream (which is just stdout)
|
||||
* back in normal mode before printing GPG verification results. */
|
||||
gs_console_end_status_line (console, NULL, NULL);
|
||||
|
||||
g_print ("\n");
|
||||
rpmostree_print_gpg_verify_result (result);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
rpmostree_builtin_upgrade_check_diff (GFile *sysroot_path,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
glnx_unref_object OstreeSysroot *sysroot = NULL;
|
||||
glnx_unref_object OstreeRepo *repo = NULL;
|
||||
glnx_unref_object OstreeSysrootUpgrader *upgrader = NULL;
|
||||
glnx_unref_object OstreeAsyncProgress *progress = NULL;
|
||||
g_autofree char *origin_description = NULL;
|
||||
GSConsole *console = NULL;
|
||||
gulong signal_handler_id = 0;
|
||||
gboolean changed = FALSE;
|
||||
gboolean ret = FALSE;
|
||||
|
||||
sysroot = ostree_sysroot_new (sysroot_path);
|
||||
if (!ostree_sysroot_load (sysroot, cancellable, error))
|
||||
goto out;
|
||||
|
||||
upgrader = ostree_sysroot_upgrader_new_for_os (sysroot, opt_osname,
|
||||
cancellable, error);
|
||||
if (!upgrader)
|
||||
goto out;
|
||||
|
||||
origin_description = ostree_sysroot_upgrader_get_origin_description (upgrader);
|
||||
if (origin_description != NULL)
|
||||
g_print ("Updating from: %s\n", origin_description);
|
||||
|
||||
if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error))
|
||||
goto out;
|
||||
|
||||
console = gs_console_get ();
|
||||
if (console != NULL)
|
||||
{
|
||||
gs_console_begin_status_line (console, "", NULL, NULL);
|
||||
progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, console);
|
||||
signal_handler_id = g_signal_connect (repo, "gpg-verify-result",
|
||||
G_CALLBACK (gpg_verify_result_cb),
|
||||
console);
|
||||
|
||||
}
|
||||
|
||||
if (!ostree_sysroot_upgrader_pull_one_dir (upgrader, "/usr/share/rpm",
|
||||
0, 0, progress, &changed,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (console != NULL)
|
||||
{
|
||||
if (!gs_console_end_status_line (console, cancellable, error))
|
||||
{
|
||||
console = NULL;
|
||||
goto out;
|
||||
}
|
||||
console = NULL;
|
||||
}
|
||||
|
||||
if (!changed)
|
||||
{
|
||||
g_print ("No upgrade available.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
glnx_unref_object GFile *rpmdbdir = NULL;
|
||||
_cleanup_rpmrev_ struct RpmRevisionData *rpmrev1 = NULL;
|
||||
_cleanup_rpmrev_ struct RpmRevisionData *rpmrev2 = NULL;
|
||||
|
||||
gs_free char *tmpd = g_mkdtemp (g_strdup ("/tmp/rpm-ostree.XXXXXX"));
|
||||
|
||||
gs_free char *ref = NULL; // location of this rev
|
||||
gs_free char *remote = NULL;
|
||||
|
||||
if (!ostree_parse_refspec (origin_description, &remote, &ref, error))
|
||||
goto out;
|
||||
|
||||
if (rpmReadConfigFiles (NULL, NULL))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"rpm failed to init: %s", rpmlogMessage());
|
||||
goto out;
|
||||
}
|
||||
|
||||
rpmdbdir = g_file_new_for_path (tmpd);
|
||||
|
||||
if (!(rpmrev1 = rpmrev_new (repo, rpmdbdir,
|
||||
ostree_deployment_get_csum (ostree_sysroot_get_booted_deployment (sysroot)),
|
||||
NULL, cancellable, error)))
|
||||
goto out;
|
||||
|
||||
if (!(rpmrev2 = rpmrev_new (repo, rpmdbdir, ref,
|
||||
NULL, cancellable, error)))
|
||||
goto out;
|
||||
|
||||
rpmhdrs_diff_prnt_diff (rpmrev1->root, rpmrev2->root,
|
||||
rpmhdrs_diff (rpmrev1->rpmdb, rpmrev2->rpmdb));
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
if (console != NULL)
|
||||
(void) gs_console_end_status_line (console, NULL, NULL);
|
||||
|
||||
if (signal_handler_id > 0)
|
||||
g_signal_handler_disconnect (repo, signal_handler_id);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
rpmostree_builtin_upgrade_for_sysroot (GFile *sysroot_path,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
glnx_unref_object OstreeSysroot *sysroot = NULL;
|
||||
glnx_unref_object OstreeRepo *repo = NULL;
|
||||
glnx_unref_object OstreeSysrootUpgrader *upgrader = NULL;
|
||||
glnx_unref_object OstreeAsyncProgress *progress = NULL;
|
||||
g_autofree char *origin_description = NULL;
|
||||
GSConsole *console = NULL;
|
||||
OstreeSysrootUpgraderPullFlags upgrader_pull_flags = 0;
|
||||
gulong signal_handler_id = 0;
|
||||
gboolean changed = FALSE;
|
||||
gboolean ret = FALSE;
|
||||
|
||||
sysroot = ostree_sysroot_new (sysroot_path);
|
||||
if (!ostree_sysroot_load (sysroot, cancellable, error))
|
||||
goto out;
|
||||
|
||||
upgrader = ostree_sysroot_upgrader_new_for_os (sysroot, opt_osname,
|
||||
cancellable, error);
|
||||
if (!upgrader)
|
||||
goto out;
|
||||
|
||||
origin_description = ostree_sysroot_upgrader_get_origin_description (upgrader);
|
||||
if (origin_description != NULL)
|
||||
g_print ("Updating from: %s\n", origin_description);
|
||||
|
||||
if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error))
|
||||
goto out;
|
||||
|
||||
console = gs_console_get ();
|
||||
if (console != NULL)
|
||||
{
|
||||
gs_console_begin_status_line (console, "", NULL, NULL);
|
||||
progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, console);
|
||||
signal_handler_id = g_signal_connect (repo, "gpg-verify-result",
|
||||
G_CALLBACK (gpg_verify_result_cb),
|
||||
console);
|
||||
|
||||
}
|
||||
|
||||
if (opt_allow_downgrade)
|
||||
upgrader_pull_flags |= OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER;
|
||||
|
||||
if (!ostree_sysroot_upgrader_pull (upgrader, 0, upgrader_pull_flags,
|
||||
progress, &changed,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (console != NULL)
|
||||
{
|
||||
if (!gs_console_end_status_line (console, cancellable, error))
|
||||
{
|
||||
console = NULL;
|
||||
goto out;
|
||||
}
|
||||
console = NULL;
|
||||
}
|
||||
|
||||
if (!changed)
|
||||
{
|
||||
g_print ("No upgrade available.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ostree_sysroot_upgrader_deploy (upgrader, cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (opt_reboot)
|
||||
gs_subprocess_simple_run_sync (NULL, GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT,
|
||||
cancellable, error,
|
||||
"systemctl", "reboot", NULL);
|
||||
else
|
||||
{
|
||||
if (!rpmostree_print_treepkg_diff (sysroot, cancellable, error))
|
||||
goto out;
|
||||
|
||||
g_print ("Upgrade prepared for next boot; run \"systemctl reboot\" to start a reboot\n");
|
||||
}
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
if (console != NULL)
|
||||
(void) gs_console_end_status_line (console, NULL, NULL);
|
||||
|
||||
if (signal_handler_id > 0)
|
||||
g_signal_handler_disconnect (repo, signal_handler_id);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
rpmostree_builtin_upgrade_system (GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
glnx_unref_object GDBusConnection *connection = NULL;
|
||||
glnx_unref_object RPMOSTreeSysroot *sysroot_proxy = NULL;
|
||||
glnx_unref_object RPMOSTreeOS *os_proxy = NULL;
|
||||
glnx_unref_object RPMOSTreeTransaction *transaction_proxy = NULL;
|
||||
g_auto(GVariantDict) options;
|
||||
g_autofree char *os_object_path = NULL;
|
||||
g_autofree char *transaction_object_path = NULL;
|
||||
gboolean ret = FALSE;
|
||||
|
||||
g_variant_dict_init (&options, NULL);
|
||||
|
||||
g_variant_dict_insert (&options,
|
||||
"allow-downgrade",
|
||||
"b", opt_allow_downgrade);
|
||||
|
||||
connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, cancellable, error);
|
||||
if (connection == NULL)
|
||||
goto out;
|
||||
|
||||
sysroot_proxy = rpmostree_sysroot_proxy_new_sync (connection,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
DBUS_NAME,
|
||||
BASE_DBUS_PATH,
|
||||
cancellable,
|
||||
error);
|
||||
if (sysroot_proxy == NULL)
|
||||
goto out;
|
||||
|
||||
if (opt_osname == NULL)
|
||||
{
|
||||
os_object_path = rpmostree_sysroot_dup_booted (sysroot_proxy);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!rpmostree_sysroot_call_get_os_sync (sysroot_proxy,
|
||||
opt_osname,
|
||||
&os_object_path,
|
||||
cancellable,
|
||||
error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
os_proxy = rpmostree_os_proxy_new_sync (connection,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
DBUS_NAME,
|
||||
os_object_path,
|
||||
cancellable,
|
||||
error);
|
||||
if (os_proxy != NULL)
|
||||
goto out;
|
||||
|
||||
if (!rpmostree_os_call_upgrade_sync (os_proxy,
|
||||
g_variant_dict_end (&options),
|
||||
&transaction_object_path,
|
||||
cancellable,
|
||||
error))
|
||||
goto out;
|
||||
|
||||
/* XXX I worry this part might be racy. If the transaction completes
|
||||
* before we connect to the interface, we may miss it entirely and
|
||||
* not know whether the transaction succeeded and end up reporting
|
||||
* a bogus D-Bus error.
|
||||
*
|
||||
* One pattern I've used in the past is to add a Start() method to
|
||||
* the transaction interface to call once the client is set up, but
|
||||
* that complicates the server-side considerably: have to abort the
|
||||
* transaction if the client dies or a timer expires before Start()
|
||||
* is called.
|
||||
*
|
||||
* Reference code for this pattern:
|
||||
* https://git.gnome.org/browse/evolution-data-server/tree/libebackend/e-authentication-mediator.c?h=evolution-data-server-3-12
|
||||
*/
|
||||
|
||||
transaction_proxy = rpmostree_transaction_proxy_new_sync (connection,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
DBUS_NAME,
|
||||
transaction_object_path,
|
||||
cancellable,
|
||||
error);
|
||||
if (transaction_proxy != NULL)
|
||||
goto out;
|
||||
|
||||
/* FIXME Monitor the transaction, report progress, etc. */
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
GVariant **value = user_data;
|
||||
g_object_get (object, pspec->name, value, NULL);
|
||||
}
|
||||
|
||||
gboolean
|
||||
@ -368,47 +76,138 @@ rpmostree_builtin_upgrade (int argc,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
gboolean is_peer = FALSE;
|
||||
|
||||
GOptionContext *context = g_option_context_new ("- Perform a system upgrade");
|
||||
g_autoptr(GFile) sysroot_path = NULL;
|
||||
glnx_unref_object GDBusConnection *connection = NULL;
|
||||
glnx_unref_object RPMOSTreeOS *os_proxy = NULL;
|
||||
glnx_unref_object RPMOSTreeSysroot *sysroot_proxy = NULL;
|
||||
g_autofree char *transaction_object_path = NULL;
|
||||
g_autoptr (GVariant) default_deployment = NULL;
|
||||
|
||||
if (!rpmostree_option_context_parse (context, option_entries, &argc, &argv, error))
|
||||
goto out;
|
||||
|
||||
/* XXX Like g_file_new_for_commandline_arg() but no URIs. */
|
||||
if (g_path_is_absolute (opt_sysroot))
|
||||
{
|
||||
sysroot_path = g_file_new_for_path (opt_sysroot);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_autofree char *current_dir = NULL;
|
||||
g_autofree char *filename = NULL;
|
||||
if (!rpmostree_load_connection_and_sysroot (opt_sysroot,
|
||||
opt_force_peer,
|
||||
cancellable,
|
||||
&connection,
|
||||
&sysroot_proxy,
|
||||
&is_peer,
|
||||
error))
|
||||
goto out;
|
||||
|
||||
current_dir = g_get_current_dir ();
|
||||
filename = g_build_filename (current_dir, opt_sysroot, NULL);
|
||||
sysroot_path = g_file_new_for_path (filename);
|
||||
}
|
||||
if (!rpmostree_load_os_proxy (sysroot_proxy, opt_osname, is_peer,
|
||||
cancellable, &os_proxy, error))
|
||||
goto out;
|
||||
|
||||
if (opt_check_diff)
|
||||
{
|
||||
if (!rpmostree_builtin_upgrade_check_diff (sysroot_path,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
else if (g_file_has_parent (sysroot_path, NULL))
|
||||
{
|
||||
if (!rpmostree_builtin_upgrade_for_sysroot (sysroot_path,
|
||||
cancellable, error))
|
||||
if (!rpmostree_os_call_download_update_rpm_diff_sync (os_proxy,
|
||||
&transaction_object_path,
|
||||
cancellable,
|
||||
error))
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!rpmostree_builtin_upgrade_system (cancellable, error))
|
||||
g_signal_connect (os_proxy, "notify::default-deployment",
|
||||
G_CALLBACK (default_changed_callback),
|
||||
&default_deployment);
|
||||
|
||||
if (!rpmostree_os_call_upgrade_sync (os_proxy,
|
||||
get_args_variant (),
|
||||
&transaction_object_path,
|
||||
cancellable,
|
||||
error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!rpmostree_transaction_get_response_sync (connection,
|
||||
transaction_object_path,
|
||||
cancellable,
|
||||
error))
|
||||
goto out;
|
||||
|
||||
if (opt_check_diff)
|
||||
{
|
||||
// yes, doing this without using dbus
|
||||
gs_unref_object OstreeSysroot *sysroot = NULL;
|
||||
gs_unref_object OstreeRepo *repo = NULL;
|
||||
gs_unref_object GFile *rpmdbdir = NULL;
|
||||
gs_unref_object GFile *sysroot_path = NULL;
|
||||
g_autofree char *origin_description = NULL;
|
||||
|
||||
_cleanup_rpmrev_ struct RpmRevisionData *rpmrev1 = NULL;
|
||||
_cleanup_rpmrev_ struct RpmRevisionData *rpmrev2 = NULL;
|
||||
|
||||
gs_free char *ref = NULL; // location of this rev
|
||||
gs_free char *remote = NULL;
|
||||
|
||||
if (!rpmostree_os_get_has_cached_update_rpm_diff (os_proxy))
|
||||
goto out;
|
||||
|
||||
sysroot_path = g_file_new_for_path (opt_sysroot);
|
||||
sysroot = ostree_sysroot_new (sysroot_path);
|
||||
|
||||
if (!ostree_sysroot_load (sysroot, cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error))
|
||||
goto out;
|
||||
|
||||
origin_description = rpmostree_os_dup_upgrade_origin (os_proxy);
|
||||
if (!ostree_parse_refspec (origin_description, &remote, &ref, error))
|
||||
goto out;
|
||||
|
||||
if (rpmReadConfigFiles (NULL, NULL))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"rpm failed to init: %s", rpmlogMessage ());
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(rpmrev1 = rpmrev_new (repo,
|
||||
ostree_deployment_get_csum (ostree_sysroot_get_booted_deployment (sysroot)),
|
||||
NULL, cancellable, error)))
|
||||
goto out;
|
||||
|
||||
if (!(rpmrev2 = rpmrev_new (repo, ref,
|
||||
NULL, cancellable, error)))
|
||||
goto out;
|
||||
|
||||
rpmhdrs_diff_prnt_diff (rpmhdrs_diff (rpmrev_get_headers (rpmrev1),
|
||||
rpmrev_get_headers (rpmrev2)));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* nothing changed */
|
||||
if (default_deployment == NULL)
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
if (opt_reboot)
|
||||
{
|
||||
gs_subprocess_simple_run_sync (NULL, GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT,
|
||||
cancellable, error,
|
||||
"systemctl", "reboot", NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!rpmostree_print_treepkg_diff_from_sysroot_path (opt_sysroot,
|
||||
cancellable,
|
||||
error))
|
||||
goto out;
|
||||
|
||||
g_print ("Run \"systemctl reboot\" to start a reboot\n");
|
||||
}
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
out:
|
||||
if (is_peer)
|
||||
rpmostree_cleanup_peer ();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
612
src/app/rpmostree-dbus-helpers.c
Normal file
612
src/app/rpmostree-dbus-helpers.c
Normal file
@ -0,0 +1,612 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* Copyright (C) 2014 Colin Walters <walters@verbum.org>
|
||||
*
|
||||
* This program 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 licence 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "rpmostree-dbus-helpers.h"
|
||||
#include "libgsystem.h"
|
||||
#include "libglnx.h"
|
||||
#include <sys/socket.h>
|
||||
#include "glib-unix.h"
|
||||
#include <signal.h>
|
||||
|
||||
static GPid peer_pid = 0;
|
||||
|
||||
void
|
||||
rpmostree_cleanup_peer ()
|
||||
{
|
||||
if (peer_pid > 0)
|
||||
kill (peer_pid, SIGTERM);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_connection_for_path (gchar *sysroot,
|
||||
gboolean force_peer,
|
||||
GCancellable *cancellable,
|
||||
GDBusConnection **out_connection,
|
||||
gboolean *out_is_peer,
|
||||
GError **error)
|
||||
{
|
||||
glnx_unref_object GDBusConnection *connection = NULL;
|
||||
glnx_unref_object GDBusObjectManager *om = NULL;
|
||||
glnx_unref_object GSocketConnection *stream = NULL;
|
||||
glnx_unref_object GSocket *socket = NULL;
|
||||
|
||||
gchar buffer[16];
|
||||
|
||||
int pair[2];
|
||||
gboolean ret = FALSE;
|
||||
gboolean is_peer = FALSE;
|
||||
|
||||
const gchar *args[] = {
|
||||
"rpm-ostreed",
|
||||
"--sysroot", sysroot,
|
||||
"--dbus-peer", buffer,
|
||||
NULL
|
||||
};
|
||||
|
||||
if (!sysroot)
|
||||
sysroot = "/";
|
||||
|
||||
if (g_strcmp0 ("/", sysroot) == 0 && force_peer == FALSE)
|
||||
{
|
||||
connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, cancellable, error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
g_print ("Running in single user mode. Be sure no other users are modifying the system\n");
|
||||
is_peer = TRUE;
|
||||
if (socketpair (AF_UNIX, SOCK_STREAM, 0, pair) < 0)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Couldn't create socket pair: %s",
|
||||
g_strerror (errno));
|
||||
goto out;
|
||||
}
|
||||
|
||||
g_snprintf (buffer, sizeof (buffer), "%d", pair[1]);
|
||||
|
||||
socket = g_socket_new_from_fd (pair[0], error);
|
||||
if (socket == NULL)
|
||||
{
|
||||
close (pair[0]);
|
||||
close (pair[1]);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!g_spawn_async (NULL, (gchar **)args, NULL,
|
||||
G_SPAWN_LEAVE_DESCRIPTORS_OPEN | G_SPAWN_DO_NOT_REAP_CHILD,
|
||||
NULL, NULL, &peer_pid, error))
|
||||
{
|
||||
close (pair[1]);
|
||||
goto out;
|
||||
}
|
||||
|
||||
stream = g_socket_connection_factory_create_connection (socket);
|
||||
connection = g_dbus_connection_new_sync (G_IO_STREAM (stream), NULL,
|
||||
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
|
||||
NULL, cancellable, error);
|
||||
|
||||
out:
|
||||
if (connection)
|
||||
{
|
||||
ret = TRUE;
|
||||
*out_connection = g_steal_pointer (&connection);
|
||||
*out_is_peer = is_peer;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* rpmostree_load_connection_and_sysroot
|
||||
* @sysroot: sysroot path
|
||||
* @force_peer: Force a peer connection
|
||||
* @cancellable: A GCancellable
|
||||
* @out_connection: (out) Return location for connection.
|
||||
* @out_sysroot: (out) Return location for sysroot
|
||||
* @out_is_peer: (out) indicates if connection is connected to a peer.
|
||||
* @error: A pointer to a GError pointer.
|
||||
*
|
||||
* Returns: True on success
|
||||
**/
|
||||
gboolean
|
||||
rpmostree_load_connection_and_sysroot (gchar *sysroot,
|
||||
gboolean force_peer,
|
||||
GCancellable *cancellable,
|
||||
GDBusConnection **out_connection,
|
||||
RPMOSTreeSysroot **out_sysroot_proxy,
|
||||
gboolean *out_is_peer,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
gboolean is_peer = FALSE;
|
||||
glnx_unref_object GDBusConnection *connection = NULL;
|
||||
glnx_unref_object RPMOSTreeSysroot *sysroot_proxy = NULL;
|
||||
|
||||
if (!get_connection_for_path (sysroot,
|
||||
force_peer,
|
||||
cancellable,
|
||||
&connection,
|
||||
&is_peer,
|
||||
error))
|
||||
goto out;
|
||||
|
||||
sysroot_proxy = rpmostree_sysroot_proxy_new_sync (connection,
|
||||
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
|
||||
is_peer ? NULL : BUS_NAME,
|
||||
"/org/projectatomic/rpmostree1/Sysroot",
|
||||
NULL,
|
||||
error);
|
||||
if (sysroot_proxy == NULL)
|
||||
goto out;
|
||||
|
||||
*out_connection = g_steal_pointer (&connection);
|
||||
*out_is_peer = is_peer;
|
||||
*out_sysroot_proxy = g_steal_pointer (&sysroot_proxy);
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
rpmostree_load_os_proxy (RPMOSTreeSysroot *sysroot_proxy,
|
||||
gchar *opt_osname,
|
||||
gboolean is_peer,
|
||||
GCancellable *cancellable,
|
||||
RPMOSTreeOS **out_os_proxy,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autofree char *os_object_path = NULL;
|
||||
glnx_unref_object RPMOSTreeOS *os_proxy = NULL;
|
||||
|
||||
GDBusConnection *connection = NULL; // owned by sysroot_proxy
|
||||
|
||||
if (opt_osname == NULL)
|
||||
{
|
||||
os_object_path = rpmostree_sysroot_dup_booted (sysroot_proxy);
|
||||
}
|
||||
|
||||
if (os_object_path == NULL)
|
||||
{
|
||||
/* Usually if opt_osname is null and the property isn't
|
||||
populated that means the daemon isn't listen on the bus
|
||||
make the call anyways to get the standard error.
|
||||
*/
|
||||
if (!opt_osname)
|
||||
opt_osname = "";
|
||||
|
||||
if (!rpmostree_sysroot_call_get_os_sync (sysroot_proxy,
|
||||
opt_osname,
|
||||
&os_object_path,
|
||||
cancellable,
|
||||
error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (sysroot_proxy));
|
||||
os_proxy = rpmostree_os_proxy_new_sync (connection,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
is_peer ? NULL : BUS_NAME,
|
||||
os_object_path,
|
||||
cancellable,
|
||||
error);
|
||||
|
||||
if (os_proxy == NULL)
|
||||
goto out;
|
||||
|
||||
*out_os_proxy = g_steal_pointer (&os_proxy);
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* transaction_console_get_progress_line
|
||||
*
|
||||
* Similar to ostree_repo_pull_default_console_progress_changed
|
||||
*
|
||||
* Displays outstanding fetch progress in bytes/sec,
|
||||
* or else outstanding content or metadata writes to the repository in
|
||||
* number of objects.
|
||||
**/
|
||||
static gchar *
|
||||
transaction_get_progress_line (guint64 start_time,
|
||||
guint64 elapsed_secs,
|
||||
guint outstanding_fetches,
|
||||
guint outstanding_writes,
|
||||
guint n_scanned_metadata,
|
||||
guint metadata_fetched,
|
||||
guint outstanding_metadata_fetches,
|
||||
guint total_delta_parts,
|
||||
guint fetched_delta_parts,
|
||||
guint total_delta_superblocks,
|
||||
guint64 total_delta_part_size,
|
||||
guint fetched,
|
||||
guint requested,
|
||||
guint64 bytes_transferred,
|
||||
guint64 bytes_sec)
|
||||
{
|
||||
GString *buf;
|
||||
|
||||
buf = g_string_new ("");
|
||||
|
||||
if (outstanding_fetches)
|
||||
{
|
||||
g_autofree gchar *formatted_bytes_transferred = g_format_size_full (bytes_transferred, 0);
|
||||
g_autofree gchar *formatted_bytes_sec = NULL;
|
||||
|
||||
if (!bytes_sec)
|
||||
formatted_bytes_sec = g_strdup ("-");
|
||||
else
|
||||
formatted_bytes_sec = g_format_size (bytes_sec);
|
||||
|
||||
if (total_delta_parts > 0)
|
||||
{
|
||||
g_autofree gchar *formatted_total = g_format_size (total_delta_part_size);
|
||||
g_string_append_printf (buf, "Receiving delta parts: %u/%u %s/s %s/%s",
|
||||
fetched_delta_parts, total_delta_parts,
|
||||
formatted_bytes_sec, formatted_bytes_transferred,
|
||||
formatted_total);
|
||||
}
|
||||
else if (outstanding_metadata_fetches)
|
||||
{
|
||||
g_string_append_printf (buf, "Receiving metadata objects: %u/(estimating) %s/s %s",
|
||||
metadata_fetched, formatted_bytes_sec, formatted_bytes_transferred);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_string_append_printf (buf, "Receiving objects: %u%% (%u/%u) %s/s %s",
|
||||
(guint)((((double)fetched) / requested) * 100),
|
||||
fetched, requested, formatted_bytes_sec, formatted_bytes_transferred);
|
||||
}
|
||||
}
|
||||
else if (outstanding_writes)
|
||||
{
|
||||
g_string_append_printf (buf, "Writing objects: %u", outstanding_writes);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_string_append_printf (buf, "Scanning metadata: %u", n_scanned_metadata);
|
||||
}
|
||||
|
||||
return g_string_free (buf, FALSE);
|
||||
}
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GSConsole *console;
|
||||
GError *error;
|
||||
GMainLoop *loop;
|
||||
gboolean complete;
|
||||
} TransactionProgress;
|
||||
|
||||
|
||||
static TransactionProgress *
|
||||
transaction_progress_new (void)
|
||||
{
|
||||
TransactionProgress *self = NULL;
|
||||
|
||||
self = g_slice_new (TransactionProgress);
|
||||
self->error = NULL;
|
||||
self->console = NULL;
|
||||
self->loop = g_main_loop_new (NULL, FALSE);
|
||||
self->complete = FALSE;
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
transaction_progress_free (TransactionProgress *self)
|
||||
{
|
||||
g_main_loop_unref (self->loop);
|
||||
g_slice_free (TransactionProgress, self);
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
end_status_line (TransactionProgress *self)
|
||||
{
|
||||
gboolean ret = TRUE;
|
||||
if (self->console != NULL)
|
||||
ret = gs_console_end_status_line (self->console, NULL, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
add_status_line (TransactionProgress *self,
|
||||
const char *line)
|
||||
{
|
||||
gboolean ret = TRUE;
|
||||
|
||||
if (self->console == NULL)
|
||||
self->console = gs_console_get ();
|
||||
|
||||
ret = gs_console_begin_status_line (self->console, line, NULL, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
transaction_progress_end (TransactionProgress *self)
|
||||
{
|
||||
end_status_line (self);
|
||||
self->console = NULL;
|
||||
g_main_loop_quit (self->loop);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
on_transaction_progress (GDBusProxy *proxy,
|
||||
gchar *sender_name,
|
||||
gchar *signal_name,
|
||||
GVariant *parameters,
|
||||
gpointer user_data)
|
||||
{
|
||||
TransactionProgress *tp = user_data;
|
||||
if (g_strcmp0(signal_name, "SignatureProgress") == 0)
|
||||
{
|
||||
g_autoptr (GVariant) sig = NULL;
|
||||
sig = g_variant_get_child_value (parameters, 0);
|
||||
rpmostree_print_signatures (g_variant_ref (sig), " ");
|
||||
add_status_line (tp, "\n");
|
||||
}
|
||||
if (g_strcmp0(signal_name, "Message") == 0)
|
||||
{
|
||||
g_autofree gchar *message = NULL;
|
||||
|
||||
g_variant_get_child (parameters, 0, "s", &message);
|
||||
add_status_line (tp, message);
|
||||
}
|
||||
else if (g_strcmp0(signal_name, "DownloadProgress") == 0)
|
||||
{
|
||||
g_autofree gchar *line = NULL;
|
||||
|
||||
guint64 start_time;
|
||||
guint64 elapsed_secs;
|
||||
guint outstanding_fetches;
|
||||
guint outstanding_writes;
|
||||
guint n_scanned_metadata;
|
||||
guint metadata_fetched;
|
||||
guint outstanding_metadata_fetches;
|
||||
guint total_delta_parts;
|
||||
guint fetched_delta_parts;
|
||||
guint total_delta_superblocks;
|
||||
guint64 total_delta_part_size;
|
||||
guint fetched;
|
||||
guint requested;
|
||||
guint64 bytes_transferred;
|
||||
guint64 bytes_sec;
|
||||
g_variant_get (parameters, "((tt)(uu)(uuu)(uuut)(uu)(tt))",
|
||||
&start_time, &elapsed_secs,
|
||||
&outstanding_fetches, &outstanding_writes,
|
||||
&n_scanned_metadata, &metadata_fetched,
|
||||
&outstanding_metadata_fetches,
|
||||
&total_delta_parts, &fetched_delta_parts,
|
||||
&total_delta_superblocks, &total_delta_part_size,
|
||||
&fetched, &requested, &bytes_transferred, &bytes_sec);
|
||||
|
||||
line = transaction_get_progress_line (start_time, elapsed_secs,
|
||||
outstanding_fetches,
|
||||
outstanding_writes,
|
||||
n_scanned_metadata,
|
||||
metadata_fetched,
|
||||
outstanding_metadata_fetches,
|
||||
total_delta_parts,
|
||||
fetched_delta_parts,
|
||||
total_delta_superblocks,
|
||||
total_delta_part_size,
|
||||
fetched,
|
||||
requested,
|
||||
bytes_transferred,
|
||||
bytes_sec);
|
||||
add_status_line (tp, line);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_owner_changed (GObject *object,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
/* Owner shouldn't change durning a transaction
|
||||
* that messes with notifications, abort, abort.
|
||||
*/
|
||||
TransactionProgress *tp = user_data;
|
||||
tp->error = g_dbus_error_new_for_dbus_error ("org.projectatomic.rpmostreed.Error.Failed",
|
||||
"Bus owner changed, aborting.");
|
||||
transaction_progress_end (tp);
|
||||
}
|
||||
|
||||
static void
|
||||
transaction_finished (RPMOSTreeTransaction *transaction,
|
||||
TransactionProgress *tp)
|
||||
{
|
||||
g_autofree gchar *message = NULL;
|
||||
gboolean success = FALSE;
|
||||
gboolean complete = FALSE;
|
||||
|
||||
/* if we are already finished don't process */
|
||||
if (tp->complete)
|
||||
return;
|
||||
|
||||
tp->complete = TRUE;
|
||||
|
||||
if (!tp->error)
|
||||
{
|
||||
complete = rpmostree_transaction_get_complete (transaction);
|
||||
success = rpmostree_transaction_get_success (transaction);
|
||||
message = rpmostree_transaction_dup_result_message (transaction);
|
||||
|
||||
g_return_if_fail (complete == TRUE);
|
||||
|
||||
if (success)
|
||||
{
|
||||
add_status_line (tp, message);
|
||||
}
|
||||
else
|
||||
{
|
||||
tp->error = g_dbus_error_new_for_dbus_error ("org.projectatomic.rpmostreed.Error.Failed",
|
||||
message);
|
||||
}
|
||||
}
|
||||
|
||||
transaction_progress_end (tp);
|
||||
}
|
||||
|
||||
static void
|
||||
on_transaction_finished (GObject *object,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
TransactionProgress *tp = user_data;
|
||||
transaction_finished (RPMOSTREE_TRANSACTION (object), tp);
|
||||
}
|
||||
|
||||
static void
|
||||
cancelled_handler (GCancellable *cancellable,
|
||||
gpointer user_data)
|
||||
{
|
||||
RPMOSTreeTransaction *transaction = user_data;
|
||||
rpmostree_transaction_call_cancel_sync (transaction, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
gboolean
|
||||
rpmostree_transaction_get_response_sync (GDBusConnection *connection,
|
||||
const gchar *object_path,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
glnx_unref_object GDBusObjectManager *object_manager = NULL;
|
||||
glnx_unref_object RPMOSTreeTransaction *transaction = NULL;
|
||||
|
||||
TransactionProgress *tp = transaction_progress_new ();
|
||||
|
||||
gint cancel_handler;
|
||||
gboolean is_peer = TRUE;
|
||||
gulong property_handler = 0;
|
||||
gulong signal_handler = 0;
|
||||
gboolean success = FALSE;
|
||||
|
||||
// If we are on the message bus, setup object manager connection
|
||||
// to notify if the owner changes.
|
||||
if (g_dbus_connection_get_unique_name (connection) != NULL)
|
||||
{
|
||||
is_peer = FALSE;
|
||||
object_manager = rpmostree_object_manager_client_new_sync (connection,
|
||||
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
|
||||
BUS_NAME,
|
||||
"/org/projectatomic/rpmostree1",
|
||||
cancellable,
|
||||
error);
|
||||
|
||||
if (object_manager == NULL)
|
||||
goto out;
|
||||
|
||||
g_signal_connect (object_manager,
|
||||
"notify::name-owner",
|
||||
G_CALLBACK (on_owner_changed),
|
||||
tp);
|
||||
}
|
||||
|
||||
transaction = rpmostree_transaction_proxy_new_sync (connection,
|
||||
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
|
||||
is_peer ? NULL : BUS_NAME,
|
||||
object_path,
|
||||
cancellable,
|
||||
error);
|
||||
if (transaction == NULL)
|
||||
goto out;
|
||||
|
||||
// setup cancel handler
|
||||
cancel_handler = g_cancellable_connect (cancellable,
|
||||
G_CALLBACK (cancelled_handler),
|
||||
transaction, NULL);
|
||||
|
||||
signal_handler = g_signal_connect (transaction, "g-signal",
|
||||
G_CALLBACK (on_transaction_progress),
|
||||
tp);
|
||||
|
||||
// Setup finished signal handlers
|
||||
property_handler = g_signal_connect (transaction, "notify::complete",
|
||||
G_CALLBACK (on_transaction_finished),
|
||||
tp);
|
||||
|
||||
if (!rpmostree_transaction_get_complete (transaction))
|
||||
g_main_loop_run (tp->loop);
|
||||
else
|
||||
transaction_finished (transaction, tp);
|
||||
|
||||
g_cancellable_disconnect (cancellable, cancel_handler);
|
||||
|
||||
if (!g_cancellable_set_error_if_cancelled (cancellable, error))
|
||||
{
|
||||
if (tp->error)
|
||||
{
|
||||
g_propagate_error (error, tp->error);
|
||||
}
|
||||
else
|
||||
{
|
||||
success = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (property_handler)
|
||||
g_signal_handler_disconnect (transaction, property_handler);
|
||||
|
||||
if (signal_handler)
|
||||
g_signal_handler_disconnect (transaction, signal_handler);
|
||||
|
||||
transaction_progress_free (tp);
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
rpmostree_print_signatures (GVariant *variant,
|
||||
const gchar *sep)
|
||||
{
|
||||
GString *sigs_buffer;
|
||||
guint i;
|
||||
guint n_sigs = g_variant_n_children (variant);
|
||||
sigs_buffer = g_string_sized_new (256);
|
||||
|
||||
for (i = 0; i < n_sigs; i++)
|
||||
{
|
||||
g_autoptr (GVariant) v = NULL;
|
||||
g_string_append_c (sigs_buffer, '\n');
|
||||
g_variant_get_child (variant, i, "v", &v);
|
||||
ostree_gpg_verify_result_describe_variant (v, sigs_buffer, sep,
|
||||
OSTREE_GPG_SIGNATURE_FORMAT_DEFAULT);
|
||||
}
|
||||
|
||||
g_print ("%s", sigs_buffer->str);
|
||||
g_string_free (sigs_buffer, TRUE);
|
||||
}
|
60
src/app/rpmostree-dbus-helpers.h
Normal file
60
src/app/rpmostree-dbus-helpers.h
Normal file
@ -0,0 +1,60 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This program 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 licence 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib-unix.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "rpm-ostreed-generated.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <ostree.h>
|
||||
|
||||
#define BUS_NAME "org.projectatomic.rpmostree1"
|
||||
|
||||
void
|
||||
rpmostree_cleanup_peer (void);
|
||||
|
||||
gboolean
|
||||
rpmostree_load_connection_and_sysroot (gchar *sysroot,
|
||||
gboolean force_peer,
|
||||
GCancellable *cancellable,
|
||||
GDBusConnection **out_connection,
|
||||
RPMOSTreeSysroot **out_manager,
|
||||
gboolean *out_is_peer,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
rpmostree_load_os_proxy (RPMOSTreeSysroot *sysroot_proxy,
|
||||
gchar *opt_osname,
|
||||
gboolean is_peer,
|
||||
GCancellable *cancellable,
|
||||
RPMOSTreeOS **out_os_proxy,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
rpmostree_transaction_get_response_sync (GDBusConnection *out_connection,
|
||||
const gchar *object_path,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
void
|
||||
rpmostree_print_signatures (GVariant *variant,
|
||||
const gchar *sep);
|
@ -26,6 +26,27 @@
|
||||
#include "rpmostree.h"
|
||||
#include "rpmostree-cleanup.h"
|
||||
|
||||
gboolean
|
||||
rpmostree_print_treepkg_diff_from_sysroot_path (const gchar *sysroot_path,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gs_unref_object OstreeSysroot *sysroot = NULL;
|
||||
gs_unref_object GFile *sysroot_file = NULL;
|
||||
gboolean ret = FALSE;
|
||||
|
||||
sysroot_file = g_file_new_for_path (sysroot_path);
|
||||
sysroot = ostree_sysroot_new (sysroot_file);
|
||||
|
||||
if (!ostree_sysroot_load (sysroot, cancellable, error))
|
||||
goto out;
|
||||
|
||||
ret = rpmostree_print_treepkg_diff (sysroot, cancellable, error);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
rpmostree_print_treepkg_diff (OstreeSysroot *sysroot,
|
||||
GCancellable *cancellable,
|
||||
@ -34,11 +55,11 @@ rpmostree_print_treepkg_diff (OstreeSysroot *sysroot,
|
||||
gboolean ret = FALSE;
|
||||
OstreeDeployment *booted_deployment;
|
||||
OstreeDeployment *new_deployment;
|
||||
gs_unref_ptrarray GPtrArray *deployments =
|
||||
gs_unref_ptrarray GPtrArray *deployments =
|
||||
ostree_sysroot_get_deployments (sysroot);
|
||||
|
||||
booted_deployment = ostree_sysroot_get_booted_deployment (sysroot);
|
||||
|
||||
|
||||
g_assert (deployments->len > 1);
|
||||
new_deployment = deployments->pdata[0];
|
||||
|
||||
@ -52,10 +73,10 @@ rpmostree_print_treepkg_diff (OstreeSysroot *sysroot,
|
||||
g_autoptr(GPtrArray) modified_old = NULL;
|
||||
g_autoptr(GPtrArray) modified_new = NULL;
|
||||
guint i;
|
||||
|
||||
|
||||
if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error))
|
||||
goto out;
|
||||
|
||||
|
||||
if (!rpm_ostree_db_diff (repo, from_rev, to_rev,
|
||||
&removed, &added, &modified_old, &modified_new,
|
||||
cancellable, error))
|
||||
|
@ -28,4 +28,9 @@ gboolean
|
||||
rpmostree_print_treepkg_diff (OstreeSysroot *sysroot,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
rpmostree_print_treepkg_diff_from_sysroot_path (const gchar *sysroot_path,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
G_END_DECLS
|
||||
|
Loading…
Reference in New Issue
Block a user