blob: 4a6f475e91b488c9de784487d5bf1b81741ddb87 [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
7#include "config.h"
8
Richard Hughes67ec8982015-03-03 11:39:27 +00009#include <appstream-glib.h>
Richard Hughes9945edb2017-06-19 10:03:55 +010010#include <fwupd.h>
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000011#include <gio/gunixfdlist.h>
12#include <glib/gi18n.h>
13#include <locale.h>
Richard Hughesf508e762015-02-27 12:49:36 +000014#include <polkit/polkit.h>
Richard Hughes67ec8982015-03-03 11:39:27 +000015#include <stdlib.h>
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000016
Richard Hughes68982c62017-09-13 15:40:14 +010017#include "fwupd-device-private.h"
Richard Hughes1642b3b2017-06-05 17:40:08 +010018#include "fwupd-release-private.h"
Richard Hughes4c369702017-06-16 15:31:38 +010019#include "fwupd-remote-private.h"
Richard Hughesd6db6b42017-04-12 15:03:10 +010020#include "fwupd-resources.h"
Richard Hughes8e9762d2016-03-17 10:14:15 +000021
Richard Hughes943d2c92017-06-21 09:04:39 +010022#include "fu-common.h"
Richard Hughes8bbfdf42015-02-26 22:28:09 +000023#include "fu-debug.h"
Richard Hughes68982c62017-09-13 15:40:14 +010024#include "fu-device-private.h"
Richard Hughes9945edb2017-06-19 10:03:55 +010025#include "fu-engine.h"
Richard Hughes4ad41f02018-05-08 14:35:36 +010026#include "fu-install-task.h"
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000027
Philip Withnallbc339aa2016-11-22 16:13:22 +000028#ifndef HAVE_POLKIT_0_114
Mario Limoncielloa98df552018-04-16 12:15:51 -050029#pragma clang diagnostic push
30#pragma clang diagnostic ignored "-Wunused-function"
Richard Hughes60f48c22015-10-08 20:25:51 +010031G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitAuthorizationResult, g_object_unref)
32G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitSubject, g_object_unref)
Mario Limoncielloa98df552018-04-16 12:15:51 -050033#pragma clang diagnostic pop
Richard Hughes60f48c22015-10-08 20:25:51 +010034#endif
35
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000036typedef struct {
37 GDBusConnection *connection;
38 GDBusNodeInfo *introspection_daemon;
Richard Hughes18423292015-03-09 17:10:50 +000039 GDBusProxy *proxy_uid;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000040 GMainLoop *loop;
Richard Hughesf508e762015-02-27 12:49:36 +000041 PolkitAuthority *authority;
Richard Hughesf0a799e2017-01-17 20:13:30 +000042 guint owner_id;
Richard Hughes9945edb2017-06-19 10:03:55 +010043 FuEngine *engine;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000044} FuMainPrivate;
45
Richard Hughesd7022b52015-03-11 19:47:06 +000046static void
Richard Hughes9945edb2017-06-19 10:03:55 +010047fu_main_engine_changed_cb (FuEngine *engine, FuMainPrivate *priv)
Richard Hughesd7022b52015-03-11 19:47:06 +000048{
49 /* not yet connected */
50 if (priv->connection == NULL)
51 return;
52 g_dbus_connection_emit_signal (priv->connection,
53 NULL,
54 FWUPD_DBUS_PATH,
55 FWUPD_DBUS_INTERFACE,
56 "Changed",
57 NULL, NULL);
58}
59
Richard Hughes8ca33782016-04-28 15:04:31 +010060static void
Richard Hughes9945edb2017-06-19 10:03:55 +010061fu_main_engine_device_added_cb (FuEngine *engine,
62 FuDevice *device,
63 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +010064{
65 GVariant *val;
66
67 /* not yet connected */
68 if (priv->connection == NULL)
69 return;
Richard Hughese0bd53e2017-09-17 08:29:02 +010070 val = fwupd_device_to_variant (FWUPD_DEVICE (device));
Richard Hughes8ca33782016-04-28 15:04:31 +010071 g_dbus_connection_emit_signal (priv->connection,
72 NULL,
73 FWUPD_DBUS_PATH,
74 FWUPD_DBUS_INTERFACE,
75 "DeviceAdded",
Richard Hughese0bd53e2017-09-17 08:29:02 +010076 g_variant_new_tuple (&val, 1), NULL);
Richard Hughes8ca33782016-04-28 15:04:31 +010077}
78
Richard Hughes8ca33782016-04-28 15:04:31 +010079static void
Richard Hughes9945edb2017-06-19 10:03:55 +010080fu_main_engine_device_removed_cb (FuEngine *engine,
81 FuDevice *device,
82 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +010083{
84 GVariant *val;
85
86 /* not yet connected */
87 if (priv->connection == NULL)
88 return;
Richard Hughese0bd53e2017-09-17 08:29:02 +010089 val = fwupd_device_to_variant (FWUPD_DEVICE (device));
Richard Hughes8ca33782016-04-28 15:04:31 +010090 g_dbus_connection_emit_signal (priv->connection,
91 NULL,
92 FWUPD_DBUS_PATH,
93 FWUPD_DBUS_INTERFACE,
94 "DeviceRemoved",
Richard Hughese0bd53e2017-09-17 08:29:02 +010095 g_variant_new_tuple (&val, 1), NULL);
Richard Hughes8ca33782016-04-28 15:04:31 +010096}
97
Richard Hughes8ca33782016-04-28 15:04:31 +010098static void
Richard Hughes9945edb2017-06-19 10:03:55 +010099fu_main_engine_device_changed_cb (FuEngine *engine,
100 FuDevice *device,
101 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +0100102{
103 GVariant *val;
104
105 /* not yet connected */
106 if (priv->connection == NULL)
107 return;
Richard Hughese0bd53e2017-09-17 08:29:02 +0100108 val = fwupd_device_to_variant (FWUPD_DEVICE (device));
Richard Hughes8ca33782016-04-28 15:04:31 +0100109 g_dbus_connection_emit_signal (priv->connection,
110 NULL,
111 FWUPD_DBUS_PATH,
112 FWUPD_DBUS_INTERFACE,
113 "DeviceChanged",
Richard Hughese0bd53e2017-09-17 08:29:02 +0100114 g_variant_new_tuple (&val, 1), NULL);
Richard Hughes8ca33782016-04-28 15:04:31 +0100115}
116
Richard Hughes773ce982015-03-09 22:40:57 +0000117static void
118fu_main_emit_property_changed (FuMainPrivate *priv,
119 const gchar *property_name,
120 GVariant *property_value)
121{
122 GVariantBuilder builder;
123 GVariantBuilder invalidated_builder;
124
125 /* not yet connected */
126 if (priv->connection == NULL)
127 return;
128
129 /* build the dict */
130 g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as"));
131 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
132 g_variant_builder_add (&builder,
133 "{sv}",
134 property_name,
135 property_value);
136 g_dbus_connection_emit_signal (priv->connection,
137 NULL,
138 FWUPD_DBUS_PATH,
139 "org.freedesktop.DBus.Properties",
140 "PropertiesChanged",
141 g_variant_new ("(sa{sv}as)",
142 FWUPD_DBUS_INTERFACE,
143 &builder,
144 &invalidated_builder),
145 NULL);
146 g_variant_builder_clear (&builder);
147 g_variant_builder_clear (&invalidated_builder);
148}
149
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100150static void
151fu_main_set_status (FuMainPrivate *priv, FwupdStatus status)
152{
153 g_debug ("Emitting PropertyChanged('Status'='%s')",
154 fwupd_status_to_string (status));
155 fu_main_emit_property_changed (priv, "Status",
156 g_variant_new_uint32 (status));
157}
Richard Hughes773ce982015-03-09 22:40:57 +0000158
Richard Hughes9945edb2017-06-19 10:03:55 +0100159static void
160fu_main_engine_status_changed_cb (FuEngine *engine,
161 FwupdStatus status,
162 FuMainPrivate *priv)
163{
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100164 fu_main_set_status (priv, status);
Richard Hughes773ce982015-03-09 22:40:57 +0000165}
166
Richard Hughes876c0072016-08-17 14:51:03 +0100167static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100168fu_main_engine_percentage_changed_cb (FuEngine *engine,
169 guint percentage,
170 FuMainPrivate *priv)
Richard Hughes876c0072016-08-17 14:51:03 +0100171{
Richard Hughes876c0072016-08-17 14:51:03 +0100172 g_debug ("Emitting PropertyChanged('Percentage'='%u%%')", percentage);
173 fu_main_emit_property_changed (priv, "Percentage",
174 g_variant_new_uint32 (percentage));
175}
176
Mario Limoncielloe3016602018-09-06 11:20:59 -0500177static gboolean
178fu_main_get_device_flags_for_sender (FuMainPrivate *priv, const char *sender,
179 FwupdDeviceFlags *flags, GError **error)
180{
181 uid_t calling_uid;
182 g_autoptr(GVariant) value = NULL;
183
184 g_return_val_if_fail (sender != NULL, FALSE);
185 g_return_val_if_fail (flags != NULL, FALSE);
186
187 value = g_dbus_proxy_call_sync (priv->proxy_uid,
188 "GetConnectionUnixUser",
189 g_variant_new ("(s)", sender),
190 G_DBUS_CALL_FLAGS_NONE,
191 2000,
192 NULL,
193 error);
194 if (value == NULL) {
195 g_prefix_error (error, "failed to read user id of caller: ");
196 return FALSE;
197 }
198 g_variant_get (value, "(u)", &calling_uid);
199 if (calling_uid == 0)
200 *flags |= FWUPD_DEVICE_FLAG_TRUSTED;
201
202 return TRUE;
203}
204
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000205static GVariant *
Mario Limoncielloe3016602018-09-06 11:20:59 -0500206fu_main_device_array_to_variant (FuMainPrivate *priv, const gchar *sender,
207 GPtrArray *devices, GError **error)
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000208{
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000209 GVariantBuilder builder;
Mario Limoncielloe3016602018-09-06 11:20:59 -0500210 FwupdDeviceFlags flags = FWUPD_DEVICE_FLAG_NONE;
211
Richard Hughes9945edb2017-06-19 10:03:55 +0100212 g_return_val_if_fail (devices->len > 0, NULL);
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000213 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
Mario Limoncielloe3016602018-09-06 11:20:59 -0500214
215 if (!fu_main_get_device_flags_for_sender (priv, sender, &flags, error))
216 return FALSE;
217
Richard Hughesf192bf02016-07-22 08:26:43 +0100218 for (guint i = 0; i < devices->len; i++) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100219 FuDevice *device = g_ptr_array_index (devices, i);
Mario Limoncielloe3016602018-09-06 11:20:59 -0500220 GVariant *tmp = fwupd_device_to_variant_full (FWUPD_DEVICE (device),
221 flags);
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000222 g_variant_builder_add_value (&builder, tmp);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000223 }
Richard Hughes9e1b1402017-09-15 16:29:54 +0100224 return g_variant_new ("(aa{sv})", &builder);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000225}
226
Richard Hughes9945edb2017-06-19 10:03:55 +0100227static GVariant *
228fu_main_release_array_to_variant (GPtrArray *results)
Richard Hughes060af612016-08-17 17:32:34 +0100229{
Richard Hughes9945edb2017-06-19 10:03:55 +0100230 GVariantBuilder builder;
231 g_return_val_if_fail (results->len > 0, NULL);
232 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
233 for (guint i = 0; i < results->len; i++) {
234 FwupdRelease *rel = g_ptr_array_index (results, i);
Richard Hughese0bd53e2017-09-17 08:29:02 +0100235 GVariant *tmp = fwupd_release_to_variant (rel);
Richard Hughes9945edb2017-06-19 10:03:55 +0100236 g_variant_builder_add_value (&builder, tmp);
237 }
238 return g_variant_new ("(aa{sv})", &builder);
Richard Hughes060af612016-08-17 17:32:34 +0100239}
240
Richard Hughes9945edb2017-06-19 10:03:55 +0100241static GVariant *
242fu_main_remote_array_to_variant (GPtrArray *remotes)
Richard Hughes060af612016-08-17 17:32:34 +0100243{
Richard Hughes9945edb2017-06-19 10:03:55 +0100244 GVariantBuilder builder;
245 g_return_val_if_fail (remotes->len > 0, NULL);
246 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
247 for (guint i = 0; i < remotes->len; i++) {
248 FwupdRemote *remote = g_ptr_array_index (remotes, i);
Richard Hughese0bd53e2017-09-17 08:29:02 +0100249 GVariant *tmp = fwupd_remote_to_variant (remote);
Richard Hughes9945edb2017-06-19 10:03:55 +0100250 g_variant_builder_add_value (&builder, tmp);
251 }
252 return g_variant_new ("(aa{sv})", &builder);
Richard Hughes060af612016-08-17 17:32:34 +0100253}
254
Richard Hughes9945edb2017-06-19 10:03:55 +0100255static GVariant *
256fu_main_result_array_to_variant (GPtrArray *results)
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000257{
Richard Hughes9945edb2017-06-19 10:03:55 +0100258 GVariantBuilder builder;
259 g_return_val_if_fail (results->len > 0, NULL);
260 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
261 for (guint i = 0; i < results->len; i++) {
Richard Hughes93b15762017-09-15 11:05:23 +0100262 FwupdDevice *result = g_ptr_array_index (results, i);
Richard Hughese0bd53e2017-09-17 08:29:02 +0100263 GVariant *tmp = fwupd_device_to_variant (result);
Richard Hughes9945edb2017-06-19 10:03:55 +0100264 g_variant_builder_add_value (&builder, tmp);
265 }
Richard Hughes9e1b1402017-09-15 16:29:54 +0100266 return g_variant_new ("(aa{sv})", &builder);
Richard Hughesf508e762015-02-27 12:49:36 +0000267}
268
Richard Hughesf508e762015-02-27 12:49:36 +0000269typedef struct {
270 GDBusMethodInvocation *invocation;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100271 PolkitSubject *subject;
272 GPtrArray *install_tasks;
273 GPtrArray *action_ids;
Richard Hughes2d6e1862016-03-18 09:20:37 +0000274 FwupdInstallFlags flags;
Richard Hughes5d14def2015-10-07 17:43:10 +0100275 GBytes *blob_cab;
Richard Hughes67ec8982015-03-03 11:39:27 +0000276 FuMainPrivate *priv;
Richard Hughes9945edb2017-06-19 10:03:55 +0100277 gchar *device_id;
Richard Hughesa6bd5582017-09-07 14:32:22 +0100278 gchar *remote_id;
279 gchar *key;
280 gchar *value;
Richard Hughesf508e762015-02-27 12:49:36 +0000281} FuMainAuthHelper;
282
Richard Hughesf508e762015-02-27 12:49:36 +0000283static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100284fu_main_auth_helper_free (FuMainAuthHelper *helper)
Richard Hughesf508e762015-02-27 12:49:36 +0000285{
Richard Hughes4ced4662016-08-26 11:02:31 +0100286 if (helper->blob_cab != NULL)
Richard Hughes5d14def2015-10-07 17:43:10 +0100287 g_bytes_unref (helper->blob_cab);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100288 if (helper->subject != NULL)
289 g_object_unref (helper->subject);
290 if (helper->install_tasks != NULL)
291 g_ptr_array_unref (helper->install_tasks);
292 if (helper->action_ids != NULL)
293 g_ptr_array_unref (helper->action_ids);
Richard Hughes9945edb2017-06-19 10:03:55 +0100294 g_free (helper->device_id);
Richard Hughesa6bd5582017-09-07 14:32:22 +0100295 g_free (helper->remote_id);
296 g_free (helper->key);
297 g_free (helper->value);
Richard Hughes67ec8982015-03-03 11:39:27 +0000298 g_object_unref (helper->invocation);
Richard Hughesf508e762015-02-27 12:49:36 +0000299 g_free (helper);
300}
301
Mario Limoncielloa98df552018-04-16 12:15:51 -0500302#pragma clang diagnostic push
303#pragma clang diagnostic ignored "-Wunused-function"
Richard Hughes9945edb2017-06-19 10:03:55 +0100304G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuMainAuthHelper, fu_main_auth_helper_free)
Mario Limoncielloa98df552018-04-16 12:15:51 -0500305#pragma clang diagnostic pop
Richard Hughes9945edb2017-06-19 10:03:55 +0100306
307/* error may or may not already have been set */
Richard Hughesb75c92d2016-02-20 20:22:00 +0000308static gboolean
Richard Hughes9945edb2017-06-19 10:03:55 +0100309fu_main_authorization_is_valid (PolkitAuthorizationResult *auth, GError **error)
Richard Hughes9a410ce2016-02-28 15:58:54 +0000310{
Richard Hughes9945edb2017-06-19 10:03:55 +0100311 /* failed */
Richard Hughesf508e762015-02-27 12:49:36 +0000312 if (auth == NULL) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100313 g_autofree gchar *message = g_strdup ((*error)->message);
314 g_clear_error (error);
315 g_set_error (error,
Richard Hughes060af612016-08-17 17:32:34 +0100316 FWUPD_ERROR,
317 FWUPD_ERROR_AUTH_FAILED,
Richard Hughes9945edb2017-06-19 10:03:55 +0100318 "Could not check for auth: %s", message);
319 return FALSE;
Richard Hughesf508e762015-02-27 12:49:36 +0000320 }
321
322 /* did not auth */
323 if (!polkit_authorization_result_get_is_authorized (auth)) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100324 g_set_error_literal (error,
Richard Hughes060af612016-08-17 17:32:34 +0100325 FWUPD_ERROR,
326 FWUPD_ERROR_AUTH_FAILED,
Richard Hughes9945edb2017-06-19 10:03:55 +0100327 "Failed to obtain auth");
328 return FALSE;
Richard Hughesf508e762015-02-27 12:49:36 +0000329 }
330
331 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100332 return TRUE;
Richard Hughes5d14def2015-10-07 17:43:10 +0100333}
334
Richard Hughesdf7950b2016-01-31 10:18:40 +0000335static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100336fu_main_authorize_unlock_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100337{
Richard Hughes9945edb2017-06-19 10:03:55 +0100338 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
339 g_autoptr(GError) error = NULL;
340 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100341
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100342
Richard Hughes9945edb2017-06-19 10:03:55 +0100343 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100344 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughes9945edb2017-06-19 10:03:55 +0100345 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
346 res, &error);
347 if (!fu_main_authorization_is_valid (auth, &error)) {
348 g_dbus_method_invocation_return_gerror (helper->invocation, error);
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100349 return;
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100350 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100351
352 /* authenticated */
353 if (!fu_engine_unlock (helper->priv->engine, helper->device_id, &error)) {
354 g_dbus_method_invocation_return_gerror (helper->invocation, error);
355 return;
356 }
357
358 /* success */
359 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100360}
361
362static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100363fu_main_authorize_verify_update_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughesdf7950b2016-01-31 10:18:40 +0000364{
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 Hughesdf7950b2016-01-31 10:18:40 +0000368
Richard Hughes9945edb2017-06-19 10:03:55 +0100369 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100370 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughes9945edb2017-06-19 10:03:55 +0100371 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
372 res, &error);
373 if (!fu_main_authorization_is_valid (auth, &error)) {
374 g_dbus_method_invocation_return_gerror (helper->invocation, error);
Richard Hughesdf7950b2016-01-31 10:18:40 +0000375 return;
Richard Hughesf192bf02016-07-22 08:26:43 +0100376 }
Richard Hughesdf7950b2016-01-31 10:18:40 +0000377
Richard Hughes9945edb2017-06-19 10:03:55 +0100378 /* authenticated */
379 if (!fu_engine_verify_update (helper->priv->engine, helper->device_id, &error)) {
380 g_dbus_method_invocation_return_gerror (helper->invocation, error);
381 return;
Richard Hughes404cc512016-12-21 16:09:48 +0000382 }
383
384 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100385 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes99147f12016-05-17 09:35:04 +0100386}
387
Richard Hughes9945edb2017-06-19 10:03:55 +0100388static void
Richard Hughesa6bd5582017-09-07 14:32:22 +0100389fu_main_authorize_modify_remote_cb (GObject *source, GAsyncResult *res, gpointer user_data)
390{
391 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
392 g_autoptr(GError) error = NULL;
393 g_autoptr(PolkitAuthorizationResult) auth = NULL;
394
395 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100396 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughesa6bd5582017-09-07 14:32:22 +0100397 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
398 res, &error);
399 if (!fu_main_authorization_is_valid (auth, &error)) {
400 g_dbus_method_invocation_return_gerror (helper->invocation, error);
401 return;
402 }
403
404 /* authenticated */
405 if (!fu_engine_modify_remote (helper->priv->engine,
406 helper->remote_id,
407 helper->key,
408 helper->value,
409 &error)) {
410 g_dbus_method_invocation_return_gerror (helper->invocation, error);
411 return;
412 }
413
414 /* success */
415 g_dbus_method_invocation_return_value (helper->invocation, NULL);
416}
417
Richard Hughes4ad41f02018-05-08 14:35:36 +0100418static void fu_main_authorize_install_queue (FuMainAuthHelper *helper);
419
Richard Hughesa6bd5582017-09-07 14:32:22 +0100420static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100421fu_main_authorize_install_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughes404cc512016-12-21 16:09:48 +0000422{
Richard Hughes9945edb2017-06-19 10:03:55 +0100423 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
Richard Hughes46832432015-09-11 13:43:15 +0100424 g_autoptr(GError) error = NULL;
Richard Hughes9945edb2017-06-19 10:03:55 +0100425 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughes18423292015-03-09 17:10:50 +0000426
Richard Hughes9945edb2017-06-19 10:03:55 +0100427 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100428 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughes9945edb2017-06-19 10:03:55 +0100429 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
430 res, &error);
431 if (!fu_main_authorization_is_valid (auth, &error)) {
432 g_dbus_method_invocation_return_gerror (helper->invocation, error);
433 return;
Richard Hughes0e883ee2015-03-18 17:22:33 +0000434 }
435
Richard Hughes4ad41f02018-05-08 14:35:36 +0100436 /* do the next authentication action ID */
437 fu_main_authorize_install_queue (g_steal_pointer (&helper));
438}
439
440static void
441fu_main_authorize_install_queue (FuMainAuthHelper *helper_ref)
442{
443 FuMainPrivate *priv = helper_ref->priv;
444 g_autoptr(FuMainAuthHelper) helper = helper_ref;
445 g_autoptr(GError) error = NULL;
446
447 /* still more things to to authenticate */
448 if (helper->action_ids->len > 0) {
449 g_autofree gchar *action_id = g_strdup (g_ptr_array_index (helper->action_ids, 0));
450 g_autoptr(PolkitSubject) subject = g_object_ref (helper->subject);
451 g_ptr_array_remove_index (helper->action_ids, 0);
452 polkit_authority_check_authorization (priv->authority, subject,
453 action_id, NULL,
454 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
455 NULL,
456 fu_main_authorize_install_cb,
457 g_steal_pointer (&helper));
Richard Hughes9945edb2017-06-19 10:03:55 +0100458 return;
Richard Hughes654f6b82016-04-25 12:29:48 +0100459 }
460
Richard Hughes4ad41f02018-05-08 14:35:36 +0100461 /* all authenticated, so install all the things */
Richard Hughesdbd8c762018-06-15 20:31:40 +0100462 if (!fu_engine_install_tasks (helper->priv->engine,
463 helper->install_tasks,
464 helper->blob_cab,
465 helper->flags,
466 &error)) {
467 g_dbus_method_invocation_return_gerror (helper->invocation, error);
468 return;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100469 }
470
Richard Hughes654f6b82016-04-25 12:29:48 +0100471 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100472 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes4c369702017-06-16 15:31:38 +0100473}
474
Richard Hughes4ad41f02018-05-08 14:35:36 +0100475#if !GLIB_CHECK_VERSION(2,54,0)
476static gboolean
477g_ptr_array_find (GPtrArray *haystack, gconstpointer needle, guint *index_)
478{
479 for (guint i = 0; i < haystack->len; i++) {
480 gconstpointer *tmp = g_ptr_array_index (haystack, i);
481 if (tmp == needle) {
482 if (index_ != NULL) {
483 *index_ = i;
484 return TRUE;
485 }
486 }
487 }
488 return FALSE;
489}
490#endif
491
Richard Hughes9f86ade2018-05-10 21:11:22 +0100492static gint
493fu_main_install_task_sort_cb (gconstpointer a, gconstpointer b)
494{
495 FuInstallTask *task_a = *((FuInstallTask **) a);
496 FuInstallTask *task_b = *((FuInstallTask **) b);
Richard Hughesc02cb832018-05-20 10:31:04 +0100497 return fu_install_task_compare (task_a, task_b);
Richard Hughes9f86ade2018-05-10 21:11:22 +0100498}
499
Richard Hughes4ad41f02018-05-08 14:35:36 +0100500static gboolean
501fu_main_install_with_helper (FuMainAuthHelper *helper_ref, GError **error)
502{
503 FuMainPrivate *priv = helper_ref->priv;
504 GPtrArray *apps;
505 g_autoptr(AsStore) store = NULL;
506 g_autoptr(FuMainAuthHelper) helper = helper_ref;
507 g_autoptr(GPtrArray) devices_possible = NULL;
508 g_autoptr(GPtrArray) errors = NULL;
509
510 /* get a list of devices that match the device_id */
511 if (g_strcmp0 (helper->device_id, FWUPD_DEVICE_ID_ANY) == 0) {
512 devices_possible = fu_engine_get_devices (priv->engine, error);
513 if (devices_possible == NULL) {
514 g_prefix_error (error, "failed to get all devices: ");
515 return FALSE;
516 }
517 } else {
518 FuDevice *device = fu_engine_get_device (priv->engine,
519 helper->device_id,
520 error);
521 if (device == NULL)
522 return FALSE;
523 devices_possible = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
524 g_ptr_array_add (devices_possible, device);
525 }
526
527 /* parse store */
528 store = fu_engine_get_store_from_blob (priv->engine,
529 helper->blob_cab,
530 error);
531 if (store == NULL)
532 return FALSE;
533
534 /* for each component in the store */
535 apps = as_store_get_apps (store);
536 helper->action_ids = g_ptr_array_new_with_free_func (g_free);
537 helper->install_tasks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
538 errors = g_ptr_array_new_with_free_func ((GDestroyNotify) g_error_free);
539 for (guint i = 0; i < apps->len; i++) {
540 AsApp *app = g_ptr_array_index (apps, i);
541
542 /* do any devices pass the requirements */
543 for (guint j = 0; j < devices_possible->len; j++) {
544 FuDevice *device = g_ptr_array_index (devices_possible, j);
545 const gchar *action_id;
546 g_autoptr(FuInstallTask) task = NULL;
547 g_autoptr(GError) error_local = NULL;
548
549 /* is this component valid for the device */
550 task = fu_install_task_new (device, app);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100551 if (!fu_engine_check_requirements (priv->engine,
Richard Hughes1d1f5cf2018-05-19 23:06:03 +0100552 task,
553 helper->flags,
Richard Hughes4ad41f02018-05-08 14:35:36 +0100554 &error_local)) {
555 g_debug ("requirement on %s:%s failed: %s",
556 fu_device_get_id (device),
557 as_app_get_id (app),
558 error_local->message);
559 g_ptr_array_add (errors, g_steal_pointer (&error_local));
560 continue;
561 }
562
563 /* get the action IDs for the valid device */
564 action_id = fu_install_task_get_action_id (task);
565 if (!g_ptr_array_find (helper->action_ids, action_id, NULL))
566 g_ptr_array_add (helper->action_ids, g_strdup (action_id));
567 g_ptr_array_add (helper->install_tasks, g_steal_pointer (&task));
568 }
569 }
570
Richard Hughes9f86ade2018-05-10 21:11:22 +0100571 /* order the install tasks by the device priority */
572 g_ptr_array_sort (helper->install_tasks, fu_main_install_task_sort_cb);
573
Richard Hughes4ad41f02018-05-08 14:35:36 +0100574 /* nothing suitable */
575 if (helper->install_tasks->len == 0) {
Richard Hughese82eef32018-05-20 10:41:26 +0100576 GError *error_tmp = fu_common_error_array_get_best (errors);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100577 g_propagate_error (error, error_tmp);
578 return FALSE;
579 }
580
581 /* authenticate all things in the action_ids */
582 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
583 fu_main_authorize_install_queue (g_steal_pointer (&helper));
584 return TRUE;
585}
586
Richard Hughesb6f79552017-11-11 07:58:17 +0000587static gboolean
588fu_main_device_id_valid (const gchar *device_id, GError **error)
589{
590 if (g_strcmp0 (device_id, FWUPD_DEVICE_ID_ANY) == 0)
591 return TRUE;
592 if (device_id != NULL && strlen (device_id) >= 4)
593 return TRUE;
594 g_set_error (error,
595 FWUPD_ERROR,
596 FWUPD_ERROR_INTERNAL,
597 "invalid device ID: %s",
598 device_id);
599 return FALSE;
600}
601
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000602static void
603fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender,
604 const gchar *object_path, const gchar *interface_name,
605 const gchar *method_name, GVariant *parameters,
606 GDBusMethodInvocation *invocation, gpointer user_data)
607{
608 FuMainPrivate *priv = (FuMainPrivate *) user_data;
Richard Hughes9945edb2017-06-19 10:03:55 +0100609 GVariant *val = NULL;
Richard Hughes060af612016-08-17 17:32:34 +0100610 g_autoptr(GError) error = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000611
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000612 if (g_strcmp0 (method_name, "GetDevices") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100613 g_autoptr(GPtrArray) devices = NULL;
Richard Hughesf508e762015-02-27 12:49:36 +0000614 g_debug ("Called %s()", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +0100615 devices = fu_engine_get_devices (priv->engine, &error);
616 if (devices == NULL) {
617 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7708a0f2015-07-21 08:41:22 +0100618 return;
619 }
Mario Limoncielloe3016602018-09-06 11:20:59 -0500620 val = fu_main_device_array_to_variant (priv, sender, devices, &error);
621 if (val == NULL) {
622 g_dbus_method_invocation_return_gerror (invocation, error);
623 return;
624 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100625 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes7708a0f2015-07-21 08:41:22 +0100626 return;
627 }
Richard Hughese4a100c2017-06-04 21:23:50 +0100628 if (g_strcmp0 (method_name, "GetReleases") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100629 const gchar *device_id;
Richard Hughese4a100c2017-06-04 21:23:50 +0100630 g_autoptr(GPtrArray) releases = NULL;
Richard Hughese4a100c2017-06-04 21:23:50 +0100631 g_variant_get (parameters, "(&s)", &device_id);
632 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000633 if (!fu_main_device_id_valid (device_id, &error)) {
634 g_dbus_method_invocation_return_gerror (invocation, error);
635 return;
636 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100637 releases = fu_engine_get_releases (priv->engine, device_id, &error);
638 if (releases == NULL) {
639 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughese4a100c2017-06-04 21:23:50 +0100640 return;
641 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100642 val = fu_main_release_array_to_variant (releases);
643 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughese4a100c2017-06-04 21:23:50 +0100644 return;
645 }
Richard Hughes97284b12017-09-13 17:07:58 +0100646 if (g_strcmp0 (method_name, "GetDowngrades") == 0) {
647 const gchar *device_id;
648 g_autoptr(GPtrArray) releases = NULL;
649 g_variant_get (parameters, "(&s)", &device_id);
650 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000651 if (!fu_main_device_id_valid (device_id, &error)) {
652 g_dbus_method_invocation_return_gerror (invocation, error);
653 return;
654 }
Richard Hughes97284b12017-09-13 17:07:58 +0100655 releases = fu_engine_get_downgrades (priv->engine, device_id, &error);
656 if (releases == NULL) {
657 g_dbus_method_invocation_return_gerror (invocation, error);
658 return;
659 }
660 val = fu_main_release_array_to_variant (releases);
661 g_dbus_method_invocation_return_value (invocation, val);
662 return;
663 }
Richard Hughesa96413a2017-09-13 17:19:59 +0100664 if (g_strcmp0 (method_name, "GetUpgrades") == 0) {
665 const gchar *device_id;
666 g_autoptr(GPtrArray) releases = NULL;
667 g_variant_get (parameters, "(&s)", &device_id);
668 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000669 if (!fu_main_device_id_valid (device_id, &error)) {
670 g_dbus_method_invocation_return_gerror (invocation, error);
671 return;
672 }
Richard Hughesa96413a2017-09-13 17:19:59 +0100673 releases = fu_engine_get_upgrades (priv->engine, device_id, &error);
674 if (releases == NULL) {
675 g_dbus_method_invocation_return_gerror (invocation, error);
676 return;
677 }
678 val = fu_main_release_array_to_variant (releases);
679 g_dbus_method_invocation_return_value (invocation, val);
680 return;
681 }
Richard Hughes4c369702017-06-16 15:31:38 +0100682 if (g_strcmp0 (method_name, "GetRemotes") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100683 g_autoptr(GPtrArray) remotes = NULL;
Richard Hughes4c369702017-06-16 15:31:38 +0100684 g_debug ("Called %s()", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +0100685 remotes = fu_engine_get_remotes (priv->engine, &error);
686 if (remotes == NULL) {
687 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes4c369702017-06-16 15:31:38 +0100688 return;
689 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100690 val = fu_main_remote_array_to_variant (remotes);
691 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes4c369702017-06-16 15:31:38 +0100692 return;
693 }
Richard Hughes476363a2018-01-11 10:08:58 +0000694 if (g_strcmp0 (method_name, "GetHistory") == 0) {
695 g_autoptr(GPtrArray) devices = NULL;
696 g_debug ("Called %s()", method_name);
697 devices = fu_engine_get_history (priv->engine, &error);
698 if (devices == NULL) {
699 g_dbus_method_invocation_return_gerror (invocation, error);
700 return;
701 }
Mario Limoncielloe3016602018-09-06 11:20:59 -0500702 val = fu_main_device_array_to_variant (priv, sender, devices, &error);
703 if (val == NULL) {
704 g_dbus_method_invocation_return_gerror (invocation, error);
705 return;
706 }
Richard Hughes476363a2018-01-11 10:08:58 +0000707 g_dbus_method_invocation_return_value (invocation, val);
708 return;
709 }
Richard Hughes0e883ee2015-03-18 17:22:33 +0000710 if (g_strcmp0 (method_name, "ClearResults") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100711 const gchar *device_id;
712 g_variant_get (parameters, "(&s)", &device_id);
713 g_debug ("Called %s(%s)", method_name, device_id);
714 if (!fu_engine_clear_results (priv->engine, device_id, &error)) {
715 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes0e883ee2015-03-18 17:22:33 +0000716 return;
717 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100718 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughes0e883ee2015-03-18 17:22:33 +0000719 return;
720 }
Richard Hughes6b222952018-01-11 10:20:48 +0000721 if (g_strcmp0 (method_name, "ModifyDevice") == 0) {
722 const gchar *device_id;
723 const gchar *key = NULL;
724 const gchar *value = NULL;
725
726 /* check the id exists */
727 g_variant_get (parameters, "(&s&s&s)", &device_id, &key, &value);
728 g_debug ("Called %s(%s,%s=%s)", method_name, device_id, key, value);
729 if (!fu_engine_modify_device (priv->engine, device_id, key, value, &error)) {
730 g_dbus_method_invocation_return_gerror (invocation, error);
731 return;
732 }
733 g_dbus_method_invocation_return_value (invocation, NULL);
734 return;
735 }
Richard Hughes0e883ee2015-03-18 17:22:33 +0000736 if (g_strcmp0 (method_name, "GetResults") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100737 const gchar *device_id = NULL;
Richard Hughes93b15762017-09-15 11:05:23 +0100738 g_autoptr(FwupdDevice) result = NULL;
Richard Hughes9945edb2017-06-19 10:03:55 +0100739 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 Hughes9945edb2017-06-19 10:03:55 +0100745 result = fu_engine_get_results (priv->engine, device_id, &error);
746 if (result == NULL) {
747 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes0e883ee2015-03-18 17:22:33 +0000748 return;
749 }
Richard Hughese0bd53e2017-09-17 08:29:02 +0100750 val = fwupd_device_to_variant (result);
751 g_dbus_method_invocation_return_value (invocation,
752 g_variant_new_tuple (&val, 1));
Richard Hughes0e883ee2015-03-18 17:22:33 +0000753 return;
754 }
Richard Hughesba73c762017-09-15 14:31:17 +0100755 if (g_strcmp0 (method_name, "UpdateMetadata") == 0) {
Richard Hughes1b50d962017-06-02 12:23:00 +0100756 GDBusMessage *message;
757 GUnixFDList *fd_list;
Richard Hughes9945edb2017-06-19 10:03:55 +0100758 const gchar *remote_id = NULL;
Richard Hughes1b50d962017-06-02 12:23:00 +0100759 gint fd_data;
760 gint fd_sig;
761
Richard Hughes9945edb2017-06-19 10:03:55 +0100762 g_variant_get (parameters, "(&shh)", &remote_id, &fd_data, &fd_sig);
763 g_debug ("Called %s(%s,%i,%i)", method_name, remote_id, fd_data, fd_sig);
Richard Hughes1b50d962017-06-02 12:23:00 +0100764
Richard Hughes5935ebd2017-06-16 15:40:31 +0100765 /* update the metadata store */
Richard Hughes1b50d962017-06-02 12:23:00 +0100766 message = g_dbus_method_invocation_get_message (invocation);
767 fd_list = g_dbus_message_get_unix_fd_list (message);
768 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 2) {
769 g_set_error (&error,
770 FWUPD_ERROR,
771 FWUPD_ERROR_INTERNAL,
772 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +0100773 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +0100774 return;
775 }
776 fd_data = g_unix_fd_list_get (fd_list, 0, &error);
777 if (fd_data < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100778 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +0100779 return;
780 }
781 fd_sig = g_unix_fd_list_get (fd_list, 1, &error);
782 if (fd_sig < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100783 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +0100784 return;
785 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100786
787 /* store new metadata (will close the fds when done) */
788 if (!fu_engine_update_metadata (priv->engine, remote_id,
789 fd_data, fd_sig, &error)) {
Richard Hughesf3d46c62017-11-28 14:01:30 +0000790 g_prefix_error (&error, "Failed to update metadata for %s: ", remote_id);
Richard Hughes9945edb2017-06-19 10:03:55 +0100791 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughesae0efdc2015-06-24 16:18:29 +0100792 return;
793 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100794 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughesae0efdc2015-06-24 16:18:29 +0100795 return;
796 }
Richard Hughes9a410ce2016-02-28 15:58:54 +0000797 if (g_strcmp0 (method_name, "Unlock") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100798 const gchar *device_id = NULL;
Richard Hughes747b9ee2018-04-16 16:46:58 +0100799 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughes9a410ce2016-02-28 15:58:54 +0000800 g_autoptr(PolkitSubject) subject = NULL;
801
Richard Hughes9945edb2017-06-19 10:03:55 +0100802 g_variant_get (parameters, "(&s)", &device_id);
803 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000804 if (!fu_main_device_id_valid (device_id, &error)) {
805 g_dbus_method_invocation_return_gerror (invocation, error);
806 return;
807 }
Richard Hughesfe5cc902016-06-29 10:00:00 +0100808
Richard Hughes9a410ce2016-02-28 15:58:54 +0000809 /* authenticate */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100810 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
Richard Hughes9945edb2017-06-19 10:03:55 +0100811 helper = g_new0 (FuMainAuthHelper, 1);
812 helper->priv = priv;
813 helper->invocation = g_object_ref (invocation);
814 helper->device_id = g_strdup (device_id);
Richard Hughes9a410ce2016-02-28 15:58:54 +0000815 subject = polkit_system_bus_name_new (sender);
Richard Hughes9945edb2017-06-19 10:03:55 +0100816 polkit_authority_check_authorization (priv->authority, subject,
Richard Hughes9a410ce2016-02-28 15:58:54 +0000817 "org.freedesktop.fwupd.device-unlock",
818 NULL,
819 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
820 NULL,
Richard Hughes9945edb2017-06-19 10:03:55 +0100821 fu_main_authorize_unlock_cb,
Richard Hughes747b9ee2018-04-16 16:46:58 +0100822 g_steal_pointer (&helper));
Richard Hughes9a410ce2016-02-28 15:58:54 +0000823 return;
824 }
Richard Hughesa6bd5582017-09-07 14:32:22 +0100825 if (g_strcmp0 (method_name, "ModifyRemote") == 0) {
Richard Hughesa6bd5582017-09-07 14:32:22 +0100826 const gchar *remote_id = NULL;
827 const gchar *key = NULL;
828 const gchar *value = NULL;
Richard Hughes747b9ee2018-04-16 16:46:58 +0100829 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughesa6bd5582017-09-07 14:32:22 +0100830 g_autoptr(PolkitSubject) subject = NULL;
831
832 /* check the id exists */
833 g_variant_get (parameters, "(&s&s&s)", &remote_id, &key, &value);
834 g_debug ("Called %s(%s,%s=%s)", method_name, remote_id, key, value);
835
836 /* create helper object */
837 helper = g_new0 (FuMainAuthHelper, 1);
838 helper->invocation = g_object_ref (invocation);
839 helper->remote_id = g_strdup (remote_id);
840 helper->key = g_strdup (key);
841 helper->value = g_strdup (value);
842 helper->priv = priv;
843
844 /* authenticate */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100845 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
Richard Hughesa6bd5582017-09-07 14:32:22 +0100846 subject = polkit_system_bus_name_new (sender);
Mario Limonciello6b9f07c2018-04-16 13:52:09 -0500847 polkit_authority_check_authorization (priv->authority, subject,
Richard Hughesa6bd5582017-09-07 14:32:22 +0100848 "org.freedesktop.fwupd.modify-remote",
849 NULL,
850 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
851 NULL,
852 fu_main_authorize_modify_remote_cb,
Richard Hughes747b9ee2018-04-16 16:46:58 +0100853 g_steal_pointer (&helper));
Richard Hughesa6bd5582017-09-07 14:32:22 +0100854 return;
855 }
Richard Hughes29c220d2016-12-14 17:09:54 +0000856 if (g_strcmp0 (method_name, "VerifyUpdate") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100857 const gchar *device_id = NULL;
Richard Hughes747b9ee2018-04-16 16:46:58 +0100858 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughes29c220d2016-12-14 17:09:54 +0000859 g_autoptr(PolkitSubject) subject = NULL;
860
861 /* check the id exists */
Richard Hughes9945edb2017-06-19 10:03:55 +0100862 g_variant_get (parameters, "(&s)", &device_id);
863 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000864 if (!fu_main_device_id_valid (device_id, &error)) {
865 g_dbus_method_invocation_return_gerror (invocation, error);
866 return;
867 }
Richard Hughes29c220d2016-12-14 17:09:54 +0000868
Richard Hughes9945edb2017-06-19 10:03:55 +0100869 /* create helper object */
Richard Hughes29c220d2016-12-14 17:09:54 +0000870 helper = g_new0 (FuMainAuthHelper, 1);
Richard Hughes29c220d2016-12-14 17:09:54 +0000871 helper->invocation = g_object_ref (invocation);
Richard Hughes9945edb2017-06-19 10:03:55 +0100872 helper->device_id = g_strdup (device_id);
Richard Hughes29c220d2016-12-14 17:09:54 +0000873 helper->priv = priv;
Richard Hughes29c220d2016-12-14 17:09:54 +0000874
875 /* authenticate */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100876 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
Richard Hughes29c220d2016-12-14 17:09:54 +0000877 subject = polkit_system_bus_name_new (sender);
Mario Limonciello6b9f07c2018-04-16 13:52:09 -0500878 polkit_authority_check_authorization (priv->authority, subject,
Richard Hughes29c220d2016-12-14 17:09:54 +0000879 "org.freedesktop.fwupd.verify-update",
880 NULL,
881 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
882 NULL,
Richard Hughes9945edb2017-06-19 10:03:55 +0100883 fu_main_authorize_verify_update_cb,
Richard Hughes747b9ee2018-04-16 16:46:58 +0100884 g_steal_pointer (&helper));
Richard Hughes29c220d2016-12-14 17:09:54 +0000885 return;
886 }
Richard Hughesa043c2e2015-06-29 08:43:18 +0100887 if (g_strcmp0 (method_name, "Verify") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100888 const gchar *device_id = NULL;
889 g_variant_get (parameters, "(&s)", &device_id);
890 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000891 if (!fu_main_device_id_valid (device_id, &error)) {
892 g_dbus_method_invocation_return_gerror (invocation, error);
893 return;
894 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100895 if (!fu_engine_verify (priv->engine, device_id, &error)) {
896 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughesa043c2e2015-06-29 08:43:18 +0100897 return;
898 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100899 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughesa043c2e2015-06-29 08:43:18 +0100900 return;
901 }
Richard Hughes63a407a2015-07-22 08:54:14 +0100902 if (g_strcmp0 (method_name, "Install") == 0) {
Richard Hughes74cc2172015-02-27 13:19:46 +0000903 GVariant *prop_value;
Richard Hughes9945edb2017-06-19 10:03:55 +0100904 const gchar *device_id = NULL;
Richard Hughes74cc2172015-02-27 13:19:46 +0000905 gchar *prop_key;
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000906 gint32 fd_handle = 0;
907 gint fd;
Richard Hughesc7bbbc22018-01-02 22:22:25 +0000908 guint64 archive_size_max;
Richard Hughes9945edb2017-06-19 10:03:55 +0100909 GDBusMessage *message;
910 GUnixFDList *fd_list;
Richard Hughes747b9ee2018-04-16 16:46:58 +0100911 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughes46832432015-09-11 13:43:15 +0100912 g_autoptr(GVariantIter) iter = NULL;
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000913
914 /* check the id exists */
Richard Hughes9945edb2017-06-19 10:03:55 +0100915 g_variant_get (parameters, "(&sha{sv})", &device_id, &fd_handle, &iter);
916 g_debug ("Called %s(%s,%i)", method_name, device_id, fd_handle);
Richard Hughesb6f79552017-11-11 07:58:17 +0000917 if (!fu_main_device_id_valid (device_id, &error)) {
918 g_dbus_method_invocation_return_gerror (invocation, error);
919 return;
920 }
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000921
Richard Hughes9945edb2017-06-19 10:03:55 +0100922 /* create helper object */
923 helper = g_new0 (FuMainAuthHelper, 1);
924 helper->invocation = g_object_ref (invocation);
925 helper->device_id = g_strdup (device_id);
926 helper->priv = priv;
927
928 /* get flags */
929 while (g_variant_iter_next (iter, "{&sv}", &prop_key, &prop_value)) {
Richard Hughes74cc2172015-02-27 13:19:46 +0000930 g_debug ("got option %s", prop_key);
931 if (g_strcmp0 (prop_key, "offline") == 0 &&
932 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +0100933 helper->flags |= FWUPD_INSTALL_FLAG_OFFLINE;
Richard Hughese7c12642015-03-04 20:28:59 +0000934 if (g_strcmp0 (prop_key, "allow-older") == 0 &&
935 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +0100936 helper->flags |= FWUPD_INSTALL_FLAG_ALLOW_OLDER;
Richard Hughese7c12642015-03-04 20:28:59 +0000937 if (g_strcmp0 (prop_key, "allow-reinstall") == 0 &&
938 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +0100939 helper->flags |= FWUPD_INSTALL_FLAG_ALLOW_REINSTALL;
Mario Limonciello71a5b982016-05-10 15:38:53 -0500940 if (g_strcmp0 (prop_key, "force") == 0 &&
941 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +0100942 helper->flags |= FWUPD_INSTALL_FLAG_FORCE;
Richard Hughes76e0f942018-05-14 16:24:00 +0100943 if (g_strcmp0 (prop_key, "no-history") == 0 &&
944 g_variant_get_boolean (prop_value) == TRUE)
945 helper->flags |= FWUPD_INSTALL_FLAG_NO_HISTORY;
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000946 g_variant_unref (prop_value);
Richard Hughes74cc2172015-02-27 13:19:46 +0000947 }
948
Richard Hughes9945edb2017-06-19 10:03:55 +0100949
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000950 /* get the fd */
951 message = g_dbus_method_invocation_get_message (invocation);
952 fd_list = g_dbus_message_get_unix_fd_list (message);
953 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 1) {
Richard Hughes060af612016-08-17 17:32:34 +0100954 g_set_error (&error,
955 FWUPD_ERROR,
956 FWUPD_ERROR_INTERNAL,
957 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +0100958 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000959 return;
960 }
Richard Hughes7419e962016-11-22 19:48:06 +0000961 fd = g_unix_fd_list_get (fd_list, 0, &error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000962 if (fd < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100963 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000964 return;
965 }
966
Richard Hughes9945edb2017-06-19 10:03:55 +0100967 /* parse the cab file before authenticating so we can work out
968 * what action ID to use, for instance, if this is trusted --
969 * this will also close the fd when done */
Richard Hughesc7bbbc22018-01-02 22:22:25 +0000970 archive_size_max = fu_engine_get_archive_size_max (priv->engine);
971 helper->blob_cab = fu_common_get_contents_fd (fd, archive_size_max, &error);
Richard Hughes9945edb2017-06-19 10:03:55 +0100972 if (helper->blob_cab == NULL) {
973 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes5d14def2015-10-07 17:43:10 +0100974 return;
975 }
Richard Hughes4ad41f02018-05-08 14:35:36 +0100976
977 /* install all the things in the store */
978 helper->subject = polkit_system_bus_name_new (sender);
979 if (!fu_main_install_with_helper (g_steal_pointer (&helper), &error)) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100980 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes18423292015-03-09 17:10:50 +0000981 return;
982 }
983
Richard Hughes4ad41f02018-05-08 14:35:36 +0100984 /* async return */
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000985 return;
986 }
Richard Hughes07f963a2017-09-15 14:28:47 +0100987 if (g_strcmp0 (method_name, "GetDetails") == 0) {
Richard Hughes7289a6b2016-05-29 09:27:47 +0100988 GDBusMessage *message;
989 GUnixFDList *fd_list;
990 gint32 fd_handle = 0;
991 gint fd;
Richard Hughes9945edb2017-06-19 10:03:55 +0100992 g_autoptr(GPtrArray) results = NULL;
Richard Hughes7289a6b2016-05-29 09:27:47 +0100993
994 /* get parameters */
995 g_variant_get (parameters, "(h)", &fd_handle);
996 g_debug ("Called %s(%i)", method_name, fd_handle);
997
998 /* get the fd */
999 message = g_dbus_method_invocation_get_message (invocation);
1000 fd_list = g_dbus_message_get_unix_fd_list (message);
1001 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 1) {
Richard Hughes060af612016-08-17 17:32:34 +01001002 g_set_error (&error,
1003 FWUPD_ERROR,
1004 FWUPD_ERROR_INTERNAL,
1005 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +01001006 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001007 return;
1008 }
Richard Hughes7419e962016-11-22 19:48:06 +00001009 fd = g_unix_fd_list_get (fd_list, 0, &error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001010 if (fd < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001011 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001012 return;
1013 }
1014
Richard Hughes9945edb2017-06-19 10:03:55 +01001015 /* get details about the file (will close the fd when done) */
Richard Hughes07f963a2017-09-15 14:28:47 +01001016 results = fu_engine_get_details (priv->engine, fd, &error);
Richard Hughes9945edb2017-06-19 10:03:55 +01001017 if (results == NULL) {
1018 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001019 return;
1020 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001021 val = fu_main_result_array_to_variant (results);
1022 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001023 return;
1024 }
Richard Hughes060af612016-08-17 17:32:34 +01001025 g_set_error (&error,
1026 G_DBUS_ERROR,
1027 G_DBUS_ERROR_UNKNOWN_METHOD,
1028 "no such method %s", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +01001029 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001030}
1031
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001032static GVariant *
1033fu_main_daemon_get_property (GDBusConnection *connection_, const gchar *sender,
1034 const gchar *object_path, const gchar *interface_name,
1035 const gchar *property_name, GError **error,
1036 gpointer user_data)
1037{
Richard Hughes773ce982015-03-09 22:40:57 +00001038 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1039
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001040 if (g_strcmp0 (property_name, "DaemonVersion") == 0)
1041 return g_variant_new_string (VERSION);
1042
Richard Hughes773ce982015-03-09 22:40:57 +00001043 if (g_strcmp0 (property_name, "Status") == 0)
Richard Hughes9945edb2017-06-19 10:03:55 +01001044 return g_variant_new_uint32 (fu_engine_get_status (priv->engine));
Richard Hughes773ce982015-03-09 22:40:57 +00001045
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001046 /* return an error */
1047 g_set_error (error,
Richard Hughes8645ec92015-03-19 10:14:32 +00001048 G_DBUS_ERROR,
1049 G_DBUS_ERROR_UNKNOWN_PROPERTY,
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001050 "failed to get daemon property %s",
1051 property_name);
1052 return NULL;
1053}
1054
Richard Hughesfd468842015-04-22 16:44:08 +01001055static void
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001056fu_main_on_bus_acquired_cb (GDBusConnection *connection,
1057 const gchar *name,
1058 gpointer user_data)
1059{
1060 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1061 guint registration_id;
Richard Hughes46832432015-09-11 13:43:15 +01001062 g_autoptr(GError) error = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001063 static const GDBusInterfaceVTable interface_vtable = {
1064 fu_main_daemon_method_call,
1065 fu_main_daemon_get_property,
1066 NULL
1067 };
1068
1069 priv->connection = g_object_ref (connection);
1070 registration_id = g_dbus_connection_register_object (connection,
1071 FWUPD_DBUS_PATH,
1072 priv->introspection_daemon->interfaces[0],
1073 &interface_vtable,
1074 priv, /* user_data */
1075 NULL, /* user_data_free_func */
1076 NULL); /* GError** */
1077 g_assert (registration_id > 0);
Richard Hughes18423292015-03-09 17:10:50 +00001078
1079 /* connect to D-Bus directly */
1080 priv->proxy_uid =
1081 g_dbus_proxy_new_sync (priv->connection,
1082 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
1083 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
1084 NULL,
1085 "org.freedesktop.DBus",
1086 "/org/freedesktop/DBus",
1087 "org.freedesktop.DBus",
1088 NULL,
1089 &error);
1090 if (priv->proxy_uid == NULL) {
1091 g_warning ("cannot connect to DBus: %s", error->message);
1092 return;
1093 }
Richard Hughes3f236502015-09-24 15:43:02 +01001094
1095 /* dump startup profile data */
Richard Hughes49fafec2017-11-09 14:30:27 +00001096 if (g_getenv ("FWUPD_VERBOSE") != NULL)
Richard Hughes9945edb2017-06-19 10:03:55 +01001097 fu_engine_profile_dump (priv->engine);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001098}
1099
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001100static void
1101fu_main_on_name_acquired_cb (GDBusConnection *connection,
1102 const gchar *name,
1103 gpointer user_data)
1104{
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001105 g_debug ("FuMain: acquired name: %s", name);
1106}
1107
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001108static void
1109fu_main_on_name_lost_cb (GDBusConnection *connection,
1110 const gchar *name,
1111 gpointer user_data)
1112{
1113 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1114 g_debug ("FuMain: lost name: %s", name);
1115 g_main_loop_quit (priv->loop);
1116}
1117
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001118static gboolean
1119fu_main_timed_exit_cb (gpointer user_data)
1120{
1121 GMainLoop *loop = (GMainLoop *) user_data;
1122 g_main_loop_quit (loop);
1123 return G_SOURCE_REMOVE;
1124}
1125
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001126static GDBusNodeInfo *
1127fu_main_load_introspection (const gchar *filename, GError **error)
1128{
Richard Hughes46832432015-09-11 13:43:15 +01001129 g_autoptr(GBytes) data = NULL;
1130 g_autofree gchar *path = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001131
1132 /* lookup data */
1133 path = g_build_filename ("/org/freedesktop/fwupd", filename, NULL);
1134 data = g_resource_lookup_data (fu_get_resource (),
1135 path,
1136 G_RESOURCE_LOOKUP_FLAGS_NONE,
1137 error);
1138 if (data == NULL)
1139 return NULL;
1140
1141 /* build introspection from XML */
1142 return g_dbus_node_info_new_for_xml (g_bytes_get_data (data, NULL), error);
1143}
1144
Richard Hughesf0a799e2017-01-17 20:13:30 +00001145static gboolean
1146fu_main_perhaps_own_name (gpointer user_data)
1147{
1148 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1149 g_autoptr(GError) error = NULL;
1150
1151 /* are any plugins pending */
Richard Hughes9945edb2017-06-19 10:03:55 +01001152 if (!fu_engine_check_plugins_pending (priv->engine, &error)) {
Richard Hughesf0a799e2017-01-17 20:13:30 +00001153 g_debug ("trying again: %s", error->message);
1154 return G_SOURCE_CONTINUE;
1155 }
1156
1157 /* own the object */
1158 g_debug ("registering D-Bus service");
1159 priv->owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
1160 FWUPD_DBUS_SERVICE,
1161 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
1162 G_BUS_NAME_OWNER_FLAGS_REPLACE,
1163 fu_main_on_bus_acquired_cb,
1164 fu_main_on_name_acquired_cb,
1165 fu_main_on_name_lost_cb,
1166 priv, NULL);
1167 return G_SOURCE_REMOVE;
1168}
1169
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001170static void
1171fu_main_private_free (FuMainPrivate *priv)
1172{
1173 if (priv->loop != NULL)
1174 g_main_loop_unref (priv->loop);
1175 if (priv->owner_id > 0)
1176 g_bus_unown_name (priv->owner_id);
1177 if (priv->proxy_uid != NULL)
1178 g_object_unref (priv->proxy_uid);
Richard Hughes9945edb2017-06-19 10:03:55 +01001179 if (priv->engine != NULL)
1180 g_object_unref (priv->engine);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001181 if (priv->connection != NULL)
1182 g_object_unref (priv->connection);
1183 if (priv->authority != NULL)
1184 g_object_unref (priv->authority);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001185 if (priv->introspection_daemon != NULL)
1186 g_dbus_node_info_unref (priv->introspection_daemon);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001187 g_free (priv);
1188}
1189
Mario Limoncielloa98df552018-04-16 12:15:51 -05001190#pragma clang diagnostic push
1191#pragma clang diagnostic ignored "-Wunused-function"
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001192G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuMainPrivate, fu_main_private_free)
Mario Limoncielloa98df552018-04-16 12:15:51 -05001193#pragma clang diagnostic pop
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001194
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001195int
1196main (int argc, char *argv[])
1197{
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001198 gboolean immediate_exit = FALSE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001199 gboolean timed_exit = FALSE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001200 const GOptionEntry options[] = {
1201 { "timed-exit", '\0', 0, G_OPTION_ARG_NONE, &timed_exit,
1202 /* TRANSLATORS: exit after we've started up, used for user profiling */
1203 _("Exit after a small delay"), NULL },
1204 { "immediate-exit", '\0', 0, G_OPTION_ARG_NONE, &immediate_exit,
1205 /* TRANSLATORS: exit straight away, used for automatic profiling */
1206 _("Exit after the engine has loaded"), NULL },
1207 { NULL}
1208 };
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001209 g_autoptr(FuMainPrivate) priv = NULL;
Richard Hughes46832432015-09-11 13:43:15 +01001210 g_autoptr(GError) error = NULL;
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001211 g_autoptr(GOptionContext) context = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001212
1213 setlocale (LC_ALL, "");
1214
1215 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
1216 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1217 textdomain (GETTEXT_PACKAGE);
1218
1219 /* TRANSLATORS: program name */
Richard Hughes63a407a2015-07-22 08:54:14 +01001220 g_set_application_name (_("Firmware Update Daemon"));
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001221 context = g_option_context_new (NULL);
1222 g_option_context_add_main_entries (context, options, NULL);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001223 g_option_context_add_group (context, fu_debug_get_option_group ());
Richard Hughes8ded6ca2015-03-16 12:51:36 +00001224 /* TRANSLATORS: program summary */
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001225 g_option_context_set_summary (context, _("Firmware Update D-Bus Service"));
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001226 if (!g_option_context_parse (context, &argc, &argv, &error)) {
1227 g_printerr ("Failed to parse command line: %s\n", error->message);
1228 return EXIT_FAILURE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001229 }
1230
1231 /* create new objects */
1232 priv = g_new0 (FuMainPrivate, 1);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001233 priv->loop = g_main_loop_new (NULL, FALSE);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001234
Richard Hughes9945edb2017-06-19 10:03:55 +01001235 /* load engine */
Richard Hughes5b5f6552018-05-18 10:22:39 +01001236 priv->engine = fu_engine_new (FU_APP_FLAGS_NONE);
Richard Hughes9945edb2017-06-19 10:03:55 +01001237 g_signal_connect (priv->engine, "changed",
1238 G_CALLBACK (fu_main_engine_changed_cb),
1239 priv);
1240 g_signal_connect (priv->engine, "device-added",
1241 G_CALLBACK (fu_main_engine_device_added_cb),
1242 priv);
1243 g_signal_connect (priv->engine, "device-removed",
1244 G_CALLBACK (fu_main_engine_device_removed_cb),
1245 priv);
1246 g_signal_connect (priv->engine, "device-changed",
1247 G_CALLBACK (fu_main_engine_device_changed_cb),
1248 priv);
1249 g_signal_connect (priv->engine, "status-changed",
1250 G_CALLBACK (fu_main_engine_status_changed_cb),
1251 priv);
1252 g_signal_connect (priv->engine, "percentage-changed",
1253 G_CALLBACK (fu_main_engine_percentage_changed_cb),
1254 priv);
1255 if (!fu_engine_load (priv->engine, &error)) {
1256 g_printerr ("Failed to load engine: %s\n", error->message);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001257 return EXIT_FAILURE;
Richard Hughes804c0752015-08-04 14:53:52 +01001258 }
1259
Richard Hughes9945edb2017-06-19 10:03:55 +01001260 /* keep polling until all the plugins are ready */
1261 g_timeout_add (200, fu_main_perhaps_own_name, priv);
Richard Hughesbc93e4a2016-12-08 17:29:51 +00001262
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001263 /* load introspection from file */
1264 priv->introspection_daemon = fu_main_load_introspection (FWUPD_DBUS_INTERFACE ".xml",
1265 &error);
1266 if (priv->introspection_daemon == NULL) {
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001267 g_printerr ("Failed to load introspection: %s\n", error->message);
1268 return EXIT_FAILURE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001269 }
1270
Richard Hughesf508e762015-02-27 12:49:36 +00001271 /* get authority */
1272 priv->authority = polkit_authority_get_sync (NULL, &error);
1273 if (priv->authority == NULL) {
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001274 g_printerr ("Failed to load authority: %s\n", error->message);
1275 return EXIT_FAILURE;
Richard Hughesf508e762015-02-27 12:49:36 +00001276 }
1277
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001278 /* Only timeout and close the mainloop if we have specified it
1279 * on the command line */
1280 if (immediate_exit)
1281 g_idle_add (fu_main_timed_exit_cb, priv->loop);
1282 else if (timed_exit)
1283 g_timeout_add_seconds (5, fu_main_timed_exit_cb, priv->loop);
1284
1285 /* wait */
Richard Hughes4619f9f2017-06-14 13:55:30 +01001286 g_message ("Daemon ready for requests");
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001287 g_main_loop_run (priv->loop);
1288
1289 /* success */
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001290 return EXIT_SUCCESS;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001291}