From 2fa46d382337bd2a294a8560aa59c1d640f22231 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 6 Feb 2023 17:12:10 +0000 Subject: [PATCH] Add support for Quit() in fwupdmgr This allows us to only shut down the P2P daemon in the installed tests. The easy fix would have been to use something like: gdbus call --address unix:path=/run/fwupd.sock --object-path / --method org.freedesktop.fwupd.Quit' ...but the daemon does not implement an ObjectManager, which gdbus requires. This worked correctly for so long because the p2p tests were being run after the bus tests, so shutting down the system daemon had no effect. Fedora 37 seems to have flipped the order for some reason -- and now it *sometimes* matters that we were doing the worng thing... --- data/bash-completion/fwupdmgr | 1 + data/fish-completion/fwupdmgr.fish | 1 + data/installed-tests/fwupdmgr-p2p.sh | 2 +- libfwupd/fwupd-client-sync.c | 42 +++++++++++++++ libfwupd/fwupd-client-sync.h | 4 ++ libfwupd/fwupd-client.c | 77 ++++++++++++++++++++++++++++ libfwupd/fwupd-client.h | 9 ++++ libfwupd/fwupd.map | 3 ++ src/fu-util.c | 13 +++++ 9 files changed, 151 insertions(+), 1 deletion(-) diff --git a/data/bash-completion/fwupdmgr b/data/bash-completion/fwupdmgr index 8fb864fd8..34001e0dd 100644 --- a/data/bash-completion/fwupdmgr +++ b/data/bash-completion/fwupdmgr @@ -26,6 +26,7 @@ _fwupdmgr_cmd_list=( 'local-install' 'modify-config' 'modify-remote' + 'quit' 'reinstall' 'refresh' 'report-history' diff --git a/data/fish-completion/fwupdmgr.fish b/data/fish-completion/fwupdmgr.fish index aab972279..85fe77e25 100644 --- a/data/fish-completion/fwupdmgr.fish +++ b/data/fish-completion/fwupdmgr.fish @@ -66,6 +66,7 @@ complete -c fwupdmgr -n '__fish_use_subcommand' -x -a verify -d 'Checks cryptogr complete -c fwupdmgr -n '__fish_use_subcommand' -x -a verify-update -d 'Update the stored cryptographic hash with current ROM contents' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a inhibit -d 'Inhibit the system to prevent upgrades' complete -c fwupdmgr -n '__fish_use_subcommand' -x -a uninhibit -d 'Uninhibit the system to allow upgrades' +complete -c fwupdmgr -n '__fish_use_subcommand' -x -a quit -d 'Asks the daemon to quit' # commands exclusively consuming device IDs set -l deviceid_consumers activate clear-results downgrade get-releases get-results get-updates reinstall switch-branch unlock update verify verify-update diff --git a/data/installed-tests/fwupdmgr-p2p.sh b/data/installed-tests/fwupdmgr-p2p.sh index 0fa734fd6..b4d5d94aa 100755 --- a/data/installed-tests/fwupdmgr-p2p.sh +++ b/data/installed-tests/fwupdmgr-p2p.sh @@ -20,7 +20,7 @@ rc=$?; if [ $rc != 0 ]; then exit $rc; fi # --- echo "Shutting down P2P daemon..." -gdbus call --system --dest org.freedesktop.fwupd --object-path / --method org.freedesktop.fwupd.Quit +fwupdmgr quit # success! exit 0 diff --git a/libfwupd/fwupd-client-sync.c b/libfwupd/fwupd-client-sync.c index 294786efe..a52d89909 100644 --- a/libfwupd/fwupd-client-sync.c +++ b/libfwupd/fwupd-client-sync.c @@ -109,6 +109,48 @@ fwupd_client_connect(FwupdClient *self, GCancellable *cancellable, GError **erro return TRUE; } +static void +fwupd_client_quit_cb(GObject *source, GAsyncResult *res, gpointer user_data) +{ + FwupdClientHelper *helper = (FwupdClientHelper *)user_data; + helper->ret = fwupd_client_quit_finish(FWUPD_CLIENT(source), res, &helper->error); + g_main_loop_quit(helper->loop); +} + +/** + * fwupd_client_quit: (skip) + * @self: a #FwupdClient + * @cancellable: (nullable): optional #GCancellable + * @error: (nullable): optional return location for an error + * + * Asks the daemon to quit. This can only be called by the root user. + * + * NOTE: This will only actually quit if an install is not already in progress. + * + * Returns: %TRUE for success + * + * Since: 1.8.11 + **/ +gboolean +fwupd_client_quit(FwupdClient *self, GCancellable *cancellable, GError **error) +{ + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE); + g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + + /* call async version and run loop until complete */ + helper = fwupd_client_helper_new(self); + fwupd_client_quit_async(self, cancellable, fwupd_client_quit_cb, helper); + g_main_loop_run(helper->loop); + if (!helper->ret) { + g_propagate_error(error, g_steal_pointer(&helper->error)); + return FALSE; + } + return TRUE; +} + static void fwupd_client_get_devices_cb(GObject *source, GAsyncResult *res, gpointer user_data) { diff --git a/libfwupd/fwupd-client-sync.h b/libfwupd/fwupd-client-sync.h index bbac721fa..d1ad3ba35 100644 --- a/libfwupd/fwupd-client-sync.h +++ b/libfwupd/fwupd-client-sync.h @@ -14,6 +14,10 @@ gboolean fwupd_client_connect(FwupdClient *self, GCancellable *cancellable, GError **error) G_GNUC_WARN_UNUSED_RESULT; +gboolean +fwupd_client_quit(FwupdClient *self, + GCancellable *cancellable, + GError **error) G_GNUC_WARN_UNUSED_RESULT; GPtrArray * fwupd_client_get_devices(FwupdClient *self, GCancellable *cancellable, diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index 77753b2d7..c18b8acf5 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -976,6 +976,83 @@ fwupd_client_disconnect(FwupdClient *self, GError **error) return TRUE; } +static void +fwupd_client_quit_cb(GObject *source, GAsyncResult *res, gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK(user_data); + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error); + if (val == NULL) { + fwupd_client_fixup_dbus_error(error); + g_task_return_error(task, g_steal_pointer(&error)); + return; + } + + /* success */ + g_task_return_boolean(task, TRUE); +} + +/** + * fwupd_client_quit_async: + * @self: a #FwupdClient + * @cancellable: (nullable): optional #GCancellable + * @callback: the function to run on completion + * @callback_data: the data to pass to @callback + * + * Asks the daemon to quit. This can only be called by the root user. + * + * NOTE: This will only actually quit if an install is not already in progress. + * + * Since: 1.8.11 + **/ +void +fwupd_client_quit_async(FwupdClient *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + FwupdClientPrivate *priv = GET_PRIVATE(self); + g_autoptr(GTask) task = NULL; + + g_return_if_fail(FWUPD_IS_CLIENT(self)); + g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable)); + g_return_if_fail(priv->proxy != NULL); + + /* call into daemon */ + task = g_task_new(self, cancellable, callback, callback_data); + g_dbus_proxy_call(priv->proxy, + "Quit", + NULL, + G_DBUS_CALL_FLAGS_NONE, + FWUPD_CLIENT_DBUS_PROXY_TIMEOUT, + cancellable, + fwupd_client_quit_cb, + g_steal_pointer(&task)); +} + +/** + * fwupd_client_quit_finish: + * @self: a #FwupdClient + * @res: (not nullable): the asynchronous result + * @error: (nullable): optional return location for an error + * + * Gets the result of [method@FwupdClient.quit_async]. + * + * Returns: %TRUE for success + * + * Since: 1.8.11 + **/ +gboolean +fwupd_client_quit_finish(FwupdClient *self, GAsyncResult *res, GError **error) +{ + g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE); + g_return_val_if_fail(g_task_is_valid(res, self), FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + return g_task_propagate_boolean(G_TASK(res), error); +} + static void fwupd_client_fixup_dbus_error(GError *error) { diff --git a/libfwupd/fwupd-client.h b/libfwupd/fwupd-client.h index ed7d6a3a9..1cddf1db5 100644 --- a/libfwupd/fwupd-client.h +++ b/libfwupd/fwupd-client.h @@ -82,6 +82,15 @@ fwupd_client_connect_finish(FwupdClient *self, gboolean fwupd_client_disconnect(FwupdClient *self, GError **error) G_GNUC_WARN_UNUSED_RESULT; void +fwupd_client_quit_async(FwupdClient *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data); +gboolean +fwupd_client_quit_finish(FwupdClient *self, + GAsyncResult *res, + GError **error) G_GNUC_WARN_UNUSED_RESULT; +void fwupd_client_get_devices_async(FwupdClient *self, GCancellable *cancellable, GAsyncReadyCallback callback, diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index 8df8c0392..4ece215ee 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -907,6 +907,9 @@ LIBFWUPD_1.8.11 { fwupd_client_inhibit; fwupd_client_inhibit_async; fwupd_client_inhibit_finish; + fwupd_client_quit; + fwupd_client_quit_async; + fwupd_client_quit_finish; fwupd_client_uninhibit; fwupd_client_uninhibit_async; fwupd_client_uninhibit_finish; diff --git a/src/fu-util.c b/src/fu-util.c index 46903479d..155c69712 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -1020,6 +1020,13 @@ fu_util_uninhibit(FuUtilPrivate *priv, gchar **values, GError **error) return fwupd_client_uninhibit(priv->client, values[0], priv->cancellable, error); } +static gboolean +fu_util_quit(FuUtilPrivate *priv, gchar **values, GError **error) +{ + /* success */ + return fwupd_client_quit(priv->client, priv->cancellable, error); +} + static gboolean fu_util_device_test(FuUtilPrivate *priv, gchar **values, GError **error) { @@ -4552,6 +4559,12 @@ main(int argc, char *argv[]) /* TRANSLATORS: command description */ _("Uninhibit the system to allow upgrades"), fu_util_uninhibit); + fu_util_cmd_array_add(cmd_array, + "quit", + NULL, + /* TRANSLATORS: command description */ + _("Asks the daemon to quit"), + fu_util_quit); fu_util_cmd_array_add( cmd_array, "get-bios-settings,get-bios-setting", -- 2.39.5