blob: 0a2b9dae4939a11cb1b298ce58deed234a31e1bc [file] [log] [blame]
Richard Hughes02c90d82018-08-09 12:13:03 +01001/*
Richard Hughesf29a6ee2017-06-02 19:50:37 +01002 * Copyright (C) 2015-2017 Richard Hughes <richard@hughsie.com>
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00003 *
Mario Limonciello51308e62018-05-28 20:05:46 -05004 * SPDX-License-Identifier: LGPL-2.1+
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00005 */
6
Richard Hughesb08e7bc2018-09-11 10:51:13 +01007#define G_LOG_DOMAIN "FuMain"
8
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00009#include "config.h"
10
Richard Hughes481aa2a2018-09-18 20:51:46 +010011#include <xmlb.h>
Richard Hughes9945edb2017-06-19 10:03:55 +010012#include <fwupd.h>
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000013#include <gio/gunixfdlist.h>
14#include <glib/gi18n.h>
Mario Limonciello6754f5a2018-10-11 10:50:03 -050015#include <glib-unix.h>
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000016#include <locale.h>
Richard Hughesf508e762015-02-27 12:49:36 +000017#include <polkit/polkit.h>
Richard Hughes67ec8982015-03-03 11:39:27 +000018#include <stdlib.h>
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000019
Richard Hughes68982c62017-09-13 15:40:14 +010020#include "fwupd-device-private.h"
Richard Hughes1642b3b2017-06-05 17:40:08 +010021#include "fwupd-release-private.h"
Richard Hughes4c369702017-06-16 15:31:38 +010022#include "fwupd-remote-private.h"
Richard Hughesd6db6b42017-04-12 15:03:10 +010023#include "fwupd-resources.h"
Richard Hughes8e9762d2016-03-17 10:14:15 +000024
Richard Hughes943d2c92017-06-21 09:04:39 +010025#include "fu-common.h"
Richard Hughes8bbfdf42015-02-26 22:28:09 +000026#include "fu-debug.h"
Richard Hughes68982c62017-09-13 15:40:14 +010027#include "fu-device-private.h"
Richard Hughes9945edb2017-06-19 10:03:55 +010028#include "fu-engine.h"
Richard Hughes4ad41f02018-05-08 14:35:36 +010029#include "fu-install-task.h"
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000030
Philip Withnallbc339aa2016-11-22 16:13:22 +000031#ifndef HAVE_POLKIT_0_114
Mario Limoncielloa98df552018-04-16 12:15:51 -050032#pragma clang diagnostic push
33#pragma clang diagnostic ignored "-Wunused-function"
Richard Hughes60f48c22015-10-08 20:25:51 +010034G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitAuthorizationResult, g_object_unref)
35G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitSubject, g_object_unref)
Mario Limoncielloa98df552018-04-16 12:15:51 -050036#pragma clang diagnostic pop
Richard Hughes60f48c22015-10-08 20:25:51 +010037#endif
38
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000039typedef struct {
40 GDBusConnection *connection;
41 GDBusNodeInfo *introspection_daemon;
Richard Hughes18423292015-03-09 17:10:50 +000042 GDBusProxy *proxy_uid;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000043 GMainLoop *loop;
Richard Hughesf508e762015-02-27 12:49:36 +000044 PolkitAuthority *authority;
Richard Hughesf0a799e2017-01-17 20:13:30 +000045 guint owner_id;
Richard Hughes9945edb2017-06-19 10:03:55 +010046 FuEngine *engine;
Mario Limonciello6754f5a2018-10-11 10:50:03 -050047 gboolean update_in_progress;
48 gboolean pending_sigterm;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000049} FuMainPrivate;
50
Mario Limonciello6754f5a2018-10-11 10:50:03 -050051static gboolean
52fu_main_sigterm_cb (gpointer user_data)
53{
54 FuMainPrivate *priv = (FuMainPrivate *) user_data;
55 if (!priv->update_in_progress) {
56 g_main_loop_quit (priv->loop);
57 return G_SOURCE_REMOVE;
58 }
59 g_warning ("Received SIGTERM during a firmware update, ignoring");
60 priv->pending_sigterm = TRUE;
61 return G_SOURCE_CONTINUE;
62}
63
Richard Hughesd7022b52015-03-11 19:47:06 +000064static void
Richard Hughes9945edb2017-06-19 10:03:55 +010065fu_main_engine_changed_cb (FuEngine *engine, FuMainPrivate *priv)
Richard Hughesd7022b52015-03-11 19:47:06 +000066{
67 /* not yet connected */
68 if (priv->connection == NULL)
69 return;
70 g_dbus_connection_emit_signal (priv->connection,
71 NULL,
72 FWUPD_DBUS_PATH,
73 FWUPD_DBUS_INTERFACE,
74 "Changed",
75 NULL, NULL);
76}
77
Richard Hughes8ca33782016-04-28 15:04:31 +010078static void
Richard Hughes9945edb2017-06-19 10:03:55 +010079fu_main_engine_device_added_cb (FuEngine *engine,
80 FuDevice *device,
81 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +010082{
83 GVariant *val;
84
85 /* not yet connected */
86 if (priv->connection == NULL)
87 return;
Richard Hughese0bd53e2017-09-17 08:29:02 +010088 val = fwupd_device_to_variant (FWUPD_DEVICE (device));
Richard Hughes8ca33782016-04-28 15:04:31 +010089 g_dbus_connection_emit_signal (priv->connection,
90 NULL,
91 FWUPD_DBUS_PATH,
92 FWUPD_DBUS_INTERFACE,
93 "DeviceAdded",
Richard Hughese0bd53e2017-09-17 08:29:02 +010094 g_variant_new_tuple (&val, 1), NULL);
Richard Hughes8ca33782016-04-28 15:04:31 +010095}
96
Richard Hughes8ca33782016-04-28 15:04:31 +010097static void
Richard Hughes9945edb2017-06-19 10:03:55 +010098fu_main_engine_device_removed_cb (FuEngine *engine,
99 FuDevice *device,
100 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +0100101{
102 GVariant *val;
103
104 /* not yet connected */
105 if (priv->connection == NULL)
106 return;
Richard Hughese0bd53e2017-09-17 08:29:02 +0100107 val = fwupd_device_to_variant (FWUPD_DEVICE (device));
Richard Hughes8ca33782016-04-28 15:04:31 +0100108 g_dbus_connection_emit_signal (priv->connection,
109 NULL,
110 FWUPD_DBUS_PATH,
111 FWUPD_DBUS_INTERFACE,
112 "DeviceRemoved",
Richard Hughese0bd53e2017-09-17 08:29:02 +0100113 g_variant_new_tuple (&val, 1), NULL);
Richard Hughes8ca33782016-04-28 15:04:31 +0100114}
115
Richard Hughes8ca33782016-04-28 15:04:31 +0100116static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100117fu_main_engine_device_changed_cb (FuEngine *engine,
118 FuDevice *device,
119 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +0100120{
121 GVariant *val;
122
123 /* not yet connected */
124 if (priv->connection == NULL)
125 return;
Richard Hughese0bd53e2017-09-17 08:29:02 +0100126 val = fwupd_device_to_variant (FWUPD_DEVICE (device));
Richard Hughes8ca33782016-04-28 15:04:31 +0100127 g_dbus_connection_emit_signal (priv->connection,
128 NULL,
129 FWUPD_DBUS_PATH,
130 FWUPD_DBUS_INTERFACE,
131 "DeviceChanged",
Richard Hughese0bd53e2017-09-17 08:29:02 +0100132 g_variant_new_tuple (&val, 1), NULL);
Richard Hughes8ca33782016-04-28 15:04:31 +0100133}
134
Richard Hughes773ce982015-03-09 22:40:57 +0000135static void
136fu_main_emit_property_changed (FuMainPrivate *priv,
137 const gchar *property_name,
138 GVariant *property_value)
139{
140 GVariantBuilder builder;
141 GVariantBuilder invalidated_builder;
142
143 /* not yet connected */
Richard Hughes34fcc022018-09-19 16:16:15 +0100144 if (priv->connection == NULL) {
145 g_variant_unref (g_variant_ref_sink (property_value));
Richard Hughes773ce982015-03-09 22:40:57 +0000146 return;
Richard Hughes34fcc022018-09-19 16:16:15 +0100147 }
Richard Hughes773ce982015-03-09 22:40:57 +0000148
149 /* build the dict */
150 g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as"));
151 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
152 g_variant_builder_add (&builder,
153 "{sv}",
154 property_name,
155 property_value);
156 g_dbus_connection_emit_signal (priv->connection,
157 NULL,
158 FWUPD_DBUS_PATH,
159 "org.freedesktop.DBus.Properties",
160 "PropertiesChanged",
161 g_variant_new ("(sa{sv}as)",
162 FWUPD_DBUS_INTERFACE,
163 &builder,
164 &invalidated_builder),
165 NULL);
166 g_variant_builder_clear (&builder);
167 g_variant_builder_clear (&invalidated_builder);
168}
169
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100170static void
171fu_main_set_status (FuMainPrivate *priv, FwupdStatus status)
172{
173 g_debug ("Emitting PropertyChanged('Status'='%s')",
174 fwupd_status_to_string (status));
175 fu_main_emit_property_changed (priv, "Status",
176 g_variant_new_uint32 (status));
177}
Richard Hughes773ce982015-03-09 22:40:57 +0000178
Richard Hughes9945edb2017-06-19 10:03:55 +0100179static void
180fu_main_engine_status_changed_cb (FuEngine *engine,
181 FwupdStatus status,
182 FuMainPrivate *priv)
183{
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100184 fu_main_set_status (priv, status);
Richard Hughes75b965d2018-11-15 13:51:21 +0000185
186 /* engine has gone idle */
187 if (status == FWUPD_STATUS_SHUTDOWN)
188 g_main_loop_quit (priv->loop);
Richard Hughes773ce982015-03-09 22:40:57 +0000189}
190
Richard Hughes876c0072016-08-17 14:51:03 +0100191static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100192fu_main_engine_percentage_changed_cb (FuEngine *engine,
193 guint percentage,
194 FuMainPrivate *priv)
Richard Hughes876c0072016-08-17 14:51:03 +0100195{
Richard Hughes876c0072016-08-17 14:51:03 +0100196 g_debug ("Emitting PropertyChanged('Percentage'='%u%%')", percentage);
197 fu_main_emit_property_changed (priv, "Percentage",
198 g_variant_new_uint32 (percentage));
199}
200
Mario Limoncielloe3016602018-09-06 11:20:59 -0500201static gboolean
202fu_main_get_device_flags_for_sender (FuMainPrivate *priv, const char *sender,
203 FwupdDeviceFlags *flags, GError **error)
204{
205 uid_t calling_uid;
206 g_autoptr(GVariant) value = NULL;
207
208 g_return_val_if_fail (sender != NULL, FALSE);
209 g_return_val_if_fail (flags != NULL, FALSE);
210
211 value = g_dbus_proxy_call_sync (priv->proxy_uid,
212 "GetConnectionUnixUser",
213 g_variant_new ("(s)", sender),
214 G_DBUS_CALL_FLAGS_NONE,
215 2000,
216 NULL,
217 error);
218 if (value == NULL) {
219 g_prefix_error (error, "failed to read user id of caller: ");
220 return FALSE;
221 }
222 g_variant_get (value, "(u)", &calling_uid);
223 if (calling_uid == 0)
224 *flags |= FWUPD_DEVICE_FLAG_TRUSTED;
225
226 return TRUE;
227}
228
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000229static GVariant *
Mario Limoncielloe3016602018-09-06 11:20:59 -0500230fu_main_device_array_to_variant (FuMainPrivate *priv, const gchar *sender,
231 GPtrArray *devices, GError **error)
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000232{
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000233 GVariantBuilder builder;
Mario Limoncielloe3016602018-09-06 11:20:59 -0500234 FwupdDeviceFlags flags = FWUPD_DEVICE_FLAG_NONE;
235
Richard Hughes9945edb2017-06-19 10:03:55 +0100236 g_return_val_if_fail (devices->len > 0, NULL);
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000237 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
Mario Limoncielloe3016602018-09-06 11:20:59 -0500238
239 if (!fu_main_get_device_flags_for_sender (priv, sender, &flags, error))
Richard Hughes83cce1b2018-09-10 16:42:30 +0100240 return NULL;
Mario Limoncielloe3016602018-09-06 11:20:59 -0500241
Richard Hughesf192bf02016-07-22 08:26:43 +0100242 for (guint i = 0; i < devices->len; i++) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100243 FuDevice *device = g_ptr_array_index (devices, i);
Mario Limoncielloe3016602018-09-06 11:20:59 -0500244 GVariant *tmp = fwupd_device_to_variant_full (FWUPD_DEVICE (device),
245 flags);
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000246 g_variant_builder_add_value (&builder, tmp);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000247 }
Richard Hughes9e1b1402017-09-15 16:29:54 +0100248 return g_variant_new ("(aa{sv})", &builder);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000249}
250
Richard Hughes9945edb2017-06-19 10:03:55 +0100251static GVariant *
252fu_main_release_array_to_variant (GPtrArray *results)
Richard Hughes060af612016-08-17 17:32:34 +0100253{
Richard Hughes9945edb2017-06-19 10:03:55 +0100254 GVariantBuilder builder;
255 g_return_val_if_fail (results->len > 0, NULL);
256 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
257 for (guint i = 0; i < results->len; i++) {
258 FwupdRelease *rel = g_ptr_array_index (results, i);
Richard Hughese0bd53e2017-09-17 08:29:02 +0100259 GVariant *tmp = fwupd_release_to_variant (rel);
Richard Hughes9945edb2017-06-19 10:03:55 +0100260 g_variant_builder_add_value (&builder, tmp);
261 }
262 return g_variant_new ("(aa{sv})", &builder);
Richard Hughes060af612016-08-17 17:32:34 +0100263}
264
Richard Hughes9945edb2017-06-19 10:03:55 +0100265static GVariant *
266fu_main_remote_array_to_variant (GPtrArray *remotes)
Richard Hughes060af612016-08-17 17:32:34 +0100267{
Richard Hughes9945edb2017-06-19 10:03:55 +0100268 GVariantBuilder builder;
269 g_return_val_if_fail (remotes->len > 0, NULL);
270 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
271 for (guint i = 0; i < remotes->len; i++) {
272 FwupdRemote *remote = g_ptr_array_index (remotes, i);
Richard Hughese0bd53e2017-09-17 08:29:02 +0100273 GVariant *tmp = fwupd_remote_to_variant (remote);
Richard Hughes9945edb2017-06-19 10:03:55 +0100274 g_variant_builder_add_value (&builder, tmp);
275 }
276 return g_variant_new ("(aa{sv})", &builder);
Richard Hughes060af612016-08-17 17:32:34 +0100277}
278
Richard Hughes9945edb2017-06-19 10:03:55 +0100279static GVariant *
280fu_main_result_array_to_variant (GPtrArray *results)
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000281{
Richard Hughes9945edb2017-06-19 10:03:55 +0100282 GVariantBuilder builder;
283 g_return_val_if_fail (results->len > 0, NULL);
284 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
285 for (guint i = 0; i < results->len; i++) {
Richard Hughes93b15762017-09-15 11:05:23 +0100286 FwupdDevice *result = g_ptr_array_index (results, i);
Richard Hughese0bd53e2017-09-17 08:29:02 +0100287 GVariant *tmp = fwupd_device_to_variant (result);
Richard Hughes9945edb2017-06-19 10:03:55 +0100288 g_variant_builder_add_value (&builder, tmp);
289 }
Richard Hughes9e1b1402017-09-15 16:29:54 +0100290 return g_variant_new ("(aa{sv})", &builder);
Richard Hughesf508e762015-02-27 12:49:36 +0000291}
292
Richard Hughesf508e762015-02-27 12:49:36 +0000293typedef struct {
294 GDBusMethodInvocation *invocation;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100295 PolkitSubject *subject;
296 GPtrArray *install_tasks;
297 GPtrArray *action_ids;
Richard Hughes2d6e1862016-03-18 09:20:37 +0000298 FwupdInstallFlags flags;
Richard Hughes5d14def2015-10-07 17:43:10 +0100299 GBytes *blob_cab;
Richard Hughes67ec8982015-03-03 11:39:27 +0000300 FuMainPrivate *priv;
Richard Hughes9945edb2017-06-19 10:03:55 +0100301 gchar *device_id;
Richard Hughesa6bd5582017-09-07 14:32:22 +0100302 gchar *remote_id;
303 gchar *key;
304 gchar *value;
Richard Hughes481aa2a2018-09-18 20:51:46 +0100305 XbSilo *silo;
Richard Hughesf508e762015-02-27 12:49:36 +0000306} FuMainAuthHelper;
307
Richard Hughesf508e762015-02-27 12:49:36 +0000308static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100309fu_main_auth_helper_free (FuMainAuthHelper *helper)
Richard Hughesf508e762015-02-27 12:49:36 +0000310{
Richard Hughes4ced4662016-08-26 11:02:31 +0100311 if (helper->blob_cab != NULL)
Richard Hughes5d14def2015-10-07 17:43:10 +0100312 g_bytes_unref (helper->blob_cab);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100313 if (helper->subject != NULL)
314 g_object_unref (helper->subject);
Richard Hughes481aa2a2018-09-18 20:51:46 +0100315 if (helper->silo != NULL)
316 g_object_unref (helper->silo);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100317 if (helper->install_tasks != NULL)
318 g_ptr_array_unref (helper->install_tasks);
319 if (helper->action_ids != NULL)
320 g_ptr_array_unref (helper->action_ids);
Richard Hughes9945edb2017-06-19 10:03:55 +0100321 g_free (helper->device_id);
Richard Hughesa6bd5582017-09-07 14:32:22 +0100322 g_free (helper->remote_id);
323 g_free (helper->key);
324 g_free (helper->value);
Richard Hughes67ec8982015-03-03 11:39:27 +0000325 g_object_unref (helper->invocation);
Richard Hughesf508e762015-02-27 12:49:36 +0000326 g_free (helper);
327}
328
Mario Limoncielloa98df552018-04-16 12:15:51 -0500329#pragma clang diagnostic push
330#pragma clang diagnostic ignored "-Wunused-function"
Richard Hughes9945edb2017-06-19 10:03:55 +0100331G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuMainAuthHelper, fu_main_auth_helper_free)
Mario Limoncielloa98df552018-04-16 12:15:51 -0500332#pragma clang diagnostic pop
Richard Hughes9945edb2017-06-19 10:03:55 +0100333
334/* error may or may not already have been set */
Richard Hughesb75c92d2016-02-20 20:22:00 +0000335static gboolean
Richard Hughes9945edb2017-06-19 10:03:55 +0100336fu_main_authorization_is_valid (PolkitAuthorizationResult *auth, GError **error)
Richard Hughes9a410ce2016-02-28 15:58:54 +0000337{
Richard Hughes9945edb2017-06-19 10:03:55 +0100338 /* failed */
Richard Hughesf508e762015-02-27 12:49:36 +0000339 if (auth == NULL) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100340 g_autofree gchar *message = g_strdup ((*error)->message);
341 g_clear_error (error);
342 g_set_error (error,
Richard Hughes060af612016-08-17 17:32:34 +0100343 FWUPD_ERROR,
344 FWUPD_ERROR_AUTH_FAILED,
Richard Hughes9945edb2017-06-19 10:03:55 +0100345 "Could not check for auth: %s", message);
346 return FALSE;
Richard Hughesf508e762015-02-27 12:49:36 +0000347 }
348
349 /* did not auth */
350 if (!polkit_authorization_result_get_is_authorized (auth)) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100351 g_set_error_literal (error,
Richard Hughes060af612016-08-17 17:32:34 +0100352 FWUPD_ERROR,
353 FWUPD_ERROR_AUTH_FAILED,
Richard Hughes9945edb2017-06-19 10:03:55 +0100354 "Failed to obtain auth");
355 return FALSE;
Richard Hughesf508e762015-02-27 12:49:36 +0000356 }
357
358 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100359 return TRUE;
Richard Hughes5d14def2015-10-07 17:43:10 +0100360}
361
Richard Hughesdf7950b2016-01-31 10:18:40 +0000362static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100363fu_main_authorize_unlock_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100364{
Richard Hughes9945edb2017-06-19 10:03:55 +0100365 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
366 g_autoptr(GError) error = NULL;
367 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100368
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100369
Richard Hughes9945edb2017-06-19 10:03:55 +0100370 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100371 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughes9945edb2017-06-19 10:03:55 +0100372 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
373 res, &error);
374 if (!fu_main_authorization_is_valid (auth, &error)) {
375 g_dbus_method_invocation_return_gerror (helper->invocation, error);
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100376 return;
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100377 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100378
379 /* authenticated */
380 if (!fu_engine_unlock (helper->priv->engine, helper->device_id, &error)) {
381 g_dbus_method_invocation_return_gerror (helper->invocation, error);
382 return;
383 }
384
385 /* success */
386 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100387}
388
389static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100390fu_main_authorize_verify_update_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughesdf7950b2016-01-31 10:18:40 +0000391{
Richard Hughes9945edb2017-06-19 10:03:55 +0100392 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
393 g_autoptr(GError) error = NULL;
394 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughesdf7950b2016-01-31 10:18:40 +0000395
Richard Hughes9945edb2017-06-19 10:03:55 +0100396 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100397 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughes9945edb2017-06-19 10:03:55 +0100398 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
399 res, &error);
400 if (!fu_main_authorization_is_valid (auth, &error)) {
401 g_dbus_method_invocation_return_gerror (helper->invocation, error);
Richard Hughesdf7950b2016-01-31 10:18:40 +0000402 return;
Richard Hughesf192bf02016-07-22 08:26:43 +0100403 }
Richard Hughesdf7950b2016-01-31 10:18:40 +0000404
Richard Hughes9945edb2017-06-19 10:03:55 +0100405 /* authenticated */
406 if (!fu_engine_verify_update (helper->priv->engine, helper->device_id, &error)) {
407 g_dbus_method_invocation_return_gerror (helper->invocation, error);
408 return;
Richard Hughes404cc512016-12-21 16:09:48 +0000409 }
410
411 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100412 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes99147f12016-05-17 09:35:04 +0100413}
414
Richard Hughes9945edb2017-06-19 10:03:55 +0100415static void
Richard Hughesa6bd5582017-09-07 14:32:22 +0100416fu_main_authorize_modify_remote_cb (GObject *source, GAsyncResult *res, gpointer user_data)
417{
418 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
419 g_autoptr(GError) error = NULL;
420 g_autoptr(PolkitAuthorizationResult) auth = NULL;
421
422 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100423 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughesa6bd5582017-09-07 14:32:22 +0100424 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
425 res, &error);
426 if (!fu_main_authorization_is_valid (auth, &error)) {
427 g_dbus_method_invocation_return_gerror (helper->invocation, error);
428 return;
429 }
430
431 /* authenticated */
432 if (!fu_engine_modify_remote (helper->priv->engine,
433 helper->remote_id,
434 helper->key,
435 helper->value,
436 &error)) {
437 g_dbus_method_invocation_return_gerror (helper->invocation, error);
438 return;
439 }
440
441 /* success */
442 g_dbus_method_invocation_return_value (helper->invocation, NULL);
443}
444
Richard Hughes4ad41f02018-05-08 14:35:36 +0100445static void fu_main_authorize_install_queue (FuMainAuthHelper *helper);
446
Richard Hughesa6bd5582017-09-07 14:32:22 +0100447static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100448fu_main_authorize_install_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughes404cc512016-12-21 16:09:48 +0000449{
Richard Hughes9945edb2017-06-19 10:03:55 +0100450 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
Richard Hughes46832432015-09-11 13:43:15 +0100451 g_autoptr(GError) error = NULL;
Richard Hughes9945edb2017-06-19 10:03:55 +0100452 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughes18423292015-03-09 17:10:50 +0000453
Richard Hughes9945edb2017-06-19 10:03:55 +0100454 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100455 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughes9945edb2017-06-19 10:03:55 +0100456 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
457 res, &error);
458 if (!fu_main_authorization_is_valid (auth, &error)) {
459 g_dbus_method_invocation_return_gerror (helper->invocation, error);
460 return;
Richard Hughes0e883ee2015-03-18 17:22:33 +0000461 }
462
Richard Hughes4ad41f02018-05-08 14:35:36 +0100463 /* do the next authentication action ID */
464 fu_main_authorize_install_queue (g_steal_pointer (&helper));
465}
466
467static void
468fu_main_authorize_install_queue (FuMainAuthHelper *helper_ref)
469{
470 FuMainPrivate *priv = helper_ref->priv;
471 g_autoptr(FuMainAuthHelper) helper = helper_ref;
472 g_autoptr(GError) error = NULL;
Mario Limonciello6754f5a2018-10-11 10:50:03 -0500473 gboolean ret;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100474
475 /* still more things to to authenticate */
476 if (helper->action_ids->len > 0) {
477 g_autofree gchar *action_id = g_strdup (g_ptr_array_index (helper->action_ids, 0));
478 g_autoptr(PolkitSubject) subject = g_object_ref (helper->subject);
479 g_ptr_array_remove_index (helper->action_ids, 0);
480 polkit_authority_check_authorization (priv->authority, subject,
481 action_id, NULL,
482 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
483 NULL,
484 fu_main_authorize_install_cb,
485 g_steal_pointer (&helper));
Richard Hughes9945edb2017-06-19 10:03:55 +0100486 return;
Richard Hughes654f6b82016-04-25 12:29:48 +0100487 }
488
Richard Hughes4ad41f02018-05-08 14:35:36 +0100489 /* all authenticated, so install all the things */
Mario Limonciello6754f5a2018-10-11 10:50:03 -0500490 priv->update_in_progress = TRUE;
491 ret = fu_engine_install_tasks (helper->priv->engine,
492 helper->install_tasks,
493 helper->blob_cab,
494 helper->flags,
495 &error);
496 priv->update_in_progress = FALSE;
497 if (priv->pending_sigterm)
498 g_main_loop_quit (priv->loop);
499 if (!ret) {
Richard Hughesdbd8c762018-06-15 20:31:40 +0100500 g_dbus_method_invocation_return_gerror (helper->invocation, error);
501 return;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100502 }
503
Richard Hughes654f6b82016-04-25 12:29:48 +0100504 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100505 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes4c369702017-06-16 15:31:38 +0100506}
507
Richard Hughes4ad41f02018-05-08 14:35:36 +0100508#if !GLIB_CHECK_VERSION(2,54,0)
509static gboolean
510g_ptr_array_find (GPtrArray *haystack, gconstpointer needle, guint *index_)
511{
512 for (guint i = 0; i < haystack->len; i++) {
513 gconstpointer *tmp = g_ptr_array_index (haystack, i);
514 if (tmp == needle) {
515 if (index_ != NULL) {
516 *index_ = i;
517 return TRUE;
518 }
519 }
520 }
521 return FALSE;
522}
523#endif
524
Richard Hughes9f86ade2018-05-10 21:11:22 +0100525static gint
526fu_main_install_task_sort_cb (gconstpointer a, gconstpointer b)
527{
528 FuInstallTask *task_a = *((FuInstallTask **) a);
529 FuInstallTask *task_b = *((FuInstallTask **) b);
Richard Hughesc02cb832018-05-20 10:31:04 +0100530 return fu_install_task_compare (task_a, task_b);
Richard Hughes9f86ade2018-05-10 21:11:22 +0100531}
532
Mario Limonciello2dd731b2018-10-09 15:25:18 -0500533static GPtrArray *
534fu_main_get_device_family (FuMainAuthHelper *helper, GError **error)
535{
536 FuDevice *parent;
537 GPtrArray *children;
538 g_autoptr(FuDevice) device = NULL;
539 g_autoptr(GPtrArray) devices_possible = NULL;
540
541 /* get the device */
542 device = fu_engine_get_device (helper->priv->engine, helper->device_id, error);
543 if (device == NULL)
544 return NULL;
545
546 /* device itself */
547 devices_possible = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
548 g_ptr_array_add (devices_possible, g_object_ref (device));
549
550 /* add device children */
551 children = fu_device_get_children (device);
552 for (guint i = 0; i < children->len; i++) {
553 FuDevice *child = g_ptr_array_index (children, i);
554 g_ptr_array_add (devices_possible, g_object_ref (child));
555 }
556
557 /* add parent and siblings, not including the device itself */
558 parent = fu_device_get_parent (device);
559 if (parent != NULL) {
560 GPtrArray *siblings = fu_device_get_children (parent);
561 g_ptr_array_add (devices_possible, g_object_ref (parent));
562 for (guint i = 0; i < siblings->len; i++) {
563 FuDevice *sibling = g_ptr_array_index (siblings, i);
564 if (sibling == device)
565 continue;
566 g_ptr_array_add (devices_possible, g_object_ref (sibling));
567 }
568 }
569
570 /* success */
571 return g_steal_pointer (&devices_possible);
572}
573
Richard Hughes4ad41f02018-05-08 14:35:36 +0100574static gboolean
575fu_main_install_with_helper (FuMainAuthHelper *helper_ref, GError **error)
576{
577 FuMainPrivate *priv = helper_ref->priv;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100578 g_autoptr(FuMainAuthHelper) helper = helper_ref;
Richard Hughes481aa2a2018-09-18 20:51:46 +0100579 g_autoptr(GPtrArray) components = NULL;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100580 g_autoptr(GPtrArray) devices_possible = NULL;
581 g_autoptr(GPtrArray) errors = NULL;
582
Mario Limonciello2dd731b2018-10-09 15:25:18 -0500583 /* get a list of devices that in some way match the device_id */
Richard Hughes4ad41f02018-05-08 14:35:36 +0100584 if (g_strcmp0 (helper->device_id, FWUPD_DEVICE_ID_ANY) == 0) {
585 devices_possible = fu_engine_get_devices (priv->engine, error);
Mario Limonciello2dd731b2018-10-09 15:25:18 -0500586 if (devices_possible == NULL)
Richard Hughes4ad41f02018-05-08 14:35:36 +0100587 return FALSE;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100588 } else {
Mario Limonciello2dd731b2018-10-09 15:25:18 -0500589 devices_possible = fu_main_get_device_family (helper, error);
590 if (devices_possible == NULL)
Richard Hughes4ad41f02018-05-08 14:35:36 +0100591 return FALSE;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100592 }
593
Richard Hughes481aa2a2018-09-18 20:51:46 +0100594 /* parse silo */
595 helper->silo = fu_engine_get_silo_from_blob (priv->engine,
596 helper->blob_cab,
597 error);
598 if (helper->silo == NULL)
Richard Hughes4ad41f02018-05-08 14:35:36 +0100599 return FALSE;
600
Richard Hughes481aa2a2018-09-18 20:51:46 +0100601 /* for each component in the silo */
602 components = xb_silo_query (helper->silo, "component", 0, error);
603 if (components == NULL)
604 return FALSE;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100605 helper->action_ids = g_ptr_array_new_with_free_func (g_free);
606 helper->install_tasks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
607 errors = g_ptr_array_new_with_free_func ((GDestroyNotify) g_error_free);
Richard Hughes481aa2a2018-09-18 20:51:46 +0100608 for (guint i = 0; i < components->len; i++) {
609 XbNode *component = g_ptr_array_index (components, i);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100610
611 /* do any devices pass the requirements */
612 for (guint j = 0; j < devices_possible->len; j++) {
613 FuDevice *device = g_ptr_array_index (devices_possible, j);
614 const gchar *action_id;
615 g_autoptr(FuInstallTask) task = NULL;
616 g_autoptr(GError) error_local = NULL;
617
618 /* is this component valid for the device */
Richard Hughes481aa2a2018-09-18 20:51:46 +0100619 task = fu_install_task_new (device, component);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100620 if (!fu_engine_check_requirements (priv->engine,
Richard Hughes1d1f5cf2018-05-19 23:06:03 +0100621 task,
622 helper->flags,
Richard Hughes4ad41f02018-05-08 14:35:36 +0100623 &error_local)) {
624 g_debug ("requirement on %s:%s failed: %s",
625 fu_device_get_id (device),
Richard Hughes481aa2a2018-09-18 20:51:46 +0100626 xb_node_query_text (component, "id", NULL),
Richard Hughes4ad41f02018-05-08 14:35:36 +0100627 error_local->message);
628 g_ptr_array_add (errors, g_steal_pointer (&error_local));
629 continue;
630 }
631
632 /* get the action IDs for the valid device */
633 action_id = fu_install_task_get_action_id (task);
634 if (!g_ptr_array_find (helper->action_ids, action_id, NULL))
635 g_ptr_array_add (helper->action_ids, g_strdup (action_id));
636 g_ptr_array_add (helper->install_tasks, g_steal_pointer (&task));
637 }
638 }
639
Richard Hughes9f86ade2018-05-10 21:11:22 +0100640 /* order the install tasks by the device priority */
641 g_ptr_array_sort (helper->install_tasks, fu_main_install_task_sort_cb);
642
Richard Hughes4ad41f02018-05-08 14:35:36 +0100643 /* nothing suitable */
644 if (helper->install_tasks->len == 0) {
Richard Hughese82eef32018-05-20 10:41:26 +0100645 GError *error_tmp = fu_common_error_array_get_best (errors);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100646 g_propagate_error (error, error_tmp);
647 return FALSE;
648 }
649
650 /* authenticate all things in the action_ids */
651 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
652 fu_main_authorize_install_queue (g_steal_pointer (&helper));
653 return TRUE;
654}
655
Richard Hughesb6f79552017-11-11 07:58:17 +0000656static gboolean
657fu_main_device_id_valid (const gchar *device_id, GError **error)
658{
659 if (g_strcmp0 (device_id, FWUPD_DEVICE_ID_ANY) == 0)
660 return TRUE;
661 if (device_id != NULL && strlen (device_id) >= 4)
662 return TRUE;
663 g_set_error (error,
664 FWUPD_ERROR,
665 FWUPD_ERROR_INTERNAL,
666 "invalid device ID: %s",
667 device_id);
668 return FALSE;
669}
670
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000671static void
672fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender,
673 const gchar *object_path, const gchar *interface_name,
674 const gchar *method_name, GVariant *parameters,
675 GDBusMethodInvocation *invocation, gpointer user_data)
676{
677 FuMainPrivate *priv = (FuMainPrivate *) user_data;
Richard Hughes9945edb2017-06-19 10:03:55 +0100678 GVariant *val = NULL;
Richard Hughes060af612016-08-17 17:32:34 +0100679 g_autoptr(GError) error = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000680
Richard Hughes75b965d2018-11-15 13:51:21 +0000681 /* activity */
682 fu_engine_idle_reset (priv->engine);
683
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000684 if (g_strcmp0 (method_name, "GetDevices") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100685 g_autoptr(GPtrArray) devices = NULL;
Richard Hughesf508e762015-02-27 12:49:36 +0000686 g_debug ("Called %s()", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +0100687 devices = fu_engine_get_devices (priv->engine, &error);
688 if (devices == NULL) {
689 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7708a0f2015-07-21 08:41:22 +0100690 return;
691 }
Mario Limoncielloe3016602018-09-06 11:20:59 -0500692 val = fu_main_device_array_to_variant (priv, sender, devices, &error);
693 if (val == NULL) {
694 g_dbus_method_invocation_return_gerror (invocation, error);
695 return;
696 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100697 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes7708a0f2015-07-21 08:41:22 +0100698 return;
699 }
Richard Hughese4a100c2017-06-04 21:23:50 +0100700 if (g_strcmp0 (method_name, "GetReleases") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100701 const gchar *device_id;
Richard Hughese4a100c2017-06-04 21:23:50 +0100702 g_autoptr(GPtrArray) releases = NULL;
Richard Hughese4a100c2017-06-04 21:23:50 +0100703 g_variant_get (parameters, "(&s)", &device_id);
704 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000705 if (!fu_main_device_id_valid (device_id, &error)) {
706 g_dbus_method_invocation_return_gerror (invocation, error);
707 return;
708 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100709 releases = fu_engine_get_releases (priv->engine, device_id, &error);
710 if (releases == NULL) {
711 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughese4a100c2017-06-04 21:23:50 +0100712 return;
713 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100714 val = fu_main_release_array_to_variant (releases);
715 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughese4a100c2017-06-04 21:23:50 +0100716 return;
717 }
Richard Hughes97284b12017-09-13 17:07:58 +0100718 if (g_strcmp0 (method_name, "GetDowngrades") == 0) {
719 const gchar *device_id;
720 g_autoptr(GPtrArray) releases = NULL;
721 g_variant_get (parameters, "(&s)", &device_id);
722 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000723 if (!fu_main_device_id_valid (device_id, &error)) {
724 g_dbus_method_invocation_return_gerror (invocation, error);
725 return;
726 }
Richard Hughes97284b12017-09-13 17:07:58 +0100727 releases = fu_engine_get_downgrades (priv->engine, device_id, &error);
728 if (releases == NULL) {
729 g_dbus_method_invocation_return_gerror (invocation, error);
730 return;
731 }
732 val = fu_main_release_array_to_variant (releases);
733 g_dbus_method_invocation_return_value (invocation, val);
734 return;
735 }
Richard Hughesa96413a2017-09-13 17:19:59 +0100736 if (g_strcmp0 (method_name, "GetUpgrades") == 0) {
737 const gchar *device_id;
738 g_autoptr(GPtrArray) releases = NULL;
739 g_variant_get (parameters, "(&s)", &device_id);
740 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000741 if (!fu_main_device_id_valid (device_id, &error)) {
742 g_dbus_method_invocation_return_gerror (invocation, error);
743 return;
744 }
Richard Hughesa96413a2017-09-13 17:19:59 +0100745 releases = fu_engine_get_upgrades (priv->engine, device_id, &error);
746 if (releases == NULL) {
747 g_dbus_method_invocation_return_gerror (invocation, error);
748 return;
749 }
750 val = fu_main_release_array_to_variant (releases);
751 g_dbus_method_invocation_return_value (invocation, val);
752 return;
753 }
Richard Hughes4c369702017-06-16 15:31:38 +0100754 if (g_strcmp0 (method_name, "GetRemotes") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100755 g_autoptr(GPtrArray) remotes = NULL;
Richard Hughes4c369702017-06-16 15:31:38 +0100756 g_debug ("Called %s()", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +0100757 remotes = fu_engine_get_remotes (priv->engine, &error);
758 if (remotes == NULL) {
759 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes4c369702017-06-16 15:31:38 +0100760 return;
761 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100762 val = fu_main_remote_array_to_variant (remotes);
763 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes4c369702017-06-16 15:31:38 +0100764 return;
765 }
Richard Hughes476363a2018-01-11 10:08:58 +0000766 if (g_strcmp0 (method_name, "GetHistory") == 0) {
767 g_autoptr(GPtrArray) devices = NULL;
768 g_debug ("Called %s()", method_name);
769 devices = fu_engine_get_history (priv->engine, &error);
770 if (devices == NULL) {
771 g_dbus_method_invocation_return_gerror (invocation, error);
772 return;
773 }
Mario Limoncielloe3016602018-09-06 11:20:59 -0500774 val = fu_main_device_array_to_variant (priv, sender, devices, &error);
775 if (val == NULL) {
776 g_dbus_method_invocation_return_gerror (invocation, error);
777 return;
778 }
Richard Hughes476363a2018-01-11 10:08:58 +0000779 g_dbus_method_invocation_return_value (invocation, val);
780 return;
781 }
Richard Hughes0e883ee2015-03-18 17:22:33 +0000782 if (g_strcmp0 (method_name, "ClearResults") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100783 const gchar *device_id;
784 g_variant_get (parameters, "(&s)", &device_id);
785 g_debug ("Called %s(%s)", method_name, device_id);
786 if (!fu_engine_clear_results (priv->engine, device_id, &error)) {
787 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes0e883ee2015-03-18 17:22:33 +0000788 return;
789 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100790 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughes0e883ee2015-03-18 17:22:33 +0000791 return;
792 }
Richard Hughes6b222952018-01-11 10:20:48 +0000793 if (g_strcmp0 (method_name, "ModifyDevice") == 0) {
794 const gchar *device_id;
795 const gchar *key = NULL;
796 const gchar *value = NULL;
797
798 /* check the id exists */
799 g_variant_get (parameters, "(&s&s&s)", &device_id, &key, &value);
800 g_debug ("Called %s(%s,%s=%s)", method_name, device_id, key, value);
801 if (!fu_engine_modify_device (priv->engine, device_id, key, value, &error)) {
802 g_dbus_method_invocation_return_gerror (invocation, error);
803 return;
804 }
805 g_dbus_method_invocation_return_value (invocation, NULL);
806 return;
807 }
Richard Hughes0e883ee2015-03-18 17:22:33 +0000808 if (g_strcmp0 (method_name, "GetResults") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100809 const gchar *device_id = NULL;
Richard Hughes93b15762017-09-15 11:05:23 +0100810 g_autoptr(FwupdDevice) result = NULL;
Richard Hughes9945edb2017-06-19 10:03:55 +0100811 g_variant_get (parameters, "(&s)", &device_id);
812 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000813 if (!fu_main_device_id_valid (device_id, &error)) {
814 g_dbus_method_invocation_return_gerror (invocation, error);
815 return;
816 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100817 result = fu_engine_get_results (priv->engine, device_id, &error);
818 if (result == NULL) {
819 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes0e883ee2015-03-18 17:22:33 +0000820 return;
821 }
Richard Hughese0bd53e2017-09-17 08:29:02 +0100822 val = fwupd_device_to_variant (result);
823 g_dbus_method_invocation_return_value (invocation,
824 g_variant_new_tuple (&val, 1));
Richard Hughes0e883ee2015-03-18 17:22:33 +0000825 return;
826 }
Richard Hughesba73c762017-09-15 14:31:17 +0100827 if (g_strcmp0 (method_name, "UpdateMetadata") == 0) {
Richard Hughes1b50d962017-06-02 12:23:00 +0100828 GDBusMessage *message;
829 GUnixFDList *fd_list;
Richard Hughes9945edb2017-06-19 10:03:55 +0100830 const gchar *remote_id = NULL;
Richard Hughes1b50d962017-06-02 12:23:00 +0100831 gint fd_data;
832 gint fd_sig;
833
Richard Hughes9945edb2017-06-19 10:03:55 +0100834 g_variant_get (parameters, "(&shh)", &remote_id, &fd_data, &fd_sig);
835 g_debug ("Called %s(%s,%i,%i)", method_name, remote_id, fd_data, fd_sig);
Richard Hughes1b50d962017-06-02 12:23:00 +0100836
Richard Hughes5935ebd2017-06-16 15:40:31 +0100837 /* update the metadata store */
Richard Hughes1b50d962017-06-02 12:23:00 +0100838 message = g_dbus_method_invocation_get_message (invocation);
839 fd_list = g_dbus_message_get_unix_fd_list (message);
840 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 2) {
841 g_set_error (&error,
842 FWUPD_ERROR,
843 FWUPD_ERROR_INTERNAL,
844 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +0100845 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +0100846 return;
847 }
848 fd_data = g_unix_fd_list_get (fd_list, 0, &error);
849 if (fd_data < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100850 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +0100851 return;
852 }
853 fd_sig = g_unix_fd_list_get (fd_list, 1, &error);
854 if (fd_sig < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100855 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +0100856 return;
857 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100858
859 /* store new metadata (will close the fds when done) */
860 if (!fu_engine_update_metadata (priv->engine, remote_id,
861 fd_data, fd_sig, &error)) {
Richard Hughesf3d46c62017-11-28 14:01:30 +0000862 g_prefix_error (&error, "Failed to update metadata for %s: ", remote_id);
Richard Hughes9945edb2017-06-19 10:03:55 +0100863 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughesae0efdc2015-06-24 16:18:29 +0100864 return;
865 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100866 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughesae0efdc2015-06-24 16:18:29 +0100867 return;
868 }
Richard Hughes9a410ce2016-02-28 15:58:54 +0000869 if (g_strcmp0 (method_name, "Unlock") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100870 const gchar *device_id = NULL;
Richard Hughes747b9ee2018-04-16 16:46:58 +0100871 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughes9a410ce2016-02-28 15:58:54 +0000872 g_autoptr(PolkitSubject) subject = NULL;
873
Richard Hughes9945edb2017-06-19 10:03:55 +0100874 g_variant_get (parameters, "(&s)", &device_id);
875 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000876 if (!fu_main_device_id_valid (device_id, &error)) {
877 g_dbus_method_invocation_return_gerror (invocation, error);
878 return;
879 }
Richard Hughesfe5cc902016-06-29 10:00:00 +0100880
Richard Hughes9a410ce2016-02-28 15:58:54 +0000881 /* authenticate */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100882 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
Richard Hughes9945edb2017-06-19 10:03:55 +0100883 helper = g_new0 (FuMainAuthHelper, 1);
884 helper->priv = priv;
885 helper->invocation = g_object_ref (invocation);
886 helper->device_id = g_strdup (device_id);
Richard Hughes9a410ce2016-02-28 15:58:54 +0000887 subject = polkit_system_bus_name_new (sender);
Richard Hughes9945edb2017-06-19 10:03:55 +0100888 polkit_authority_check_authorization (priv->authority, subject,
Richard Hughes9a410ce2016-02-28 15:58:54 +0000889 "org.freedesktop.fwupd.device-unlock",
890 NULL,
891 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
892 NULL,
Richard Hughes9945edb2017-06-19 10:03:55 +0100893 fu_main_authorize_unlock_cb,
Richard Hughes747b9ee2018-04-16 16:46:58 +0100894 g_steal_pointer (&helper));
Richard Hughes9a410ce2016-02-28 15:58:54 +0000895 return;
896 }
Richard Hughesa6bd5582017-09-07 14:32:22 +0100897 if (g_strcmp0 (method_name, "ModifyRemote") == 0) {
Richard Hughesa6bd5582017-09-07 14:32:22 +0100898 const gchar *remote_id = NULL;
899 const gchar *key = NULL;
900 const gchar *value = NULL;
Richard Hughes747b9ee2018-04-16 16:46:58 +0100901 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughesa6bd5582017-09-07 14:32:22 +0100902 g_autoptr(PolkitSubject) subject = NULL;
903
904 /* check the id exists */
905 g_variant_get (parameters, "(&s&s&s)", &remote_id, &key, &value);
906 g_debug ("Called %s(%s,%s=%s)", method_name, remote_id, key, value);
907
908 /* create helper object */
909 helper = g_new0 (FuMainAuthHelper, 1);
910 helper->invocation = g_object_ref (invocation);
911 helper->remote_id = g_strdup (remote_id);
912 helper->key = g_strdup (key);
913 helper->value = g_strdup (value);
914 helper->priv = priv;
915
916 /* authenticate */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100917 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
Richard Hughesa6bd5582017-09-07 14:32:22 +0100918 subject = polkit_system_bus_name_new (sender);
Mario Limonciello6b9f07c2018-04-16 13:52:09 -0500919 polkit_authority_check_authorization (priv->authority, subject,
Richard Hughesa6bd5582017-09-07 14:32:22 +0100920 "org.freedesktop.fwupd.modify-remote",
921 NULL,
922 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
923 NULL,
924 fu_main_authorize_modify_remote_cb,
Richard Hughes747b9ee2018-04-16 16:46:58 +0100925 g_steal_pointer (&helper));
Richard Hughesa6bd5582017-09-07 14:32:22 +0100926 return;
927 }
Richard Hughes29c220d2016-12-14 17:09:54 +0000928 if (g_strcmp0 (method_name, "VerifyUpdate") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100929 const gchar *device_id = NULL;
Richard Hughes747b9ee2018-04-16 16:46:58 +0100930 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughes29c220d2016-12-14 17:09:54 +0000931 g_autoptr(PolkitSubject) subject = NULL;
932
933 /* check the id exists */
Richard Hughes9945edb2017-06-19 10:03:55 +0100934 g_variant_get (parameters, "(&s)", &device_id);
935 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000936 if (!fu_main_device_id_valid (device_id, &error)) {
937 g_dbus_method_invocation_return_gerror (invocation, error);
938 return;
939 }
Richard Hughes29c220d2016-12-14 17:09:54 +0000940
Richard Hughes9945edb2017-06-19 10:03:55 +0100941 /* create helper object */
Richard Hughes29c220d2016-12-14 17:09:54 +0000942 helper = g_new0 (FuMainAuthHelper, 1);
Richard Hughes29c220d2016-12-14 17:09:54 +0000943 helper->invocation = g_object_ref (invocation);
Richard Hughes9945edb2017-06-19 10:03:55 +0100944 helper->device_id = g_strdup (device_id);
Richard Hughes29c220d2016-12-14 17:09:54 +0000945 helper->priv = priv;
Richard Hughes29c220d2016-12-14 17:09:54 +0000946
947 /* authenticate */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100948 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
Richard Hughes29c220d2016-12-14 17:09:54 +0000949 subject = polkit_system_bus_name_new (sender);
Mario Limonciello6b9f07c2018-04-16 13:52:09 -0500950 polkit_authority_check_authorization (priv->authority, subject,
Richard Hughes29c220d2016-12-14 17:09:54 +0000951 "org.freedesktop.fwupd.verify-update",
952 NULL,
953 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
954 NULL,
Richard Hughes9945edb2017-06-19 10:03:55 +0100955 fu_main_authorize_verify_update_cb,
Richard Hughes747b9ee2018-04-16 16:46:58 +0100956 g_steal_pointer (&helper));
Richard Hughes29c220d2016-12-14 17:09:54 +0000957 return;
958 }
Richard Hughesa043c2e2015-06-29 08:43:18 +0100959 if (g_strcmp0 (method_name, "Verify") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100960 const gchar *device_id = NULL;
961 g_variant_get (parameters, "(&s)", &device_id);
962 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000963 if (!fu_main_device_id_valid (device_id, &error)) {
964 g_dbus_method_invocation_return_gerror (invocation, error);
965 return;
966 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100967 if (!fu_engine_verify (priv->engine, device_id, &error)) {
968 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughesa043c2e2015-06-29 08:43:18 +0100969 return;
970 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100971 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughesa043c2e2015-06-29 08:43:18 +0100972 return;
973 }
Richard Hughes63a407a2015-07-22 08:54:14 +0100974 if (g_strcmp0 (method_name, "Install") == 0) {
Richard Hughes74cc2172015-02-27 13:19:46 +0000975 GVariant *prop_value;
Richard Hughes9945edb2017-06-19 10:03:55 +0100976 const gchar *device_id = NULL;
Richard Hughes74cc2172015-02-27 13:19:46 +0000977 gchar *prop_key;
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000978 gint32 fd_handle = 0;
979 gint fd;
Richard Hughesc7bbbc22018-01-02 22:22:25 +0000980 guint64 archive_size_max;
Richard Hughes9945edb2017-06-19 10:03:55 +0100981 GDBusMessage *message;
982 GUnixFDList *fd_list;
Richard Hughes747b9ee2018-04-16 16:46:58 +0100983 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughes46832432015-09-11 13:43:15 +0100984 g_autoptr(GVariantIter) iter = NULL;
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000985
986 /* check the id exists */
Richard Hughes9945edb2017-06-19 10:03:55 +0100987 g_variant_get (parameters, "(&sha{sv})", &device_id, &fd_handle, &iter);
988 g_debug ("Called %s(%s,%i)", method_name, device_id, fd_handle);
Richard Hughesb6f79552017-11-11 07:58:17 +0000989 if (!fu_main_device_id_valid (device_id, &error)) {
990 g_dbus_method_invocation_return_gerror (invocation, error);
991 return;
992 }
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000993
Richard Hughes9945edb2017-06-19 10:03:55 +0100994 /* create helper object */
995 helper = g_new0 (FuMainAuthHelper, 1);
996 helper->invocation = g_object_ref (invocation);
997 helper->device_id = g_strdup (device_id);
998 helper->priv = priv;
999
1000 /* get flags */
1001 while (g_variant_iter_next (iter, "{&sv}", &prop_key, &prop_value)) {
Richard Hughes74cc2172015-02-27 13:19:46 +00001002 g_debug ("got option %s", prop_key);
1003 if (g_strcmp0 (prop_key, "offline") == 0 &&
1004 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +01001005 helper->flags |= FWUPD_INSTALL_FLAG_OFFLINE;
Richard Hughese7c12642015-03-04 20:28:59 +00001006 if (g_strcmp0 (prop_key, "allow-older") == 0 &&
1007 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +01001008 helper->flags |= FWUPD_INSTALL_FLAG_ALLOW_OLDER;
Richard Hughese7c12642015-03-04 20:28:59 +00001009 if (g_strcmp0 (prop_key, "allow-reinstall") == 0 &&
1010 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +01001011 helper->flags |= FWUPD_INSTALL_FLAG_ALLOW_REINSTALL;
Mario Limonciello71a5b982016-05-10 15:38:53 -05001012 if (g_strcmp0 (prop_key, "force") == 0 &&
1013 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +01001014 helper->flags |= FWUPD_INSTALL_FLAG_FORCE;
Richard Hughes76e0f942018-05-14 16:24:00 +01001015 if (g_strcmp0 (prop_key, "no-history") == 0 &&
1016 g_variant_get_boolean (prop_value) == TRUE)
1017 helper->flags |= FWUPD_INSTALL_FLAG_NO_HISTORY;
Richard Hughes1ffde6c2015-03-02 22:44:48 +00001018 g_variant_unref (prop_value);
Richard Hughes74cc2172015-02-27 13:19:46 +00001019 }
1020
Richard Hughes9945edb2017-06-19 10:03:55 +01001021
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001022 /* get the fd */
1023 message = g_dbus_method_invocation_get_message (invocation);
1024 fd_list = g_dbus_message_get_unix_fd_list (message);
1025 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 1) {
Richard Hughes060af612016-08-17 17:32:34 +01001026 g_set_error (&error,
1027 FWUPD_ERROR,
1028 FWUPD_ERROR_INTERNAL,
1029 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +01001030 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001031 return;
1032 }
Richard Hughes7419e962016-11-22 19:48:06 +00001033 fd = g_unix_fd_list_get (fd_list, 0, &error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001034 if (fd < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001035 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001036 return;
1037 }
1038
Richard Hughes9945edb2017-06-19 10:03:55 +01001039 /* parse the cab file before authenticating so we can work out
1040 * what action ID to use, for instance, if this is trusted --
1041 * this will also close the fd when done */
Richard Hughesc7bbbc22018-01-02 22:22:25 +00001042 archive_size_max = fu_engine_get_archive_size_max (priv->engine);
1043 helper->blob_cab = fu_common_get_contents_fd (fd, archive_size_max, &error);
Richard Hughes9945edb2017-06-19 10:03:55 +01001044 if (helper->blob_cab == NULL) {
1045 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes5d14def2015-10-07 17:43:10 +01001046 return;
1047 }
Richard Hughes4ad41f02018-05-08 14:35:36 +01001048
1049 /* install all the things in the store */
1050 helper->subject = polkit_system_bus_name_new (sender);
1051 if (!fu_main_install_with_helper (g_steal_pointer (&helper), &error)) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001052 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes18423292015-03-09 17:10:50 +00001053 return;
1054 }
1055
Richard Hughes4ad41f02018-05-08 14:35:36 +01001056 /* async return */
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001057 return;
1058 }
Richard Hughes07f963a2017-09-15 14:28:47 +01001059 if (g_strcmp0 (method_name, "GetDetails") == 0) {
Richard Hughes7289a6b2016-05-29 09:27:47 +01001060 GDBusMessage *message;
1061 GUnixFDList *fd_list;
1062 gint32 fd_handle = 0;
1063 gint fd;
Richard Hughes9945edb2017-06-19 10:03:55 +01001064 g_autoptr(GPtrArray) results = NULL;
Richard Hughes7289a6b2016-05-29 09:27:47 +01001065
1066 /* get parameters */
1067 g_variant_get (parameters, "(h)", &fd_handle);
1068 g_debug ("Called %s(%i)", method_name, fd_handle);
1069
1070 /* get the fd */
1071 message = g_dbus_method_invocation_get_message (invocation);
1072 fd_list = g_dbus_message_get_unix_fd_list (message);
1073 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 1) {
Richard Hughes060af612016-08-17 17:32:34 +01001074 g_set_error (&error,
1075 FWUPD_ERROR,
1076 FWUPD_ERROR_INTERNAL,
1077 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +01001078 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001079 return;
1080 }
Richard Hughes7419e962016-11-22 19:48:06 +00001081 fd = g_unix_fd_list_get (fd_list, 0, &error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001082 if (fd < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001083 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001084 return;
1085 }
1086
Richard Hughes9945edb2017-06-19 10:03:55 +01001087 /* get details about the file (will close the fd when done) */
Richard Hughes07f963a2017-09-15 14:28:47 +01001088 results = fu_engine_get_details (priv->engine, fd, &error);
Richard Hughes9945edb2017-06-19 10:03:55 +01001089 if (results == NULL) {
1090 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001091 return;
1092 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001093 val = fu_main_result_array_to_variant (results);
1094 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001095 return;
1096 }
Richard Hughes060af612016-08-17 17:32:34 +01001097 g_set_error (&error,
1098 G_DBUS_ERROR,
1099 G_DBUS_ERROR_UNKNOWN_METHOD,
1100 "no such method %s", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +01001101 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001102}
1103
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001104static GVariant *
1105fu_main_daemon_get_property (GDBusConnection *connection_, const gchar *sender,
1106 const gchar *object_path, const gchar *interface_name,
1107 const gchar *property_name, GError **error,
1108 gpointer user_data)
1109{
Richard Hughes773ce982015-03-09 22:40:57 +00001110 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1111
Richard Hughes75b965d2018-11-15 13:51:21 +00001112 /* activity */
1113 fu_engine_idle_reset (priv->engine);
1114
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001115 if (g_strcmp0 (property_name, "DaemonVersion") == 0)
1116 return g_variant_new_string (VERSION);
1117
Richard Hughesf425d292019-01-18 17:57:39 +00001118 if (g_strcmp0 (property_name, "Tainted") == 0)
1119 return g_variant_new_boolean (fu_engine_get_tainted (priv->engine));
1120
Richard Hughes773ce982015-03-09 22:40:57 +00001121 if (g_strcmp0 (property_name, "Status") == 0)
Richard Hughes9945edb2017-06-19 10:03:55 +01001122 return g_variant_new_uint32 (fu_engine_get_status (priv->engine));
Richard Hughes773ce982015-03-09 22:40:57 +00001123
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001124 /* return an error */
1125 g_set_error (error,
Richard Hughes8645ec92015-03-19 10:14:32 +00001126 G_DBUS_ERROR,
1127 G_DBUS_ERROR_UNKNOWN_PROPERTY,
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001128 "failed to get daemon property %s",
1129 property_name);
1130 return NULL;
1131}
1132
Richard Hughesfd468842015-04-22 16:44:08 +01001133static void
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001134fu_main_on_bus_acquired_cb (GDBusConnection *connection,
1135 const gchar *name,
1136 gpointer user_data)
1137{
1138 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1139 guint registration_id;
Richard Hughes46832432015-09-11 13:43:15 +01001140 g_autoptr(GError) error = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001141 static const GDBusInterfaceVTable interface_vtable = {
1142 fu_main_daemon_method_call,
1143 fu_main_daemon_get_property,
1144 NULL
1145 };
1146
1147 priv->connection = g_object_ref (connection);
1148 registration_id = g_dbus_connection_register_object (connection,
1149 FWUPD_DBUS_PATH,
1150 priv->introspection_daemon->interfaces[0],
1151 &interface_vtable,
1152 priv, /* user_data */
1153 NULL, /* user_data_free_func */
1154 NULL); /* GError** */
1155 g_assert (registration_id > 0);
Richard Hughes18423292015-03-09 17:10:50 +00001156
1157 /* connect to D-Bus directly */
1158 priv->proxy_uid =
1159 g_dbus_proxy_new_sync (priv->connection,
1160 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
1161 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
1162 NULL,
1163 "org.freedesktop.DBus",
1164 "/org/freedesktop/DBus",
1165 "org.freedesktop.DBus",
1166 NULL,
1167 &error);
1168 if (priv->proxy_uid == NULL) {
1169 g_warning ("cannot connect to DBus: %s", error->message);
1170 return;
1171 }
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001172}
1173
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001174static void
1175fu_main_on_name_acquired_cb (GDBusConnection *connection,
1176 const gchar *name,
1177 gpointer user_data)
1178{
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001179 g_debug ("FuMain: acquired name: %s", name);
1180}
1181
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001182static void
1183fu_main_on_name_lost_cb (GDBusConnection *connection,
1184 const gchar *name,
1185 gpointer user_data)
1186{
1187 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1188 g_debug ("FuMain: lost name: %s", name);
1189 g_main_loop_quit (priv->loop);
1190}
1191
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001192static gboolean
1193fu_main_timed_exit_cb (gpointer user_data)
1194{
1195 GMainLoop *loop = (GMainLoop *) user_data;
1196 g_main_loop_quit (loop);
1197 return G_SOURCE_REMOVE;
1198}
1199
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001200static GDBusNodeInfo *
1201fu_main_load_introspection (const gchar *filename, GError **error)
1202{
Richard Hughes46832432015-09-11 13:43:15 +01001203 g_autoptr(GBytes) data = NULL;
1204 g_autofree gchar *path = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001205
1206 /* lookup data */
1207 path = g_build_filename ("/org/freedesktop/fwupd", filename, NULL);
1208 data = g_resource_lookup_data (fu_get_resource (),
1209 path,
1210 G_RESOURCE_LOOKUP_FLAGS_NONE,
1211 error);
1212 if (data == NULL)
1213 return NULL;
1214
1215 /* build introspection from XML */
1216 return g_dbus_node_info_new_for_xml (g_bytes_get_data (data, NULL), error);
1217}
1218
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001219static void
1220fu_main_private_free (FuMainPrivate *priv)
1221{
1222 if (priv->loop != NULL)
1223 g_main_loop_unref (priv->loop);
1224 if (priv->owner_id > 0)
1225 g_bus_unown_name (priv->owner_id);
1226 if (priv->proxy_uid != NULL)
1227 g_object_unref (priv->proxy_uid);
Richard Hughes9945edb2017-06-19 10:03:55 +01001228 if (priv->engine != NULL)
1229 g_object_unref (priv->engine);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001230 if (priv->connection != NULL)
1231 g_object_unref (priv->connection);
1232 if (priv->authority != NULL)
1233 g_object_unref (priv->authority);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001234 if (priv->introspection_daemon != NULL)
1235 g_dbus_node_info_unref (priv->introspection_daemon);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001236 g_free (priv);
1237}
1238
Mario Limoncielloa98df552018-04-16 12:15:51 -05001239#pragma clang diagnostic push
1240#pragma clang diagnostic ignored "-Wunused-function"
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001241G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuMainPrivate, fu_main_private_free)
Mario Limoncielloa98df552018-04-16 12:15:51 -05001242#pragma clang diagnostic pop
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001243
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001244int
1245main (int argc, char *argv[])
1246{
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001247 gboolean immediate_exit = FALSE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001248 gboolean timed_exit = FALSE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001249 const GOptionEntry options[] = {
1250 { "timed-exit", '\0', 0, G_OPTION_ARG_NONE, &timed_exit,
1251 /* TRANSLATORS: exit after we've started up, used for user profiling */
1252 _("Exit after a small delay"), NULL },
1253 { "immediate-exit", '\0', 0, G_OPTION_ARG_NONE, &immediate_exit,
1254 /* TRANSLATORS: exit straight away, used for automatic profiling */
1255 _("Exit after the engine has loaded"), NULL },
1256 { NULL}
1257 };
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001258 g_autoptr(FuMainPrivate) priv = NULL;
Richard Hughes46832432015-09-11 13:43:15 +01001259 g_autoptr(GError) error = NULL;
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001260 g_autoptr(GOptionContext) context = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001261
1262 setlocale (LC_ALL, "");
1263
1264 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
1265 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1266 textdomain (GETTEXT_PACKAGE);
1267
1268 /* TRANSLATORS: program name */
Richard Hughes63a407a2015-07-22 08:54:14 +01001269 g_set_application_name (_("Firmware Update Daemon"));
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001270 context = g_option_context_new (NULL);
1271 g_option_context_add_main_entries (context, options, NULL);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001272 g_option_context_add_group (context, fu_debug_get_option_group ());
Richard Hughes8ded6ca2015-03-16 12:51:36 +00001273 /* TRANSLATORS: program summary */
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001274 g_option_context_set_summary (context, _("Firmware Update D-Bus Service"));
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001275 if (!g_option_context_parse (context, &argc, &argv, &error)) {
1276 g_printerr ("Failed to parse command line: %s\n", error->message);
1277 return EXIT_FAILURE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001278 }
1279
1280 /* create new objects */
1281 priv = g_new0 (FuMainPrivate, 1);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001282 priv->loop = g_main_loop_new (NULL, FALSE);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001283
Richard Hughes9945edb2017-06-19 10:03:55 +01001284 /* load engine */
Richard Hughes5b5f6552018-05-18 10:22:39 +01001285 priv->engine = fu_engine_new (FU_APP_FLAGS_NONE);
Richard Hughes9945edb2017-06-19 10:03:55 +01001286 g_signal_connect (priv->engine, "changed",
1287 G_CALLBACK (fu_main_engine_changed_cb),
1288 priv);
1289 g_signal_connect (priv->engine, "device-added",
1290 G_CALLBACK (fu_main_engine_device_added_cb),
1291 priv);
1292 g_signal_connect (priv->engine, "device-removed",
1293 G_CALLBACK (fu_main_engine_device_removed_cb),
1294 priv);
1295 g_signal_connect (priv->engine, "device-changed",
1296 G_CALLBACK (fu_main_engine_device_changed_cb),
1297 priv);
1298 g_signal_connect (priv->engine, "status-changed",
1299 G_CALLBACK (fu_main_engine_status_changed_cb),
1300 priv);
1301 g_signal_connect (priv->engine, "percentage-changed",
1302 G_CALLBACK (fu_main_engine_percentage_changed_cb),
1303 priv);
1304 if (!fu_engine_load (priv->engine, &error)) {
1305 g_printerr ("Failed to load engine: %s\n", error->message);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001306 return EXIT_FAILURE;
Richard Hughes804c0752015-08-04 14:53:52 +01001307 }
1308
Mario Limonciello6754f5a2018-10-11 10:50:03 -05001309 g_unix_signal_add_full (G_PRIORITY_DEFAULT,
1310 SIGTERM, fu_main_sigterm_cb,
1311 priv, NULL);
1312
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001313 /* load introspection from file */
1314 priv->introspection_daemon = fu_main_load_introspection (FWUPD_DBUS_INTERFACE ".xml",
1315 &error);
1316 if (priv->introspection_daemon == NULL) {
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001317 g_printerr ("Failed to load introspection: %s\n", error->message);
1318 return EXIT_FAILURE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001319 }
1320
Richard Hughesf508e762015-02-27 12:49:36 +00001321 /* get authority */
1322 priv->authority = polkit_authority_get_sync (NULL, &error);
1323 if (priv->authority == NULL) {
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001324 g_printerr ("Failed to load authority: %s\n", error->message);
1325 return EXIT_FAILURE;
Richard Hughesf508e762015-02-27 12:49:36 +00001326 }
1327
Richard Hughesebae3962018-09-09 13:40:49 +01001328 /* own the object */
1329 priv->owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
1330 FWUPD_DBUS_SERVICE,
1331 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
1332 G_BUS_NAME_OWNER_FLAGS_REPLACE,
1333 fu_main_on_bus_acquired_cb,
1334 fu_main_on_name_acquired_cb,
1335 fu_main_on_name_lost_cb,
1336 priv, NULL);
1337
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001338 /* Only timeout and close the mainloop if we have specified it
1339 * on the command line */
1340 if (immediate_exit)
1341 g_idle_add (fu_main_timed_exit_cb, priv->loop);
1342 else if (timed_exit)
1343 g_timeout_add_seconds (5, fu_main_timed_exit_cb, priv->loop);
1344
Mario Limonciello46bb4e92019-01-07 09:44:31 -06001345 g_debug ("Started with locale %s", g_getenv ("LANG"));
1346
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001347 /* wait */
Richard Hughes4619f9f2017-06-14 13:55:30 +01001348 g_message ("Daemon ready for requests");
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001349 g_main_loop_run (priv->loop);
1350
1351 /* success */
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001352 return EXIT_SUCCESS;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001353}