blob: 5e896dfcea96497fabfc626ac8f7058e1c9a60dc [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 *
Richard Hughesf29a6ee2017-06-02 19:50:37 +01003 * Copyright (C) 2015-2017 Richard Hughes <richard@hughsie.com>
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00004 *
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 Hughes67ec8982015-03-03 11:39:27 +000024#include <appstream-glib.h>
Richard Hughes9945edb2017-06-19 10:03:55 +010025#include <fwupd.h>
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000026#include <gio/gunixfdlist.h>
27#include <glib/gi18n.h>
28#include <locale.h>
Richard Hughesf508e762015-02-27 12:49:36 +000029#include <polkit/polkit.h>
Richard Hughes67ec8982015-03-03 11:39:27 +000030#include <stdlib.h>
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000031
Richard Hughes68982c62017-09-13 15:40:14 +010032#include "fwupd-device-private.h"
Richard Hughes1642b3b2017-06-05 17:40:08 +010033#include "fwupd-release-private.h"
Richard Hughes4c369702017-06-16 15:31:38 +010034#include "fwupd-remote-private.h"
Richard Hughesd6db6b42017-04-12 15:03:10 +010035#include "fwupd-resources.h"
Richard Hughes8e9762d2016-03-17 10:14:15 +000036
Richard Hughes943d2c92017-06-21 09:04:39 +010037#include "fu-common.h"
Richard Hughes8bbfdf42015-02-26 22:28:09 +000038#include "fu-debug.h"
Richard Hughes68982c62017-09-13 15:40:14 +010039#include "fu-device-private.h"
Richard Hughes9945edb2017-06-19 10:03:55 +010040#include "fu-engine.h"
Richard Hughes4ad41f02018-05-08 14:35:36 +010041#include "fu-install-task.h"
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000042
Philip Withnallbc339aa2016-11-22 16:13:22 +000043#ifndef HAVE_POLKIT_0_114
Mario Limoncielloa98df552018-04-16 12:15:51 -050044#pragma clang diagnostic push
45#pragma clang diagnostic ignored "-Wunused-function"
Richard Hughes60f48c22015-10-08 20:25:51 +010046G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitAuthorizationResult, g_object_unref)
47G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitSubject, g_object_unref)
Mario Limoncielloa98df552018-04-16 12:15:51 -050048#pragma clang diagnostic pop
Richard Hughes60f48c22015-10-08 20:25:51 +010049#endif
50
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000051typedef struct {
52 GDBusConnection *connection;
53 GDBusNodeInfo *introspection_daemon;
Richard Hughes18423292015-03-09 17:10:50 +000054 GDBusProxy *proxy_uid;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000055 GMainLoop *loop;
Richard Hughesf508e762015-02-27 12:49:36 +000056 PolkitAuthority *authority;
Richard Hughesf0a799e2017-01-17 20:13:30 +000057 guint owner_id;
Richard Hughes9945edb2017-06-19 10:03:55 +010058 FuEngine *engine;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000059} FuMainPrivate;
60
Richard Hughesd7022b52015-03-11 19:47:06 +000061static void
Richard Hughes9945edb2017-06-19 10:03:55 +010062fu_main_engine_changed_cb (FuEngine *engine, FuMainPrivate *priv)
Richard Hughesd7022b52015-03-11 19:47:06 +000063{
64 /* not yet connected */
65 if (priv->connection == NULL)
66 return;
67 g_dbus_connection_emit_signal (priv->connection,
68 NULL,
69 FWUPD_DBUS_PATH,
70 FWUPD_DBUS_INTERFACE,
71 "Changed",
72 NULL, NULL);
73}
74
Richard Hughes8ca33782016-04-28 15:04:31 +010075static void
Richard Hughes9945edb2017-06-19 10:03:55 +010076fu_main_engine_device_added_cb (FuEngine *engine,
77 FuDevice *device,
78 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +010079{
80 GVariant *val;
81
82 /* not yet connected */
83 if (priv->connection == NULL)
84 return;
Richard Hughese0bd53e2017-09-17 08:29:02 +010085 val = fwupd_device_to_variant (FWUPD_DEVICE (device));
Richard Hughes8ca33782016-04-28 15:04:31 +010086 g_dbus_connection_emit_signal (priv->connection,
87 NULL,
88 FWUPD_DBUS_PATH,
89 FWUPD_DBUS_INTERFACE,
90 "DeviceAdded",
Richard Hughese0bd53e2017-09-17 08:29:02 +010091 g_variant_new_tuple (&val, 1), NULL);
Richard Hughes8ca33782016-04-28 15:04:31 +010092}
93
Richard Hughes8ca33782016-04-28 15:04:31 +010094static void
Richard Hughes9945edb2017-06-19 10:03:55 +010095fu_main_engine_device_removed_cb (FuEngine *engine,
96 FuDevice *device,
97 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +010098{
99 GVariant *val;
100
101 /* not yet connected */
102 if (priv->connection == NULL)
103 return;
Richard Hughese0bd53e2017-09-17 08:29:02 +0100104 val = fwupd_device_to_variant (FWUPD_DEVICE (device));
Richard Hughes8ca33782016-04-28 15:04:31 +0100105 g_dbus_connection_emit_signal (priv->connection,
106 NULL,
107 FWUPD_DBUS_PATH,
108 FWUPD_DBUS_INTERFACE,
109 "DeviceRemoved",
Richard Hughese0bd53e2017-09-17 08:29:02 +0100110 g_variant_new_tuple (&val, 1), NULL);
Richard Hughes8ca33782016-04-28 15:04:31 +0100111}
112
Richard Hughes8ca33782016-04-28 15:04:31 +0100113static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100114fu_main_engine_device_changed_cb (FuEngine *engine,
115 FuDevice *device,
116 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +0100117{
118 GVariant *val;
119
120 /* not yet connected */
121 if (priv->connection == NULL)
122 return;
Richard Hughese0bd53e2017-09-17 08:29:02 +0100123 val = fwupd_device_to_variant (FWUPD_DEVICE (device));
Richard Hughes8ca33782016-04-28 15:04:31 +0100124 g_dbus_connection_emit_signal (priv->connection,
125 NULL,
126 FWUPD_DBUS_PATH,
127 FWUPD_DBUS_INTERFACE,
128 "DeviceChanged",
Richard Hughese0bd53e2017-09-17 08:29:02 +0100129 g_variant_new_tuple (&val, 1), NULL);
Richard Hughes8ca33782016-04-28 15:04:31 +0100130}
131
Richard Hughes773ce982015-03-09 22:40:57 +0000132static void
133fu_main_emit_property_changed (FuMainPrivate *priv,
134 const gchar *property_name,
135 GVariant *property_value)
136{
137 GVariantBuilder builder;
138 GVariantBuilder invalidated_builder;
139
140 /* not yet connected */
141 if (priv->connection == NULL)
142 return;
143
144 /* build the dict */
145 g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as"));
146 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
147 g_variant_builder_add (&builder,
148 "{sv}",
149 property_name,
150 property_value);
151 g_dbus_connection_emit_signal (priv->connection,
152 NULL,
153 FWUPD_DBUS_PATH,
154 "org.freedesktop.DBus.Properties",
155 "PropertiesChanged",
156 g_variant_new ("(sa{sv}as)",
157 FWUPD_DBUS_INTERFACE,
158 &builder,
159 &invalidated_builder),
160 NULL);
161 g_variant_builder_clear (&builder);
162 g_variant_builder_clear (&invalidated_builder);
163}
164
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100165static void
166fu_main_set_status (FuMainPrivate *priv, FwupdStatus status)
167{
168 g_debug ("Emitting PropertyChanged('Status'='%s')",
169 fwupd_status_to_string (status));
170 fu_main_emit_property_changed (priv, "Status",
171 g_variant_new_uint32 (status));
172}
Richard Hughes773ce982015-03-09 22:40:57 +0000173
Richard Hughes9945edb2017-06-19 10:03:55 +0100174static void
175fu_main_engine_status_changed_cb (FuEngine *engine,
176 FwupdStatus status,
177 FuMainPrivate *priv)
178{
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100179 fu_main_set_status (priv, status);
Richard Hughes773ce982015-03-09 22:40:57 +0000180}
181
Richard Hughes876c0072016-08-17 14:51:03 +0100182static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100183fu_main_engine_percentage_changed_cb (FuEngine *engine,
184 guint percentage,
185 FuMainPrivate *priv)
Richard Hughes876c0072016-08-17 14:51:03 +0100186{
Richard Hughes876c0072016-08-17 14:51:03 +0100187 g_debug ("Emitting PropertyChanged('Percentage'='%u%%')", percentage);
188 fu_main_emit_property_changed (priv, "Percentage",
189 g_variant_new_uint32 (percentage));
190}
191
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000192static GVariant *
Richard Hughes9945edb2017-06-19 10:03:55 +0100193fu_main_device_array_to_variant (GPtrArray *devices)
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000194{
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000195 GVariantBuilder builder;
Richard Hughes9945edb2017-06-19 10:03:55 +0100196 g_return_val_if_fail (devices->len > 0, NULL);
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000197 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
Richard Hughesf192bf02016-07-22 08:26:43 +0100198 for (guint i = 0; i < devices->len; i++) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100199 FuDevice *device = g_ptr_array_index (devices, i);
Richard Hughese0bd53e2017-09-17 08:29:02 +0100200 GVariant *tmp = fwupd_device_to_variant (FWUPD_DEVICE (device));
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000201 g_variant_builder_add_value (&builder, tmp);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000202 }
Richard Hughes9e1b1402017-09-15 16:29:54 +0100203 return g_variant_new ("(aa{sv})", &builder);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000204}
205
Richard Hughes9945edb2017-06-19 10:03:55 +0100206static GVariant *
207fu_main_release_array_to_variant (GPtrArray *results)
Richard Hughes060af612016-08-17 17:32:34 +0100208{
Richard Hughes9945edb2017-06-19 10:03:55 +0100209 GVariantBuilder builder;
210 g_return_val_if_fail (results->len > 0, NULL);
211 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
212 for (guint i = 0; i < results->len; i++) {
213 FwupdRelease *rel = g_ptr_array_index (results, i);
Richard Hughese0bd53e2017-09-17 08:29:02 +0100214 GVariant *tmp = fwupd_release_to_variant (rel);
Richard Hughes9945edb2017-06-19 10:03:55 +0100215 g_variant_builder_add_value (&builder, tmp);
216 }
217 return g_variant_new ("(aa{sv})", &builder);
Richard Hughes060af612016-08-17 17:32:34 +0100218}
219
Richard Hughes9945edb2017-06-19 10:03:55 +0100220static GVariant *
221fu_main_remote_array_to_variant (GPtrArray *remotes)
Richard Hughes060af612016-08-17 17:32:34 +0100222{
Richard Hughes9945edb2017-06-19 10:03:55 +0100223 GVariantBuilder builder;
224 g_return_val_if_fail (remotes->len > 0, NULL);
225 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
226 for (guint i = 0; i < remotes->len; i++) {
227 FwupdRemote *remote = g_ptr_array_index (remotes, i);
Richard Hughese0bd53e2017-09-17 08:29:02 +0100228 GVariant *tmp = fwupd_remote_to_variant (remote);
Richard Hughes9945edb2017-06-19 10:03:55 +0100229 g_variant_builder_add_value (&builder, tmp);
230 }
231 return g_variant_new ("(aa{sv})", &builder);
Richard Hughes060af612016-08-17 17:32:34 +0100232}
233
Richard Hughes9945edb2017-06-19 10:03:55 +0100234static GVariant *
235fu_main_result_array_to_variant (GPtrArray *results)
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000236{
Richard Hughes9945edb2017-06-19 10:03:55 +0100237 GVariantBuilder builder;
238 g_return_val_if_fail (results->len > 0, NULL);
239 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
240 for (guint i = 0; i < results->len; i++) {
Richard Hughes93b15762017-09-15 11:05:23 +0100241 FwupdDevice *result = g_ptr_array_index (results, i);
Richard Hughese0bd53e2017-09-17 08:29:02 +0100242 GVariant *tmp = fwupd_device_to_variant (result);
Richard Hughes9945edb2017-06-19 10:03:55 +0100243 g_variant_builder_add_value (&builder, tmp);
244 }
Richard Hughes9e1b1402017-09-15 16:29:54 +0100245 return g_variant_new ("(aa{sv})", &builder);
Richard Hughesf508e762015-02-27 12:49:36 +0000246}
247
Richard Hughesf508e762015-02-27 12:49:36 +0000248typedef struct {
249 GDBusMethodInvocation *invocation;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100250 PolkitSubject *subject;
251 GPtrArray *install_tasks;
252 GPtrArray *action_ids;
Richard Hughes2d6e1862016-03-18 09:20:37 +0000253 FwupdInstallFlags flags;
Richard Hughes5d14def2015-10-07 17:43:10 +0100254 GBytes *blob_cab;
Richard Hughes67ec8982015-03-03 11:39:27 +0000255 FuMainPrivate *priv;
Richard Hughes9945edb2017-06-19 10:03:55 +0100256 gchar *device_id;
Richard Hughesa6bd5582017-09-07 14:32:22 +0100257 gchar *remote_id;
258 gchar *key;
259 gchar *value;
Richard Hughesf508e762015-02-27 12:49:36 +0000260} FuMainAuthHelper;
261
Richard Hughesf508e762015-02-27 12:49:36 +0000262static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100263fu_main_auth_helper_free (FuMainAuthHelper *helper)
Richard Hughesf508e762015-02-27 12:49:36 +0000264{
Richard Hughes4ced4662016-08-26 11:02:31 +0100265 if (helper->blob_cab != NULL)
Richard Hughes5d14def2015-10-07 17:43:10 +0100266 g_bytes_unref (helper->blob_cab);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100267 if (helper->subject != NULL)
268 g_object_unref (helper->subject);
269 if (helper->install_tasks != NULL)
270 g_ptr_array_unref (helper->install_tasks);
271 if (helper->action_ids != NULL)
272 g_ptr_array_unref (helper->action_ids);
Richard Hughes9945edb2017-06-19 10:03:55 +0100273 g_free (helper->device_id);
Richard Hughesa6bd5582017-09-07 14:32:22 +0100274 g_free (helper->remote_id);
275 g_free (helper->key);
276 g_free (helper->value);
Richard Hughes67ec8982015-03-03 11:39:27 +0000277 g_object_unref (helper->invocation);
Richard Hughesf508e762015-02-27 12:49:36 +0000278 g_free (helper);
279}
280
Mario Limoncielloa98df552018-04-16 12:15:51 -0500281#pragma clang diagnostic push
282#pragma clang diagnostic ignored "-Wunused-function"
Richard Hughes9945edb2017-06-19 10:03:55 +0100283G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuMainAuthHelper, fu_main_auth_helper_free)
Mario Limoncielloa98df552018-04-16 12:15:51 -0500284#pragma clang diagnostic pop
Richard Hughes9945edb2017-06-19 10:03:55 +0100285
286/* error may or may not already have been set */
Richard Hughesb75c92d2016-02-20 20:22:00 +0000287static gboolean
Richard Hughes9945edb2017-06-19 10:03:55 +0100288fu_main_authorization_is_valid (PolkitAuthorizationResult *auth, GError **error)
Richard Hughes9a410ce2016-02-28 15:58:54 +0000289{
Richard Hughes9945edb2017-06-19 10:03:55 +0100290 /* failed */
Richard Hughesf508e762015-02-27 12:49:36 +0000291 if (auth == NULL) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100292 g_autofree gchar *message = g_strdup ((*error)->message);
293 g_clear_error (error);
294 g_set_error (error,
Richard Hughes060af612016-08-17 17:32:34 +0100295 FWUPD_ERROR,
296 FWUPD_ERROR_AUTH_FAILED,
Richard Hughes9945edb2017-06-19 10:03:55 +0100297 "Could not check for auth: %s", message);
298 return FALSE;
Richard Hughesf508e762015-02-27 12:49:36 +0000299 }
300
301 /* did not auth */
302 if (!polkit_authorization_result_get_is_authorized (auth)) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100303 g_set_error_literal (error,
Richard Hughes060af612016-08-17 17:32:34 +0100304 FWUPD_ERROR,
305 FWUPD_ERROR_AUTH_FAILED,
Richard Hughes9945edb2017-06-19 10:03:55 +0100306 "Failed to obtain auth");
307 return FALSE;
Richard Hughesf508e762015-02-27 12:49:36 +0000308 }
309
310 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100311 return TRUE;
Richard Hughes5d14def2015-10-07 17:43:10 +0100312}
313
Richard Hughesdf7950b2016-01-31 10:18:40 +0000314static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100315fu_main_authorize_unlock_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100316{
Richard Hughes9945edb2017-06-19 10:03:55 +0100317 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
318 g_autoptr(GError) error = NULL;
319 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100320
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100321
Richard Hughes9945edb2017-06-19 10:03:55 +0100322 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100323 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughes9945edb2017-06-19 10:03:55 +0100324 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
325 res, &error);
326 if (!fu_main_authorization_is_valid (auth, &error)) {
327 g_dbus_method_invocation_return_gerror (helper->invocation, error);
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100328 return;
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100329 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100330
331 /* authenticated */
332 if (!fu_engine_unlock (helper->priv->engine, helper->device_id, &error)) {
333 g_dbus_method_invocation_return_gerror (helper->invocation, error);
334 return;
335 }
336
337 /* success */
338 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100339}
340
341static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100342fu_main_authorize_verify_update_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughesdf7950b2016-01-31 10:18:40 +0000343{
Richard Hughes9945edb2017-06-19 10:03:55 +0100344 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
345 g_autoptr(GError) error = NULL;
346 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughesdf7950b2016-01-31 10:18:40 +0000347
Richard Hughes9945edb2017-06-19 10:03:55 +0100348 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100349 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughes9945edb2017-06-19 10:03:55 +0100350 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
351 res, &error);
352 if (!fu_main_authorization_is_valid (auth, &error)) {
353 g_dbus_method_invocation_return_gerror (helper->invocation, error);
Richard Hughesdf7950b2016-01-31 10:18:40 +0000354 return;
Richard Hughesf192bf02016-07-22 08:26:43 +0100355 }
Richard Hughesdf7950b2016-01-31 10:18:40 +0000356
Richard Hughes9945edb2017-06-19 10:03:55 +0100357 /* authenticated */
358 if (!fu_engine_verify_update (helper->priv->engine, helper->device_id, &error)) {
359 g_dbus_method_invocation_return_gerror (helper->invocation, error);
360 return;
Richard Hughes404cc512016-12-21 16:09:48 +0000361 }
362
363 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100364 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes99147f12016-05-17 09:35:04 +0100365}
366
Richard Hughes9945edb2017-06-19 10:03:55 +0100367static void
Richard Hughesa6bd5582017-09-07 14:32:22 +0100368fu_main_authorize_modify_remote_cb (GObject *source, GAsyncResult *res, gpointer user_data)
369{
370 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
371 g_autoptr(GError) error = NULL;
372 g_autoptr(PolkitAuthorizationResult) auth = NULL;
373
374 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100375 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughesa6bd5582017-09-07 14:32:22 +0100376 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
377 res, &error);
378 if (!fu_main_authorization_is_valid (auth, &error)) {
379 g_dbus_method_invocation_return_gerror (helper->invocation, error);
380 return;
381 }
382
383 /* authenticated */
384 if (!fu_engine_modify_remote (helper->priv->engine,
385 helper->remote_id,
386 helper->key,
387 helper->value,
388 &error)) {
389 g_dbus_method_invocation_return_gerror (helper->invocation, error);
390 return;
391 }
392
393 /* success */
394 g_dbus_method_invocation_return_value (helper->invocation, NULL);
395}
396
Richard Hughes4ad41f02018-05-08 14:35:36 +0100397static void fu_main_authorize_install_queue (FuMainAuthHelper *helper);
398
Richard Hughesa6bd5582017-09-07 14:32:22 +0100399static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100400fu_main_authorize_install_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughes404cc512016-12-21 16:09:48 +0000401{
Richard Hughes9945edb2017-06-19 10:03:55 +0100402 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
Richard Hughes46832432015-09-11 13:43:15 +0100403 g_autoptr(GError) error = NULL;
Richard Hughes9945edb2017-06-19 10:03:55 +0100404 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughes18423292015-03-09 17:10:50 +0000405
Richard Hughes9945edb2017-06-19 10:03:55 +0100406 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100407 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughes9945edb2017-06-19 10:03:55 +0100408 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
409 res, &error);
410 if (!fu_main_authorization_is_valid (auth, &error)) {
411 g_dbus_method_invocation_return_gerror (helper->invocation, error);
412 return;
Richard Hughes0e883ee2015-03-18 17:22:33 +0000413 }
414
Richard Hughes4ad41f02018-05-08 14:35:36 +0100415 /* do the next authentication action ID */
416 fu_main_authorize_install_queue (g_steal_pointer (&helper));
417}
418
419static void
420fu_main_authorize_install_queue (FuMainAuthHelper *helper_ref)
421{
422 FuMainPrivate *priv = helper_ref->priv;
423 g_autoptr(FuMainAuthHelper) helper = helper_ref;
424 g_autoptr(GError) error = NULL;
425
426 /* still more things to to authenticate */
427 if (helper->action_ids->len > 0) {
428 g_autofree gchar *action_id = g_strdup (g_ptr_array_index (helper->action_ids, 0));
429 g_autoptr(PolkitSubject) subject = g_object_ref (helper->subject);
430 g_ptr_array_remove_index (helper->action_ids, 0);
431 polkit_authority_check_authorization (priv->authority, subject,
432 action_id, NULL,
433 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
434 NULL,
435 fu_main_authorize_install_cb,
436 g_steal_pointer (&helper));
Richard Hughes9945edb2017-06-19 10:03:55 +0100437 return;
Richard Hughes654f6b82016-04-25 12:29:48 +0100438 }
439
Richard Hughes4ad41f02018-05-08 14:35:36 +0100440 /* all authenticated, so install all the things */
441 for (guint i = 0; i < helper->install_tasks->len; i++) {
442 FuInstallTask *task = g_ptr_array_index (helper->install_tasks, i);
443 if (!fu_engine_install (helper->priv->engine,
444 fu_install_task_get_device (task),
445 fu_install_task_get_app (task),
446 helper->blob_cab,
447 helper->flags,
448 &error)) {
449 g_dbus_method_invocation_return_gerror (helper->invocation, error);
450 return;
451 }
452 }
453
Richard Hughes654f6b82016-04-25 12:29:48 +0100454 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100455 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes4c369702017-06-16 15:31:38 +0100456}
457
Richard Hughes4ad41f02018-05-08 14:35:36 +0100458static const GError *
459fu_main_error_array_find (GPtrArray *errors, FwupdError error_code)
460{
461 for (guint j = 0; j < errors->len; j++) {
462 const GError *error = g_ptr_array_index (errors, j);
463 if (g_error_matches (error, FWUPD_ERROR, error_code))
464 return error;
465 }
466 return NULL;
467}
468
469static guint
470fu_main_error_array_count (GPtrArray *errors, FwupdError error_code)
471{
472 guint cnt = 0;
473 for (guint j = 0; j < errors->len; j++) {
474 const GError *error = g_ptr_array_index (errors, j);
475 if (g_error_matches (error, FWUPD_ERROR, error_code))
476 cnt++;
477 }
478 return cnt;
479}
480
481static gboolean
482fu_main_error_array_matches_any (GPtrArray *errors, FwupdError *error_codes)
483{
484 for (guint j = 0; j < errors->len; j++) {
485 const GError *error = g_ptr_array_index (errors, j);
486 gboolean matches_any = FALSE;
487 for (guint i = 0; error_codes[i] != FWUPD_ERROR_LAST; i++) {
488 if (g_error_matches (error, FWUPD_ERROR, error_codes[i])) {
489 matches_any = TRUE;
490 break;
491 }
492 }
493 if (!matches_any)
494 return FALSE;
495 }
496 return TRUE;
497}
498
499static GError *
500fu_main_error_array_build_composite (GPtrArray *errors)
501{
502 FwupdError err_prio[] = { FWUPD_ERROR_INVALID_FILE,
503 FWUPD_ERROR_VERSION_SAME,
504 FWUPD_ERROR_VERSION_NEWER,
505 FWUPD_ERROR_NOT_SUPPORTED,
506 FWUPD_ERROR_INTERNAL,
507 FWUPD_ERROR_NOT_FOUND,
508 FWUPD_ERROR_LAST };
509 FwupdError err_all_uptodate[] = { FWUPD_ERROR_VERSION_SAME,
510 FWUPD_ERROR_NOT_FOUND,
511 FWUPD_ERROR_NOT_SUPPORTED,
512 FWUPD_ERROR_LAST };
513 FwupdError err_all_newer[] = { FWUPD_ERROR_VERSION_NEWER,
514 FWUPD_ERROR_VERSION_SAME,
515 FWUPD_ERROR_NOT_FOUND,
516 FWUPD_ERROR_NOT_SUPPORTED,
517 FWUPD_ERROR_LAST };
518
519 /* are all the errors either GUID-not-matched or version-same? */
520 if (fu_main_error_array_count (errors, FWUPD_ERROR_VERSION_SAME) > 1 &&
521 fu_main_error_array_matches_any (errors, err_all_uptodate)) {
522 return g_error_new (FWUPD_ERROR,
523 FWUPD_ERROR_NOTHING_TO_DO,
524 "All updatable firmware is already installed");
525 }
526
527 /* are all the errors either GUID-not-matched or version same or newer? */
528 if (fu_main_error_array_count (errors, FWUPD_ERROR_VERSION_NEWER) > 1 &&
529 fu_main_error_array_matches_any (errors, err_all_newer)) {
530 return g_error_new (FWUPD_ERROR,
531 FWUPD_ERROR_NOTHING_TO_DO,
532 "All updatable devices already have newer versions");
533 }
534
535 /* get the most important single error */
536 for (guint i = 0; err_prio[i] != FWUPD_ERROR_LAST; i++) {
537 const GError *error_tmp = fu_main_error_array_find (errors, err_prio[i]);
538 if (error_tmp != NULL)
539 return g_error_copy (error_tmp);
540 }
541
542 /* fall back to something */
543 return g_error_new (FWUPD_ERROR,
544 FWUPD_ERROR_NOT_FOUND,
545 "No supported devices found");
546}
547
548#if !GLIB_CHECK_VERSION(2,54,0)
549static gboolean
550g_ptr_array_find (GPtrArray *haystack, gconstpointer needle, guint *index_)
551{
552 for (guint i = 0; i < haystack->len; i++) {
553 gconstpointer *tmp = g_ptr_array_index (haystack, i);
554 if (tmp == needle) {
555 if (index_ != NULL) {
556 *index_ = i;
557 return TRUE;
558 }
559 }
560 }
561 return FALSE;
562}
563#endif
564
Richard Hughes9f86ade2018-05-10 21:11:22 +0100565static gint
566fu_main_install_task_sort_cb (gconstpointer a, gconstpointer b)
567{
568 FuInstallTask *task_a = *((FuInstallTask **) a);
569 FuInstallTask *task_b = *((FuInstallTask **) b);
570 FuDevice *device_a = fu_install_task_get_device (task_a);
571 FuDevice *device_b = fu_install_task_get_device (task_b);
572 if (fu_device_get_order (device_a) < fu_device_get_order (device_b))
573 return -1;
574 if (fu_device_get_order (device_a) > fu_device_get_order (device_b))
575 return 1;
576 return 0;
577}
578
Richard Hughes4ad41f02018-05-08 14:35:36 +0100579static gboolean
580fu_main_install_with_helper (FuMainAuthHelper *helper_ref, GError **error)
581{
582 FuMainPrivate *priv = helper_ref->priv;
583 GPtrArray *apps;
584 g_autoptr(AsStore) store = NULL;
585 g_autoptr(FuMainAuthHelper) helper = helper_ref;
586 g_autoptr(GPtrArray) devices_possible = NULL;
587 g_autoptr(GPtrArray) errors = NULL;
588
589 /* get a list of devices that match the device_id */
590 if (g_strcmp0 (helper->device_id, FWUPD_DEVICE_ID_ANY) == 0) {
591 devices_possible = fu_engine_get_devices (priv->engine, error);
592 if (devices_possible == NULL) {
593 g_prefix_error (error, "failed to get all devices: ");
594 return FALSE;
595 }
596 } else {
597 FuDevice *device = fu_engine_get_device (priv->engine,
598 helper->device_id,
599 error);
600 if (device == NULL)
601 return FALSE;
602 devices_possible = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
603 g_ptr_array_add (devices_possible, device);
604 }
605
606 /* parse store */
607 store = fu_engine_get_store_from_blob (priv->engine,
608 helper->blob_cab,
609 error);
610 if (store == NULL)
611 return FALSE;
612
613 /* for each component in the store */
614 apps = as_store_get_apps (store);
615 helper->action_ids = g_ptr_array_new_with_free_func (g_free);
616 helper->install_tasks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
617 errors = g_ptr_array_new_with_free_func ((GDestroyNotify) g_error_free);
618 for (guint i = 0; i < apps->len; i++) {
619 AsApp *app = g_ptr_array_index (apps, i);
620
621 /* do any devices pass the requirements */
622 for (guint j = 0; j < devices_possible->len; j++) {
623 FuDevice *device = g_ptr_array_index (devices_possible, j);
624 const gchar *action_id;
625 g_autoptr(FuInstallTask) task = NULL;
626 g_autoptr(GError) error_local = NULL;
627
628 /* is this component valid for the device */
629 task = fu_install_task_new (device, app);
630 if (!fu_install_task_check_requirements (task, helper->flags, &error_local)) {
631 g_debug ("requirement on %s:%s failed: %s",
632 fu_device_get_id (device),
633 as_app_get_id (app),
634 error_local->message);
635 g_ptr_array_add (errors, g_steal_pointer (&error_local));
636 continue;
637 }
638 if (!fu_engine_check_requirements (priv->engine,
639 app, device,
640 &error_local)) {
641 g_debug ("requirement on %s:%s failed: %s",
642 fu_device_get_id (device),
643 as_app_get_id (app),
644 error_local->message);
645 g_ptr_array_add (errors, g_steal_pointer (&error_local));
646 continue;
647 }
648
649 /* get the action IDs for the valid device */
650 action_id = fu_install_task_get_action_id (task);
651 if (!g_ptr_array_find (helper->action_ids, action_id, NULL))
652 g_ptr_array_add (helper->action_ids, g_strdup (action_id));
653 g_ptr_array_add (helper->install_tasks, g_steal_pointer (&task));
654 }
655 }
656
Richard Hughes9f86ade2018-05-10 21:11:22 +0100657 /* order the install tasks by the device priority */
658 g_ptr_array_sort (helper->install_tasks, fu_main_install_task_sort_cb);
659
Richard Hughes4ad41f02018-05-08 14:35:36 +0100660 /* nothing suitable */
661 if (helper->install_tasks->len == 0) {
662 GError *error_tmp = fu_main_error_array_build_composite (errors);
663 g_propagate_error (error, error_tmp);
664 return FALSE;
665 }
666
667 /* authenticate all things in the action_ids */
668 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
669 fu_main_authorize_install_queue (g_steal_pointer (&helper));
670 return TRUE;
671}
672
Richard Hughesb6f79552017-11-11 07:58:17 +0000673static gboolean
674fu_main_device_id_valid (const gchar *device_id, GError **error)
675{
676 if (g_strcmp0 (device_id, FWUPD_DEVICE_ID_ANY) == 0)
677 return TRUE;
678 if (device_id != NULL && strlen (device_id) >= 4)
679 return TRUE;
680 g_set_error (error,
681 FWUPD_ERROR,
682 FWUPD_ERROR_INTERNAL,
683 "invalid device ID: %s",
684 device_id);
685 return FALSE;
686}
687
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000688static void
689fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender,
690 const gchar *object_path, const gchar *interface_name,
691 const gchar *method_name, GVariant *parameters,
692 GDBusMethodInvocation *invocation, gpointer user_data)
693{
694 FuMainPrivate *priv = (FuMainPrivate *) user_data;
Richard Hughes9945edb2017-06-19 10:03:55 +0100695 GVariant *val = NULL;
Richard Hughes060af612016-08-17 17:32:34 +0100696 g_autoptr(GError) error = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000697
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000698 if (g_strcmp0 (method_name, "GetDevices") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100699 g_autoptr(GPtrArray) devices = NULL;
Richard Hughesf508e762015-02-27 12:49:36 +0000700 g_debug ("Called %s()", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +0100701 devices = fu_engine_get_devices (priv->engine, &error);
702 if (devices == NULL) {
703 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7708a0f2015-07-21 08:41:22 +0100704 return;
705 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100706 val = fu_main_device_array_to_variant (devices);
707 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes7708a0f2015-07-21 08:41:22 +0100708 return;
709 }
Richard Hughese4a100c2017-06-04 21:23:50 +0100710 if (g_strcmp0 (method_name, "GetReleases") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100711 const gchar *device_id;
Richard Hughese4a100c2017-06-04 21:23:50 +0100712 g_autoptr(GPtrArray) releases = NULL;
Richard Hughese4a100c2017-06-04 21:23:50 +0100713 g_variant_get (parameters, "(&s)", &device_id);
714 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000715 if (!fu_main_device_id_valid (device_id, &error)) {
716 g_dbus_method_invocation_return_gerror (invocation, error);
717 return;
718 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100719 releases = fu_engine_get_releases (priv->engine, device_id, &error);
720 if (releases == NULL) {
721 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughese4a100c2017-06-04 21:23:50 +0100722 return;
723 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100724 val = fu_main_release_array_to_variant (releases);
725 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughese4a100c2017-06-04 21:23:50 +0100726 return;
727 }
Richard Hughes97284b12017-09-13 17:07:58 +0100728 if (g_strcmp0 (method_name, "GetDowngrades") == 0) {
729 const gchar *device_id;
730 g_autoptr(GPtrArray) releases = NULL;
731 g_variant_get (parameters, "(&s)", &device_id);
732 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000733 if (!fu_main_device_id_valid (device_id, &error)) {
734 g_dbus_method_invocation_return_gerror (invocation, error);
735 return;
736 }
Richard Hughes97284b12017-09-13 17:07:58 +0100737 releases = fu_engine_get_downgrades (priv->engine, device_id, &error);
738 if (releases == NULL) {
739 g_dbus_method_invocation_return_gerror (invocation, error);
740 return;
741 }
742 val = fu_main_release_array_to_variant (releases);
743 g_dbus_method_invocation_return_value (invocation, val);
744 return;
745 }
Richard Hughesa96413a2017-09-13 17:19:59 +0100746 if (g_strcmp0 (method_name, "GetUpgrades") == 0) {
747 const gchar *device_id;
748 g_autoptr(GPtrArray) releases = NULL;
749 g_variant_get (parameters, "(&s)", &device_id);
750 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000751 if (!fu_main_device_id_valid (device_id, &error)) {
752 g_dbus_method_invocation_return_gerror (invocation, error);
753 return;
754 }
Richard Hughesa96413a2017-09-13 17:19:59 +0100755 releases = fu_engine_get_upgrades (priv->engine, device_id, &error);
756 if (releases == NULL) {
757 g_dbus_method_invocation_return_gerror (invocation, error);
758 return;
759 }
760 val = fu_main_release_array_to_variant (releases);
761 g_dbus_method_invocation_return_value (invocation, val);
762 return;
763 }
Richard Hughes4c369702017-06-16 15:31:38 +0100764 if (g_strcmp0 (method_name, "GetRemotes") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100765 g_autoptr(GPtrArray) remotes = NULL;
Richard Hughes4c369702017-06-16 15:31:38 +0100766 g_debug ("Called %s()", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +0100767 remotes = fu_engine_get_remotes (priv->engine, &error);
768 if (remotes == NULL) {
769 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes4c369702017-06-16 15:31:38 +0100770 return;
771 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100772 val = fu_main_remote_array_to_variant (remotes);
773 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes4c369702017-06-16 15:31:38 +0100774 return;
775 }
Richard Hughes476363a2018-01-11 10:08:58 +0000776 if (g_strcmp0 (method_name, "GetHistory") == 0) {
777 g_autoptr(GPtrArray) devices = NULL;
778 g_debug ("Called %s()", method_name);
779 devices = fu_engine_get_history (priv->engine, &error);
780 if (devices == NULL) {
781 g_dbus_method_invocation_return_gerror (invocation, error);
782 return;
783 }
784 val = fu_main_device_array_to_variant (devices);
785 g_dbus_method_invocation_return_value (invocation, val);
786 return;
787 }
Richard Hughes0e883ee2015-03-18 17:22:33 +0000788 if (g_strcmp0 (method_name, "ClearResults") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100789 const gchar *device_id;
790 g_variant_get (parameters, "(&s)", &device_id);
791 g_debug ("Called %s(%s)", method_name, device_id);
792 if (!fu_engine_clear_results (priv->engine, device_id, &error)) {
793 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes0e883ee2015-03-18 17:22:33 +0000794 return;
795 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100796 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughes0e883ee2015-03-18 17:22:33 +0000797 return;
798 }
Richard Hughes6b222952018-01-11 10:20:48 +0000799 if (g_strcmp0 (method_name, "ModifyDevice") == 0) {
800 const gchar *device_id;
801 const gchar *key = NULL;
802 const gchar *value = NULL;
803
804 /* check the id exists */
805 g_variant_get (parameters, "(&s&s&s)", &device_id, &key, &value);
806 g_debug ("Called %s(%s,%s=%s)", method_name, device_id, key, value);
807 if (!fu_engine_modify_device (priv->engine, device_id, key, value, &error)) {
808 g_dbus_method_invocation_return_gerror (invocation, error);
809 return;
810 }
811 g_dbus_method_invocation_return_value (invocation, NULL);
812 return;
813 }
Richard Hughes0e883ee2015-03-18 17:22:33 +0000814 if (g_strcmp0 (method_name, "GetResults") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100815 const gchar *device_id = NULL;
Richard Hughes93b15762017-09-15 11:05:23 +0100816 g_autoptr(FwupdDevice) result = NULL;
Richard Hughes9945edb2017-06-19 10:03:55 +0100817 g_variant_get (parameters, "(&s)", &device_id);
818 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000819 if (!fu_main_device_id_valid (device_id, &error)) {
820 g_dbus_method_invocation_return_gerror (invocation, error);
821 return;
822 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100823 result = fu_engine_get_results (priv->engine, device_id, &error);
824 if (result == NULL) {
825 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes0e883ee2015-03-18 17:22:33 +0000826 return;
827 }
Richard Hughese0bd53e2017-09-17 08:29:02 +0100828 val = fwupd_device_to_variant (result);
829 g_dbus_method_invocation_return_value (invocation,
830 g_variant_new_tuple (&val, 1));
Richard Hughes0e883ee2015-03-18 17:22:33 +0000831 return;
832 }
Richard Hughesba73c762017-09-15 14:31:17 +0100833 if (g_strcmp0 (method_name, "UpdateMetadata") == 0) {
Richard Hughes1b50d962017-06-02 12:23:00 +0100834 GDBusMessage *message;
835 GUnixFDList *fd_list;
Richard Hughes9945edb2017-06-19 10:03:55 +0100836 const gchar *remote_id = NULL;
Richard Hughes1b50d962017-06-02 12:23:00 +0100837 gint fd_data;
838 gint fd_sig;
839
Richard Hughes9945edb2017-06-19 10:03:55 +0100840 g_variant_get (parameters, "(&shh)", &remote_id, &fd_data, &fd_sig);
841 g_debug ("Called %s(%s,%i,%i)", method_name, remote_id, fd_data, fd_sig);
Richard Hughes1b50d962017-06-02 12:23:00 +0100842
Richard Hughes5935ebd2017-06-16 15:40:31 +0100843 /* update the metadata store */
Richard Hughes1b50d962017-06-02 12:23:00 +0100844 message = g_dbus_method_invocation_get_message (invocation);
845 fd_list = g_dbus_message_get_unix_fd_list (message);
846 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 2) {
847 g_set_error (&error,
848 FWUPD_ERROR,
849 FWUPD_ERROR_INTERNAL,
850 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +0100851 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +0100852 return;
853 }
854 fd_data = g_unix_fd_list_get (fd_list, 0, &error);
855 if (fd_data < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100856 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +0100857 return;
858 }
859 fd_sig = g_unix_fd_list_get (fd_list, 1, &error);
860 if (fd_sig < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100861 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +0100862 return;
863 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100864
865 /* store new metadata (will close the fds when done) */
866 if (!fu_engine_update_metadata (priv->engine, remote_id,
867 fd_data, fd_sig, &error)) {
Richard Hughesf3d46c62017-11-28 14:01:30 +0000868 g_prefix_error (&error, "Failed to update metadata for %s: ", remote_id);
Richard Hughes9945edb2017-06-19 10:03:55 +0100869 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughesae0efdc2015-06-24 16:18:29 +0100870 return;
871 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100872 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughesae0efdc2015-06-24 16:18:29 +0100873 return;
874 }
Richard Hughes9a410ce2016-02-28 15:58:54 +0000875 if (g_strcmp0 (method_name, "Unlock") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100876 const gchar *device_id = NULL;
Richard Hughes747b9ee2018-04-16 16:46:58 +0100877 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughes9a410ce2016-02-28 15:58:54 +0000878 g_autoptr(PolkitSubject) subject = NULL;
879
Richard Hughes9945edb2017-06-19 10:03:55 +0100880 g_variant_get (parameters, "(&s)", &device_id);
881 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000882 if (!fu_main_device_id_valid (device_id, &error)) {
883 g_dbus_method_invocation_return_gerror (invocation, error);
884 return;
885 }
Richard Hughesfe5cc902016-06-29 10:00:00 +0100886
Richard Hughes9a410ce2016-02-28 15:58:54 +0000887 /* authenticate */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100888 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
Richard Hughes9945edb2017-06-19 10:03:55 +0100889 helper = g_new0 (FuMainAuthHelper, 1);
890 helper->priv = priv;
891 helper->invocation = g_object_ref (invocation);
892 helper->device_id = g_strdup (device_id);
Richard Hughes9a410ce2016-02-28 15:58:54 +0000893 subject = polkit_system_bus_name_new (sender);
Richard Hughes9945edb2017-06-19 10:03:55 +0100894 polkit_authority_check_authorization (priv->authority, subject,
Richard Hughes9a410ce2016-02-28 15:58:54 +0000895 "org.freedesktop.fwupd.device-unlock",
896 NULL,
897 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
898 NULL,
Richard Hughes9945edb2017-06-19 10:03:55 +0100899 fu_main_authorize_unlock_cb,
Richard Hughes747b9ee2018-04-16 16:46:58 +0100900 g_steal_pointer (&helper));
Richard Hughes9a410ce2016-02-28 15:58:54 +0000901 return;
902 }
Richard Hughesa6bd5582017-09-07 14:32:22 +0100903 if (g_strcmp0 (method_name, "ModifyRemote") == 0) {
Richard Hughesa6bd5582017-09-07 14:32:22 +0100904 const gchar *remote_id = NULL;
905 const gchar *key = NULL;
906 const gchar *value = NULL;
Richard Hughes747b9ee2018-04-16 16:46:58 +0100907 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughesa6bd5582017-09-07 14:32:22 +0100908 g_autoptr(PolkitSubject) subject = NULL;
909
910 /* check the id exists */
911 g_variant_get (parameters, "(&s&s&s)", &remote_id, &key, &value);
912 g_debug ("Called %s(%s,%s=%s)", method_name, remote_id, key, value);
913
914 /* create helper object */
915 helper = g_new0 (FuMainAuthHelper, 1);
916 helper->invocation = g_object_ref (invocation);
917 helper->remote_id = g_strdup (remote_id);
918 helper->key = g_strdup (key);
919 helper->value = g_strdup (value);
920 helper->priv = priv;
921
922 /* authenticate */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100923 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
Richard Hughesa6bd5582017-09-07 14:32:22 +0100924 subject = polkit_system_bus_name_new (sender);
Mario Limonciello6b9f07c2018-04-16 13:52:09 -0500925 polkit_authority_check_authorization (priv->authority, subject,
Richard Hughesa6bd5582017-09-07 14:32:22 +0100926 "org.freedesktop.fwupd.modify-remote",
927 NULL,
928 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
929 NULL,
930 fu_main_authorize_modify_remote_cb,
Richard Hughes747b9ee2018-04-16 16:46:58 +0100931 g_steal_pointer (&helper));
Richard Hughesa6bd5582017-09-07 14:32:22 +0100932 return;
933 }
Richard Hughes29c220d2016-12-14 17:09:54 +0000934 if (g_strcmp0 (method_name, "VerifyUpdate") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100935 const gchar *device_id = NULL;
Richard Hughes747b9ee2018-04-16 16:46:58 +0100936 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughes29c220d2016-12-14 17:09:54 +0000937 g_autoptr(PolkitSubject) subject = NULL;
938
939 /* check the id exists */
Richard Hughes9945edb2017-06-19 10:03:55 +0100940 g_variant_get (parameters, "(&s)", &device_id);
941 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000942 if (!fu_main_device_id_valid (device_id, &error)) {
943 g_dbus_method_invocation_return_gerror (invocation, error);
944 return;
945 }
Richard Hughes29c220d2016-12-14 17:09:54 +0000946
Richard Hughes9945edb2017-06-19 10:03:55 +0100947 /* create helper object */
Richard Hughes29c220d2016-12-14 17:09:54 +0000948 helper = g_new0 (FuMainAuthHelper, 1);
Richard Hughes29c220d2016-12-14 17:09:54 +0000949 helper->invocation = g_object_ref (invocation);
Richard Hughes9945edb2017-06-19 10:03:55 +0100950 helper->device_id = g_strdup (device_id);
Richard Hughes29c220d2016-12-14 17:09:54 +0000951 helper->priv = priv;
Richard Hughes29c220d2016-12-14 17:09:54 +0000952
953 /* authenticate */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100954 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
Richard Hughes29c220d2016-12-14 17:09:54 +0000955 subject = polkit_system_bus_name_new (sender);
Mario Limonciello6b9f07c2018-04-16 13:52:09 -0500956 polkit_authority_check_authorization (priv->authority, subject,
Richard Hughes29c220d2016-12-14 17:09:54 +0000957 "org.freedesktop.fwupd.verify-update",
958 NULL,
959 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
960 NULL,
Richard Hughes9945edb2017-06-19 10:03:55 +0100961 fu_main_authorize_verify_update_cb,
Richard Hughes747b9ee2018-04-16 16:46:58 +0100962 g_steal_pointer (&helper));
Richard Hughes29c220d2016-12-14 17:09:54 +0000963 return;
964 }
Richard Hughesa043c2e2015-06-29 08:43:18 +0100965 if (g_strcmp0 (method_name, "Verify") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100966 const gchar *device_id = NULL;
967 g_variant_get (parameters, "(&s)", &device_id);
968 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000969 if (!fu_main_device_id_valid (device_id, &error)) {
970 g_dbus_method_invocation_return_gerror (invocation, error);
971 return;
972 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100973 if (!fu_engine_verify (priv->engine, device_id, &error)) {
974 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughesa043c2e2015-06-29 08:43:18 +0100975 return;
976 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100977 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughesa043c2e2015-06-29 08:43:18 +0100978 return;
979 }
Richard Hughes63a407a2015-07-22 08:54:14 +0100980 if (g_strcmp0 (method_name, "Install") == 0) {
Richard Hughes74cc2172015-02-27 13:19:46 +0000981 GVariant *prop_value;
Richard Hughes9945edb2017-06-19 10:03:55 +0100982 const gchar *device_id = NULL;
Richard Hughes74cc2172015-02-27 13:19:46 +0000983 gchar *prop_key;
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000984 gint32 fd_handle = 0;
985 gint fd;
Richard Hughesc7bbbc22018-01-02 22:22:25 +0000986 guint64 archive_size_max;
Richard Hughes9945edb2017-06-19 10:03:55 +0100987 GDBusMessage *message;
988 GUnixFDList *fd_list;
Richard Hughes747b9ee2018-04-16 16:46:58 +0100989 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughes46832432015-09-11 13:43:15 +0100990 g_autoptr(GVariantIter) iter = NULL;
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000991
992 /* check the id exists */
Richard Hughes9945edb2017-06-19 10:03:55 +0100993 g_variant_get (parameters, "(&sha{sv})", &device_id, &fd_handle, &iter);
994 g_debug ("Called %s(%s,%i)", method_name, device_id, fd_handle);
Richard Hughesb6f79552017-11-11 07:58:17 +0000995 if (!fu_main_device_id_valid (device_id, &error)) {
996 g_dbus_method_invocation_return_gerror (invocation, error);
997 return;
998 }
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000999
Richard Hughes9945edb2017-06-19 10:03:55 +01001000 /* create helper object */
1001 helper = g_new0 (FuMainAuthHelper, 1);
1002 helper->invocation = g_object_ref (invocation);
1003 helper->device_id = g_strdup (device_id);
1004 helper->priv = priv;
1005
1006 /* get flags */
1007 while (g_variant_iter_next (iter, "{&sv}", &prop_key, &prop_value)) {
Richard Hughes74cc2172015-02-27 13:19:46 +00001008 g_debug ("got option %s", prop_key);
1009 if (g_strcmp0 (prop_key, "offline") == 0 &&
1010 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +01001011 helper->flags |= FWUPD_INSTALL_FLAG_OFFLINE;
Richard Hughese7c12642015-03-04 20:28:59 +00001012 if (g_strcmp0 (prop_key, "allow-older") == 0 &&
1013 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +01001014 helper->flags |= FWUPD_INSTALL_FLAG_ALLOW_OLDER;
Richard Hughese7c12642015-03-04 20:28:59 +00001015 if (g_strcmp0 (prop_key, "allow-reinstall") == 0 &&
1016 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +01001017 helper->flags |= FWUPD_INSTALL_FLAG_ALLOW_REINSTALL;
Mario Limonciello71a5b982016-05-10 15:38:53 -05001018 if (g_strcmp0 (prop_key, "force") == 0 &&
1019 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +01001020 helper->flags |= FWUPD_INSTALL_FLAG_FORCE;
Richard Hughes76e0f942018-05-14 16:24:00 +01001021 if (g_strcmp0 (prop_key, "no-history") == 0 &&
1022 g_variant_get_boolean (prop_value) == TRUE)
1023 helper->flags |= FWUPD_INSTALL_FLAG_NO_HISTORY;
Richard Hughes1ffde6c2015-03-02 22:44:48 +00001024 g_variant_unref (prop_value);
Richard Hughes74cc2172015-02-27 13:19:46 +00001025 }
1026
Richard Hughes9945edb2017-06-19 10:03:55 +01001027
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001028 /* get the fd */
1029 message = g_dbus_method_invocation_get_message (invocation);
1030 fd_list = g_dbus_message_get_unix_fd_list (message);
1031 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 1) {
Richard Hughes060af612016-08-17 17:32:34 +01001032 g_set_error (&error,
1033 FWUPD_ERROR,
1034 FWUPD_ERROR_INTERNAL,
1035 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +01001036 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001037 return;
1038 }
Richard Hughes7419e962016-11-22 19:48:06 +00001039 fd = g_unix_fd_list_get (fd_list, 0, &error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001040 if (fd < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001041 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001042 return;
1043 }
1044
Richard Hughes9945edb2017-06-19 10:03:55 +01001045 /* parse the cab file before authenticating so we can work out
1046 * what action ID to use, for instance, if this is trusted --
1047 * this will also close the fd when done */
Richard Hughesc7bbbc22018-01-02 22:22:25 +00001048 archive_size_max = fu_engine_get_archive_size_max (priv->engine);
1049 helper->blob_cab = fu_common_get_contents_fd (fd, archive_size_max, &error);
Richard Hughes9945edb2017-06-19 10:03:55 +01001050 if (helper->blob_cab == NULL) {
1051 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes5d14def2015-10-07 17:43:10 +01001052 return;
1053 }
Richard Hughes4ad41f02018-05-08 14:35:36 +01001054
1055 /* install all the things in the store */
1056 helper->subject = polkit_system_bus_name_new (sender);
1057 if (!fu_main_install_with_helper (g_steal_pointer (&helper), &error)) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001058 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes18423292015-03-09 17:10:50 +00001059 return;
1060 }
1061
Richard Hughes4ad41f02018-05-08 14:35:36 +01001062 /* async return */
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001063 return;
1064 }
Richard Hughes07f963a2017-09-15 14:28:47 +01001065 if (g_strcmp0 (method_name, "GetDetails") == 0) {
Richard Hughes7289a6b2016-05-29 09:27:47 +01001066 GDBusMessage *message;
1067 GUnixFDList *fd_list;
1068 gint32 fd_handle = 0;
1069 gint fd;
Richard Hughes9945edb2017-06-19 10:03:55 +01001070 g_autoptr(GPtrArray) results = NULL;
Richard Hughes7289a6b2016-05-29 09:27:47 +01001071
1072 /* get parameters */
1073 g_variant_get (parameters, "(h)", &fd_handle);
1074 g_debug ("Called %s(%i)", method_name, fd_handle);
1075
1076 /* get the fd */
1077 message = g_dbus_method_invocation_get_message (invocation);
1078 fd_list = g_dbus_message_get_unix_fd_list (message);
1079 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 1) {
Richard Hughes060af612016-08-17 17:32:34 +01001080 g_set_error (&error,
1081 FWUPD_ERROR,
1082 FWUPD_ERROR_INTERNAL,
1083 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +01001084 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001085 return;
1086 }
Richard Hughes7419e962016-11-22 19:48:06 +00001087 fd = g_unix_fd_list_get (fd_list, 0, &error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001088 if (fd < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001089 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001090 return;
1091 }
1092
Richard Hughes9945edb2017-06-19 10:03:55 +01001093 /* get details about the file (will close the fd when done) */
Richard Hughes07f963a2017-09-15 14:28:47 +01001094 results = fu_engine_get_details (priv->engine, fd, &error);
Richard Hughes9945edb2017-06-19 10:03:55 +01001095 if (results == NULL) {
1096 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001097 return;
1098 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001099 val = fu_main_result_array_to_variant (results);
1100 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001101 return;
1102 }
Richard Hughes060af612016-08-17 17:32:34 +01001103 g_set_error (&error,
1104 G_DBUS_ERROR,
1105 G_DBUS_ERROR_UNKNOWN_METHOD,
1106 "no such method %s", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +01001107 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001108}
1109
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001110static GVariant *
1111fu_main_daemon_get_property (GDBusConnection *connection_, const gchar *sender,
1112 const gchar *object_path, const gchar *interface_name,
1113 const gchar *property_name, GError **error,
1114 gpointer user_data)
1115{
Richard Hughes773ce982015-03-09 22:40:57 +00001116 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1117
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001118 if (g_strcmp0 (property_name, "DaemonVersion") == 0)
1119 return g_variant_new_string (VERSION);
1120
Richard Hughes773ce982015-03-09 22:40:57 +00001121 if (g_strcmp0 (property_name, "Status") == 0)
Richard Hughes9945edb2017-06-19 10:03:55 +01001122 return g_variant_new_uint32 (fu_engine_get_status (priv->engine));
Richard Hughes773ce982015-03-09 22:40:57 +00001123
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001124 /* return an error */
1125 g_set_error (error,
Richard Hughes8645ec92015-03-19 10:14:32 +00001126 G_DBUS_ERROR,
1127 G_DBUS_ERROR_UNKNOWN_PROPERTY,
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001128 "failed to get daemon property %s",
1129 property_name);
1130 return NULL;
1131}
1132
Richard Hughesfd468842015-04-22 16:44:08 +01001133static void
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001134fu_main_on_bus_acquired_cb (GDBusConnection *connection,
1135 const gchar *name,
1136 gpointer user_data)
1137{
1138 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1139 guint registration_id;
Richard Hughes46832432015-09-11 13:43:15 +01001140 g_autoptr(GError) error = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001141 static const GDBusInterfaceVTable interface_vtable = {
1142 fu_main_daemon_method_call,
1143 fu_main_daemon_get_property,
1144 NULL
1145 };
1146
1147 priv->connection = g_object_ref (connection);
1148 registration_id = g_dbus_connection_register_object (connection,
1149 FWUPD_DBUS_PATH,
1150 priv->introspection_daemon->interfaces[0],
1151 &interface_vtable,
1152 priv, /* user_data */
1153 NULL, /* user_data_free_func */
1154 NULL); /* GError** */
1155 g_assert (registration_id > 0);
Richard Hughes18423292015-03-09 17:10:50 +00001156
1157 /* connect to D-Bus directly */
1158 priv->proxy_uid =
1159 g_dbus_proxy_new_sync (priv->connection,
1160 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
1161 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
1162 NULL,
1163 "org.freedesktop.DBus",
1164 "/org/freedesktop/DBus",
1165 "org.freedesktop.DBus",
1166 NULL,
1167 &error);
1168 if (priv->proxy_uid == NULL) {
1169 g_warning ("cannot connect to DBus: %s", error->message);
1170 return;
1171 }
Richard Hughes3f236502015-09-24 15:43:02 +01001172
1173 /* dump startup profile data */
Richard Hughes49fafec2017-11-09 14:30:27 +00001174 if (g_getenv ("FWUPD_VERBOSE") != NULL)
Richard Hughes9945edb2017-06-19 10:03:55 +01001175 fu_engine_profile_dump (priv->engine);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001176}
1177
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001178static void
1179fu_main_on_name_acquired_cb (GDBusConnection *connection,
1180 const gchar *name,
1181 gpointer user_data)
1182{
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001183 g_debug ("FuMain: acquired name: %s", name);
1184}
1185
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001186static void
1187fu_main_on_name_lost_cb (GDBusConnection *connection,
1188 const gchar *name,
1189 gpointer user_data)
1190{
1191 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1192 g_debug ("FuMain: lost name: %s", name);
1193 g_main_loop_quit (priv->loop);
1194}
1195
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001196static gboolean
1197fu_main_timed_exit_cb (gpointer user_data)
1198{
1199 GMainLoop *loop = (GMainLoop *) user_data;
1200 g_main_loop_quit (loop);
1201 return G_SOURCE_REMOVE;
1202}
1203
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001204static GDBusNodeInfo *
1205fu_main_load_introspection (const gchar *filename, GError **error)
1206{
Richard Hughes46832432015-09-11 13:43:15 +01001207 g_autoptr(GBytes) data = NULL;
1208 g_autofree gchar *path = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001209
1210 /* lookup data */
1211 path = g_build_filename ("/org/freedesktop/fwupd", filename, NULL);
1212 data = g_resource_lookup_data (fu_get_resource (),
1213 path,
1214 G_RESOURCE_LOOKUP_FLAGS_NONE,
1215 error);
1216 if (data == NULL)
1217 return NULL;
1218
1219 /* build introspection from XML */
1220 return g_dbus_node_info_new_for_xml (g_bytes_get_data (data, NULL), error);
1221}
1222
Richard Hughesf0a799e2017-01-17 20:13:30 +00001223static gboolean
1224fu_main_perhaps_own_name (gpointer user_data)
1225{
1226 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1227 g_autoptr(GError) error = NULL;
1228
1229 /* are any plugins pending */
Richard Hughes9945edb2017-06-19 10:03:55 +01001230 if (!fu_engine_check_plugins_pending (priv->engine, &error)) {
Richard Hughesf0a799e2017-01-17 20:13:30 +00001231 g_debug ("trying again: %s", error->message);
1232 return G_SOURCE_CONTINUE;
1233 }
1234
1235 /* own the object */
1236 g_debug ("registering D-Bus service");
1237 priv->owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
1238 FWUPD_DBUS_SERVICE,
1239 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
1240 G_BUS_NAME_OWNER_FLAGS_REPLACE,
1241 fu_main_on_bus_acquired_cb,
1242 fu_main_on_name_acquired_cb,
1243 fu_main_on_name_lost_cb,
1244 priv, NULL);
1245 return G_SOURCE_REMOVE;
1246}
1247
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001248static void
1249fu_main_private_free (FuMainPrivate *priv)
1250{
1251 if (priv->loop != NULL)
1252 g_main_loop_unref (priv->loop);
1253 if (priv->owner_id > 0)
1254 g_bus_unown_name (priv->owner_id);
1255 if (priv->proxy_uid != NULL)
1256 g_object_unref (priv->proxy_uid);
Richard Hughes9945edb2017-06-19 10:03:55 +01001257 if (priv->engine != NULL)
1258 g_object_unref (priv->engine);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001259 if (priv->connection != NULL)
1260 g_object_unref (priv->connection);
1261 if (priv->authority != NULL)
1262 g_object_unref (priv->authority);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001263 if (priv->introspection_daemon != NULL)
1264 g_dbus_node_info_unref (priv->introspection_daemon);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001265 g_free (priv);
1266}
1267
Mario Limoncielloa98df552018-04-16 12:15:51 -05001268#pragma clang diagnostic push
1269#pragma clang diagnostic ignored "-Wunused-function"
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001270G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuMainPrivate, fu_main_private_free)
Mario Limoncielloa98df552018-04-16 12:15:51 -05001271#pragma clang diagnostic pop
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001272
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001273int
1274main (int argc, char *argv[])
1275{
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001276 gboolean immediate_exit = FALSE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001277 gboolean timed_exit = FALSE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001278 const GOptionEntry options[] = {
1279 { "timed-exit", '\0', 0, G_OPTION_ARG_NONE, &timed_exit,
1280 /* TRANSLATORS: exit after we've started up, used for user profiling */
1281 _("Exit after a small delay"), NULL },
1282 { "immediate-exit", '\0', 0, G_OPTION_ARG_NONE, &immediate_exit,
1283 /* TRANSLATORS: exit straight away, used for automatic profiling */
1284 _("Exit after the engine has loaded"), NULL },
1285 { NULL}
1286 };
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001287 g_autoptr(FuMainPrivate) priv = NULL;
Richard Hughes46832432015-09-11 13:43:15 +01001288 g_autoptr(GError) error = NULL;
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001289 g_autoptr(GOptionContext) context = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001290
1291 setlocale (LC_ALL, "");
1292
1293 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
1294 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1295 textdomain (GETTEXT_PACKAGE);
1296
1297 /* TRANSLATORS: program name */
Richard Hughes63a407a2015-07-22 08:54:14 +01001298 g_set_application_name (_("Firmware Update Daemon"));
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001299 context = g_option_context_new (NULL);
1300 g_option_context_add_main_entries (context, options, NULL);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001301 g_option_context_add_group (context, fu_debug_get_option_group ());
Richard Hughes8ded6ca2015-03-16 12:51:36 +00001302 /* TRANSLATORS: program summary */
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001303 g_option_context_set_summary (context, _("Firmware Update D-Bus Service"));
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001304 if (!g_option_context_parse (context, &argc, &argv, &error)) {
1305 g_printerr ("Failed to parse command line: %s\n", error->message);
1306 return EXIT_FAILURE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001307 }
1308
1309 /* create new objects */
1310 priv = g_new0 (FuMainPrivate, 1);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001311 priv->loop = g_main_loop_new (NULL, FALSE);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001312
Richard Hughes9945edb2017-06-19 10:03:55 +01001313 /* load engine */
Richard Hughes5b5f6552018-05-18 10:22:39 +01001314 priv->engine = fu_engine_new (FU_APP_FLAGS_NONE);
Richard Hughes9945edb2017-06-19 10:03:55 +01001315 g_signal_connect (priv->engine, "changed",
1316 G_CALLBACK (fu_main_engine_changed_cb),
1317 priv);
1318 g_signal_connect (priv->engine, "device-added",
1319 G_CALLBACK (fu_main_engine_device_added_cb),
1320 priv);
1321 g_signal_connect (priv->engine, "device-removed",
1322 G_CALLBACK (fu_main_engine_device_removed_cb),
1323 priv);
1324 g_signal_connect (priv->engine, "device-changed",
1325 G_CALLBACK (fu_main_engine_device_changed_cb),
1326 priv);
1327 g_signal_connect (priv->engine, "status-changed",
1328 G_CALLBACK (fu_main_engine_status_changed_cb),
1329 priv);
1330 g_signal_connect (priv->engine, "percentage-changed",
1331 G_CALLBACK (fu_main_engine_percentage_changed_cb),
1332 priv);
1333 if (!fu_engine_load (priv->engine, &error)) {
1334 g_printerr ("Failed to load engine: %s\n", error->message);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001335 return EXIT_FAILURE;
Richard Hughes804c0752015-08-04 14:53:52 +01001336 }
1337
Richard Hughes9945edb2017-06-19 10:03:55 +01001338 /* keep polling until all the plugins are ready */
1339 g_timeout_add (200, fu_main_perhaps_own_name, priv);
Richard Hughesbc93e4a2016-12-08 17:29:51 +00001340
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001341 /* load introspection from file */
1342 priv->introspection_daemon = fu_main_load_introspection (FWUPD_DBUS_INTERFACE ".xml",
1343 &error);
1344 if (priv->introspection_daemon == NULL) {
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001345 g_printerr ("Failed to load introspection: %s\n", error->message);
1346 return EXIT_FAILURE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001347 }
1348
Richard Hughesf508e762015-02-27 12:49:36 +00001349 /* get authority */
1350 priv->authority = polkit_authority_get_sync (NULL, &error);
1351 if (priv->authority == NULL) {
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001352 g_printerr ("Failed to load authority: %s\n", error->message);
1353 return EXIT_FAILURE;
Richard Hughesf508e762015-02-27 12:49:36 +00001354 }
1355
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001356 /* Only timeout and close the mainloop if we have specified it
1357 * on the command line */
1358 if (immediate_exit)
1359 g_idle_add (fu_main_timed_exit_cb, priv->loop);
1360 else if (timed_exit)
1361 g_timeout_add_seconds (5, fu_main_timed_exit_cb, priv->loop);
1362
1363 /* wait */
Richard Hughes4619f9f2017-06-14 13:55:30 +01001364 g_message ("Daemon ready for requests");
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001365 g_main_loop_run (priv->loop);
1366
1367 /* success */
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001368 return EXIT_SUCCESS;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001369}