blob: 2c1eea01ad7352fdeb36bcf5c61b59c9cd99f23e [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 Hughes68982c62017-09-13 15:40:14 +010035#include "fwupd-result-private.h"
Richard Hughesd6db6b42017-04-12 15:03:10 +010036#include "fwupd-resources.h"
Richard Hughes8e9762d2016-03-17 10:14:15 +000037
Richard Hughes943d2c92017-06-21 09:04:39 +010038#include "fu-common.h"
Richard Hughes8bbfdf42015-02-26 22:28:09 +000039#include "fu-debug.h"
Richard Hughes68982c62017-09-13 15:40:14 +010040#include "fu-device-private.h"
Richard Hughes9945edb2017-06-19 10:03:55 +010041#include "fu-engine.h"
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000042
Philip Withnallbc339aa2016-11-22 16:13:22 +000043#ifndef HAVE_POLKIT_0_114
Richard Hughes60f48c22015-10-08 20:25:51 +010044G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitAuthorizationResult, g_object_unref)
45G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitSubject, g_object_unref)
46#endif
47
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000048typedef struct {
49 GDBusConnection *connection;
50 GDBusNodeInfo *introspection_daemon;
Richard Hughes18423292015-03-09 17:10:50 +000051 GDBusProxy *proxy_uid;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000052 GMainLoop *loop;
Richard Hughesf508e762015-02-27 12:49:36 +000053 PolkitAuthority *authority;
Richard Hughesf0a799e2017-01-17 20:13:30 +000054 guint owner_id;
Richard Hughes9945edb2017-06-19 10:03:55 +010055 FuEngine *engine;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000056} FuMainPrivate;
57
Richard Hughesd7022b52015-03-11 19:47:06 +000058static void
Richard Hughes9945edb2017-06-19 10:03:55 +010059fu_main_engine_changed_cb (FuEngine *engine, FuMainPrivate *priv)
Richard Hughesd7022b52015-03-11 19:47:06 +000060{
61 /* not yet connected */
62 if (priv->connection == NULL)
63 return;
64 g_dbus_connection_emit_signal (priv->connection,
65 NULL,
66 FWUPD_DBUS_PATH,
67 FWUPD_DBUS_INTERFACE,
68 "Changed",
69 NULL, NULL);
70}
71
Richard Hughes8ca33782016-04-28 15:04:31 +010072static void
Richard Hughes9945edb2017-06-19 10:03:55 +010073fu_main_engine_device_added_cb (FuEngine *engine,
74 FuDevice *device,
75 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +010076{
77 GVariant *val;
78
79 /* not yet connected */
80 if (priv->connection == NULL)
81 return;
Richard Hughes68982c62017-09-13 15:40:14 +010082 val = fwupd_device_to_data (FWUPD_DEVICE (device), "(a{sv})");
Richard Hughes8ca33782016-04-28 15:04:31 +010083 g_dbus_connection_emit_signal (priv->connection,
84 NULL,
85 FWUPD_DBUS_PATH,
86 FWUPD_DBUS_INTERFACE,
87 "DeviceAdded",
88 val, NULL);
89}
90
Richard Hughes8ca33782016-04-28 15:04:31 +010091static void
Richard Hughes9945edb2017-06-19 10:03:55 +010092fu_main_engine_device_removed_cb (FuEngine *engine,
93 FuDevice *device,
94 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +010095{
96 GVariant *val;
97
98 /* not yet connected */
99 if (priv->connection == NULL)
100 return;
Richard Hughes68982c62017-09-13 15:40:14 +0100101 val = fwupd_device_to_data (FWUPD_DEVICE (device), "(a{sv})");
Richard Hughes8ca33782016-04-28 15:04:31 +0100102 g_dbus_connection_emit_signal (priv->connection,
103 NULL,
104 FWUPD_DBUS_PATH,
105 FWUPD_DBUS_INTERFACE,
106 "DeviceRemoved",
107 val, NULL);
108}
109
Richard Hughes8ca33782016-04-28 15:04:31 +0100110static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100111fu_main_engine_device_changed_cb (FuEngine *engine,
112 FuDevice *device,
113 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +0100114{
115 GVariant *val;
116
117 /* not yet connected */
118 if (priv->connection == NULL)
119 return;
Richard Hughes68982c62017-09-13 15:40:14 +0100120 val = fwupd_device_to_data (FWUPD_DEVICE (device), "(a{sv})");
Richard Hughes8ca33782016-04-28 15:04:31 +0100121 g_dbus_connection_emit_signal (priv->connection,
122 NULL,
123 FWUPD_DBUS_PATH,
124 FWUPD_DBUS_INTERFACE,
125 "DeviceChanged",
126 val, NULL);
127}
128
Richard Hughes773ce982015-03-09 22:40:57 +0000129static void
130fu_main_emit_property_changed (FuMainPrivate *priv,
131 const gchar *property_name,
132 GVariant *property_value)
133{
134 GVariantBuilder builder;
135 GVariantBuilder invalidated_builder;
136
137 /* not yet connected */
138 if (priv->connection == NULL)
139 return;
140
141 /* build the dict */
142 g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as"));
143 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
144 g_variant_builder_add (&builder,
145 "{sv}",
146 property_name,
147 property_value);
148 g_dbus_connection_emit_signal (priv->connection,
149 NULL,
150 FWUPD_DBUS_PATH,
151 "org.freedesktop.DBus.Properties",
152 "PropertiesChanged",
153 g_variant_new ("(sa{sv}as)",
154 FWUPD_DBUS_INTERFACE,
155 &builder,
156 &invalidated_builder),
157 NULL);
158 g_variant_builder_clear (&builder);
159 g_variant_builder_clear (&invalidated_builder);
160}
161
Richard Hughes773ce982015-03-09 22:40:57 +0000162
Richard Hughes9945edb2017-06-19 10:03:55 +0100163static void
164fu_main_engine_status_changed_cb (FuEngine *engine,
165 FwupdStatus status,
166 FuMainPrivate *priv)
167{
Richard Hughes88181512015-03-19 10:57:44 +0000168 g_debug ("Emitting PropertyChanged('Status'='%s')",
169 fwupd_status_to_string (status));
Richard Hughes9945edb2017-06-19 10:03:55 +0100170 fu_main_emit_property_changed (priv, "Status",
171 g_variant_new_uint32 (status));
Richard Hughes773ce982015-03-09 22:40:57 +0000172}
173
Richard Hughes876c0072016-08-17 14:51:03 +0100174static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100175fu_main_engine_percentage_changed_cb (FuEngine *engine,
176 guint percentage,
177 FuMainPrivate *priv)
Richard Hughes876c0072016-08-17 14:51:03 +0100178{
Richard Hughes876c0072016-08-17 14:51:03 +0100179 g_debug ("Emitting PropertyChanged('Percentage'='%u%%')", percentage);
180 fu_main_emit_property_changed (priv, "Percentage",
181 g_variant_new_uint32 (percentage));
182}
183
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000184static GVariant *
Richard Hughes9945edb2017-06-19 10:03:55 +0100185fu_main_device_array_to_variant (GPtrArray *devices)
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000186{
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000187 GVariantBuilder builder;
Richard Hughes9945edb2017-06-19 10:03:55 +0100188 g_return_val_if_fail (devices->len > 0, NULL);
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000189 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
Richard Hughesf192bf02016-07-22 08:26:43 +0100190 for (guint i = 0; i < devices->len; i++) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100191 FuDevice *device = g_ptr_array_index (devices, i);
Richard Hughescc3de2e2017-09-13 19:28:17 +0100192 GVariant *tmp = fwupd_device_to_data (FWUPD_DEVICE (device), "{sa{sv}}");
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000193 g_variant_builder_add_value (&builder, tmp);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000194 }
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000195 return g_variant_new ("(a{sa{sv}})", &builder);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000196}
197
Richard Hughes9945edb2017-06-19 10:03:55 +0100198static GVariant *
199fu_main_release_array_to_variant (GPtrArray *results)
Richard Hughes060af612016-08-17 17:32:34 +0100200{
Richard Hughes9945edb2017-06-19 10:03:55 +0100201 GVariantBuilder builder;
202 g_return_val_if_fail (results->len > 0, NULL);
203 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
204 for (guint i = 0; i < results->len; i++) {
205 FwupdRelease *rel = g_ptr_array_index (results, i);
206 GVariant *tmp = fwupd_release_to_data (rel, "a{sv}");
207 g_variant_builder_add_value (&builder, tmp);
208 }
209 return g_variant_new ("(aa{sv})", &builder);
Richard Hughes060af612016-08-17 17:32:34 +0100210}
211
Richard Hughes9945edb2017-06-19 10:03:55 +0100212static GVariant *
213fu_main_remote_array_to_variant (GPtrArray *remotes)
Richard Hughes060af612016-08-17 17:32:34 +0100214{
Richard Hughes9945edb2017-06-19 10:03:55 +0100215 GVariantBuilder builder;
216 g_return_val_if_fail (remotes->len > 0, NULL);
217 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
218 for (guint i = 0; i < remotes->len; i++) {
219 FwupdRemote *remote = g_ptr_array_index (remotes, i);
220 GVariant *tmp = fwupd_remote_to_data (remote, "a{sv}");
221 g_variant_builder_add_value (&builder, tmp);
222 }
223 return g_variant_new ("(aa{sv})", &builder);
Richard Hughes060af612016-08-17 17:32:34 +0100224}
225
Richard Hughes9945edb2017-06-19 10:03:55 +0100226static GVariant *
227fu_main_result_array_to_variant (GPtrArray *results)
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000228{
Richard Hughes9945edb2017-06-19 10:03:55 +0100229 GVariantBuilder builder;
230 g_return_val_if_fail (results->len > 0, NULL);
231 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
232 for (guint i = 0; i < results->len; i++) {
Richard Hughes93b15762017-09-15 11:05:23 +0100233 FwupdDevice *result = g_ptr_array_index (results, i);
234 GVariant *tmp = fwupd_device_to_data (result, "{sa{sv}}");
Richard Hughes9945edb2017-06-19 10:03:55 +0100235 g_variant_builder_add_value (&builder, tmp);
236 }
237 return g_variant_new ("(a{sa{sv}})", &builder);
Richard Hughesf508e762015-02-27 12:49:36 +0000238}
239
Richard Hughesf508e762015-02-27 12:49:36 +0000240typedef struct {
241 GDBusMethodInvocation *invocation;
Richard Hughes5d14def2015-10-07 17:43:10 +0100242 AsStore *store;
Richard Hughes2d6e1862016-03-18 09:20:37 +0000243 FwupdInstallFlags flags;
Richard Hughes5d14def2015-10-07 17:43:10 +0100244 GBytes *blob_cab;
Richard Hughes67ec8982015-03-03 11:39:27 +0000245 FuMainPrivate *priv;
Richard Hughes9945edb2017-06-19 10:03:55 +0100246 gchar *device_id;
Richard Hughesa6bd5582017-09-07 14:32:22 +0100247 gchar *remote_id;
248 gchar *key;
249 gchar *value;
Richard Hughesf508e762015-02-27 12:49:36 +0000250} FuMainAuthHelper;
251
Richard Hughesf508e762015-02-27 12:49:36 +0000252static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100253fu_main_auth_helper_free (FuMainAuthHelper *helper)
Richard Hughesf508e762015-02-27 12:49:36 +0000254{
Richard Hughes4ced4662016-08-26 11:02:31 +0100255 if (helper->blob_cab != NULL)
Richard Hughes5d14def2015-10-07 17:43:10 +0100256 g_bytes_unref (helper->blob_cab);
Richard Hughes9a410ce2016-02-28 15:58:54 +0000257 if (helper->store != NULL)
258 g_object_unref (helper->store);
Richard Hughes9945edb2017-06-19 10:03:55 +0100259 g_free (helper->device_id);
Richard Hughesa6bd5582017-09-07 14:32:22 +0100260 g_free (helper->remote_id);
261 g_free (helper->key);
262 g_free (helper->value);
Richard Hughes67ec8982015-03-03 11:39:27 +0000263 g_object_unref (helper->invocation);
Richard Hughesf508e762015-02-27 12:49:36 +0000264 g_free (helper);
265}
266
Richard Hughes9945edb2017-06-19 10:03:55 +0100267G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuMainAuthHelper, fu_main_auth_helper_free)
268
269/* error may or may not already have been set */
Richard Hughesb75c92d2016-02-20 20:22:00 +0000270static gboolean
Richard Hughes9945edb2017-06-19 10:03:55 +0100271fu_main_authorization_is_valid (PolkitAuthorizationResult *auth, GError **error)
Richard Hughes9a410ce2016-02-28 15:58:54 +0000272{
Richard Hughes9945edb2017-06-19 10:03:55 +0100273 /* failed */
Richard Hughesf508e762015-02-27 12:49:36 +0000274 if (auth == NULL) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100275 g_autofree gchar *message = g_strdup ((*error)->message);
276 g_clear_error (error);
277 g_set_error (error,
Richard Hughes060af612016-08-17 17:32:34 +0100278 FWUPD_ERROR,
279 FWUPD_ERROR_AUTH_FAILED,
Richard Hughes9945edb2017-06-19 10:03:55 +0100280 "Could not check for auth: %s", message);
281 return FALSE;
Richard Hughesf508e762015-02-27 12:49:36 +0000282 }
283
284 /* did not auth */
285 if (!polkit_authorization_result_get_is_authorized (auth)) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100286 g_set_error_literal (error,
Richard Hughes060af612016-08-17 17:32:34 +0100287 FWUPD_ERROR,
288 FWUPD_ERROR_AUTH_FAILED,
Richard Hughes9945edb2017-06-19 10:03:55 +0100289 "Failed to obtain auth");
290 return FALSE;
Richard Hughesf508e762015-02-27 12:49:36 +0000291 }
292
293 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100294 return TRUE;
Richard Hughes5d14def2015-10-07 17:43:10 +0100295}
296
Richard Hughesdf7950b2016-01-31 10:18:40 +0000297static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100298fu_main_authorize_unlock_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100299{
Richard Hughes9945edb2017-06-19 10:03:55 +0100300 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
301 g_autoptr(GError) error = NULL;
302 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100303
Richard Hughes9945edb2017-06-19 10:03:55 +0100304 /* get result */
305 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
306 res, &error);
307 if (!fu_main_authorization_is_valid (auth, &error)) {
308 g_dbus_method_invocation_return_gerror (helper->invocation, error);
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100309 return;
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100310 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100311
312 /* authenticated */
313 if (!fu_engine_unlock (helper->priv->engine, helper->device_id, &error)) {
314 g_dbus_method_invocation_return_gerror (helper->invocation, error);
315 return;
316 }
317
318 /* success */
319 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100320}
321
322static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100323fu_main_authorize_verify_update_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughesdf7950b2016-01-31 10:18:40 +0000324{
Richard Hughes9945edb2017-06-19 10:03:55 +0100325 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
326 g_autoptr(GError) error = NULL;
327 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughesdf7950b2016-01-31 10:18:40 +0000328
Richard Hughes9945edb2017-06-19 10:03:55 +0100329 /* get result */
330 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
331 res, &error);
332 if (!fu_main_authorization_is_valid (auth, &error)) {
333 g_dbus_method_invocation_return_gerror (helper->invocation, error);
Richard Hughesdf7950b2016-01-31 10:18:40 +0000334 return;
Richard Hughesf192bf02016-07-22 08:26:43 +0100335 }
Richard Hughesdf7950b2016-01-31 10:18:40 +0000336
Richard Hughes9945edb2017-06-19 10:03:55 +0100337 /* authenticated */
338 if (!fu_engine_verify_update (helper->priv->engine, helper->device_id, &error)) {
339 g_dbus_method_invocation_return_gerror (helper->invocation, error);
340 return;
Richard Hughes404cc512016-12-21 16:09:48 +0000341 }
342
343 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100344 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes99147f12016-05-17 09:35:04 +0100345}
346
Richard Hughes9945edb2017-06-19 10:03:55 +0100347static void
Richard Hughesa6bd5582017-09-07 14:32:22 +0100348fu_main_authorize_modify_remote_cb (GObject *source, GAsyncResult *res, gpointer user_data)
349{
350 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
351 g_autoptr(GError) error = NULL;
352 g_autoptr(PolkitAuthorizationResult) auth = NULL;
353
354 /* get result */
355 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
356 res, &error);
357 if (!fu_main_authorization_is_valid (auth, &error)) {
358 g_dbus_method_invocation_return_gerror (helper->invocation, error);
359 return;
360 }
361
362 /* authenticated */
363 if (!fu_engine_modify_remote (helper->priv->engine,
364 helper->remote_id,
365 helper->key,
366 helper->value,
367 &error)) {
368 g_dbus_method_invocation_return_gerror (helper->invocation, error);
369 return;
370 }
371
372 /* success */
373 g_dbus_method_invocation_return_value (helper->invocation, NULL);
374}
375
376static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100377fu_main_authorize_install_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughes404cc512016-12-21 16:09:48 +0000378{
Richard Hughes9945edb2017-06-19 10:03:55 +0100379 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
Richard Hughes46832432015-09-11 13:43:15 +0100380 g_autoptr(GError) error = NULL;
Richard Hughes9945edb2017-06-19 10:03:55 +0100381 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughes18423292015-03-09 17:10:50 +0000382
Richard Hughes9945edb2017-06-19 10:03:55 +0100383 /* get result */
384 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
385 res, &error);
386 if (!fu_main_authorization_is_valid (auth, &error)) {
387 g_dbus_method_invocation_return_gerror (helper->invocation, error);
388 return;
Richard Hughes0e883ee2015-03-18 17:22:33 +0000389 }
390
Richard Hughes9945edb2017-06-19 10:03:55 +0100391 /* authenticated */
392 if (!fu_engine_install (helper->priv->engine,
393 helper->device_id,
394 helper->store,
395 helper->blob_cab,
396 helper->flags,
397 &error)) {
398 g_dbus_method_invocation_return_gerror (helper->invocation, error);
399 return;
Richard Hughes654f6b82016-04-25 12:29:48 +0100400 }
401
402 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100403 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes4c369702017-06-16 15:31:38 +0100404}
405
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000406static void
407fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender,
408 const gchar *object_path, const gchar *interface_name,
409 const gchar *method_name, GVariant *parameters,
410 GDBusMethodInvocation *invocation, gpointer user_data)
411{
412 FuMainPrivate *priv = (FuMainPrivate *) user_data;
Richard Hughes9945edb2017-06-19 10:03:55 +0100413 GVariant *val = NULL;
Richard Hughes060af612016-08-17 17:32:34 +0100414 g_autoptr(GError) error = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000415
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000416 if (g_strcmp0 (method_name, "GetDevices") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100417 g_autoptr(GPtrArray) devices = NULL;
Richard Hughesf508e762015-02-27 12:49:36 +0000418 g_debug ("Called %s()", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +0100419 devices = fu_engine_get_devices (priv->engine, &error);
420 if (devices == NULL) {
421 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7708a0f2015-07-21 08:41:22 +0100422 return;
423 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100424 val = fu_main_device_array_to_variant (devices);
425 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes7708a0f2015-07-21 08:41:22 +0100426 return;
427 }
Richard Hughes7708a0f2015-07-21 08:41:22 +0100428 if (g_strcmp0 (method_name, "GetUpdates") == 0) {
Richard Hughes46832432015-09-11 13:43:15 +0100429 g_autoptr(GPtrArray) updates = NULL;
Richard Hughes7708a0f2015-07-21 08:41:22 +0100430 g_debug ("Called %s()", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +0100431 updates = fu_engine_get_updates (priv->engine, &error);
Richard Hughes7708a0f2015-07-21 08:41:22 +0100432 if (updates == NULL) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100433 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7708a0f2015-07-21 08:41:22 +0100434 return;
435 }
Richard Hughescc3de2e2017-09-13 19:28:17 +0100436 val = fu_main_result_array_to_variant (updates);
Richard Hughes9945edb2017-06-19 10:03:55 +0100437 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000438 return;
439 }
Richard Hughese4a100c2017-06-04 21:23:50 +0100440 if (g_strcmp0 (method_name, "GetReleases") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100441 const gchar *device_id;
Richard Hughese4a100c2017-06-04 21:23:50 +0100442 g_autoptr(GPtrArray) releases = NULL;
Richard Hughese4a100c2017-06-04 21:23:50 +0100443 g_variant_get (parameters, "(&s)", &device_id);
444 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughes9945edb2017-06-19 10:03:55 +0100445 releases = fu_engine_get_releases (priv->engine, device_id, &error);
446 if (releases == NULL) {
447 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughese4a100c2017-06-04 21:23:50 +0100448 return;
449 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100450 val = fu_main_release_array_to_variant (releases);
451 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughese4a100c2017-06-04 21:23:50 +0100452 return;
453 }
Richard Hughes97284b12017-09-13 17:07:58 +0100454 if (g_strcmp0 (method_name, "GetDowngrades") == 0) {
455 const gchar *device_id;
456 g_autoptr(GPtrArray) releases = NULL;
457 g_variant_get (parameters, "(&s)", &device_id);
458 g_debug ("Called %s(%s)", method_name, device_id);
459 releases = fu_engine_get_downgrades (priv->engine, device_id, &error);
460 if (releases == NULL) {
461 g_dbus_method_invocation_return_gerror (invocation, error);
462 return;
463 }
464 val = fu_main_release_array_to_variant (releases);
465 g_dbus_method_invocation_return_value (invocation, val);
466 return;
467 }
Richard Hughesa96413a2017-09-13 17:19:59 +0100468 if (g_strcmp0 (method_name, "GetUpgrades") == 0) {
469 const gchar *device_id;
470 g_autoptr(GPtrArray) releases = NULL;
471 g_variant_get (parameters, "(&s)", &device_id);
472 g_debug ("Called %s(%s)", method_name, device_id);
473 releases = fu_engine_get_upgrades (priv->engine, device_id, &error);
474 if (releases == NULL) {
475 g_dbus_method_invocation_return_gerror (invocation, error);
476 return;
477 }
478 val = fu_main_release_array_to_variant (releases);
479 g_dbus_method_invocation_return_value (invocation, val);
480 return;
481 }
Richard Hughes4c369702017-06-16 15:31:38 +0100482 if (g_strcmp0 (method_name, "GetRemotes") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100483 g_autoptr(GPtrArray) remotes = NULL;
Richard Hughes4c369702017-06-16 15:31:38 +0100484 g_debug ("Called %s()", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +0100485 remotes = fu_engine_get_remotes (priv->engine, &error);
486 if (remotes == NULL) {
487 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes4c369702017-06-16 15:31:38 +0100488 return;
489 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100490 val = fu_main_remote_array_to_variant (remotes);
491 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes4c369702017-06-16 15:31:38 +0100492 return;
493 }
Richard Hughes0e883ee2015-03-18 17:22:33 +0000494 if (g_strcmp0 (method_name, "ClearResults") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100495 const gchar *device_id;
496 g_variant_get (parameters, "(&s)", &device_id);
497 g_debug ("Called %s(%s)", method_name, device_id);
498 if (!fu_engine_clear_results (priv->engine, device_id, &error)) {
499 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes0e883ee2015-03-18 17:22:33 +0000500 return;
501 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100502 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughes0e883ee2015-03-18 17:22:33 +0000503 return;
504 }
Richard Hughes0e883ee2015-03-18 17:22:33 +0000505 if (g_strcmp0 (method_name, "GetResults") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100506 const gchar *device_id = NULL;
Richard Hughes93b15762017-09-15 11:05:23 +0100507 g_autoptr(FwupdDevice) result = NULL;
Richard Hughes9945edb2017-06-19 10:03:55 +0100508 g_variant_get (parameters, "(&s)", &device_id);
509 g_debug ("Called %s(%s)", method_name, device_id);
510 result = fu_engine_get_results (priv->engine, device_id, &error);
511 if (result == NULL) {
512 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes0e883ee2015-03-18 17:22:33 +0000513 return;
514 }
Richard Hughes93b15762017-09-15 11:05:23 +0100515 val = fwupd_device_to_data (result, "(a{sv})");
Richard Hughes9945edb2017-06-19 10:03:55 +0100516 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes0e883ee2015-03-18 17:22:33 +0000517 return;
518 }
Richard Hughes1b50d962017-06-02 12:23:00 +0100519 if (g_strcmp0 (method_name, "UpdateMetadataWithId") == 0) {
520 GDBusMessage *message;
521 GUnixFDList *fd_list;
Richard Hughes9945edb2017-06-19 10:03:55 +0100522 const gchar *remote_id = NULL;
Richard Hughes1b50d962017-06-02 12:23:00 +0100523 gint fd_data;
524 gint fd_sig;
525
Richard Hughes9945edb2017-06-19 10:03:55 +0100526 g_variant_get (parameters, "(&shh)", &remote_id, &fd_data, &fd_sig);
527 g_debug ("Called %s(%s,%i,%i)", method_name, remote_id, fd_data, fd_sig);
Richard Hughes1b50d962017-06-02 12:23:00 +0100528
Richard Hughes5935ebd2017-06-16 15:40:31 +0100529 /* update the metadata store */
Richard Hughes1b50d962017-06-02 12:23:00 +0100530 message = g_dbus_method_invocation_get_message (invocation);
531 fd_list = g_dbus_message_get_unix_fd_list (message);
532 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 2) {
533 g_set_error (&error,
534 FWUPD_ERROR,
535 FWUPD_ERROR_INTERNAL,
536 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +0100537 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +0100538 return;
539 }
540 fd_data = g_unix_fd_list_get (fd_list, 0, &error);
541 if (fd_data < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100542 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +0100543 return;
544 }
545 fd_sig = g_unix_fd_list_get (fd_list, 1, &error);
546 if (fd_sig < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100547 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +0100548 return;
549 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100550
551 /* store new metadata (will close the fds when done) */
552 if (!fu_engine_update_metadata (priv->engine, remote_id,
553 fd_data, fd_sig, &error)) {
554 g_prefix_error (&error, "Failed to update metadata: ");
555 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughesae0efdc2015-06-24 16:18:29 +0100556 return;
557 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100558 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughesae0efdc2015-06-24 16:18:29 +0100559 return;
560 }
Richard Hughes9a410ce2016-02-28 15:58:54 +0000561 if (g_strcmp0 (method_name, "Unlock") == 0) {
Richard Hughes9a410ce2016-02-28 15:58:54 +0000562 FuMainAuthHelper *helper;
Richard Hughes9945edb2017-06-19 10:03:55 +0100563 const gchar *device_id = NULL;
Richard Hughes9a410ce2016-02-28 15:58:54 +0000564 g_autoptr(PolkitSubject) subject = NULL;
565
Richard Hughes9945edb2017-06-19 10:03:55 +0100566 g_variant_get (parameters, "(&s)", &device_id);
567 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesfe5cc902016-06-29 10:00:00 +0100568
Richard Hughes9a410ce2016-02-28 15:58:54 +0000569 /* authenticate */
Richard Hughes9945edb2017-06-19 10:03:55 +0100570 helper = g_new0 (FuMainAuthHelper, 1);
571 helper->priv = priv;
572 helper->invocation = g_object_ref (invocation);
573 helper->device_id = g_strdup (device_id);
Richard Hughes9a410ce2016-02-28 15:58:54 +0000574 subject = polkit_system_bus_name_new (sender);
Richard Hughes9945edb2017-06-19 10:03:55 +0100575 polkit_authority_check_authorization (priv->authority, subject,
Richard Hughes9a410ce2016-02-28 15:58:54 +0000576 "org.freedesktop.fwupd.device-unlock",
577 NULL,
578 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
579 NULL,
Richard Hughes9945edb2017-06-19 10:03:55 +0100580 fu_main_authorize_unlock_cb,
Richard Hughes9a410ce2016-02-28 15:58:54 +0000581 helper);
582 return;
583 }
Richard Hughesa6bd5582017-09-07 14:32:22 +0100584 if (g_strcmp0 (method_name, "ModifyRemote") == 0) {
585 FuMainAuthHelper *helper;
586 const gchar *remote_id = NULL;
587 const gchar *key = NULL;
588 const gchar *value = NULL;
589 g_autoptr(PolkitSubject) subject = NULL;
590
591 /* check the id exists */
592 g_variant_get (parameters, "(&s&s&s)", &remote_id, &key, &value);
593 g_debug ("Called %s(%s,%s=%s)", method_name, remote_id, key, value);
594
595 /* create helper object */
596 helper = g_new0 (FuMainAuthHelper, 1);
597 helper->invocation = g_object_ref (invocation);
598 helper->remote_id = g_strdup (remote_id);
599 helper->key = g_strdup (key);
600 helper->value = g_strdup (value);
601 helper->priv = priv;
602
603 /* authenticate */
604 subject = polkit_system_bus_name_new (sender);
605 polkit_authority_check_authorization (helper->priv->authority, subject,
606 "org.freedesktop.fwupd.modify-remote",
607 NULL,
608 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
609 NULL,
610 fu_main_authorize_modify_remote_cb,
611 helper);
612 return;
613 }
Richard Hughes29c220d2016-12-14 17:09:54 +0000614 if (g_strcmp0 (method_name, "VerifyUpdate") == 0) {
Richard Hughes29c220d2016-12-14 17:09:54 +0000615 FuMainAuthHelper *helper;
Richard Hughes9945edb2017-06-19 10:03:55 +0100616 const gchar *device_id = NULL;
Richard Hughes29c220d2016-12-14 17:09:54 +0000617 g_autoptr(PolkitSubject) subject = NULL;
618
619 /* check the id exists */
Richard Hughes9945edb2017-06-19 10:03:55 +0100620 g_variant_get (parameters, "(&s)", &device_id);
621 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughes29c220d2016-12-14 17:09:54 +0000622
Richard Hughes9945edb2017-06-19 10:03:55 +0100623 /* create helper object */
Richard Hughes29c220d2016-12-14 17:09:54 +0000624 helper = g_new0 (FuMainAuthHelper, 1);
Richard Hughes29c220d2016-12-14 17:09:54 +0000625 helper->invocation = g_object_ref (invocation);
Richard Hughes9945edb2017-06-19 10:03:55 +0100626 helper->device_id = g_strdup (device_id);
Richard Hughes29c220d2016-12-14 17:09:54 +0000627 helper->priv = priv;
Richard Hughes29c220d2016-12-14 17:09:54 +0000628
629 /* authenticate */
630 subject = polkit_system_bus_name_new (sender);
631 polkit_authority_check_authorization (helper->priv->authority, subject,
632 "org.freedesktop.fwupd.verify-update",
633 NULL,
634 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
635 NULL,
Richard Hughes9945edb2017-06-19 10:03:55 +0100636 fu_main_authorize_verify_update_cb,
Richard Hughes29c220d2016-12-14 17:09:54 +0000637 helper);
638 return;
639 }
Richard Hughesa043c2e2015-06-29 08:43:18 +0100640 if (g_strcmp0 (method_name, "Verify") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100641 const gchar *device_id = NULL;
642 g_variant_get (parameters, "(&s)", &device_id);
643 g_debug ("Called %s(%s)", method_name, device_id);
644 if (!fu_engine_verify (priv->engine, device_id, &error)) {
645 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughesa043c2e2015-06-29 08:43:18 +0100646 return;
647 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100648 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughesa043c2e2015-06-29 08:43:18 +0100649 return;
650 }
Richard Hughes63a407a2015-07-22 08:54:14 +0100651 if (g_strcmp0 (method_name, "Install") == 0) {
Richard Hughesf508e762015-02-27 12:49:36 +0000652 FuMainAuthHelper *helper;
Richard Hughes74cc2172015-02-27 13:19:46 +0000653 GVariant *prop_value;
Richard Hughesa8e83942015-03-09 17:19:35 +0000654 const gchar *action_id;
Richard Hughes9945edb2017-06-19 10:03:55 +0100655 const gchar *device_id = NULL;
Richard Hughes74cc2172015-02-27 13:19:46 +0000656 gchar *prop_key;
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000657 gint32 fd_handle = 0;
658 gint fd;
Richard Hughes9945edb2017-06-19 10:03:55 +0100659 GDBusMessage *message;
660 GUnixFDList *fd_list;
Richard Hughes60f48c22015-10-08 20:25:51 +0100661 g_autoptr(PolkitSubject) subject = NULL;
Richard Hughes46832432015-09-11 13:43:15 +0100662 g_autoptr(GVariantIter) iter = NULL;
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000663
664 /* check the id exists */
Richard Hughes9945edb2017-06-19 10:03:55 +0100665 g_variant_get (parameters, "(&sha{sv})", &device_id, &fd_handle, &iter);
666 g_debug ("Called %s(%s,%i)", method_name, device_id, fd_handle);
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000667
Richard Hughes9945edb2017-06-19 10:03:55 +0100668 /* create helper object */
669 helper = g_new0 (FuMainAuthHelper, 1);
670 helper->invocation = g_object_ref (invocation);
671 helper->device_id = g_strdup (device_id);
672 helper->priv = priv;
673
674 /* get flags */
675 while (g_variant_iter_next (iter, "{&sv}", &prop_key, &prop_value)) {
Richard Hughes74cc2172015-02-27 13:19:46 +0000676 g_debug ("got option %s", prop_key);
677 if (g_strcmp0 (prop_key, "offline") == 0 &&
678 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +0100679 helper->flags |= FWUPD_INSTALL_FLAG_OFFLINE;
Richard Hughese7c12642015-03-04 20:28:59 +0000680 if (g_strcmp0 (prop_key, "allow-older") == 0 &&
681 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +0100682 helper->flags |= FWUPD_INSTALL_FLAG_ALLOW_OLDER;
Richard Hughese7c12642015-03-04 20:28:59 +0000683 if (g_strcmp0 (prop_key, "allow-reinstall") == 0 &&
684 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +0100685 helper->flags |= FWUPD_INSTALL_FLAG_ALLOW_REINSTALL;
Mario Limonciello71a5b982016-05-10 15:38:53 -0500686 if (g_strcmp0 (prop_key, "force") == 0 &&
687 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +0100688 helper->flags |= FWUPD_INSTALL_FLAG_FORCE;
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000689 g_variant_unref (prop_value);
Richard Hughes74cc2172015-02-27 13:19:46 +0000690 }
691
Richard Hughes9945edb2017-06-19 10:03:55 +0100692
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000693 /* get the fd */
694 message = g_dbus_method_invocation_get_message (invocation);
695 fd_list = g_dbus_message_get_unix_fd_list (message);
696 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 1) {
Richard Hughes060af612016-08-17 17:32:34 +0100697 g_set_error (&error,
698 FWUPD_ERROR,
699 FWUPD_ERROR_INTERNAL,
700 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +0100701 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000702 return;
703 }
Richard Hughes7419e962016-11-22 19:48:06 +0000704 fd = g_unix_fd_list_get (fd_list, 0, &error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000705 if (fd < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100706 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000707 return;
708 }
709
Richard Hughes9945edb2017-06-19 10:03:55 +0100710 /* parse the cab file before authenticating so we can work out
711 * what action ID to use, for instance, if this is trusted --
712 * this will also close the fd when done */
Richard Hughes943d2c92017-06-21 09:04:39 +0100713 helper->blob_cab = fu_common_get_contents_fd (fd, FU_ENGINE_FIRMWARE_SIZE_MAX, &error);
Richard Hughes9945edb2017-06-19 10:03:55 +0100714 if (helper->blob_cab == NULL) {
715 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes5d14def2015-10-07 17:43:10 +0100716 return;
717 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100718 helper->store = fu_engine_get_store_from_blob (priv->engine,
719 helper->blob_cab,
720 &error);
721 if (helper->store == NULL) {
722 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes18423292015-03-09 17:10:50 +0000723 return;
724 }
725
Richard Hughes67ec8982015-03-03 11:39:27 +0000726 /* authenticate */
Richard Hughes9945edb2017-06-19 10:03:55 +0100727 action_id = fu_engine_get_action_id_for_device (priv->engine,
728 helper->device_id,
729 helper->store,
730 helper->flags,
731 &error);
732 if (action_id == NULL) {
733 g_dbus_method_invocation_return_gerror (invocation, error);
734 return;
735 }
Richard Hughesf508e762015-02-27 12:49:36 +0000736 subject = polkit_system_bus_name_new (sender);
Richard Hughes9945edb2017-06-19 10:03:55 +0100737 polkit_authority_check_authorization (priv->authority, subject,
738 action_id, NULL,
Richard Hughesf508e762015-02-27 12:49:36 +0000739 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
740 NULL,
Richard Hughes9945edb2017-06-19 10:03:55 +0100741 fu_main_authorize_install_cb,
Richard Hughesf508e762015-02-27 12:49:36 +0000742 helper);
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000743 return;
744 }
Richard Hughes7289a6b2016-05-29 09:27:47 +0100745 if (g_strcmp0 (method_name, "GetDetailsLocal") == 0) {
746 GDBusMessage *message;
747 GUnixFDList *fd_list;
748 gint32 fd_handle = 0;
749 gint fd;
Richard Hughes9945edb2017-06-19 10:03:55 +0100750 g_autoptr(GPtrArray) results = NULL;
Richard Hughes7289a6b2016-05-29 09:27:47 +0100751
752 /* get parameters */
753 g_variant_get (parameters, "(h)", &fd_handle);
754 g_debug ("Called %s(%i)", method_name, fd_handle);
755
756 /* get the fd */
757 message = g_dbus_method_invocation_get_message (invocation);
758 fd_list = g_dbus_message_get_unix_fd_list (message);
759 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 1) {
Richard Hughes060af612016-08-17 17:32:34 +0100760 g_set_error (&error,
761 FWUPD_ERROR,
762 FWUPD_ERROR_INTERNAL,
763 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +0100764 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +0100765 return;
766 }
Richard Hughes7419e962016-11-22 19:48:06 +0000767 fd = g_unix_fd_list_get (fd_list, 0, &error);
Richard Hughes7289a6b2016-05-29 09:27:47 +0100768 if (fd < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100769 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +0100770 return;
771 }
772
Richard Hughes9945edb2017-06-19 10:03:55 +0100773 /* get details about the file (will close the fd when done) */
774 results = fu_engine_get_details_local (priv->engine, fd, &error);
775 if (results == NULL) {
776 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +0100777 return;
778 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100779 val = fu_main_result_array_to_variant (results);
780 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes7289a6b2016-05-29 09:27:47 +0100781 return;
782 }
Richard Hughes060af612016-08-17 17:32:34 +0100783 g_set_error (&error,
784 G_DBUS_ERROR,
785 G_DBUS_ERROR_UNKNOWN_METHOD,
786 "no such method %s", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +0100787 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000788}
789
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000790static GVariant *
791fu_main_daemon_get_property (GDBusConnection *connection_, const gchar *sender,
792 const gchar *object_path, const gchar *interface_name,
793 const gchar *property_name, GError **error,
794 gpointer user_data)
795{
Richard Hughes773ce982015-03-09 22:40:57 +0000796 FuMainPrivate *priv = (FuMainPrivate *) user_data;
797
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000798 if (g_strcmp0 (property_name, "DaemonVersion") == 0)
799 return g_variant_new_string (VERSION);
800
Richard Hughes773ce982015-03-09 22:40:57 +0000801 if (g_strcmp0 (property_name, "Status") == 0)
Richard Hughes9945edb2017-06-19 10:03:55 +0100802 return g_variant_new_uint32 (fu_engine_get_status (priv->engine));
Richard Hughes773ce982015-03-09 22:40:57 +0000803
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000804 /* return an error */
805 g_set_error (error,
Richard Hughes8645ec92015-03-19 10:14:32 +0000806 G_DBUS_ERROR,
807 G_DBUS_ERROR_UNKNOWN_PROPERTY,
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000808 "failed to get daemon property %s",
809 property_name);
810 return NULL;
811}
812
Richard Hughesfd468842015-04-22 16:44:08 +0100813static void
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000814fu_main_on_bus_acquired_cb (GDBusConnection *connection,
815 const gchar *name,
816 gpointer user_data)
817{
818 FuMainPrivate *priv = (FuMainPrivate *) user_data;
819 guint registration_id;
Richard Hughes46832432015-09-11 13:43:15 +0100820 g_autoptr(GError) error = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000821 static const GDBusInterfaceVTable interface_vtable = {
822 fu_main_daemon_method_call,
823 fu_main_daemon_get_property,
824 NULL
825 };
826
827 priv->connection = g_object_ref (connection);
828 registration_id = g_dbus_connection_register_object (connection,
829 FWUPD_DBUS_PATH,
830 priv->introspection_daemon->interfaces[0],
831 &interface_vtable,
832 priv, /* user_data */
833 NULL, /* user_data_free_func */
834 NULL); /* GError** */
835 g_assert (registration_id > 0);
Richard Hughes18423292015-03-09 17:10:50 +0000836
837 /* connect to D-Bus directly */
838 priv->proxy_uid =
839 g_dbus_proxy_new_sync (priv->connection,
840 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
841 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
842 NULL,
843 "org.freedesktop.DBus",
844 "/org/freedesktop/DBus",
845 "org.freedesktop.DBus",
846 NULL,
847 &error);
848 if (priv->proxy_uid == NULL) {
849 g_warning ("cannot connect to DBus: %s", error->message);
850 return;
851 }
Richard Hughes3f236502015-09-24 15:43:02 +0100852
853 /* dump startup profile data */
Richard Hughes2a1e75d2015-12-18 17:42:53 +0000854 if (fu_debug_is_verbose ())
Richard Hughes9945edb2017-06-19 10:03:55 +0100855 fu_engine_profile_dump (priv->engine);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000856}
857
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000858static void
859fu_main_on_name_acquired_cb (GDBusConnection *connection,
860 const gchar *name,
861 gpointer user_data)
862{
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000863 g_debug ("FuMain: acquired name: %s", name);
864}
865
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000866static void
867fu_main_on_name_lost_cb (GDBusConnection *connection,
868 const gchar *name,
869 gpointer user_data)
870{
871 FuMainPrivate *priv = (FuMainPrivate *) user_data;
872 g_debug ("FuMain: lost name: %s", name);
873 g_main_loop_quit (priv->loop);
874}
875
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000876static gboolean
877fu_main_timed_exit_cb (gpointer user_data)
878{
879 GMainLoop *loop = (GMainLoop *) user_data;
880 g_main_loop_quit (loop);
881 return G_SOURCE_REMOVE;
882}
883
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000884static GDBusNodeInfo *
885fu_main_load_introspection (const gchar *filename, GError **error)
886{
Richard Hughes46832432015-09-11 13:43:15 +0100887 g_autoptr(GBytes) data = NULL;
888 g_autofree gchar *path = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000889
890 /* lookup data */
891 path = g_build_filename ("/org/freedesktop/fwupd", filename, NULL);
892 data = g_resource_lookup_data (fu_get_resource (),
893 path,
894 G_RESOURCE_LOOKUP_FLAGS_NONE,
895 error);
896 if (data == NULL)
897 return NULL;
898
899 /* build introspection from XML */
900 return g_dbus_node_info_new_for_xml (g_bytes_get_data (data, NULL), error);
901}
902
Richard Hughesf0a799e2017-01-17 20:13:30 +0000903static gboolean
904fu_main_perhaps_own_name (gpointer user_data)
905{
906 FuMainPrivate *priv = (FuMainPrivate *) user_data;
907 g_autoptr(GError) error = NULL;
908
909 /* are any plugins pending */
Richard Hughes9945edb2017-06-19 10:03:55 +0100910 if (!fu_engine_check_plugins_pending (priv->engine, &error)) {
Richard Hughesf0a799e2017-01-17 20:13:30 +0000911 g_debug ("trying again: %s", error->message);
912 return G_SOURCE_CONTINUE;
913 }
914
915 /* own the object */
916 g_debug ("registering D-Bus service");
917 priv->owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
918 FWUPD_DBUS_SERVICE,
919 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
920 G_BUS_NAME_OWNER_FLAGS_REPLACE,
921 fu_main_on_bus_acquired_cb,
922 fu_main_on_name_acquired_cb,
923 fu_main_on_name_lost_cb,
924 priv, NULL);
925 return G_SOURCE_REMOVE;
926}
927
Richard Hughesf29a6ee2017-06-02 19:50:37 +0100928static void
929fu_main_private_free (FuMainPrivate *priv)
930{
931 if (priv->loop != NULL)
932 g_main_loop_unref (priv->loop);
933 if (priv->owner_id > 0)
934 g_bus_unown_name (priv->owner_id);
935 if (priv->proxy_uid != NULL)
936 g_object_unref (priv->proxy_uid);
Richard Hughes9945edb2017-06-19 10:03:55 +0100937 if (priv->engine != NULL)
938 g_object_unref (priv->engine);
Richard Hughesf29a6ee2017-06-02 19:50:37 +0100939 if (priv->connection != NULL)
940 g_object_unref (priv->connection);
941 if (priv->authority != NULL)
942 g_object_unref (priv->authority);
Richard Hughesf29a6ee2017-06-02 19:50:37 +0100943 if (priv->introspection_daemon != NULL)
944 g_dbus_node_info_unref (priv->introspection_daemon);
Richard Hughesf29a6ee2017-06-02 19:50:37 +0100945 g_free (priv);
946}
947
948G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuMainPrivate, fu_main_private_free)
949
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000950int
951main (int argc, char *argv[])
952{
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000953 gboolean immediate_exit = FALSE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000954 gboolean timed_exit = FALSE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000955 const GOptionEntry options[] = {
956 { "timed-exit", '\0', 0, G_OPTION_ARG_NONE, &timed_exit,
957 /* TRANSLATORS: exit after we've started up, used for user profiling */
958 _("Exit after a small delay"), NULL },
959 { "immediate-exit", '\0', 0, G_OPTION_ARG_NONE, &immediate_exit,
960 /* TRANSLATORS: exit straight away, used for automatic profiling */
961 _("Exit after the engine has loaded"), NULL },
962 { NULL}
963 };
Richard Hughesf29a6ee2017-06-02 19:50:37 +0100964 g_autoptr(FuMainPrivate) priv = NULL;
Richard Hughes46832432015-09-11 13:43:15 +0100965 g_autoptr(GError) error = NULL;
Richard Hughesf29a6ee2017-06-02 19:50:37 +0100966 g_autoptr(GOptionContext) context = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000967
968 setlocale (LC_ALL, "");
969
970 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
971 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
972 textdomain (GETTEXT_PACKAGE);
973
974 /* TRANSLATORS: program name */
Richard Hughes63a407a2015-07-22 08:54:14 +0100975 g_set_application_name (_("Firmware Update Daemon"));
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000976 context = g_option_context_new (NULL);
977 g_option_context_add_main_entries (context, options, NULL);
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000978 g_option_context_add_group (context, fu_debug_get_option_group ());
Richard Hughes8ded6ca2015-03-16 12:51:36 +0000979 /* TRANSLATORS: program summary */
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000980 g_option_context_set_summary (context, _("Firmware Update D-Bus Service"));
Richard Hughesf29a6ee2017-06-02 19:50:37 +0100981 if (!g_option_context_parse (context, &argc, &argv, &error)) {
982 g_printerr ("Failed to parse command line: %s\n", error->message);
983 return EXIT_FAILURE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000984 }
985
986 /* create new objects */
987 priv = g_new0 (FuMainPrivate, 1);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000988 priv->loop = g_main_loop_new (NULL, FALSE);
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000989
Richard Hughes9945edb2017-06-19 10:03:55 +0100990 /* load engine */
991 priv->engine = fu_engine_new ();
992 g_signal_connect (priv->engine, "changed",
993 G_CALLBACK (fu_main_engine_changed_cb),
994 priv);
995 g_signal_connect (priv->engine, "device-added",
996 G_CALLBACK (fu_main_engine_device_added_cb),
997 priv);
998 g_signal_connect (priv->engine, "device-removed",
999 G_CALLBACK (fu_main_engine_device_removed_cb),
1000 priv);
1001 g_signal_connect (priv->engine, "device-changed",
1002 G_CALLBACK (fu_main_engine_device_changed_cb),
1003 priv);
1004 g_signal_connect (priv->engine, "status-changed",
1005 G_CALLBACK (fu_main_engine_status_changed_cb),
1006 priv);
1007 g_signal_connect (priv->engine, "percentage-changed",
1008 G_CALLBACK (fu_main_engine_percentage_changed_cb),
1009 priv);
1010 if (!fu_engine_load (priv->engine, &error)) {
1011 g_printerr ("Failed to load engine: %s\n", error->message);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001012 return EXIT_FAILURE;
Richard Hughes804c0752015-08-04 14:53:52 +01001013 }
1014
Richard Hughes9945edb2017-06-19 10:03:55 +01001015 /* keep polling until all the plugins are ready */
1016 g_timeout_add (200, fu_main_perhaps_own_name, priv);
Richard Hughesbc93e4a2016-12-08 17:29:51 +00001017
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001018 /* load introspection from file */
1019 priv->introspection_daemon = fu_main_load_introspection (FWUPD_DBUS_INTERFACE ".xml",
1020 &error);
1021 if (priv->introspection_daemon == NULL) {
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001022 g_printerr ("Failed to load introspection: %s\n", error->message);
1023 return EXIT_FAILURE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001024 }
1025
Richard Hughesf508e762015-02-27 12:49:36 +00001026 /* get authority */
1027 priv->authority = polkit_authority_get_sync (NULL, &error);
1028 if (priv->authority == NULL) {
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001029 g_printerr ("Failed to load authority: %s\n", error->message);
1030 return EXIT_FAILURE;
Richard Hughesf508e762015-02-27 12:49:36 +00001031 }
1032
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001033 /* Only timeout and close the mainloop if we have specified it
1034 * on the command line */
1035 if (immediate_exit)
1036 g_idle_add (fu_main_timed_exit_cb, priv->loop);
1037 else if (timed_exit)
1038 g_timeout_add_seconds (5, fu_main_timed_exit_cb, priv->loop);
1039
1040 /* wait */
Richard Hughes4619f9f2017-06-14 13:55:30 +01001041 g_message ("Daemon ready for requests");
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001042 g_main_loop_run (priv->loop);
1043
1044 /* success */
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001045 return EXIT_SUCCESS;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001046}