diff --git a/src/fu-engine-request.c b/src/fu-engine-request.c
index 1ba8f5fdf..c39427976 100644
--- a/src/fu-engine-request.c
+++ b/src/fu-engine-request.c
@@ -80,6 +80,13 @@ fu_engine_request_set_device_flags(FuEngineRequest *self, FwupdDeviceFlags devic
self->device_flags = device_flags;
}
+gboolean
+fu_engine_request_has_device_flag(FuEngineRequest *self, FwupdDeviceFlags device_flag)
+{
+ g_return_val_if_fail(FU_IS_ENGINE_REQUEST(self), FALSE);
+ return (self->device_flags & device_flag) > 0;
+}
+
static void
fu_engine_request_init(FuEngineRequest *self)
{
diff --git a/src/fu-engine-request.h b/src/fu-engine-request.h
index c26fc79b9..c33cade0f 100644
--- a/src/fu-engine-request.h
+++ b/src/fu-engine-request.h
@@ -31,6 +31,8 @@ void
fu_engine_request_set_locale(FuEngineRequest *self, const gchar *locale);
gboolean
fu_engine_request_has_feature_flag(FuEngineRequest *self, FwupdFeatureFlags feature_flag);
+gboolean
+fu_engine_request_has_device_flag(FuEngineRequest *self, FwupdDeviceFlags device_flag);
FwupdDeviceFlags
fu_engine_request_get_device_flags(FuEngineRequest *self);
void
diff --git a/src/fu-main.c b/src/fu-main.c
index fa8845c4d..aedc82ea5 100644
--- a/src/fu-main.c
+++ b/src/fu-main.c
@@ -77,6 +77,7 @@ typedef struct {
PolkitAuthority *authority;
#endif
guint owner_id;
+ guint process_quit_id;
FuEngine *engine;
gboolean update_in_progress;
gboolean pending_sigterm;
@@ -982,6 +983,32 @@ fu_main_device_id_valid(const gchar *device_id, GError **error)
return FALSE;
}
+static gboolean
+fu_main_schedule_process_quit_cb(gpointer user_data)
+{
+ FuMainPrivate *priv = (FuMainPrivate *)user_data;
+
+ g_debug("daemon asked to quit, shutting down");
+ priv->process_quit_id = 0;
+ g_main_loop_quit(priv->loop);
+ return G_SOURCE_REMOVE;
+}
+
+static void
+fu_main_schedule_process_quit(FuMainPrivate *priv)
+{
+ /* busy? */
+ if (priv->update_in_progress) {
+ g_warning("asked to quit during a firmware update, ignoring");
+ return;
+ }
+
+ /* allow the daemon to respond to the request, then quit */
+ if (priv->process_quit_id != 0)
+ g_source_remove(priv->process_quit_id);
+ priv->process_quit_id = g_idle_add(fu_main_schedule_process_quit_cb, priv);
+}
+
static void
fu_main_daemon_method_call(GDBusConnection *connection,
const gchar *sender,
@@ -1165,6 +1192,18 @@ fu_main_daemon_method_call(GDBusConnection *connection,
#endif /* HAVE_POLKIT */
return;
}
+ if (g_strcmp0(method_name, "Quit") == 0) {
+ if (!fu_engine_request_has_device_flag(request, FWUPD_DEVICE_FLAG_TRUSTED)) {
+ g_dbus_method_invocation_return_error_literal(invocation,
+ FWUPD_ERROR,
+ FWUPD_ERROR_PERMISSION_DENIED,
+ "Permission denied");
+ return;
+ }
+ fu_main_schedule_process_quit(priv);
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ return;
+ }
if (g_strcmp0(method_name, "SelfSign") == 0) {
GVariant *prop_value;
const gchar *prop_key;
@@ -1990,6 +2029,8 @@ static void
fu_main_private_free(FuMainPrivate *priv)
{
g_hash_table_unref(priv->sender_items);
+ if (priv->process_quit_id != 0)
+ g_source_remove(priv->process_quit_id);
if (priv->loop != NULL)
g_main_loop_unref(priv->loop);
if (priv->owner_id > 0)
diff --git a/src/org.freedesktop.fwupd.xml b/src/org.freedesktop.fwupd.xml
index d7502a82c..2d34d675a 100644
--- a/src/org.freedesktop.fwupd.xml
+++ b/src/org.freedesktop.fwupd.xml
@@ -821,6 +821,17 @@
+
+
+
+
+
+ Ask the daemon to quit. This can only be called by the root user.
+
+
+
+
+