blob: 692040ff8f9a45b12359d1b1c07c217ade47a2ce [file] [log] [blame]
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
4 *
5 * Licensed under the GNU General Public License Version 2
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22#include "config.h"
23
Richard Hughes8645ec92015-03-19 10:14:32 +000024#include <fwupd.h>
Richard Hughes67ec8982015-03-03 11:39:27 +000025#include <appstream-glib.h>
26#include <glib/gstdio.h>
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000027#include <gio/gio.h>
28#include <gio/gunixfdlist.h>
Richard Hughesae0efdc2015-06-24 16:18:29 +010029#include <gio/gunixinputstream.h>
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000030#include <glib/gi18n.h>
31#include <locale.h>
Richard Hughesf508e762015-02-27 12:49:36 +000032#include <polkit/polkit.h>
Richard Hughes67ec8982015-03-03 11:39:27 +000033#include <stdlib.h>
34#include <fcntl.h>
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000035
Richard Hughes8bbfdf42015-02-26 22:28:09 +000036#include "fu-debug.h"
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000037#include "fu-device.h"
Richard Hughesae0efdc2015-06-24 16:18:29 +010038#include "fu-keyring.h"
Richard Hughes0e883ee2015-03-18 17:22:33 +000039#include "fu-pending.h"
Richard Hughes3c99ba42015-03-05 12:17:48 +000040#include "fu-provider.h"
Richard Hughes5d057a82015-11-24 18:09:57 +000041#include "fu-provider-dfu.h"
Richard Hughes25cf6ab2015-08-04 21:34:12 +010042#include "fu-provider-rpi.h"
Richard Hughesebb58a32015-05-29 15:35:37 +010043#include "fu-provider-udev.h"
Richard Hughesc89c1b02015-05-05 15:21:18 +010044#include "fu-provider-usb.h"
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000045#include "fu-resources.h"
Mario Limonciello918f3932016-02-03 12:47:23 -060046#include "fu-quirks.h"
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000047
Richard Hughes3c99ba42015-03-05 12:17:48 +000048#ifdef HAVE_COLORHUG
49 #include "fu-provider-chug.h"
50#endif
51#ifdef HAVE_UEFI
52 #include "fu-provider-uefi.h"
53#endif
54
Richard Hughes60f48c22015-10-08 20:25:51 +010055#ifndef PolkitAuthorizationResult_autoptr
56G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitAuthorizationResult, g_object_unref)
57G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitSubject, g_object_unref)
58#endif
59
Richard Hughes5d14def2015-10-07 17:43:10 +010060#define FU_MAIN_FIRMWARE_SIZE_MAX (32 * 1024 * 1024) /* bytes */
61
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000062typedef struct {
63 GDBusConnection *connection;
64 GDBusNodeInfo *introspection_daemon;
Richard Hughes18423292015-03-09 17:10:50 +000065 GDBusProxy *proxy_uid;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000066 GMainLoop *loop;
Richard Hughes5d14def2015-10-07 17:43:10 +010067 GPtrArray *devices; /* of FuDeviceItem */
Richard Hughes8bbfdf42015-02-26 22:28:09 +000068 GPtrArray *providers;
Richard Hughesf508e762015-02-27 12:49:36 +000069 PolkitAuthority *authority;
Richard Hughesf910ac92015-03-19 10:43:42 +000070 FwupdStatus status;
Richard Hughes0e883ee2015-03-18 17:22:33 +000071 FuPending *pending;
Richard Hughes3f236502015-09-24 15:43:02 +010072 AsProfile *profile;
Richard Hughes7708a0f2015-07-21 08:41:22 +010073 AsStore *store;
Richard Hughes033ccba2015-09-10 14:51:28 +010074 guint store_changed_id;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000075} FuMainPrivate;
76
Richard Hughesf508e762015-02-27 12:49:36 +000077typedef struct {
78 FuDevice *device;
79 FuProvider *provider;
80} FuDeviceItem;
81
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000082/**
Richard Hughesd7022b52015-03-11 19:47:06 +000083 * fu_main_emit_changed:
84 **/
85static void
86fu_main_emit_changed (FuMainPrivate *priv)
87{
88 /* not yet connected */
89 if (priv->connection == NULL)
90 return;
91 g_dbus_connection_emit_signal (priv->connection,
92 NULL,
93 FWUPD_DBUS_PATH,
94 FWUPD_DBUS_INTERFACE,
95 "Changed",
96 NULL, NULL);
97}
98
99/**
Richard Hughes773ce982015-03-09 22:40:57 +0000100 * fu_main_emit_property_changed:
101 **/
102static void
103fu_main_emit_property_changed (FuMainPrivate *priv,
104 const gchar *property_name,
105 GVariant *property_value)
106{
107 GVariantBuilder builder;
108 GVariantBuilder invalidated_builder;
109
110 /* not yet connected */
111 if (priv->connection == NULL)
112 return;
113
114 /* build the dict */
115 g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as"));
116 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
117 g_variant_builder_add (&builder,
118 "{sv}",
119 property_name,
120 property_value);
121 g_dbus_connection_emit_signal (priv->connection,
122 NULL,
123 FWUPD_DBUS_PATH,
124 "org.freedesktop.DBus.Properties",
125 "PropertiesChanged",
126 g_variant_new ("(sa{sv}as)",
127 FWUPD_DBUS_INTERFACE,
128 &builder,
129 &invalidated_builder),
130 NULL);
131 g_variant_builder_clear (&builder);
132 g_variant_builder_clear (&invalidated_builder);
133}
134
135/**
136 * fu_main_set_status:
137 **/
138static void
Richard Hughesf910ac92015-03-19 10:43:42 +0000139fu_main_set_status (FuMainPrivate *priv, FwupdStatus status)
Richard Hughes773ce982015-03-09 22:40:57 +0000140{
Richard Hughes773ce982015-03-09 22:40:57 +0000141 if (priv->status == status)
142 return;
143 priv->status = status;
144
145 /* emit changed */
Richard Hughes88181512015-03-19 10:57:44 +0000146 g_debug ("Emitting PropertyChanged('Status'='%s')",
147 fwupd_status_to_string (status));
148 fu_main_emit_property_changed (priv, "Status", g_variant_new_uint32 (status));
Richard Hughes773ce982015-03-09 22:40:57 +0000149}
150
151/**
Richard Hughes67ec8982015-03-03 11:39:27 +0000152 * fu_main_device_array_to_variant:
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000153 **/
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000154static GVariant *
Richard Hughes7708a0f2015-07-21 08:41:22 +0100155fu_main_device_array_to_variant (GPtrArray *devices, GError **error)
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000156{
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000157 GVariantBuilder builder;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000158 guint i;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000159
Richard Hughes9a38c032015-03-17 20:58:46 +0000160 /* no devices */
Richard Hughes7708a0f2015-07-21 08:41:22 +0100161 if (devices->len == 0) {
Richard Hughes9a38c032015-03-17 20:58:46 +0000162 g_set_error_literal (error,
Richard Hughes8645ec92015-03-19 10:14:32 +0000163 FWUPD_ERROR,
164 FWUPD_ERROR_NOTHING_TO_DO,
Richard Hughes9d76a872015-09-17 12:49:07 +0100165 "Nothing to do");
Richard Hughes9a38c032015-03-17 20:58:46 +0000166 return NULL;
167 }
168
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000169 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
Richard Hughes7708a0f2015-07-21 08:41:22 +0100170 for (i = 0; i < devices->len; i++) {
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000171 GVariant *tmp;
172 FuDeviceItem *item;
Richard Hughes7708a0f2015-07-21 08:41:22 +0100173 item = g_ptr_array_index (devices, i);
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000174 tmp = fu_device_to_variant (item->device);
175 g_variant_builder_add_value (&builder, tmp);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000176 }
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000177 return g_variant_new ("(a{sa{sv}})", &builder);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000178}
179
180/**
Richard Hughesf508e762015-02-27 12:49:36 +0000181 * fu_main_item_free:
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000182 **/
Richard Hughesf508e762015-02-27 12:49:36 +0000183static void
184fu_main_item_free (FuDeviceItem *item)
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000185{
Richard Hughesf508e762015-02-27 12:49:36 +0000186 g_object_unref (item->device);
187 g_object_unref (item->provider);
188 g_free (item);
189}
190
191/**
192 * fu_main_get_item_by_id:
193 **/
194static FuDeviceItem *
195fu_main_get_item_by_id (FuMainPrivate *priv, const gchar *id)
196{
197 FuDeviceItem *item;
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000198 guint i;
199
200 for (i = 0; i < priv->devices->len; i++) {
Richard Hughesf508e762015-02-27 12:49:36 +0000201 item = g_ptr_array_index (priv->devices, i);
202 if (g_strcmp0 (fu_device_get_id (item->device), id) == 0)
203 return item;
Richard Hughesb1b59d82016-01-06 13:20:53 +0000204 if (g_strcmp0 (fu_device_get_equivalent_id (item->device), id) == 0)
205 return item;
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000206 }
207 return NULL;
208}
209
Richard Hughesd079b1a2015-03-06 10:09:55 +0000210/**
Richard Hughes0e883ee2015-03-18 17:22:33 +0000211 * fu_main_get_provider_by_name:
212 **/
213static FuProvider *
214fu_main_get_provider_by_name (FuMainPrivate *priv, const gchar *name)
215{
216 FuProvider *provider;
217 guint i;
218
219 for (i = 0; i < priv->providers->len; i++) {
220 provider = g_ptr_array_index (priv->providers, i);
221 if (g_strcmp0 (fu_provider_get_name (provider), name) == 0)
222 return provider;
223 }
224 return NULL;
225}
226
Richard Hughes5d14def2015-10-07 17:43:10 +0100227/**
228 * fu_main_get_release_trust_flags:
229 **/
230static gboolean
231fu_main_get_release_trust_flags (AsRelease *release,
232 FwupdTrustFlags *trust_flags,
233 GError **error)
234{
235 AsChecksum *csum_tmp;
236 GBytes *blob_payload;
237 GBytes *blob_signature;
238 const gchar *fn;
239 g_autofree gchar *pki_dir = NULL;
240 g_autofree gchar *fn_signature = NULL;
241 g_autoptr(GError) error_local = NULL;
242 g_autoptr(FuKeyring) kr = NULL;
243
244 /* no filename? */
245 csum_tmp = as_release_get_checksum_by_target (release, AS_CHECKSUM_TARGET_CONTENT);
246 fn = as_checksum_get_filename (csum_tmp);
247 if (fn == NULL) {
248 g_set_error_literal (error,
249 FWUPD_ERROR,
250 FWUPD_ERROR_INVALID_FILE,
251 "no filename");
252 return FALSE;
253 }
254
255 /* no signature == no trust */
256 fn_signature = g_strdup_printf ("%s.asc", fn);
257 blob_signature = as_release_get_blob (release, fn_signature);
258 if (blob_signature == NULL) {
259 g_debug ("firmware archive contained no GPG signature");
260 return TRUE;
261 }
262
263 /* get payload */
264 blob_payload = as_release_get_blob (release, fn);
265 if (blob_payload == NULL) {
266 g_set_error_literal (error,
267 FWUPD_ERROR,
268 FWUPD_ERROR_INVALID_FILE,
269 "no payload");
270 return FALSE;
271 }
272
273 /* check we were installed correctly */
274 pki_dir = g_build_filename (SYSCONFDIR, "pki", "fwupd", NULL);
275 if (!g_file_test (pki_dir, G_FILE_TEST_EXISTS)) {
276 g_set_error (error,
277 FWUPD_ERROR,
278 FWUPD_ERROR_NOT_FOUND,
279 "PKI directory %s not found", pki_dir);
280 return FALSE;
281 }
282
283 /* verify against the system trusted keys */
284 kr = fu_keyring_new ();
285 if (!fu_keyring_add_public_keys (kr, pki_dir, error))
286 return FALSE;
287 if (!fu_keyring_verify_data (kr, blob_payload, blob_signature, &error_local)) {
288 g_warning ("untrusted as failed to verify: %s",
289 error_local->message);
290 return TRUE;
291 }
292
293 /* awesome! */
294 g_debug ("marking payload as trusted");
295 *trust_flags |= FWUPD_TRUST_FLAG_PAYLOAD;
296 return TRUE;
297}
298
Richard Hughesf508e762015-02-27 12:49:36 +0000299typedef struct {
300 GDBusMethodInvocation *invocation;
Richard Hughes5d14def2015-10-07 17:43:10 +0100301 AsStore *store;
302 FwupdTrustFlags trust_flags;
Richard Hughes67ec8982015-03-03 11:39:27 +0000303 FuDevice *device;
Richard Hughes74cc2172015-02-27 13:19:46 +0000304 FuProviderFlags flags;
Richard Hughes5d14def2015-10-07 17:43:10 +0100305 GBytes *blob_fw;
306 GBytes *blob_cab;
Richard Hughes63bbbf52015-04-14 16:12:16 +0100307 gint vercmp;
Richard Hughes67ec8982015-03-03 11:39:27 +0000308 FuMainPrivate *priv;
Richard Hughesf508e762015-02-27 12:49:36 +0000309} FuMainAuthHelper;
310
311/**
312 * fu_main_helper_free:
313 **/
314static void
315fu_main_helper_free (FuMainAuthHelper *helper)
316{
Richard Hughes67ec8982015-03-03 11:39:27 +0000317 /* free */
Richard Hughesd079b1a2015-03-06 10:09:55 +0000318 if (helper->device != NULL)
319 g_object_unref (helper->device);
Richard Hughes5d14def2015-10-07 17:43:10 +0100320 if (helper->blob_fw > 0)
321 g_bytes_unref (helper->blob_fw);
322 if (helper->blob_cab > 0)
323 g_bytes_unref (helper->blob_cab);
Richard Hughes67ec8982015-03-03 11:39:27 +0000324 g_object_unref (helper->invocation);
Richard Hughes5d14def2015-10-07 17:43:10 +0100325 g_object_unref (helper->store);
Richard Hughesf508e762015-02-27 12:49:36 +0000326 g_free (helper);
327}
328
329/**
Richard Hughesb75c92d2016-02-20 20:22:00 +0000330 * fu_main_on_battery:
331 **/
332static gboolean
333fu_main_on_battery (void)
334{
335 g_autoptr(GDBusProxy) proxy = NULL;
336 g_autoptr(GError) error = NULL;
337 g_autoptr(GVariant) value = NULL;
338
339 proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
340 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
341 NULL,
342 "org.freedesktop.UPower",
343 "/org/freedesktop/UPower",
344 "org.freedesktop.UPower",
345 NULL,
346 &error);
347 if (proxy == NULL) {
348 g_warning ("Failed to conect UPower: %s", error->message);
349 return FALSE;
350 }
351 value = g_dbus_proxy_get_cached_property (proxy, "OnBattery");
352 if (value == NULL) {
353 g_warning ("Failed to get OnBattery property value");
354 return FALSE;
355 }
356 return g_variant_get_boolean (value);
357}
358
359/**
Richard Hughes18423292015-03-09 17:10:50 +0000360 * fu_main_provider_update_authenticated:
361 **/
362static gboolean
363fu_main_provider_update_authenticated (FuMainAuthHelper *helper, GError **error)
364{
365 FuDeviceItem *item;
366
367 /* check the device still exists */
368 item = fu_main_get_item_by_id (helper->priv, fu_device_get_id (helper->device));
369 if (item == NULL) {
370 g_set_error (error,
Richard Hughes8645ec92015-03-19 10:14:32 +0000371 FWUPD_ERROR,
372 FWUPD_ERROR_INVALID_FILE,
Richard Hughes18423292015-03-09 17:10:50 +0000373 "device %s was removed",
374 fu_device_get_id (helper->device));
375 return FALSE;
376 }
377
Richard Hughesb75c92d2016-02-20 20:22:00 +0000378 /* can we only do this on AC power */
379 if (fu_device_get_flags (item->device) & FU_DEVICE_FLAG_REQUIRE_AC) {
380 if (fu_main_on_battery ()) {
381 g_set_error_literal (error,
382 FWUPD_ERROR,
383 FWUPD_ERROR_NOT_SUPPORTED,
384 "Cannot install update "
385 "when not on AC power");
386 return FALSE;
387 }
388 }
389
Richard Hughes18423292015-03-09 17:10:50 +0000390 /* run the correct provider that added this */
Richard Hughesa3a8f502015-11-24 12:31:59 +0000391 if (!fu_provider_update (item->provider,
392 item->device,
393 helper->blob_cab,
394 helper->blob_fw,
395 helper->flags,
396 error))
397 return FALSE;
398
399 /* make the UI update */
Richard Hughes1d966332016-01-27 13:12:06 +0000400 fu_device_set_modified (item->device, g_get_real_time () / G_USEC_PER_SEC);
Richard Hughesa3a8f502015-11-24 12:31:59 +0000401 fu_main_emit_changed (helper->priv);
402 return TRUE;
Richard Hughes18423292015-03-09 17:10:50 +0000403}
404
405/**
Richard Hughesf508e762015-02-27 12:49:36 +0000406 * fu_main_check_authorization_cb:
407 **/
408static void
409fu_main_check_authorization_cb (GObject *source, GAsyncResult *res, gpointer user_data)
410{
411 FuMainAuthHelper *helper = (FuMainAuthHelper *) user_data;
Richard Hughes46832432015-09-11 13:43:15 +0100412 g_autoptr(GError) error = NULL;
Richard Hughes60f48c22015-10-08 20:25:51 +0100413 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughesf508e762015-02-27 12:49:36 +0000414
415 /* get result */
416 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
417 res, &error);
418 if (auth == NULL) {
419 g_dbus_method_invocation_return_error (helper->invocation,
Richard Hughes8645ec92015-03-19 10:14:32 +0000420 FWUPD_ERROR,
421 FWUPD_ERROR_AUTH_FAILED,
Richard Hughesf508e762015-02-27 12:49:36 +0000422 "could not check for auth: %s",
423 error->message);
424 fu_main_helper_free (helper);
425 return;
426 }
427
428 /* did not auth */
429 if (!polkit_authorization_result_get_is_authorized (auth)) {
430 g_dbus_method_invocation_return_error (helper->invocation,
Richard Hughes8645ec92015-03-19 10:14:32 +0000431 FWUPD_ERROR,
432 FWUPD_ERROR_AUTH_FAILED,
Richard Hughesf508e762015-02-27 12:49:36 +0000433 "failed to obtain auth");
434 fu_main_helper_free (helper);
435 return;
436 }
437
Richard Hughes18423292015-03-09 17:10:50 +0000438 /* we're good to go */
439 if (!fu_main_provider_update_authenticated (helper, &error)) {
440 g_dbus_method_invocation_return_gerror (helper->invocation, error);
Richard Hughesf508e762015-02-27 12:49:36 +0000441 fu_main_helper_free (helper);
442 return;
443 }
444
445 /* success */
446 g_dbus_method_invocation_return_value (helper->invocation, NULL);
447 fu_main_helper_free (helper);
448}
449
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000450/**
Richard Hughes5d14def2015-10-07 17:43:10 +0100451 * fu_main_get_guids_from_store:
452 **/
453static gchar *
454fu_main_get_guids_from_store (AsStore *store)
455{
456 AsApp *app;
457 AsProvide *prov;
458 GPtrArray *provides;
459 GPtrArray *apps;
460 GString *str = g_string_new ("");
461 guint i;
462 guint j;
463
464 /* return a string with all the firmware apps in the store */
465 apps = as_store_get_apps (store);
466 for (i = 0; i < apps->len; i++) {
467 app = AS_APP (g_ptr_array_index (apps, i));
468 provides = as_app_get_provides (app);
469 for (j = 0; j < provides->len; j++) {
470 prov = AS_PROVIDE (g_ptr_array_index (provides, j));
471 if (as_provide_get_kind (prov) != AS_PROVIDE_KIND_FIRMWARE_FLASHED)
472 continue;
473 g_string_append_printf (str, "%s,", as_provide_get_value (prov));
474 }
475 }
476 if (str->len == 0)
477 return NULL;
478 g_string_truncate (str, str->len - 1);
479 return g_string_free (str, FALSE);
480}
481
482/**
Richard Hughesdf7950b2016-01-31 10:18:40 +0000483 * fu_main_vendor_quirk_release_version:
484 **/
485static void
486fu_main_vendor_quirk_release_version (AsApp *app)
487{
488 AsVersionParseFlag flags = AS_VERSION_PARSE_FLAG_USE_TRIPLET;
489 GPtrArray *releases;
490 guint i;
491
492 /* no quirk required */
493 if (as_app_get_id_kind (app) != AS_ID_KIND_FIRMWARE)
494 return;
495
Mario Limonciello918f3932016-02-03 12:47:23 -0600496 for (i = 0; quirk_table[i].identifier != NULL; i++)
497 if (g_str_has_prefix (as_app_get_id(app), quirk_table[i].identifier))
498 flags = quirk_table[i].flags;
Richard Hughesdf7950b2016-01-31 10:18:40 +0000499
500 /* fix each release */
501 releases = as_app_get_releases (app);
502 for (i = 0; i < releases->len; i++) {
503 AsRelease *rel;
504 const gchar *version;
505 guint64 ver_uint32;
506 g_autofree gchar *version_new = NULL;
507
508 rel = g_ptr_array_index (releases, i);
509 version = as_release_get_version (rel);
510 if (version == NULL)
511 continue;
512 if (g_strstr_len (version, -1, ".") != NULL)
513 continue;
514
515 /* metainfo files use hex and the LVFS uses decimal */
516 if (g_str_has_prefix (version, "0x")) {
517 ver_uint32 = g_ascii_strtoull (version + 2, NULL, 16);
518 } else {
519 ver_uint32 = g_ascii_strtoull (version, NULL, 10);
520 }
521 if (ver_uint32 == 0)
522 continue;
523
524 /* convert to dotted decimal */
525 version_new = as_utils_version_from_uint32 (ver_uint32, flags);
526 as_release_set_version (rel, version_new);
527 }
528}
529
530/**
Richard Hughes67ec8982015-03-03 11:39:27 +0000531 * fu_main_update_helper:
532 **/
533static gboolean
534fu_main_update_helper (FuMainAuthHelper *helper, GError **error)
535{
Richard Hughes5d14def2015-10-07 17:43:10 +0100536 AsApp *app;
537 AsChecksum *csum_tmp;
538 AsRelease *rel;
Richard Hughesdef31752015-03-04 19:26:54 +0000539 const gchar *tmp;
Richard Hughescccc7752015-03-06 11:13:19 +0000540 const gchar *version;
Richard Hughes5d14def2015-10-07 17:43:10 +0100541 guint i;
Richard Hughes67ec8982015-03-03 11:39:27 +0000542
Richard Hughes5d14def2015-10-07 17:43:10 +0100543 /* load store file which also decompresses firmware */
544 fu_main_set_status (helper->priv, FWUPD_STATUS_DECOMPRESSING);
545 if (!as_store_from_bytes (helper->store, helper->blob_cab, NULL, error))
Richard Hughes67ec8982015-03-03 11:39:27 +0000546 return FALSE;
Richard Hughesd079b1a2015-03-06 10:09:55 +0000547
Richard Hughes5d14def2015-10-07 17:43:10 +0100548 /* if we've not chosen a device, try and find anything in the
549 * cabinet 'store' that matches any installed device */
Richard Hughesd079b1a2015-03-06 10:09:55 +0000550 if (helper->device == NULL) {
Richard Hughes5d14def2015-10-07 17:43:10 +0100551 for (i = 0; i < helper->priv->devices->len; i++) {
552 FuDeviceItem *item;
553 item = g_ptr_array_index (helper->priv->devices, i);
554 app = as_store_get_app_by_provide (helper->store,
555 AS_PROVIDE_KIND_FIRMWARE_FLASHED,
556 fu_device_get_guid (item->device));
557 if (app != NULL) {
558 helper->device = g_object_ref (item->device);
559 break;
560 }
561 }
562
563 /* nothing found */
564 if (helper->device == NULL) {
565 g_autofree gchar *guid = NULL;
566 guid = fu_main_get_guids_from_store (helper->store);
Richard Hughesd079b1a2015-03-06 10:09:55 +0000567 g_set_error (error,
Richard Hughes8645ec92015-03-19 10:14:32 +0000568 FWUPD_ERROR,
569 FWUPD_ERROR_INVALID_FILE,
Richard Hughes5d14def2015-10-07 17:43:10 +0100570 "no attached hardware matched %s",
Richard Hughesd079b1a2015-03-06 10:09:55 +0000571 guid);
572 return FALSE;
573 }
Richard Hughes5d14def2015-10-07 17:43:10 +0100574 } else {
575 /* find an application from the cabinet 'store' for the
576 * chosen device */
577 app = as_store_get_app_by_provide (helper->store,
578 AS_PROVIDE_KIND_FIRMWARE_FLASHED,
579 fu_device_get_guid (helper->device));
580 if (app == NULL) {
581 g_autofree gchar *guid = NULL;
582 guid = fu_main_get_guids_from_store (helper->store);
583 g_set_error (error,
584 FWUPD_ERROR,
585 FWUPD_ERROR_INVALID_FILE,
586 "firmware is not for this hw: required %s got %s",
587 fu_device_get_guid (helper->device), guid);
588 return FALSE;
589 }
Richard Hughesdef31752015-03-04 19:26:54 +0000590 }
591
Richard Hughesdef31752015-03-04 19:26:54 +0000592 /* parse the DriverVer */
Richard Hughes5d14def2015-10-07 17:43:10 +0100593 rel = as_app_get_release_default (app);
594 if (rel == NULL) {
595 g_set_error_literal (error,
596 FWUPD_ERROR,
597 FWUPD_ERROR_INVALID_FILE,
598 "no releases in the firmware component");
599 return FALSE;
600 }
601
602 /* get the blob */
603 csum_tmp = as_release_get_checksum_by_target (rel, AS_CHECKSUM_TARGET_CONTENT);
604 tmp = as_checksum_get_filename (csum_tmp);
605 g_assert (tmp != NULL);
606 helper->blob_fw = as_release_get_blob (rel, tmp);
607 if (helper->blob_fw == NULL) {
608 g_set_error_literal (error,
609 FWUPD_ERROR,
610 FWUPD_ERROR_READ,
611 "failed to get firmware blob");
612 return FALSE;
613 }
614
Richard Hughesdf7950b2016-01-31 10:18:40 +0000615 /* possibly convert the version from 0x to dotted */
616 fu_main_vendor_quirk_release_version (app);
617
Richard Hughes5d14def2015-10-07 17:43:10 +0100618 version = as_release_get_version (rel);
Richard Hughes2257cee2015-09-08 14:46:17 +0100619 fu_device_set_metadata (helper->device, FU_DEVICE_KEY_UPDATE_VERSION, version);
Richard Hughesdef31752015-03-04 19:26:54 +0000620
Richard Hughes18e75912015-03-05 13:17:17 +0000621 /* compare to the lowest supported version, if it exists */
622 tmp = fu_device_get_metadata (helper->device, FU_DEVICE_KEY_VERSION_LOWEST);
623 if (tmp != NULL && as_utils_vercmp (tmp, version) > 0) {
624 g_set_error (error,
Richard Hughes8645ec92015-03-19 10:14:32 +0000625 FWUPD_ERROR,
626 FWUPD_ERROR_VERSION_NEWER,
Richard Hughes18e75912015-03-05 13:17:17 +0000627 "Specified firmware is older than the minimum "
628 "required version '%s < %s'", tmp, version);
629 return FALSE;
630 }
631
Richard Hughesdef31752015-03-04 19:26:54 +0000632 /* compare the versions of what we have installed */
633 tmp = fu_device_get_metadata (helper->device, FU_DEVICE_KEY_VERSION);
Richard Hughesd1e823c2015-03-04 22:18:30 +0000634 if (tmp == NULL) {
635 g_set_error (error,
Richard Hughes8645ec92015-03-19 10:14:32 +0000636 FWUPD_ERROR,
637 FWUPD_ERROR_INTERNAL,
Richard Hughesd1e823c2015-03-04 22:18:30 +0000638 "Device %s does not yet have a current version",
639 fu_device_get_id (helper->device));
640 return FALSE;
641 }
Richard Hughes63bbbf52015-04-14 16:12:16 +0100642 helper->vercmp = as_utils_vercmp (tmp, version);
643 if (helper->vercmp == 0 && (helper->flags & FU_PROVIDER_UPDATE_FLAG_ALLOW_REINSTALL) == 0) {
Richard Hughesdef31752015-03-04 19:26:54 +0000644 g_set_error (error,
Richard Hughes8645ec92015-03-19 10:14:32 +0000645 FWUPD_ERROR,
646 FWUPD_ERROR_VERSION_SAME,
Richard Hughesdef31752015-03-04 19:26:54 +0000647 "Specified firmware is already installed '%s'",
648 tmp);
649 return FALSE;
650 }
Richard Hughes63bbbf52015-04-14 16:12:16 +0100651 if (helper->vercmp > 0 && (helper->flags & FU_PROVIDER_UPDATE_FLAG_ALLOW_OLDER) == 0) {
Richard Hughesdef31752015-03-04 19:26:54 +0000652 g_set_error (error,
Richard Hughes8645ec92015-03-19 10:14:32 +0000653 FWUPD_ERROR,
654 FWUPD_ERROR_VERSION_NEWER,
Richard Hughesdef31752015-03-04 19:26:54 +0000655 "Specified firmware is older than installed '%s < %s'",
656 tmp, version);
Richard Hughes67ec8982015-03-03 11:39:27 +0000657 return FALSE;
658 }
659
Richard Hughes5d14def2015-10-07 17:43:10 +0100660 /* verify */
661 if (!fu_main_get_release_trust_flags (rel, &helper->trust_flags, error))
Richard Hughes1a886b12015-07-15 17:22:10 +0100662 return FALSE;
Richard Hughes67ec8982015-03-03 11:39:27 +0000663 return TRUE;
664}
665
666/**
Richard Hughes18423292015-03-09 17:10:50 +0000667 * fu_main_dbus_get_uid:
668 *
669 * Return value: the UID, or %G_MAXUINT if it could not be obtained
670 **/
671static guint
672fu_main_dbus_get_uid (FuMainPrivate *priv, const gchar *sender)
673{
674 guint uid;
Richard Hughes46832432015-09-11 13:43:15 +0100675 g_autoptr(GError) error = NULL;
676 g_autoptr(GVariant) value = NULL;
Richard Hughes18423292015-03-09 17:10:50 +0000677
678 if (priv->proxy_uid == NULL)
679 return G_MAXUINT;
680 value = g_dbus_proxy_call_sync (priv->proxy_uid,
681 "GetConnectionUnixUser",
682 g_variant_new ("(s)", sender),
683 G_DBUS_CALL_FLAGS_NONE,
684 -1,
685 NULL,
686 &error);
687 if (value == NULL) {
688 g_warning ("Failed to get uid for %s: %s",
689 sender, error->message);
690 return G_MAXUINT;
691 }
692 g_variant_get (value, "(u)", &uid);
693 return uid;
694}
695
696/**
Richard Hughes0e883ee2015-03-18 17:22:33 +0000697 * fu_main_get_item_by_id_fallback_pending:
698 **/
699static FuDeviceItem *
700fu_main_get_item_by_id_fallback_pending (FuMainPrivate *priv, const gchar *id, GError **error)
701{
702 FuDevice *dev;
703 FuProvider *provider;
704 FuDeviceItem *item = NULL;
705 const gchar *tmp;
706 guint i;
Richard Hughes46832432015-09-11 13:43:15 +0100707 g_autoptr(GPtrArray) devices = NULL;
Richard Hughes0e883ee2015-03-18 17:22:33 +0000708
709 /* not a wildcard */
710 if (g_strcmp0 (id, FWUPD_DEVICE_ID_ANY) != 0) {
711 item = fu_main_get_item_by_id (priv, id);
712 if (item == NULL) {
713 g_set_error (error,
Richard Hughes8645ec92015-03-19 10:14:32 +0000714 FWUPD_ERROR,
715 FWUPD_ERROR_NOT_FOUND,
Richard Hughes0e883ee2015-03-18 17:22:33 +0000716 "no suitable device found for %s", id);
717 }
718 return item;
719 }
720
721 /* allow '*' for any */
722 devices = fu_pending_get_devices (priv->pending, error);
723 if (devices == NULL)
724 return NULL;
725 for (i = 0; i < devices->len; i++) {
726 dev = g_ptr_array_index (devices, i);
727 tmp = fu_device_get_metadata (dev, FU_DEVICE_KEY_PENDING_STATE);
728 if (tmp == NULL)
729 continue;
730 if (g_strcmp0 (tmp, "scheduled") == 0)
731 continue;
732
733 /* if the device is not still connected, fake a FuDeviceItem */
734 item = fu_main_get_item_by_id (priv, fu_device_get_id (dev));
735 if (item == NULL) {
736 tmp = fu_device_get_metadata (dev, FU_DEVICE_KEY_PROVIDER);
737 provider = fu_main_get_provider_by_name (priv, tmp);
738 if (provider == NULL) {
739 g_set_error (error,
Richard Hughes8645ec92015-03-19 10:14:32 +0000740 FWUPD_ERROR,
741 FWUPD_ERROR_NOT_FOUND,
Richard Hughes0e883ee2015-03-18 17:22:33 +0000742 "no provider %s found", tmp);
743 }
744 item = g_new0 (FuDeviceItem, 1);
745 item->device = g_object_ref (dev);
746 item->provider = g_object_ref (provider);
747 g_ptr_array_add (priv->devices, item);
748
749 /* FIXME: just a boolean on FuDeviceItem? */
750 fu_device_set_metadata (dev, "FakeDevice", "TRUE");
751 }
752 break;
753 }
754
755 /* no device found */
756 if (item == NULL) {
757 g_set_error_literal (error,
Richard Hughes8645ec92015-03-19 10:14:32 +0000758 FWUPD_ERROR,
759 FWUPD_ERROR_NOT_FOUND,
Richard Hughes0e883ee2015-03-18 17:22:33 +0000760 "no suitable devices found");
761 }
762 return item;
763}
764
765/**
Richard Hughes63bbbf52015-04-14 16:12:16 +0100766 * fu_main_get_action_id_for_device:
767 **/
768static const gchar *
769fu_main_get_action_id_for_device (FuMainAuthHelper *helper)
770{
Richard Hughes63bbbf52015-04-14 16:12:16 +0100771 gboolean is_trusted;
772 gboolean is_downgrade;
773
774 /* only test the payload */
Richard Hughes5d14def2015-10-07 17:43:10 +0100775 is_trusted = (helper->trust_flags & FWUPD_TRUST_FLAG_PAYLOAD) > 0;
Richard Hughes63bbbf52015-04-14 16:12:16 +0100776 is_downgrade = helper->vercmp > 0;
777
778 /* relax authentication checks for removable devices */
Richard Hughesd7dba982015-05-05 16:02:17 +0100779 if ((fu_device_get_flags (helper->device) & FU_DEVICE_FLAG_INTERNAL) == 0) {
Richard Hughes63bbbf52015-04-14 16:12:16 +0100780 if (is_downgrade)
781 return "org.freedesktop.fwupd.downgrade-hotplug";
782 if (is_trusted)
783 return "org.freedesktop.fwupd.update-hotplug-trusted";
784 return "org.freedesktop.fwupd.update-hotplug";
785 }
786
787 /* internal device */
788 if (is_downgrade)
789 return "org.freedesktop.fwupd.downgrade-internal";
790 if (is_trusted)
791 return "org.freedesktop.fwupd.update-internal-trusted";
792 return "org.freedesktop.fwupd.update-internal";
793}
794
795/**
Richard Hughesae0efdc2015-06-24 16:18:29 +0100796 * fu_main_daemon_update_metadata:
797 *
798 * Supports optionally GZipped AppStream files up to 1MiB in size.
799 **/
800static gboolean
Mario Limonciello3ed54472015-07-23 13:19:39 -0500801fu_main_daemon_update_metadata (FuMainPrivate *priv, gint fd, gint fd_sig, GError **error)
Richard Hughesae0efdc2015-06-24 16:18:29 +0100802{
Richard Hughesf2fca012015-10-30 08:44:44 +0000803 const guint8 *data;
Richard Hughes727664f2015-10-27 09:56:04 +0000804 guint i;
Richard Hughesf2fca012015-10-30 08:44:44 +0000805 gsize size;
Richard Hughes727664f2015-10-27 09:56:04 +0000806 GPtrArray *apps;
Richard Hughesbb840ce2015-10-30 08:47:24 +0000807 g_autofree gchar *xml = NULL;
Richard Hughes727664f2015-10-27 09:56:04 +0000808 g_autoptr(AsStore) store = NULL;
Richard Hughes46832432015-09-11 13:43:15 +0100809 g_autoptr(GBytes) bytes = NULL;
810 g_autoptr(GBytes) bytes_raw = NULL;
811 g_autoptr(GBytes) bytes_sig = NULL;
812 g_autoptr(FuKeyring) kr = NULL;
813 g_autoptr(GConverter) converter = NULL;
814 g_autoptr(GFile) file = NULL;
815 g_autoptr(GInputStream) stream_buf = NULL;
816 g_autoptr(GInputStream) stream_fd = NULL;
817 g_autoptr(GInputStream) stream = NULL;
818 g_autoptr(GInputStream) stream_sig = NULL;
Richard Hughesae0efdc2015-06-24 16:18:29 +0100819
Richard Hughesae0efdc2015-06-24 16:18:29 +0100820 /* read the entire file into memory */
821 stream_fd = g_unix_input_stream_new (fd, TRUE);
822 bytes_raw = g_input_stream_read_bytes (stream_fd, 0x100000, NULL, error);
823 if (bytes_raw == NULL)
824 return FALSE;
825 stream_buf = g_memory_input_stream_new ();
826 g_memory_input_stream_add_bytes (G_MEMORY_INPUT_STREAM (stream_buf), bytes_raw);
827
828 /* peek the file type and get data */
Richard Hughesf2fca012015-10-30 08:44:44 +0000829 data = g_bytes_get_data (bytes_raw, &size);
830 if (size < 2) {
831 g_set_error_literal (error,
832 FWUPD_ERROR,
833 FWUPD_ERROR_INVALID_FILE,
834 "file is too small");
Richard Hughesae0efdc2015-06-24 16:18:29 +0100835 return FALSE;
Richard Hughesf2fca012015-10-30 08:44:44 +0000836 }
837 if (data[0] == 0x1f && data[1] == 0x8b) {
Richard Hughesae0efdc2015-06-24 16:18:29 +0100838 g_debug ("using GZip decompressor for data");
Richard Hughesae0efdc2015-06-24 16:18:29 +0100839 converter = G_CONVERTER (g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP));
840 stream = g_converter_input_stream_new (stream_buf, converter);
841 bytes = g_input_stream_read_bytes (stream, 0x100000, NULL, error);
842 if (bytes == NULL)
843 return FALSE;
Richard Hughesf2fca012015-10-30 08:44:44 +0000844 } else if (data[0] == '<' && data[1] == '?') {
Richard Hughesae0efdc2015-06-24 16:18:29 +0100845 g_debug ("using no decompressor for data");
846 bytes = g_bytes_ref (bytes_raw);
847 } else {
848 g_set_error (error,
849 FWUPD_ERROR,
850 FWUPD_ERROR_INVALID_FILE,
851 "file type '0x%02x,0x%02x' not supported",
Richard Hughesf2fca012015-10-30 08:44:44 +0000852 data[0], data[1]);
Richard Hughesae0efdc2015-06-24 16:18:29 +0100853 return FALSE;
854 }
855
856 /* read signature */
857 stream_sig = g_unix_input_stream_new (fd_sig, TRUE);
858 bytes_sig = g_input_stream_read_bytes (stream_sig, 0x800, NULL, error);
859 if (bytes_sig == NULL)
860 return FALSE;
861
862 /* verify file */
863 kr = fu_keyring_new ();
864 if (!fu_keyring_add_public_keys (kr, "/etc/pki/fwupd-metadata", error))
865 return FALSE;
866 if (!fu_keyring_verify_data (kr, bytes_raw, bytes_sig, error))
867 return FALSE;
868
Richard Hughes727664f2015-10-27 09:56:04 +0000869 /* load the store locally until we know it is valid */
870 store = as_store_new ();
Richard Hughesbb840ce2015-10-30 08:47:24 +0000871 data = g_bytes_get_data (bytes, &size);
872 xml = g_strndup ((const gchar *) data, size);
873 if (!as_store_from_xml (store, xml, NULL, error))
Richard Hughesae0efdc2015-06-24 16:18:29 +0100874 return FALSE;
Richard Hughesae0efdc2015-06-24 16:18:29 +0100875
Richard Hughes727664f2015-10-27 09:56:04 +0000876 /* add the new application from the store */
877 as_store_remove_all (priv->store);
878 apps = as_store_get_apps (store);
879 for (i = 0; i < apps->len; i++) {
880 AsApp *app = g_ptr_array_index (apps, i);
881 as_store_add_app (priv->store, app);
882 }
883
Richard Hughesae0efdc2015-06-24 16:18:29 +0100884 /* save the new file */
Richard Hughes033ccba2015-09-10 14:51:28 +0100885 as_store_set_api_version (priv->store, 0.9);
886 file = g_file_new_for_path ("/var/cache/app-info/xmls/fwupd.xml");
887 if (!as_store_to_file (priv->store, file,
Richard Hughesae0efdc2015-06-24 16:18:29 +0100888 AS_NODE_TO_XML_FLAG_ADD_HEADER |
889 AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE |
890 AS_NODE_TO_XML_FLAG_FORMAT_INDENT,
891 NULL, error)) {
892 return FALSE;
893 }
894
895 return TRUE;
896}
897
898/**
Richard Hughes033ccba2015-09-10 14:51:28 +0100899 * fu_main_store_delay_cb:
900 **/
901static gboolean
902fu_main_store_delay_cb (gpointer user_data)
903{
904 AsApp *app;
905 GPtrArray *apps;
906 guint i;
907 FuMainPrivate *priv = (FuMainPrivate *) user_data;
908
Richard Hughes033ccba2015-09-10 14:51:28 +0100909 apps = as_store_get_apps (priv->store);
Richard Hughes0a36f442016-01-06 14:57:20 +0000910 if (apps->len == 0) {
911 g_debug ("no devices in store");
912 } else {
913 g_debug ("devices now in store:");
914 for (i = 0; i < apps->len; i++) {
915 app = g_ptr_array_index (apps, i);
916 g_debug ("%i\t%s\t%s", i + 1,
917 as_app_get_id (app),
918 as_app_get_name (app, NULL));
919 }
Richard Hughes033ccba2015-09-10 14:51:28 +0100920 }
921 priv->store_changed_id = 0;
922 return G_SOURCE_REMOVE;
923}
924
925/**
926 * fu_main_store_changed_cb:
927 **/
928static void
929fu_main_store_changed_cb (AsStore *store, FuMainPrivate *priv)
930{
931 if (priv->store_changed_id != 0)
932 return;
933 priv->store_changed_id = g_timeout_add (200, fu_main_store_delay_cb, priv);
934}
935
936/**
Richard Hughes7708a0f2015-07-21 08:41:22 +0100937 * fu_main_get_updates:
938 **/
939static GPtrArray *
940fu_main_get_updates (FuMainPrivate *priv, GError **error)
941{
942 AsApp *app;
943 AsRelease *rel;
944 FuDeviceItem *item;
945 GPtrArray *updates;
946 guint i;
947 const gchar *tmp;
948
949 /* find any updates using the AppStream metadata */
950 updates = g_ptr_array_new ();
951 for (i = 0; i < priv->devices->len; i++) {
952 const gchar *version;
Richard Hughes9985a242015-08-03 13:22:31 +0100953 AsChecksum *csum;
Richard Hughes7708a0f2015-07-21 08:41:22 +0100954
955 item = g_ptr_array_index (priv->devices, i);
956
957 /* get device version */
958 version = fu_device_get_metadata (item->device, FU_DEVICE_KEY_VERSION);
959 if (version == NULL)
960 continue;
961
962 /* match the GUID in the XML */
Richard Hughesba145822015-08-11 14:34:08 +0100963 app = as_store_get_app_by_provide (priv->store,
964 AS_PROVIDE_KIND_FIRMWARE_FLASHED,
965 fu_device_get_guid (item->device));
Richard Hughes7708a0f2015-07-21 08:41:22 +0100966 if (app == NULL)
967 continue;
968
Richard Hughesdf7950b2016-01-31 10:18:40 +0000969 /* possibly convert the version from 0x to dotted */
970 fu_main_vendor_quirk_release_version (app);
971
Richard Hughes7708a0f2015-07-21 08:41:22 +0100972 /* get latest release */
973 rel = as_app_get_release_default (app);
974 if (rel == NULL) {
975 g_debug ("%s has no firmware update metadata",
976 fu_device_get_id (item->device));
977 continue;
978 }
979
980 /* check if actually newer than what we have installed */
981 if (as_utils_vercmp (as_release_get_version (rel), version) <= 0) {
982 g_debug ("%s has no firmware updates",
983 fu_device_get_id (item->device));
984 continue;
985 }
986
Richard Hughes82856d92015-09-08 14:30:38 +0100987 /* add application metadata */
Richard Hughesa2b2b1c2015-11-25 15:00:51 +0000988 fu_device_set_metadata (item->device,
989 FU_DEVICE_KEY_APPSTREAM_ID,
990 as_app_get_id (app));
Richard Hughes82856d92015-09-08 14:30:38 +0100991 tmp = as_app_get_developer_name (app, NULL);
992 if (tmp != NULL) {
993 fu_device_set_metadata (item->device,
994 FU_DEVICE_KEY_VENDOR, tmp);
995 }
996 tmp = as_app_get_name (app, NULL);
997 if (tmp != NULL) {
998 fu_device_set_metadata (item->device,
999 FU_DEVICE_KEY_NAME, tmp);
1000 }
1001 tmp = as_app_get_comment (app, NULL);
1002 if (tmp != NULL) {
1003 fu_device_set_metadata (item->device,
1004 FU_DEVICE_KEY_SUMMARY, tmp);
1005 }
1006 tmp = as_app_get_description (app, NULL);
1007 if (tmp != NULL) {
1008 fu_device_set_metadata (item->device,
1009 FU_DEVICE_KEY_DESCRIPTION, tmp);
1010 }
1011 tmp = as_app_get_url_item (app, AS_URL_KIND_HOMEPAGE);
1012 if (tmp != NULL) {
1013 fu_device_set_metadata (item->device,
1014 FU_DEVICE_KEY_URL_HOMEPAGE, tmp);
1015 }
1016 tmp = as_app_get_project_license (app);
1017 if (tmp != NULL) {
1018 fu_device_set_metadata (item->device,
1019 FU_DEVICE_KEY_LICENSE, tmp);
1020 }
1021
1022 /* add release information */
Richard Hughes7708a0f2015-07-21 08:41:22 +01001023 tmp = as_release_get_version (rel);
1024 if (tmp != NULL) {
1025 fu_device_set_metadata (item->device,
1026 FU_DEVICE_KEY_UPDATE_VERSION, tmp);
1027 }
Richard Hughes9985a242015-08-03 13:22:31 +01001028 csum = as_release_get_checksum_by_target (rel, AS_CHECKSUM_TARGET_CONTAINER);
1029 if (csum != NULL) {
1030 fu_device_set_metadata (item->device,
1031 FU_DEVICE_KEY_UPDATE_HASH,
1032 as_checksum_get_value (csum));
1033 }
Richard Hughes7708a0f2015-07-21 08:41:22 +01001034 tmp = as_release_get_location_default (rel);
1035 if (tmp != NULL) {
1036 fu_device_set_metadata (item->device,
1037 FU_DEVICE_KEY_UPDATE_URI, tmp);
1038 }
1039 tmp = as_release_get_description (rel, NULL);
1040 if (tmp != NULL) {
Richard Hughesfe8b96e2015-07-28 12:18:16 +01001041 fu_device_set_metadata (item->device,
1042 FU_DEVICE_KEY_UPDATE_DESCRIPTION,
1043 tmp);
Richard Hughes7708a0f2015-07-21 08:41:22 +01001044 }
1045 g_ptr_array_add (updates, item);
1046 }
1047
1048 return updates;
1049}
1050
1051/**
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001052 * fu_main_daemon_method_call:
1053 **/
1054static void
1055fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender,
1056 const gchar *object_path, const gchar *interface_name,
1057 const gchar *method_name, GVariant *parameters,
1058 GDBusMethodInvocation *invocation, gpointer user_data)
1059{
1060 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1061 GVariant *val;
1062
1063 /* return 'as' */
1064 if (g_strcmp0 (method_name, "GetDevices") == 0) {
Richard Hughes46832432015-09-11 13:43:15 +01001065 g_autoptr(GError) error = NULL;
Richard Hughesf508e762015-02-27 12:49:36 +00001066 g_debug ("Called %s()", method_name);
Richard Hughes7708a0f2015-07-21 08:41:22 +01001067 val = fu_main_device_array_to_variant (priv->devices, &error);
1068 if (val == NULL) {
Richard Hughes9d76a872015-09-17 12:49:07 +01001069 if (g_error_matches (error,
1070 FWUPD_ERROR,
1071 FWUPD_ERROR_NOTHING_TO_DO)) {
1072 g_prefix_error (&error, "No detected devices: ");
1073 }
Richard Hughes7708a0f2015-07-21 08:41:22 +01001074 g_dbus_method_invocation_return_gerror (invocation, error);
1075 return;
1076 }
1077 g_dbus_method_invocation_return_value (invocation, val);
1078 fu_main_set_status (priv, FWUPD_STATUS_IDLE);
1079 return;
1080 }
1081
1082 /* return 'as' */
1083 if (g_strcmp0 (method_name, "GetUpdates") == 0) {
Richard Hughes46832432015-09-11 13:43:15 +01001084 g_autoptr(GError) error = NULL;
1085 g_autoptr(GPtrArray) updates = NULL;
Richard Hughes7708a0f2015-07-21 08:41:22 +01001086 g_debug ("Called %s()", method_name);
1087 updates = fu_main_get_updates (priv, &error);
1088 if (updates == NULL) {
1089 g_dbus_method_invocation_return_gerror (invocation, error);
1090 return;
1091 }
1092 val = fu_main_device_array_to_variant (updates, &error);
Richard Hughes9a38c032015-03-17 20:58:46 +00001093 if (val == NULL) {
Richard Hughes9d76a872015-09-17 12:49:07 +01001094 if (g_error_matches (error,
1095 FWUPD_ERROR,
1096 FWUPD_ERROR_NOTHING_TO_DO)) {
1097 g_prefix_error (&error, "No devices can be updated: ");
1098 }
Richard Hughes9a38c032015-03-17 20:58:46 +00001099 g_dbus_method_invocation_return_gerror (invocation, error);
1100 return;
1101 }
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001102 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughesf910ac92015-03-19 10:43:42 +00001103 fu_main_set_status (priv, FWUPD_STATUS_IDLE);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001104 return;
1105 }
1106
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001107 /* return '' */
Richard Hughes0e883ee2015-03-18 17:22:33 +00001108 if (g_strcmp0 (method_name, "ClearResults") == 0) {
1109 FuDeviceItem *item = NULL;
1110 const gchar *id = NULL;
Richard Hughes46832432015-09-11 13:43:15 +01001111 g_autoptr(GError) error = NULL;
Richard Hughes0e883ee2015-03-18 17:22:33 +00001112
1113 g_variant_get (parameters, "(&s)", &id);
1114 g_debug ("Called %s(%s)", method_name, id);
1115
1116 /* find device */
1117 item = fu_main_get_item_by_id_fallback_pending (priv, id, &error);
1118 if (item == NULL) {
1119 g_dbus_method_invocation_return_gerror (invocation, error);
1120 return;
1121 }
1122
1123 /* call into the provider */
1124 if (!fu_provider_clear_results (item->provider, item->device, &error)) {
1125 g_dbus_method_invocation_return_gerror (invocation, error);
1126 return;
1127 }
1128
1129 /* success */
1130 g_dbus_method_invocation_return_value (invocation, NULL);
1131 return;
1132 }
1133
1134 /* return 'a{sv}' */
1135 if (g_strcmp0 (method_name, "GetResults") == 0) {
1136 FuDeviceItem *item = NULL;
1137 const gchar *id = NULL;
Richard Hughes46832432015-09-11 13:43:15 +01001138 g_autoptr(GError) error = NULL;
Richard Hughes0e883ee2015-03-18 17:22:33 +00001139
1140 g_variant_get (parameters, "(&s)", &id);
1141 g_debug ("Called %s(%s)", method_name, id);
1142
1143 /* find device */
1144 item = fu_main_get_item_by_id_fallback_pending (priv, id, &error);
1145 if (item == NULL) {
1146 g_dbus_method_invocation_return_gerror (invocation, error);
1147 return;
1148 }
1149
1150 /* call into the provider */
1151 if (!fu_provider_get_results (item->provider, item->device, &error)) {
1152 g_dbus_method_invocation_return_gerror (invocation, error);
1153 return;
1154 }
1155
1156 /* success */
1157 val = fu_device_get_metadata_as_variant (item->device);
1158 g_dbus_method_invocation_return_value (invocation, val);
1159 return;
1160 }
1161
1162 /* return '' */
Richard Hughesae0efdc2015-06-24 16:18:29 +01001163 if (g_strcmp0 (method_name, "UpdateMetadata") == 0) {
1164 GDBusMessage *message;
1165 GUnixFDList *fd_list;
1166 gint fd_data;
1167 gint fd_sig;
Richard Hughes46832432015-09-11 13:43:15 +01001168 g_autoptr(GError) error = NULL;
Richard Hughesae0efdc2015-06-24 16:18:29 +01001169
1170 message = g_dbus_method_invocation_get_message (invocation);
1171 fd_list = g_dbus_message_get_unix_fd_list (message);
1172 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 2) {
1173 g_dbus_method_invocation_return_error (invocation,
1174 FWUPD_ERROR,
1175 FWUPD_ERROR_INTERNAL,
1176 "invalid handle");
1177 return;
1178 }
1179 fd_data = g_unix_fd_list_get (fd_list, 0, &error);
1180 if (fd_data < 0) {
1181 g_dbus_method_invocation_return_gerror (invocation, error);
1182 return;
1183 }
1184 fd_sig = g_unix_fd_list_get (fd_list, 1, &error);
1185 if (fd_sig < 0) {
1186 g_dbus_method_invocation_return_gerror (invocation, error);
1187 return;
1188 }
Mario Limonciello3ed54472015-07-23 13:19:39 -05001189 if (!fu_main_daemon_update_metadata (priv, fd_data, fd_sig, &error)) {
Richard Hughesae0efdc2015-06-24 16:18:29 +01001190 g_prefix_error (&error, "failed to update metadata: ");
1191 g_dbus_method_invocation_return_gerror (invocation, error);
1192 return;
1193 }
1194 g_dbus_method_invocation_return_value (invocation, NULL);
1195 return;
1196 }
1197
Richard Hughesa043c2e2015-06-29 08:43:18 +01001198 /* return 's' */
1199 if (g_strcmp0 (method_name, "Verify") == 0) {
Richard Hughesc6ff8fa2015-08-03 18:00:51 +01001200 AsApp *app;
Richard Hughesc6ff8fa2015-08-03 18:00:51 +01001201 AsChecksum *csum;
Richard Hughesc6ff8fa2015-08-03 18:00:51 +01001202 AsRelease *release;
Richard Hughesa043c2e2015-06-29 08:43:18 +01001203 FuDeviceItem *item = NULL;
Richard Hughesa043c2e2015-06-29 08:43:18 +01001204 const gchar *hash = NULL;
Richard Hughesc6ff8fa2015-08-03 18:00:51 +01001205 const gchar *id = NULL;
1206 const gchar *version = NULL;
Richard Hughes46832432015-09-11 13:43:15 +01001207 g_autoptr(GError) error = NULL;
Richard Hughesa043c2e2015-06-29 08:43:18 +01001208
1209 /* check the id exists */
1210 g_variant_get (parameters, "(&s)", &id);
1211 g_debug ("Called %s(%s)", method_name, id);
1212 item = fu_main_get_item_by_id (priv, id);
1213 if (item == NULL) {
1214 g_dbus_method_invocation_return_error (invocation,
1215 FWUPD_ERROR,
1216 FWUPD_ERROR_NOT_FOUND,
Richard Hughesc6ff8fa2015-08-03 18:00:51 +01001217 "No such device %s",
Richard Hughesa043c2e2015-06-29 08:43:18 +01001218 id);
1219 return;
1220 }
Richard Hughesc6ff8fa2015-08-03 18:00:51 +01001221
1222 /* set the device firmware hash */
Richard Hughesa043c2e2015-06-29 08:43:18 +01001223 if (!fu_provider_verify (item->provider, item->device,
1224 FU_PROVIDER_VERIFY_FLAG_NONE, &error)) {
1225 g_dbus_method_invocation_return_gerror (invocation, error);
1226 return;
1227 }
Richard Hughesc6ff8fa2015-08-03 18:00:51 +01001228
1229 /* find component in metadata */
Richard Hughes709d0112015-10-09 12:17:08 +01001230 app = as_store_get_app_by_provide (priv->store,
1231 AS_PROVIDE_KIND_FIRMWARE_FLASHED,
1232 fu_device_get_guid (item->device));
Richard Hughesc6ff8fa2015-08-03 18:00:51 +01001233 if (app == NULL) {
1234 g_dbus_method_invocation_return_error (invocation,
1235 FWUPD_ERROR,
1236 FWUPD_ERROR_NOT_SUPPORTED,
1237 "No metadata");
1238 return;
1239 }
1240
1241 /* find version in metadata */
1242 version = fu_device_get_metadata (item->device, FU_DEVICE_KEY_VERSION);
1243 release = as_app_get_release (app, version);
1244 if (release == NULL) {
1245 g_dbus_method_invocation_return_error (invocation,
1246 FWUPD_ERROR,
1247 FWUPD_ERROR_NOT_SUPPORTED,
1248 "No version %s",
1249 version);
1250 return;
1251 }
1252
1253 /* find checksum */
Richard Hughesc6ff8fa2015-08-03 18:00:51 +01001254 csum = as_release_get_checksum_by_target (release, AS_CHECKSUM_TARGET_CONTENT);
1255 if (csum == NULL) {
1256 g_dbus_method_invocation_return_error (invocation,
1257 FWUPD_ERROR,
1258 FWUPD_ERROR_NOT_SUPPORTED,
1259 "No content checksum for %s",
1260 version);
1261 return;
1262 }
Richard Hughesa043c2e2015-06-29 08:43:18 +01001263 hash = fu_device_get_metadata (item->device, FU_DEVICE_KEY_FIRMWARE_HASH);
Richard Hughesc6ff8fa2015-08-03 18:00:51 +01001264 if (g_strcmp0 (as_checksum_get_value (csum), hash) != 0) {
1265 g_dbus_method_invocation_return_error (invocation,
1266 FWUPD_ERROR,
1267 FWUPD_ERROR_NOT_SUPPORTED,
1268 "For v%s expected %s, got %s",
1269 version,
1270 as_checksum_get_value (csum),
1271 hash);
1272 return;
1273 }
Richard Hughesc6ff8fa2015-08-03 18:00:51 +01001274 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughesa043c2e2015-06-29 08:43:18 +01001275 return;
1276 }
1277
Richard Hughesae0efdc2015-06-24 16:18:29 +01001278 /* return '' */
Richard Hughes63a407a2015-07-22 08:54:14 +01001279 if (g_strcmp0 (method_name, "Install") == 0) {
Richard Hughesd079b1a2015-03-06 10:09:55 +00001280 FuDeviceItem *item = NULL;
Richard Hughesf508e762015-02-27 12:49:36 +00001281 FuMainAuthHelper *helper;
Richard Hughes74cc2172015-02-27 13:19:46 +00001282 FuProviderFlags flags = FU_PROVIDER_UPDATE_FLAG_NONE;
1283 GDBusMessage *message;
1284 GUnixFDList *fd_list;
1285 GVariant *prop_value;
Richard Hughesa8e83942015-03-09 17:19:35 +00001286 const gchar *action_id;
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001287 const gchar *id = NULL;
Richard Hughes74cc2172015-02-27 13:19:46 +00001288 gchar *prop_key;
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001289 gint32 fd_handle = 0;
1290 gint fd;
Richard Hughes46832432015-09-11 13:43:15 +01001291 g_autoptr(GError) error = NULL;
Richard Hughes60f48c22015-10-08 20:25:51 +01001292 g_autoptr(PolkitSubject) subject = NULL;
Richard Hughes46832432015-09-11 13:43:15 +01001293 g_autoptr(GVariantIter) iter = NULL;
Richard Hughes5d14def2015-10-07 17:43:10 +01001294 g_autoptr(GBytes) blob_cab = NULL;
1295 g_autoptr(GInputStream) stream = NULL;
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001296
1297 /* check the id exists */
Richard Hughes74cc2172015-02-27 13:19:46 +00001298 g_variant_get (parameters, "(&sha{sv})", &id, &fd_handle, &iter);
Richard Hughesf508e762015-02-27 12:49:36 +00001299 g_debug ("Called %s(%s,%i)", method_name, id, fd_handle);
Richard Hughesd079b1a2015-03-06 10:09:55 +00001300 if (g_strcmp0 (id, FWUPD_DEVICE_ID_ANY) != 0) {
1301 item = fu_main_get_item_by_id (priv, id);
1302 if (item == NULL) {
1303 g_dbus_method_invocation_return_error (invocation,
Richard Hughes8645ec92015-03-19 10:14:32 +00001304 FWUPD_ERROR,
1305 FWUPD_ERROR_NOT_FOUND,
Richard Hughesd079b1a2015-03-06 10:09:55 +00001306 "no such device %s",
1307 id);
1308 return;
1309 }
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001310 }
1311
Richard Hughes74cc2172015-02-27 13:19:46 +00001312 /* get options */
1313 while (g_variant_iter_next (iter, "{&sv}",
1314 &prop_key, &prop_value)) {
1315 g_debug ("got option %s", prop_key);
1316 if (g_strcmp0 (prop_key, "offline") == 0 &&
1317 g_variant_get_boolean (prop_value) == TRUE)
1318 flags |= FU_PROVIDER_UPDATE_FLAG_OFFLINE;
Richard Hughese7c12642015-03-04 20:28:59 +00001319 if (g_strcmp0 (prop_key, "allow-older") == 0 &&
1320 g_variant_get_boolean (prop_value) == TRUE)
1321 flags |= FU_PROVIDER_UPDATE_FLAG_ALLOW_OLDER;
1322 if (g_strcmp0 (prop_key, "allow-reinstall") == 0 &&
1323 g_variant_get_boolean (prop_value) == TRUE)
1324 flags |= FU_PROVIDER_UPDATE_FLAG_ALLOW_REINSTALL;
Richard Hughes1ffde6c2015-03-02 22:44:48 +00001325 g_variant_unref (prop_value);
Richard Hughes74cc2172015-02-27 13:19:46 +00001326 }
1327
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001328 /* get the fd */
1329 message = g_dbus_method_invocation_get_message (invocation);
1330 fd_list = g_dbus_message_get_unix_fd_list (message);
1331 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 1) {
1332 g_dbus_method_invocation_return_error (invocation,
Richard Hughes8645ec92015-03-19 10:14:32 +00001333 FWUPD_ERROR,
1334 FWUPD_ERROR_INTERNAL,
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001335 "invalid handle");
1336 return;
1337 }
1338 fd = g_unix_fd_list_get (fd_list, fd_handle, &error);
1339 if (fd < 0) {
1340 g_dbus_method_invocation_return_gerror (invocation,
1341 error);
1342 return;
1343 }
1344
Richard Hughes5d14def2015-10-07 17:43:10 +01001345 /* read the entire fd to a data blob */
1346 stream = g_unix_input_stream_new (fd, TRUE);
1347 blob_cab = g_input_stream_read_bytes (stream,
1348 FU_MAIN_FIRMWARE_SIZE_MAX,
1349 NULL, &error);
1350 if (blob_cab == NULL){
1351 g_dbus_method_invocation_return_gerror (invocation,
1352 error);
1353 return;
1354 }
1355
Richard Hughes67ec8982015-03-03 11:39:27 +00001356 /* process the firmware */
Richard Hughesf508e762015-02-27 12:49:36 +00001357 helper = g_new0 (FuMainAuthHelper, 1);
1358 helper->invocation = g_object_ref (invocation);
Richard Hughes5d14def2015-10-07 17:43:10 +01001359 helper->trust_flags = FWUPD_TRUST_FLAG_NONE;
1360 helper->blob_cab = g_bytes_ref (blob_cab);
Richard Hughes74cc2172015-02-27 13:19:46 +00001361 helper->flags = flags;
Richard Hughesf508e762015-02-27 12:49:36 +00001362 helper->priv = priv;
Richard Hughes5d14def2015-10-07 17:43:10 +01001363 helper->store = as_store_new ();
Richard Hughesd079b1a2015-03-06 10:09:55 +00001364 if (item != NULL)
1365 helper->device = g_object_ref (item->device);
Richard Hughes67ec8982015-03-03 11:39:27 +00001366 if (!fu_main_update_helper (helper, &error)) {
1367 g_dbus_method_invocation_return_gerror (helper->invocation,
1368 error);
Richard Hughesf910ac92015-03-19 10:43:42 +00001369 fu_main_set_status (priv, FWUPD_STATUS_IDLE);
Richard Hughes67ec8982015-03-03 11:39:27 +00001370 fu_main_helper_free (helper);
1371 return;
1372 }
1373
Richard Hughes18423292015-03-09 17:10:50 +00001374 /* is root */
1375 if (fu_main_dbus_get_uid (priv, sender) == 0) {
1376 if (!fu_main_provider_update_authenticated (helper, &error)) {
1377 g_dbus_method_invocation_return_gerror (invocation, error);
1378 } else {
1379 g_dbus_method_invocation_return_value (invocation, NULL);
1380 }
Richard Hughesf910ac92015-03-19 10:43:42 +00001381 fu_main_set_status (priv, FWUPD_STATUS_IDLE);
Richard Hughes18423292015-03-09 17:10:50 +00001382 fu_main_helper_free (helper);
1383 return;
1384 }
1385
Richard Hughes67ec8982015-03-03 11:39:27 +00001386 /* authenticate */
Richard Hughes63bbbf52015-04-14 16:12:16 +01001387 action_id = fu_main_get_action_id_for_device (helper);
Richard Hughesf508e762015-02-27 12:49:36 +00001388 subject = polkit_system_bus_name_new (sender);
Richard Hughes67ec8982015-03-03 11:39:27 +00001389 polkit_authority_check_authorization (helper->priv->authority, subject,
Richard Hughesa8e83942015-03-09 17:19:35 +00001390 action_id,
Richard Hughesf508e762015-02-27 12:49:36 +00001391 NULL,
1392 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
1393 NULL,
1394 fu_main_check_authorization_cb,
1395 helper);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001396 return;
1397 }
1398
Richard Hughescccc7752015-03-06 11:13:19 +00001399 /* return 'a{sv}' */
1400 if (g_strcmp0 (method_name, "GetDetails") == 0) {
Richard Hughes5d14def2015-10-07 17:43:10 +01001401 AsApp *app = NULL;
1402 AsRelease *rel;
Richard Hughescccc7752015-03-06 11:13:19 +00001403 GDBusMessage *message;
Richard Hughes5d14def2015-10-07 17:43:10 +01001404 GPtrArray *apps;
1405 GPtrArray *provides;
Richard Hughescccc7752015-03-06 11:13:19 +00001406 GUnixFDList *fd_list;
1407 GVariantBuilder builder;
Richard Hughes5d14def2015-10-07 17:43:10 +01001408 FwupdTrustFlags trust_flags = FWUPD_TRUST_FLAG_NONE;
Richard Hughes3bf94802015-03-10 15:57:30 +00001409 const gchar *tmp;
Richard Hughes5d14def2015-10-07 17:43:10 +01001410 const gchar *guid = NULL;
Richard Hughescccc7752015-03-06 11:13:19 +00001411 gint32 fd_handle = 0;
Richard Hughes5d14def2015-10-07 17:43:10 +01001412 guint i;
Richard Hughescccc7752015-03-06 11:13:19 +00001413 gint fd;
Richard Hughes5d14def2015-10-07 17:43:10 +01001414 g_autoptr(AsStore) store = NULL;
1415 g_autoptr(GBytes) blob_cab = NULL;
Richard Hughes46832432015-09-11 13:43:15 +01001416 g_autoptr(GError) error = NULL;
Richard Hughes5d14def2015-10-07 17:43:10 +01001417 g_autoptr(GInputStream) stream = NULL;
Richard Hughescccc7752015-03-06 11:13:19 +00001418
1419 /* check the id exists */
1420 g_variant_get (parameters, "(h)", &fd_handle);
1421 g_debug ("Called %s(%i)", method_name, fd_handle);
1422
1423 /* get the fd */
1424 message = g_dbus_method_invocation_get_message (invocation);
1425 fd_list = g_dbus_message_get_unix_fd_list (message);
1426 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 1) {
1427 g_dbus_method_invocation_return_error (invocation,
Richard Hughes8645ec92015-03-19 10:14:32 +00001428 FWUPD_ERROR,
1429 FWUPD_ERROR_INTERNAL,
Richard Hughescccc7752015-03-06 11:13:19 +00001430 "invalid handle");
1431 return;
1432 }
1433 fd = g_unix_fd_list_get (fd_list, fd_handle, &error);
1434 if (fd < 0) {
1435 g_dbus_method_invocation_return_gerror (invocation,
1436 error);
1437 return;
1438 }
1439
Richard Hughes5d14def2015-10-07 17:43:10 +01001440 /* read the entire fd to a data blob */
1441 stream = g_unix_input_stream_new (fd, TRUE);
1442 blob_cab = g_input_stream_read_bytes (stream,
1443 FU_MAIN_FIRMWARE_SIZE_MAX,
1444 NULL, &error);
1445 if (blob_cab == NULL){
1446 g_dbus_method_invocation_return_gerror (invocation,
1447 error);
Richard Hughescccc7752015-03-06 11:13:19 +00001448 return;
1449 }
Richard Hughes5d14def2015-10-07 17:43:10 +01001450
1451 /* load file */
1452 store = as_store_new ();
1453 if (!as_store_from_bytes (store, blob_cab, NULL, &error)) {
Richard Hughescccc7752015-03-06 11:13:19 +00001454 g_dbus_method_invocation_return_gerror (invocation, error);
1455 return;
1456 }
1457
Richard Hughes5d14def2015-10-07 17:43:10 +01001458 /* get default app */
1459 apps = as_store_get_apps (store);
1460 if (apps->len == 0) {
1461 g_dbus_method_invocation_return_error (invocation,
1462 FWUPD_ERROR,
1463 FWUPD_ERROR_INVALID_FILE,
1464 "no components");
1465 return;
1466 }
1467 if (apps->len > 1) {
1468 /* we've got a .cab file with multiple components,
1469 * so try to find the first thing that's installed */
1470 for (i = 0; i < priv->devices->len; i++) {
1471 FuDeviceItem *item;
1472 item = g_ptr_array_index (priv->devices, i);
1473 app = as_store_get_app_by_provide (store,
1474 AS_PROVIDE_KIND_FIRMWARE_FLASHED,
1475 fu_device_get_guid (item->device));
1476 if (app != NULL)
1477 break;
1478 }
1479 }
1480
1481 /* well, we've tried our best, just show the first entry */
1482 if (app == NULL)
1483 app = AS_APP (g_ptr_array_index (apps, 0));
1484
1485 /* get guid */
1486 provides = as_app_get_provides (app);
1487 for (i = 0; i < provides->len; i++) {
1488 AsProvide *prov = AS_PROVIDE (g_ptr_array_index (provides, i));
1489 if (as_provide_get_kind (prov) == AS_PROVIDE_KIND_FIRMWARE_FLASHED) {
1490 guid = as_provide_get_value (prov);
1491 break;
1492 }
1493 }
1494 if (guid == NULL) {
1495 g_dbus_method_invocation_return_error (invocation,
1496 FWUPD_ERROR,
1497 FWUPD_ERROR_INTERNAL,
1498 "component has no GUID");
1499 return;
1500 }
1501
1502 /* verify trust */
1503 rel = as_app_get_release_default (app);
1504 if (!fu_main_get_release_trust_flags (rel, &trust_flags, &error)) {
Richard Hughesd8fa0492015-04-14 15:56:56 +01001505 g_dbus_method_invocation_return_gerror (invocation, error);
1506 return;
1507 }
1508
Richard Hughesdf7950b2016-01-31 10:18:40 +00001509 /* possibly convert the version from 0x to dotted */
1510 fu_main_vendor_quirk_release_version (app);
1511
Richard Hughescccc7752015-03-06 11:13:19 +00001512 /* create an array with all the metadata in */
1513 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
1514 g_variant_builder_add (&builder, "{sv}",
1515 FU_DEVICE_KEY_VERSION,
Richard Hughes5d14def2015-10-07 17:43:10 +01001516 g_variant_new_string (as_release_get_version (rel)));
Richard Hughescccc7752015-03-06 11:13:19 +00001517 g_variant_builder_add (&builder, "{sv}",
1518 FU_DEVICE_KEY_GUID,
Richard Hughes5d14def2015-10-07 17:43:10 +01001519 g_variant_new_string (guid));
Richard Hughesbbac6d72015-03-11 22:09:44 +00001520 g_variant_builder_add (&builder, "{sv}",
1521 FU_DEVICE_KEY_SIZE,
Richard Hughes5d14def2015-10-07 17:43:10 +01001522 g_variant_new_uint64 (as_release_get_size (rel, AS_SIZE_KIND_INSTALLED)));
Richard Hughes3bf94802015-03-10 15:57:30 +00001523
1524 /* optional properties */
Richard Hughes5d14def2015-10-07 17:43:10 +01001525 tmp = as_app_get_developer_name (app, NULL);
Richard Hughes3bf94802015-03-10 15:57:30 +00001526 if (tmp != NULL) {
1527 g_variant_builder_add (&builder, "{sv}",
1528 FU_DEVICE_KEY_VENDOR,
1529 g_variant_new_string (tmp));
1530 }
Richard Hughes5d14def2015-10-07 17:43:10 +01001531 tmp = as_app_get_name (app, NULL);
Richard Hughes3bf94802015-03-10 15:57:30 +00001532 if (tmp != NULL) {
1533 g_variant_builder_add (&builder, "{sv}",
1534 FU_DEVICE_KEY_NAME,
1535 g_variant_new_string (tmp));
1536 }
Richard Hughes5d14def2015-10-07 17:43:10 +01001537 tmp = as_app_get_comment (app, NULL);
Richard Hughes3bf94802015-03-10 15:57:30 +00001538 if (tmp != NULL) {
1539 g_variant_builder_add (&builder, "{sv}",
1540 FU_DEVICE_KEY_SUMMARY,
1541 g_variant_new_string (tmp));
1542 }
Richard Hughes5d14def2015-10-07 17:43:10 +01001543 tmp = as_app_get_description (app, NULL);
Richard Hughesbbac6d72015-03-11 22:09:44 +00001544 if (tmp != NULL) {
1545 g_variant_builder_add (&builder, "{sv}",
1546 FU_DEVICE_KEY_DESCRIPTION,
1547 g_variant_new_string (tmp));
1548 }
Richard Hughes5d14def2015-10-07 17:43:10 +01001549 tmp = as_app_get_url_item (app, AS_URL_KIND_HOMEPAGE);
Richard Hughesbbac6d72015-03-11 22:09:44 +00001550 if (tmp != NULL) {
1551 g_variant_builder_add (&builder, "{sv}",
1552 FU_DEVICE_KEY_URL_HOMEPAGE,
1553 g_variant_new_string (tmp));
1554 }
Richard Hughes5d14def2015-10-07 17:43:10 +01001555 tmp = as_app_get_project_license (app);
Richard Hughesbbac6d72015-03-11 22:09:44 +00001556 if (tmp != NULL) {
1557 g_variant_builder_add (&builder, "{sv}",
1558 FU_DEVICE_KEY_LICENSE,
1559 g_variant_new_string (tmp));
1560 }
Richard Hughesd4494472015-10-08 20:10:44 +01001561 tmp = as_release_get_description (rel, NULL);
1562 if (tmp != NULL) {
1563 g_variant_builder_add (&builder, "{sv}",
1564 FU_DEVICE_KEY_UPDATE_DESCRIPTION,
1565 g_variant_new_string (tmp));
1566 }
Richard Hughesd8fa0492015-04-14 15:56:56 +01001567 g_variant_builder_add (&builder, "{sv}",
1568 FU_DEVICE_KEY_TRUSTED,
1569 g_variant_new_uint64 (trust_flags));
Richard Hughescccc7752015-03-06 11:13:19 +00001570
1571 /* return whole array */
1572 val = g_variant_new ("(a{sv})", &builder);
1573 g_dbus_method_invocation_return_value (invocation, val);
1574 return;
1575 }
1576
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001577 /* we suck */
1578 g_dbus_method_invocation_return_error (invocation,
Richard Hughes8645ec92015-03-19 10:14:32 +00001579 G_DBUS_ERROR,
1580 G_DBUS_ERROR_UNKNOWN_METHOD,
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001581 "no such method %s",
1582 method_name);
1583}
1584
1585/**
1586 * fu_main_daemon_get_property:
1587 **/
1588static GVariant *
1589fu_main_daemon_get_property (GDBusConnection *connection_, const gchar *sender,
1590 const gchar *object_path, const gchar *interface_name,
1591 const gchar *property_name, GError **error,
1592 gpointer user_data)
1593{
Richard Hughes773ce982015-03-09 22:40:57 +00001594 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1595
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001596 if (g_strcmp0 (property_name, "DaemonVersion") == 0)
1597 return g_variant_new_string (VERSION);
1598
Richard Hughes773ce982015-03-09 22:40:57 +00001599 if (g_strcmp0 (property_name, "Status") == 0)
Richard Hughesf910ac92015-03-19 10:43:42 +00001600 return g_variant_new_string (fwupd_status_to_string (priv->status));
Richard Hughes773ce982015-03-09 22:40:57 +00001601
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001602 /* return an error */
1603 g_set_error (error,
Richard Hughes8645ec92015-03-19 10:14:32 +00001604 G_DBUS_ERROR,
1605 G_DBUS_ERROR_UNKNOWN_PROPERTY,
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001606 "failed to get daemon property %s",
1607 property_name);
1608 return NULL;
1609}
1610
1611/**
Richard Hughesfd468842015-04-22 16:44:08 +01001612 * fu_main_providers_coldplug:
1613 **/
1614static void
1615fu_main_providers_coldplug (FuMainPrivate *priv)
1616{
1617 FuProvider *provider;
1618 guint i;
Richard Hughes3f236502015-09-24 15:43:02 +01001619 g_autoptr(AsProfileTask) ptask = NULL;
Richard Hughesfd468842015-04-22 16:44:08 +01001620
Richard Hughes3f236502015-09-24 15:43:02 +01001621 ptask = as_profile_start_literal (priv->profile, "FuMain:coldplug");
Richard Hughesfd468842015-04-22 16:44:08 +01001622 for (i = 0; i < priv->providers->len; i++) {
Richard Hughes46832432015-09-11 13:43:15 +01001623 g_autoptr(GError) error = NULL;
Richard Hughes3f236502015-09-24 15:43:02 +01001624 g_autoptr(AsProfileTask) ptask2 = NULL;
Richard Hughesfd468842015-04-22 16:44:08 +01001625 provider = g_ptr_array_index (priv->providers, i);
Richard Hughes3f236502015-09-24 15:43:02 +01001626 ptask2 = as_profile_start (priv->profile,
1627 "FuMain:coldplug{%s}",
1628 fu_provider_get_name (provider));
Richard Hughesfd468842015-04-22 16:44:08 +01001629 if (!fu_provider_coldplug (FU_PROVIDER (provider), &error))
1630 g_warning ("Failed to coldplug: %s", error->message);
1631 }
1632}
1633
1634/**
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001635 * fu_main_on_bus_acquired_cb:
1636 **/
1637static void
1638fu_main_on_bus_acquired_cb (GDBusConnection *connection,
1639 const gchar *name,
1640 gpointer user_data)
1641{
1642 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1643 guint registration_id;
Richard Hughes46832432015-09-11 13:43:15 +01001644 g_autoptr(GError) error = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001645 static const GDBusInterfaceVTable interface_vtable = {
1646 fu_main_daemon_method_call,
1647 fu_main_daemon_get_property,
1648 NULL
1649 };
1650
1651 priv->connection = g_object_ref (connection);
1652 registration_id = g_dbus_connection_register_object (connection,
1653 FWUPD_DBUS_PATH,
1654 priv->introspection_daemon->interfaces[0],
1655 &interface_vtable,
1656 priv, /* user_data */
1657 NULL, /* user_data_free_func */
1658 NULL); /* GError** */
1659 g_assert (registration_id > 0);
Richard Hughes18423292015-03-09 17:10:50 +00001660
Richard Hughesfd468842015-04-22 16:44:08 +01001661 /* add devices */
1662 fu_main_providers_coldplug (priv);
1663
Richard Hughes18423292015-03-09 17:10:50 +00001664 /* connect to D-Bus directly */
1665 priv->proxy_uid =
1666 g_dbus_proxy_new_sync (priv->connection,
1667 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
1668 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
1669 NULL,
1670 "org.freedesktop.DBus",
1671 "/org/freedesktop/DBus",
1672 "org.freedesktop.DBus",
1673 NULL,
1674 &error);
1675 if (priv->proxy_uid == NULL) {
1676 g_warning ("cannot connect to DBus: %s", error->message);
1677 return;
1678 }
Richard Hughes3f236502015-09-24 15:43:02 +01001679
1680 /* dump startup profile data */
Richard Hughes2a1e75d2015-12-18 17:42:53 +00001681 if (fu_debug_is_verbose ())
1682 as_profile_dump (priv->profile);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001683}
1684
1685/**
1686 * fu_main_on_name_acquired_cb:
1687 **/
1688static void
1689fu_main_on_name_acquired_cb (GDBusConnection *connection,
1690 const gchar *name,
1691 gpointer user_data)
1692{
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001693 g_debug ("FuMain: acquired name: %s", name);
1694}
1695
1696/**
1697 * fu_main_on_name_lost_cb:
1698 **/
1699static void
1700fu_main_on_name_lost_cb (GDBusConnection *connection,
1701 const gchar *name,
1702 gpointer user_data)
1703{
1704 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1705 g_debug ("FuMain: lost name: %s", name);
1706 g_main_loop_quit (priv->loop);
1707}
1708
1709/**
1710 * fu_main_timed_exit_cb:
1711 **/
1712static gboolean
1713fu_main_timed_exit_cb (gpointer user_data)
1714{
1715 GMainLoop *loop = (GMainLoop *) user_data;
1716 g_main_loop_quit (loop);
1717 return G_SOURCE_REMOVE;
1718}
1719
1720/**
1721 * fu_main_load_introspection:
1722 **/
1723static GDBusNodeInfo *
1724fu_main_load_introspection (const gchar *filename, GError **error)
1725{
Richard Hughes46832432015-09-11 13:43:15 +01001726 g_autoptr(GBytes) data = NULL;
1727 g_autofree gchar *path = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001728
1729 /* lookup data */
1730 path = g_build_filename ("/org/freedesktop/fwupd", filename, NULL);
1731 data = g_resource_lookup_data (fu_get_resource (),
1732 path,
1733 G_RESOURCE_LOOKUP_FLAGS_NONE,
1734 error);
1735 if (data == NULL)
1736 return NULL;
1737
1738 /* build introspection from XML */
1739 return g_dbus_node_info_new_for_xml (g_bytes_get_data (data, NULL), error);
1740}
1741
1742/**
1743 * cd_main_provider_device_added_cb:
1744 **/
1745static void
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001746cd_main_provider_device_added_cb (FuProvider *provider,
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001747 FuDevice *device,
1748 gpointer user_data)
1749{
1750 FuMainPrivate *priv = (FuMainPrivate *) user_data;
Richard Hughesf508e762015-02-27 12:49:36 +00001751 FuDeviceItem *item;
1752
Richard Hughes0e883ee2015-03-18 17:22:33 +00001753 /* remove any fake device */
1754 item = fu_main_get_item_by_id (priv, fu_device_get_id (device));
Richard Hughes5d057a82015-11-24 18:09:57 +00001755 if (item != NULL) {
1756 g_debug ("already added %s by %s, ignoring same device from %s",
1757 fu_device_get_id (item->device),
1758 fu_device_get_metadata (item->device, FU_DEVICE_KEY_PROVIDER),
1759 fu_provider_get_name (provider));
1760 return;
1761 }
Richard Hughes0e883ee2015-03-18 17:22:33 +00001762
1763 /* create new device */
Richard Hughesf508e762015-02-27 12:49:36 +00001764 item = g_new0 (FuDeviceItem, 1);
1765 item->device = g_object_ref (device);
1766 item->provider = g_object_ref (provider);
1767 g_ptr_array_add (priv->devices, item);
Richard Hughesd7022b52015-03-11 19:47:06 +00001768 fu_main_emit_changed (priv);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001769}
1770
1771/**
1772 * cd_main_provider_device_removed_cb:
1773 **/
1774static void
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001775cd_main_provider_device_removed_cb (FuProvider *provider,
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001776 FuDevice *device,
1777 gpointer user_data)
1778{
1779 FuMainPrivate *priv = (FuMainPrivate *) user_data;
Richard Hughesf508e762015-02-27 12:49:36 +00001780 FuDeviceItem *item;
1781
1782 item = fu_main_get_item_by_id (priv, fu_device_get_id (device));
1783 if (item == NULL) {
Richard Hughes5d057a82015-11-24 18:09:57 +00001784 g_debug ("no device to remove %s", fu_device_get_id (device));
Richard Hughesf508e762015-02-27 12:49:36 +00001785 return;
1786 }
Richard Hughes5d057a82015-11-24 18:09:57 +00001787
1788 /* check this came from the same provider */
1789 if (g_strcmp0 (fu_provider_get_name (provider),
1790 fu_provider_get_name (item->provider)) != 0) {
1791 g_debug ("ignoring duplicate removal from %s",
1792 fu_provider_get_name (provider));
1793 return;
1794 }
1795
Richard Hughesf508e762015-02-27 12:49:36 +00001796 g_ptr_array_remove (priv->devices, item);
Richard Hughesd7022b52015-03-11 19:47:06 +00001797 fu_main_emit_changed (priv);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001798}
1799
1800/**
Richard Hughes773ce982015-03-09 22:40:57 +00001801 * cd_main_provider_status_changed_cb:
1802 **/
1803static void
1804cd_main_provider_status_changed_cb (FuProvider *provider,
Richard Hughesf910ac92015-03-19 10:43:42 +00001805 FwupdStatus status,
Richard Hughes773ce982015-03-09 22:40:57 +00001806 gpointer user_data)
1807{
1808 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1809 fu_main_set_status (priv, status);
1810}
1811
1812/**
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001813 * fu_main_add_provider:
1814 **/
1815static void
1816fu_main_add_provider (FuMainPrivate *priv, FuProvider *provider)
1817{
1818 g_signal_connect (provider, "device-added",
1819 G_CALLBACK (cd_main_provider_device_added_cb),
1820 priv);
1821 g_signal_connect (provider, "device-removed",
1822 G_CALLBACK (cd_main_provider_device_removed_cb),
1823 priv);
Richard Hughes773ce982015-03-09 22:40:57 +00001824 g_signal_connect (provider, "status-changed",
1825 G_CALLBACK (cd_main_provider_status_changed_cb),
1826 priv);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001827 g_ptr_array_add (priv->providers, provider);
1828}
1829
1830/**
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001831 * main:
1832 **/
1833int
1834main (int argc, char *argv[])
1835{
1836 FuMainPrivate *priv = NULL;
1837 gboolean immediate_exit = FALSE;
1838 gboolean ret;
1839 gboolean timed_exit = FALSE;
1840 GOptionContext *context;
1841 guint owner_id = 0;
1842 guint retval = 1;
1843 const GOptionEntry options[] = {
1844 { "timed-exit", '\0', 0, G_OPTION_ARG_NONE, &timed_exit,
1845 /* TRANSLATORS: exit after we've started up, used for user profiling */
1846 _("Exit after a small delay"), NULL },
1847 { "immediate-exit", '\0', 0, G_OPTION_ARG_NONE, &immediate_exit,
1848 /* TRANSLATORS: exit straight away, used for automatic profiling */
1849 _("Exit after the engine has loaded"), NULL },
1850 { NULL}
1851 };
Richard Hughes46832432015-09-11 13:43:15 +01001852 g_autoptr(GError) error = NULL;
1853 g_autofree gchar *config_file = NULL;
1854 g_autoptr(GKeyFile) config = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001855
1856 setlocale (LC_ALL, "");
1857
1858 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
1859 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1860 textdomain (GETTEXT_PACKAGE);
1861
1862 /* TRANSLATORS: program name */
Richard Hughes63a407a2015-07-22 08:54:14 +01001863 g_set_application_name (_("Firmware Update Daemon"));
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001864 context = g_option_context_new (NULL);
1865 g_option_context_add_main_entries (context, options, NULL);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001866 g_option_context_add_group (context, fu_debug_get_option_group ());
Richard Hughes8ded6ca2015-03-16 12:51:36 +00001867 /* TRANSLATORS: program summary */
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001868 g_option_context_set_summary (context, _("Firmware Update D-Bus Service"));
1869 ret = g_option_context_parse (context, &argc, &argv, &error);
1870 if (!ret) {
1871 g_warning ("FuMain: failed to parse command line arguments: %s",
1872 error->message);
1873 goto out;
1874 }
1875
1876 /* create new objects */
1877 priv = g_new0 (FuMainPrivate, 1);
Richard Hughesf910ac92015-03-19 10:43:42 +00001878 priv->status = FWUPD_STATUS_IDLE;
Richard Hughesf508e762015-02-27 12:49:36 +00001879 priv->devices = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_main_item_free);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001880 priv->loop = g_main_loop_new (NULL, FALSE);
Richard Hughes0e883ee2015-03-18 17:22:33 +00001881 priv->pending = fu_pending_new ();
Richard Hughes7708a0f2015-07-21 08:41:22 +01001882 priv->store = as_store_new ();
Richard Hughes3f236502015-09-24 15:43:02 +01001883 priv->profile = as_profile_new ();
Richard Hughes033ccba2015-09-10 14:51:28 +01001884 g_signal_connect (priv->store, "changed",
1885 G_CALLBACK (fu_main_store_changed_cb), priv);
1886 as_store_set_watch_flags (priv->store, AS_STORE_WATCH_FLAG_ADDED |
1887 AS_STORE_WATCH_FLAG_REMOVED);
Richard Hughes7708a0f2015-07-21 08:41:22 +01001888
1889 /* load AppStream */
1890 as_store_add_filter (priv->store, AS_ID_KIND_FIRMWARE);
1891 if (!as_store_load (priv->store,
1892 AS_STORE_LOAD_FLAG_APP_INFO_SYSTEM,
1893 NULL, &error)){
1894 g_warning ("FuMain: failed to load AppStream data: %s",
1895 error->message);
1896 return FALSE;
1897 }
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001898
Richard Hughes804c0752015-08-04 14:53:52 +01001899 /* read config file */
1900 config = g_key_file_new ();
1901 config_file = g_build_filename (SYSCONFDIR, "fwupd.conf", NULL);
1902 g_debug ("Loading fallback values from %s", config_file);
1903 if (!g_key_file_load_from_file (config, config_file,
1904 G_KEY_FILE_NONE, &error)) {
1905 g_print ("failed to load config file %s: %s\n",
1906 config_file, error->message);
1907 retval = EXIT_FAILURE;
1908 goto out;
1909 }
1910
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001911 /* add providers */
1912 priv->providers = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
Richard Hughes804c0752015-08-04 14:53:52 +01001913 if (g_key_file_get_boolean (config, "fwupd", "EnableOptionROM", NULL))
1914 fu_main_add_provider (priv, fu_provider_udev_new ());
Richard Hughes5d057a82015-11-24 18:09:57 +00001915 fu_main_add_provider (priv, fu_provider_dfu_new ());
Richard Hughes25cf6ab2015-08-04 21:34:12 +01001916 fu_main_add_provider (priv, fu_provider_rpi_new ());
Richard Hughes3c99ba42015-03-05 12:17:48 +00001917#ifdef HAVE_COLORHUG
Richard Hughes72dff812015-03-03 15:13:25 +00001918 fu_main_add_provider (priv, fu_provider_chug_new ());
Richard Hughes3c99ba42015-03-05 12:17:48 +00001919#endif
1920#ifdef HAVE_UEFI
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001921 fu_main_add_provider (priv, fu_provider_uefi_new ());
Richard Hughes3c99ba42015-03-05 12:17:48 +00001922#endif
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001923
Richard Hughes5d057a82015-11-24 18:09:57 +00001924 /* last as least priority */
1925 fu_main_add_provider (priv, fu_provider_usb_new ());
1926
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001927 /* load introspection from file */
1928 priv->introspection_daemon = fu_main_load_introspection (FWUPD_DBUS_INTERFACE ".xml",
1929 &error);
1930 if (priv->introspection_daemon == NULL) {
1931 g_warning ("FuMain: failed to load daemon introspection: %s",
1932 error->message);
1933 goto out;
1934 }
1935
Richard Hughesf508e762015-02-27 12:49:36 +00001936 /* get authority */
1937 priv->authority = polkit_authority_get_sync (NULL, &error);
1938 if (priv->authority == NULL) {
1939 g_warning ("FuMain: failed to load polkit authority: %s",
1940 error->message);
1941 goto out;
1942 }
1943
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001944 /* own the object */
1945 owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
1946 FWUPD_DBUS_SERVICE,
1947 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
1948 G_BUS_NAME_OWNER_FLAGS_REPLACE,
1949 fu_main_on_bus_acquired_cb,
1950 fu_main_on_name_acquired_cb,
1951 fu_main_on_name_lost_cb,
1952 priv, NULL);
1953
1954 /* Only timeout and close the mainloop if we have specified it
1955 * on the command line */
1956 if (immediate_exit)
1957 g_idle_add (fu_main_timed_exit_cb, priv->loop);
1958 else if (timed_exit)
1959 g_timeout_add_seconds (5, fu_main_timed_exit_cb, priv->loop);
1960
1961 /* wait */
1962 g_info ("Daemon ready for requests");
1963 g_main_loop_run (priv->loop);
1964
1965 /* success */
1966 retval = 0;
1967out:
1968 g_option_context_free (context);
1969 if (owner_id > 0)
1970 g_bus_unown_name (owner_id);
1971 if (priv != NULL) {
1972 if (priv->loop != NULL)
1973 g_main_loop_unref (priv->loop);
Richard Hughes18423292015-03-09 17:10:50 +00001974 if (priv->proxy_uid != NULL)
1975 g_object_unref (priv->proxy_uid);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001976 if (priv->connection != NULL)
1977 g_object_unref (priv->connection);
Richard Hughesf508e762015-02-27 12:49:36 +00001978 if (priv->authority != NULL)
1979 g_object_unref (priv->authority);
Richard Hughes3f236502015-09-24 15:43:02 +01001980 if (priv->profile != NULL)
1981 g_object_unref (priv->profile);
Richard Hughes7708a0f2015-07-21 08:41:22 +01001982 if (priv->store != NULL)
1983 g_object_unref (priv->store);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001984 if (priv->introspection_daemon != NULL)
1985 g_dbus_node_info_unref (priv->introspection_daemon);
Richard Hughes033ccba2015-09-10 14:51:28 +01001986 if (priv->store_changed_id != 0)
1987 g_source_remove (priv->store_changed_id);
Richard Hughes0e883ee2015-03-18 17:22:33 +00001988 g_object_unref (priv->pending);
Richard Hughes804c0752015-08-04 14:53:52 +01001989 if (priv->providers != NULL)
1990 g_ptr_array_unref (priv->providers);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001991 g_ptr_array_unref (priv->devices);
1992 g_free (priv);
1993 }
1994 return retval;
1995}
1996