blob: 48ff5db10f02e02ec36e031fc89ea118839956f7 [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 Hughes1642b3b2017-06-05 17:40:08 +010032#include "fwupd-release-private.h"
Richard Hughes4c369702017-06-16 15:31:38 +010033#include "fwupd-remote-private.h"
Richard Hughesd6db6b42017-04-12 15:03:10 +010034#include "fwupd-resources.h"
Richard Hughes8e9762d2016-03-17 10:14:15 +000035
Richard Hughes8bbfdf42015-02-26 22:28:09 +000036#include "fu-debug.h"
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000037#include "fu-device.h"
Richard Hughes9945edb2017-06-19 10:03:55 +010038#include "fu-engine.h"
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000039
Philip Withnallbc339aa2016-11-22 16:13:22 +000040#ifndef HAVE_POLKIT_0_114
Richard Hughes60f48c22015-10-08 20:25:51 +010041G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitAuthorizationResult, g_object_unref)
42G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitSubject, g_object_unref)
43#endif
44
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000045typedef struct {
46 GDBusConnection *connection;
47 GDBusNodeInfo *introspection_daemon;
Richard Hughes18423292015-03-09 17:10:50 +000048 GDBusProxy *proxy_uid;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000049 GMainLoop *loop;
Richard Hughesf508e762015-02-27 12:49:36 +000050 PolkitAuthority *authority;
Richard Hughesf0a799e2017-01-17 20:13:30 +000051 guint owner_id;
Richard Hughes9945edb2017-06-19 10:03:55 +010052 FuEngine *engine;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000053} FuMainPrivate;
54
Richard Hughesd7022b52015-03-11 19:47:06 +000055static void
Richard Hughes9945edb2017-06-19 10:03:55 +010056fu_main_engine_changed_cb (FuEngine *engine, FuMainPrivate *priv)
Richard Hughesd7022b52015-03-11 19:47:06 +000057{
58 /* not yet connected */
59 if (priv->connection == NULL)
60 return;
61 g_dbus_connection_emit_signal (priv->connection,
62 NULL,
63 FWUPD_DBUS_PATH,
64 FWUPD_DBUS_INTERFACE,
65 "Changed",
66 NULL, NULL);
67}
68
Richard Hughes8ca33782016-04-28 15:04:31 +010069static void
Richard Hughes9945edb2017-06-19 10:03:55 +010070fu_main_engine_device_added_cb (FuEngine *engine,
71 FuDevice *device,
72 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +010073{
74 GVariant *val;
75
76 /* not yet connected */
77 if (priv->connection == NULL)
78 return;
79 val = fwupd_result_to_data (FWUPD_RESULT (device), "(a{sv})");
80 g_dbus_connection_emit_signal (priv->connection,
81 NULL,
82 FWUPD_DBUS_PATH,
83 FWUPD_DBUS_INTERFACE,
84 "DeviceAdded",
85 val, NULL);
86}
87
Richard Hughes8ca33782016-04-28 15:04:31 +010088static void
Richard Hughes9945edb2017-06-19 10:03:55 +010089fu_main_engine_device_removed_cb (FuEngine *engine,
90 FuDevice *device,
91 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +010092{
93 GVariant *val;
94
95 /* not yet connected */
96 if (priv->connection == NULL)
97 return;
98 val = fwupd_result_to_data (FWUPD_RESULT (device), "(a{sv})");
99 g_dbus_connection_emit_signal (priv->connection,
100 NULL,
101 FWUPD_DBUS_PATH,
102 FWUPD_DBUS_INTERFACE,
103 "DeviceRemoved",
104 val, NULL);
105}
106
Richard Hughes8ca33782016-04-28 15:04:31 +0100107static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100108fu_main_engine_device_changed_cb (FuEngine *engine,
109 FuDevice *device,
110 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +0100111{
112 GVariant *val;
113
114 /* not yet connected */
115 if (priv->connection == NULL)
116 return;
117 val = fwupd_result_to_data (FWUPD_RESULT (device), "(a{sv})");
118 g_dbus_connection_emit_signal (priv->connection,
119 NULL,
120 FWUPD_DBUS_PATH,
121 FWUPD_DBUS_INTERFACE,
122 "DeviceChanged",
123 val, NULL);
124}
125
Richard Hughes773ce982015-03-09 22:40:57 +0000126static void
127fu_main_emit_property_changed (FuMainPrivate *priv,
128 const gchar *property_name,
129 GVariant *property_value)
130{
131 GVariantBuilder builder;
132 GVariantBuilder invalidated_builder;
133
134 /* not yet connected */
135 if (priv->connection == NULL)
136 return;
137
138 /* build the dict */
139 g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as"));
140 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
141 g_variant_builder_add (&builder,
142 "{sv}",
143 property_name,
144 property_value);
145 g_dbus_connection_emit_signal (priv->connection,
146 NULL,
147 FWUPD_DBUS_PATH,
148 "org.freedesktop.DBus.Properties",
149 "PropertiesChanged",
150 g_variant_new ("(sa{sv}as)",
151 FWUPD_DBUS_INTERFACE,
152 &builder,
153 &invalidated_builder),
154 NULL);
155 g_variant_builder_clear (&builder);
156 g_variant_builder_clear (&invalidated_builder);
157}
158
Richard Hughes773ce982015-03-09 22:40:57 +0000159
Richard Hughes9945edb2017-06-19 10:03:55 +0100160static void
161fu_main_engine_status_changed_cb (FuEngine *engine,
162 FwupdStatus status,
163 FuMainPrivate *priv)
164{
Richard Hughes88181512015-03-19 10:57:44 +0000165 g_debug ("Emitting PropertyChanged('Status'='%s')",
166 fwupd_status_to_string (status));
Richard Hughes9945edb2017-06-19 10:03:55 +0100167 fu_main_emit_property_changed (priv, "Status",
168 g_variant_new_uint32 (status));
Richard Hughes773ce982015-03-09 22:40:57 +0000169}
170
Richard Hughes876c0072016-08-17 14:51:03 +0100171static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100172fu_main_engine_percentage_changed_cb (FuEngine *engine,
173 guint percentage,
174 FuMainPrivate *priv)
Richard Hughes876c0072016-08-17 14:51:03 +0100175{
Richard Hughes876c0072016-08-17 14:51:03 +0100176 g_debug ("Emitting PropertyChanged('Percentage'='%u%%')", percentage);
177 fu_main_emit_property_changed (priv, "Percentage",
178 g_variant_new_uint32 (percentage));
179}
180
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000181static GVariant *
Richard Hughes9945edb2017-06-19 10:03:55 +0100182fu_main_device_array_to_variant (GPtrArray *devices)
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000183{
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000184 GVariantBuilder builder;
Richard Hughes9945edb2017-06-19 10:03:55 +0100185 g_return_val_if_fail (devices->len > 0, NULL);
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000186 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
Richard Hughesf192bf02016-07-22 08:26:43 +0100187 for (guint i = 0; i < devices->len; i++) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100188 FuDevice *device = g_ptr_array_index (devices, i);
189 GVariant *tmp = fwupd_result_to_data (FWUPD_RESULT (device), "{sa{sv}}");
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000190 g_variant_builder_add_value (&builder, tmp);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000191 }
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000192 return g_variant_new ("(a{sa{sv}})", &builder);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000193}
194
Richard Hughes9945edb2017-06-19 10:03:55 +0100195static GVariant *
196fu_main_release_array_to_variant (GPtrArray *results)
Richard Hughes060af612016-08-17 17:32:34 +0100197{
Richard Hughes9945edb2017-06-19 10:03:55 +0100198 GVariantBuilder builder;
199 g_return_val_if_fail (results->len > 0, NULL);
200 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
201 for (guint i = 0; i < results->len; i++) {
202 FwupdRelease *rel = g_ptr_array_index (results, i);
203 GVariant *tmp = fwupd_release_to_data (rel, "a{sv}");
204 g_variant_builder_add_value (&builder, tmp);
205 }
206 return g_variant_new ("(aa{sv})", &builder);
Richard Hughes060af612016-08-17 17:32:34 +0100207}
208
Richard Hughes9945edb2017-06-19 10:03:55 +0100209static GVariant *
210fu_main_remote_array_to_variant (GPtrArray *remotes)
Richard Hughes060af612016-08-17 17:32:34 +0100211{
Richard Hughes9945edb2017-06-19 10:03:55 +0100212 GVariantBuilder builder;
213 g_return_val_if_fail (remotes->len > 0, NULL);
214 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
215 for (guint i = 0; i < remotes->len; i++) {
216 FwupdRemote *remote = g_ptr_array_index (remotes, i);
217 GVariant *tmp = fwupd_remote_to_data (remote, "a{sv}");
218 g_variant_builder_add_value (&builder, tmp);
219 }
220 return g_variant_new ("(aa{sv})", &builder);
Richard Hughes060af612016-08-17 17:32:34 +0100221}
222
Richard Hughes9945edb2017-06-19 10:03:55 +0100223static GVariant *
224fu_main_result_array_to_variant (GPtrArray *results)
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000225{
Richard Hughes9945edb2017-06-19 10:03:55 +0100226 GVariantBuilder builder;
227 g_return_val_if_fail (results->len > 0, NULL);
228 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
229 for (guint i = 0; i < results->len; i++) {
230 FwupdResult *result = g_ptr_array_index (results, i);
231 GVariant *tmp = fwupd_result_to_data (result, "{sa{sv}}");
232 g_variant_builder_add_value (&builder, tmp);
233 }
234 return g_variant_new ("(a{sa{sv}})", &builder);
Richard Hughesf508e762015-02-27 12:49:36 +0000235}
236
Richard Hughesf508e762015-02-27 12:49:36 +0000237typedef struct {
238 GDBusMethodInvocation *invocation;
Richard Hughes5d14def2015-10-07 17:43:10 +0100239 AsStore *store;
Richard Hughes2d6e1862016-03-18 09:20:37 +0000240 FwupdInstallFlags flags;
Richard Hughes5d14def2015-10-07 17:43:10 +0100241 GBytes *blob_cab;
Richard Hughes67ec8982015-03-03 11:39:27 +0000242 FuMainPrivate *priv;
Richard Hughes9945edb2017-06-19 10:03:55 +0100243 gchar *device_id;
Richard Hughesf508e762015-02-27 12:49:36 +0000244} FuMainAuthHelper;
245
Richard Hughesf508e762015-02-27 12:49:36 +0000246static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100247fu_main_auth_helper_free (FuMainAuthHelper *helper)
Richard Hughesf508e762015-02-27 12:49:36 +0000248{
Richard Hughes4ced4662016-08-26 11:02:31 +0100249 if (helper->blob_cab != NULL)
Richard Hughes5d14def2015-10-07 17:43:10 +0100250 g_bytes_unref (helper->blob_cab);
Richard Hughes9a410ce2016-02-28 15:58:54 +0000251 if (helper->store != NULL)
252 g_object_unref (helper->store);
Richard Hughes9945edb2017-06-19 10:03:55 +0100253 g_free (helper->device_id);
Richard Hughes67ec8982015-03-03 11:39:27 +0000254 g_object_unref (helper->invocation);
Richard Hughesf508e762015-02-27 12:49:36 +0000255 g_free (helper);
256}
257
Richard Hughes9945edb2017-06-19 10:03:55 +0100258G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuMainAuthHelper, fu_main_auth_helper_free)
259
260/* error may or may not already have been set */
Richard Hughesb75c92d2016-02-20 20:22:00 +0000261static gboolean
Richard Hughes9945edb2017-06-19 10:03:55 +0100262fu_main_authorization_is_valid (PolkitAuthorizationResult *auth, GError **error)
Richard Hughes9a410ce2016-02-28 15:58:54 +0000263{
Richard Hughes9945edb2017-06-19 10:03:55 +0100264 /* failed */
Richard Hughesf508e762015-02-27 12:49:36 +0000265 if (auth == NULL) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100266 g_autofree gchar *message = g_strdup ((*error)->message);
267 g_clear_error (error);
268 g_set_error (error,
Richard Hughes060af612016-08-17 17:32:34 +0100269 FWUPD_ERROR,
270 FWUPD_ERROR_AUTH_FAILED,
Richard Hughes9945edb2017-06-19 10:03:55 +0100271 "Could not check for auth: %s", message);
272 return FALSE;
Richard Hughesf508e762015-02-27 12:49:36 +0000273 }
274
275 /* did not auth */
276 if (!polkit_authorization_result_get_is_authorized (auth)) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100277 g_set_error_literal (error,
Richard Hughes060af612016-08-17 17:32:34 +0100278 FWUPD_ERROR,
279 FWUPD_ERROR_AUTH_FAILED,
Richard Hughes9945edb2017-06-19 10:03:55 +0100280 "Failed to obtain auth");
281 return FALSE;
Richard Hughesf508e762015-02-27 12:49:36 +0000282 }
283
284 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100285 return TRUE;
Richard Hughes5d14def2015-10-07 17:43:10 +0100286}
287
Richard Hughesdf7950b2016-01-31 10:18:40 +0000288static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100289fu_main_authorize_unlock_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100290{
Richard Hughes9945edb2017-06-19 10:03:55 +0100291 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
292 g_autoptr(GError) error = NULL;
293 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100294
Richard Hughes9945edb2017-06-19 10:03:55 +0100295 /* get result */
296 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
297 res, &error);
298 if (!fu_main_authorization_is_valid (auth, &error)) {
299 g_dbus_method_invocation_return_gerror (helper->invocation, error);
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100300 return;
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100301 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100302
303 /* authenticated */
304 if (!fu_engine_unlock (helper->priv->engine, helper->device_id, &error)) {
305 g_dbus_method_invocation_return_gerror (helper->invocation, error);
306 return;
307 }
308
309 /* success */
310 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100311}
312
313static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100314fu_main_authorize_verify_update_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughesdf7950b2016-01-31 10:18:40 +0000315{
Richard Hughes9945edb2017-06-19 10:03:55 +0100316 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
317 g_autoptr(GError) error = NULL;
318 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughesdf7950b2016-01-31 10:18:40 +0000319
Richard Hughes9945edb2017-06-19 10:03:55 +0100320 /* get result */
321 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
322 res, &error);
323 if (!fu_main_authorization_is_valid (auth, &error)) {
324 g_dbus_method_invocation_return_gerror (helper->invocation, error);
Richard Hughesdf7950b2016-01-31 10:18:40 +0000325 return;
Richard Hughesf192bf02016-07-22 08:26:43 +0100326 }
Richard Hughesdf7950b2016-01-31 10:18:40 +0000327
Richard Hughes9945edb2017-06-19 10:03:55 +0100328 /* authenticated */
329 if (!fu_engine_verify_update (helper->priv->engine, helper->device_id, &error)) {
330 g_dbus_method_invocation_return_gerror (helper->invocation, error);
331 return;
Richard Hughes404cc512016-12-21 16:09:48 +0000332 }
333
334 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100335 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes99147f12016-05-17 09:35:04 +0100336}
337
Richard Hughes9945edb2017-06-19 10:03:55 +0100338static void
339fu_main_authorize_install_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughes404cc512016-12-21 16:09:48 +0000340{
Richard Hughes9945edb2017-06-19 10:03:55 +0100341 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
Richard Hughes46832432015-09-11 13:43:15 +0100342 g_autoptr(GError) error = NULL;
Richard Hughes9945edb2017-06-19 10:03:55 +0100343 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughes18423292015-03-09 17:10:50 +0000344
Richard Hughes9945edb2017-06-19 10:03:55 +0100345 /* get result */
346 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
347 res, &error);
348 if (!fu_main_authorization_is_valid (auth, &error)) {
349 g_dbus_method_invocation_return_gerror (helper->invocation, error);
350 return;
Richard Hughes0e883ee2015-03-18 17:22:33 +0000351 }
352
Richard Hughes9945edb2017-06-19 10:03:55 +0100353 /* authenticated */
354 if (!fu_engine_install (helper->priv->engine,
355 helper->device_id,
356 helper->store,
357 helper->blob_cab,
358 helper->flags,
359 &error)) {
360 g_dbus_method_invocation_return_gerror (helper->invocation, error);
361 return;
Richard Hughes654f6b82016-04-25 12:29:48 +0100362 }
363
364 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100365 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes4c369702017-06-16 15:31:38 +0100366}
367
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000368static void
369fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender,
370 const gchar *object_path, const gchar *interface_name,
371 const gchar *method_name, GVariant *parameters,
372 GDBusMethodInvocation *invocation, gpointer user_data)
373{
374 FuMainPrivate *priv = (FuMainPrivate *) user_data;
Richard Hughes9945edb2017-06-19 10:03:55 +0100375 GVariant *val = NULL;
Richard Hughes060af612016-08-17 17:32:34 +0100376 g_autoptr(GError) error = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000377
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000378 if (g_strcmp0 (method_name, "GetDevices") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100379 g_autoptr(GPtrArray) devices = NULL;
Richard Hughesf508e762015-02-27 12:49:36 +0000380 g_debug ("Called %s()", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +0100381 devices = fu_engine_get_devices (priv->engine, &error);
382 if (devices == NULL) {
383 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7708a0f2015-07-21 08:41:22 +0100384 return;
385 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100386 val = fu_main_device_array_to_variant (devices);
387 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes7708a0f2015-07-21 08:41:22 +0100388 return;
389 }
Richard Hughes7708a0f2015-07-21 08:41:22 +0100390 if (g_strcmp0 (method_name, "GetUpdates") == 0) {
Richard Hughes46832432015-09-11 13:43:15 +0100391 g_autoptr(GPtrArray) updates = NULL;
Richard Hughes7708a0f2015-07-21 08:41:22 +0100392 g_debug ("Called %s()", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +0100393 updates = fu_engine_get_updates (priv->engine, &error);
Richard Hughes7708a0f2015-07-21 08:41:22 +0100394 if (updates == NULL) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100395 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7708a0f2015-07-21 08:41:22 +0100396 return;
397 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100398 val = fu_main_device_array_to_variant (updates);
399 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000400 return;
401 }
Richard Hughese4a100c2017-06-04 21:23:50 +0100402 if (g_strcmp0 (method_name, "GetReleases") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100403 const gchar *device_id;
Richard Hughese4a100c2017-06-04 21:23:50 +0100404 g_autoptr(GPtrArray) releases = NULL;
Richard Hughese4a100c2017-06-04 21:23:50 +0100405 g_variant_get (parameters, "(&s)", &device_id);
406 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughes9945edb2017-06-19 10:03:55 +0100407 releases = fu_engine_get_releases (priv->engine, device_id, &error);
408 if (releases == NULL) {
409 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughese4a100c2017-06-04 21:23:50 +0100410 return;
411 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100412 val = fu_main_release_array_to_variant (releases);
413 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughese4a100c2017-06-04 21:23:50 +0100414 return;
415 }
Richard Hughes4c369702017-06-16 15:31:38 +0100416 if (g_strcmp0 (method_name, "GetRemotes") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100417 g_autoptr(GPtrArray) remotes = NULL;
Richard Hughes4c369702017-06-16 15:31:38 +0100418 g_debug ("Called %s()", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +0100419 remotes = fu_engine_get_remotes (priv->engine, &error);
420 if (remotes == NULL) {
421 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes4c369702017-06-16 15:31:38 +0100422 return;
423 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100424 val = fu_main_remote_array_to_variant (remotes);
425 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes4c369702017-06-16 15:31:38 +0100426 return;
427 }
Richard Hughes0e883ee2015-03-18 17:22:33 +0000428 if (g_strcmp0 (method_name, "ClearResults") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100429 const gchar *device_id;
430 g_variant_get (parameters, "(&s)", &device_id);
431 g_debug ("Called %s(%s)", method_name, device_id);
432 if (!fu_engine_clear_results (priv->engine, device_id, &error)) {
433 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes0e883ee2015-03-18 17:22:33 +0000434 return;
435 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100436 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughes0e883ee2015-03-18 17:22:33 +0000437 return;
438 }
Richard Hughes0e883ee2015-03-18 17:22:33 +0000439 if (g_strcmp0 (method_name, "GetResults") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100440 const gchar *device_id = NULL;
441 g_autoptr(FwupdResult) result = NULL;
442 g_variant_get (parameters, "(&s)", &device_id);
443 g_debug ("Called %s(%s)", method_name, device_id);
444 result = fu_engine_get_results (priv->engine, device_id, &error);
445 if (result == NULL) {
446 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes0e883ee2015-03-18 17:22:33 +0000447 return;
448 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100449 val = fwupd_result_to_data (result, "(a{sv})");
450 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes0e883ee2015-03-18 17:22:33 +0000451 return;
452 }
Richard Hughes1b50d962017-06-02 12:23:00 +0100453 if (g_strcmp0 (method_name, "UpdateMetadataWithId") == 0) {
454 GDBusMessage *message;
455 GUnixFDList *fd_list;
Richard Hughes9945edb2017-06-19 10:03:55 +0100456 const gchar *remote_id = NULL;
Richard Hughes1b50d962017-06-02 12:23:00 +0100457 gint fd_data;
458 gint fd_sig;
459
Richard Hughes9945edb2017-06-19 10:03:55 +0100460 g_variant_get (parameters, "(&shh)", &remote_id, &fd_data, &fd_sig);
461 g_debug ("Called %s(%s,%i,%i)", method_name, remote_id, fd_data, fd_sig);
Richard Hughes1b50d962017-06-02 12:23:00 +0100462
Richard Hughes5935ebd2017-06-16 15:40:31 +0100463 /* update the metadata store */
Richard Hughes1b50d962017-06-02 12:23:00 +0100464 message = g_dbus_method_invocation_get_message (invocation);
465 fd_list = g_dbus_message_get_unix_fd_list (message);
466 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 2) {
467 g_set_error (&error,
468 FWUPD_ERROR,
469 FWUPD_ERROR_INTERNAL,
470 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +0100471 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +0100472 return;
473 }
474 fd_data = g_unix_fd_list_get (fd_list, 0, &error);
475 if (fd_data < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100476 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +0100477 return;
478 }
479 fd_sig = g_unix_fd_list_get (fd_list, 1, &error);
480 if (fd_sig < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100481 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +0100482 return;
483 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100484
485 /* store new metadata (will close the fds when done) */
486 if (!fu_engine_update_metadata (priv->engine, remote_id,
487 fd_data, fd_sig, &error)) {
488 g_prefix_error (&error, "Failed to update metadata: ");
489 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughesae0efdc2015-06-24 16:18:29 +0100490 return;
491 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100492 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughesae0efdc2015-06-24 16:18:29 +0100493 return;
494 }
Richard Hughes9a410ce2016-02-28 15:58:54 +0000495 if (g_strcmp0 (method_name, "Unlock") == 0) {
Richard Hughes9a410ce2016-02-28 15:58:54 +0000496 FuMainAuthHelper *helper;
Richard Hughes9945edb2017-06-19 10:03:55 +0100497 const gchar *device_id = NULL;
Richard Hughes9a410ce2016-02-28 15:58:54 +0000498 g_autoptr(PolkitSubject) subject = NULL;
499
Richard Hughes9945edb2017-06-19 10:03:55 +0100500 g_variant_get (parameters, "(&s)", &device_id);
501 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesfe5cc902016-06-29 10:00:00 +0100502
Richard Hughes9a410ce2016-02-28 15:58:54 +0000503 /* authenticate */
Richard Hughes9945edb2017-06-19 10:03:55 +0100504 helper = g_new0 (FuMainAuthHelper, 1);
505 helper->priv = priv;
506 helper->invocation = g_object_ref (invocation);
507 helper->device_id = g_strdup (device_id);
Richard Hughes9a410ce2016-02-28 15:58:54 +0000508 subject = polkit_system_bus_name_new (sender);
Richard Hughes9945edb2017-06-19 10:03:55 +0100509 polkit_authority_check_authorization (priv->authority, subject,
Richard Hughes9a410ce2016-02-28 15:58:54 +0000510 "org.freedesktop.fwupd.device-unlock",
511 NULL,
512 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
513 NULL,
Richard Hughes9945edb2017-06-19 10:03:55 +0100514 fu_main_authorize_unlock_cb,
Richard Hughes9a410ce2016-02-28 15:58:54 +0000515 helper);
516 return;
517 }
Richard Hughes29c220d2016-12-14 17:09:54 +0000518 if (g_strcmp0 (method_name, "VerifyUpdate") == 0) {
Richard Hughes29c220d2016-12-14 17:09:54 +0000519 FuMainAuthHelper *helper;
Richard Hughes9945edb2017-06-19 10:03:55 +0100520 const gchar *device_id = NULL;
Richard Hughes29c220d2016-12-14 17:09:54 +0000521 g_autoptr(PolkitSubject) subject = NULL;
522
523 /* check the id exists */
Richard Hughes9945edb2017-06-19 10:03:55 +0100524 g_variant_get (parameters, "(&s)", &device_id);
525 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughes29c220d2016-12-14 17:09:54 +0000526
Richard Hughes9945edb2017-06-19 10:03:55 +0100527 /* create helper object */
Richard Hughes29c220d2016-12-14 17:09:54 +0000528 helper = g_new0 (FuMainAuthHelper, 1);
Richard Hughes29c220d2016-12-14 17:09:54 +0000529 helper->invocation = g_object_ref (invocation);
Richard Hughes9945edb2017-06-19 10:03:55 +0100530 helper->device_id = g_strdup (device_id);
Richard Hughes29c220d2016-12-14 17:09:54 +0000531 helper->priv = priv;
Richard Hughes29c220d2016-12-14 17:09:54 +0000532
533 /* authenticate */
534 subject = polkit_system_bus_name_new (sender);
535 polkit_authority_check_authorization (helper->priv->authority, subject,
536 "org.freedesktop.fwupd.verify-update",
537 NULL,
538 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
539 NULL,
Richard Hughes9945edb2017-06-19 10:03:55 +0100540 fu_main_authorize_verify_update_cb,
Richard Hughes29c220d2016-12-14 17:09:54 +0000541 helper);
542 return;
543 }
Richard Hughesa043c2e2015-06-29 08:43:18 +0100544 if (g_strcmp0 (method_name, "Verify") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100545 const gchar *device_id = NULL;
546 g_variant_get (parameters, "(&s)", &device_id);
547 g_debug ("Called %s(%s)", method_name, device_id);
548 if (!fu_engine_verify (priv->engine, device_id, &error)) {
549 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughesa043c2e2015-06-29 08:43:18 +0100550 return;
551 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100552 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughesa043c2e2015-06-29 08:43:18 +0100553 return;
554 }
Richard Hughes63a407a2015-07-22 08:54:14 +0100555 if (g_strcmp0 (method_name, "Install") == 0) {
Richard Hughesf508e762015-02-27 12:49:36 +0000556 FuMainAuthHelper *helper;
Richard Hughes74cc2172015-02-27 13:19:46 +0000557 GVariant *prop_value;
Richard Hughesa8e83942015-03-09 17:19:35 +0000558 const gchar *action_id;
Richard Hughes9945edb2017-06-19 10:03:55 +0100559 const gchar *device_id = NULL;
Richard Hughes74cc2172015-02-27 13:19:46 +0000560 gchar *prop_key;
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000561 gint32 fd_handle = 0;
562 gint fd;
Richard Hughes9945edb2017-06-19 10:03:55 +0100563 GDBusMessage *message;
564 GUnixFDList *fd_list;
Richard Hughes60f48c22015-10-08 20:25:51 +0100565 g_autoptr(PolkitSubject) subject = NULL;
Richard Hughes46832432015-09-11 13:43:15 +0100566 g_autoptr(GVariantIter) iter = NULL;
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000567
568 /* check the id exists */
Richard Hughes9945edb2017-06-19 10:03:55 +0100569 g_variant_get (parameters, "(&sha{sv})", &device_id, &fd_handle, &iter);
570 g_debug ("Called %s(%s,%i)", method_name, device_id, fd_handle);
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000571
Richard Hughes9945edb2017-06-19 10:03:55 +0100572 /* create helper object */
573 helper = g_new0 (FuMainAuthHelper, 1);
574 helper->invocation = g_object_ref (invocation);
575 helper->device_id = g_strdup (device_id);
576 helper->priv = priv;
577
578 /* get flags */
579 while (g_variant_iter_next (iter, "{&sv}", &prop_key, &prop_value)) {
Richard Hughes74cc2172015-02-27 13:19:46 +0000580 g_debug ("got option %s", prop_key);
581 if (g_strcmp0 (prop_key, "offline") == 0 &&
582 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +0100583 helper->flags |= FWUPD_INSTALL_FLAG_OFFLINE;
Richard Hughese7c12642015-03-04 20:28:59 +0000584 if (g_strcmp0 (prop_key, "allow-older") == 0 &&
585 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +0100586 helper->flags |= FWUPD_INSTALL_FLAG_ALLOW_OLDER;
Richard Hughese7c12642015-03-04 20:28:59 +0000587 if (g_strcmp0 (prop_key, "allow-reinstall") == 0 &&
588 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +0100589 helper->flags |= FWUPD_INSTALL_FLAG_ALLOW_REINSTALL;
Mario Limonciello71a5b982016-05-10 15:38:53 -0500590 if (g_strcmp0 (prop_key, "force") == 0 &&
591 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +0100592 helper->flags |= FWUPD_INSTALL_FLAG_FORCE;
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000593 g_variant_unref (prop_value);
Richard Hughes74cc2172015-02-27 13:19:46 +0000594 }
595
Richard Hughes9945edb2017-06-19 10:03:55 +0100596
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000597 /* get the fd */
598 message = g_dbus_method_invocation_get_message (invocation);
599 fd_list = g_dbus_message_get_unix_fd_list (message);
600 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 1) {
Richard Hughes060af612016-08-17 17:32:34 +0100601 g_set_error (&error,
602 FWUPD_ERROR,
603 FWUPD_ERROR_INTERNAL,
604 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +0100605 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000606 return;
607 }
Richard Hughes7419e962016-11-22 19:48:06 +0000608 fd = g_unix_fd_list_get (fd_list, 0, &error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000609 if (fd < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100610 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000611 return;
612 }
613
Richard Hughes9945edb2017-06-19 10:03:55 +0100614 /* parse the cab file before authenticating so we can work out
615 * what action ID to use, for instance, if this is trusted --
616 * this will also close the fd when done */
617 helper->blob_cab = fu_engine_read_from_fd (fd, FU_ENGINE_FIRMWARE_SIZE_MAX, &error);
618 if (helper->blob_cab == NULL) {
619 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes5d14def2015-10-07 17:43:10 +0100620 return;
621 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100622 helper->store = fu_engine_get_store_from_blob (priv->engine,
623 helper->blob_cab,
624 &error);
625 if (helper->store == NULL) {
626 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes18423292015-03-09 17:10:50 +0000627 return;
628 }
629
Richard Hughes67ec8982015-03-03 11:39:27 +0000630 /* authenticate */
Richard Hughes9945edb2017-06-19 10:03:55 +0100631 action_id = fu_engine_get_action_id_for_device (priv->engine,
632 helper->device_id,
633 helper->store,
634 helper->flags,
635 &error);
636 if (action_id == NULL) {
637 g_dbus_method_invocation_return_gerror (invocation, error);
638 return;
639 }
Richard Hughesf508e762015-02-27 12:49:36 +0000640 subject = polkit_system_bus_name_new (sender);
Richard Hughes9945edb2017-06-19 10:03:55 +0100641 polkit_authority_check_authorization (priv->authority, subject,
642 action_id, NULL,
Richard Hughesf508e762015-02-27 12:49:36 +0000643 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
644 NULL,
Richard Hughes9945edb2017-06-19 10:03:55 +0100645 fu_main_authorize_install_cb,
Richard Hughesf508e762015-02-27 12:49:36 +0000646 helper);
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000647 return;
648 }
Richard Hughes7289a6b2016-05-29 09:27:47 +0100649 if (g_strcmp0 (method_name, "GetDetailsLocal") == 0) {
650 GDBusMessage *message;
651 GUnixFDList *fd_list;
652 gint32 fd_handle = 0;
653 gint fd;
Richard Hughes9945edb2017-06-19 10:03:55 +0100654 g_autoptr(GPtrArray) results = NULL;
Richard Hughes7289a6b2016-05-29 09:27:47 +0100655
656 /* get parameters */
657 g_variant_get (parameters, "(h)", &fd_handle);
658 g_debug ("Called %s(%i)", method_name, fd_handle);
659
660 /* get the fd */
661 message = g_dbus_method_invocation_get_message (invocation);
662 fd_list = g_dbus_message_get_unix_fd_list (message);
663 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 1) {
Richard Hughes060af612016-08-17 17:32:34 +0100664 g_set_error (&error,
665 FWUPD_ERROR,
666 FWUPD_ERROR_INTERNAL,
667 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +0100668 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +0100669 return;
670 }
Richard Hughes7419e962016-11-22 19:48:06 +0000671 fd = g_unix_fd_list_get (fd_list, 0, &error);
Richard Hughes7289a6b2016-05-29 09:27:47 +0100672 if (fd < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100673 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +0100674 return;
675 }
676
Richard Hughes9945edb2017-06-19 10:03:55 +0100677 /* get details about the file (will close the fd when done) */
678 results = fu_engine_get_details_local (priv->engine, fd, &error);
679 if (results == NULL) {
680 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +0100681 return;
682 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100683 val = fu_main_result_array_to_variant (results);
684 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes7289a6b2016-05-29 09:27:47 +0100685 return;
686 }
Richard Hughes060af612016-08-17 17:32:34 +0100687 g_set_error (&error,
688 G_DBUS_ERROR,
689 G_DBUS_ERROR_UNKNOWN_METHOD,
690 "no such method %s", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +0100691 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000692}
693
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000694static GVariant *
695fu_main_daemon_get_property (GDBusConnection *connection_, const gchar *sender,
696 const gchar *object_path, const gchar *interface_name,
697 const gchar *property_name, GError **error,
698 gpointer user_data)
699{
Richard Hughes773ce982015-03-09 22:40:57 +0000700 FuMainPrivate *priv = (FuMainPrivate *) user_data;
701
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000702 if (g_strcmp0 (property_name, "DaemonVersion") == 0)
703 return g_variant_new_string (VERSION);
704
Richard Hughes773ce982015-03-09 22:40:57 +0000705 if (g_strcmp0 (property_name, "Status") == 0)
Richard Hughes9945edb2017-06-19 10:03:55 +0100706 return g_variant_new_uint32 (fu_engine_get_status (priv->engine));
Richard Hughes773ce982015-03-09 22:40:57 +0000707
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000708 /* return an error */
709 g_set_error (error,
Richard Hughes8645ec92015-03-19 10:14:32 +0000710 G_DBUS_ERROR,
711 G_DBUS_ERROR_UNKNOWN_PROPERTY,
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000712 "failed to get daemon property %s",
713 property_name);
714 return NULL;
715}
716
Richard Hughesfd468842015-04-22 16:44:08 +0100717static void
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000718fu_main_on_bus_acquired_cb (GDBusConnection *connection,
719 const gchar *name,
720 gpointer user_data)
721{
722 FuMainPrivate *priv = (FuMainPrivate *) user_data;
723 guint registration_id;
Richard Hughes46832432015-09-11 13:43:15 +0100724 g_autoptr(GError) error = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000725 static const GDBusInterfaceVTable interface_vtable = {
726 fu_main_daemon_method_call,
727 fu_main_daemon_get_property,
728 NULL
729 };
730
731 priv->connection = g_object_ref (connection);
732 registration_id = g_dbus_connection_register_object (connection,
733 FWUPD_DBUS_PATH,
734 priv->introspection_daemon->interfaces[0],
735 &interface_vtable,
736 priv, /* user_data */
737 NULL, /* user_data_free_func */
738 NULL); /* GError** */
739 g_assert (registration_id > 0);
Richard Hughes18423292015-03-09 17:10:50 +0000740
741 /* connect to D-Bus directly */
742 priv->proxy_uid =
743 g_dbus_proxy_new_sync (priv->connection,
744 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
745 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
746 NULL,
747 "org.freedesktop.DBus",
748 "/org/freedesktop/DBus",
749 "org.freedesktop.DBus",
750 NULL,
751 &error);
752 if (priv->proxy_uid == NULL) {
753 g_warning ("cannot connect to DBus: %s", error->message);
754 return;
755 }
Richard Hughes3f236502015-09-24 15:43:02 +0100756
757 /* dump startup profile data */
Richard Hughes2a1e75d2015-12-18 17:42:53 +0000758 if (fu_debug_is_verbose ())
Richard Hughes9945edb2017-06-19 10:03:55 +0100759 fu_engine_profile_dump (priv->engine);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000760}
761
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000762static void
763fu_main_on_name_acquired_cb (GDBusConnection *connection,
764 const gchar *name,
765 gpointer user_data)
766{
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000767 g_debug ("FuMain: acquired name: %s", name);
768}
769
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000770static void
771fu_main_on_name_lost_cb (GDBusConnection *connection,
772 const gchar *name,
773 gpointer user_data)
774{
775 FuMainPrivate *priv = (FuMainPrivate *) user_data;
776 g_debug ("FuMain: lost name: %s", name);
777 g_main_loop_quit (priv->loop);
778}
779
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000780static gboolean
781fu_main_timed_exit_cb (gpointer user_data)
782{
783 GMainLoop *loop = (GMainLoop *) user_data;
784 g_main_loop_quit (loop);
785 return G_SOURCE_REMOVE;
786}
787
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000788static GDBusNodeInfo *
789fu_main_load_introspection (const gchar *filename, GError **error)
790{
Richard Hughes46832432015-09-11 13:43:15 +0100791 g_autoptr(GBytes) data = NULL;
792 g_autofree gchar *path = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000793
794 /* lookup data */
795 path = g_build_filename ("/org/freedesktop/fwupd", filename, NULL);
796 data = g_resource_lookup_data (fu_get_resource (),
797 path,
798 G_RESOURCE_LOOKUP_FLAGS_NONE,
799 error);
800 if (data == NULL)
801 return NULL;
802
803 /* build introspection from XML */
804 return g_dbus_node_info_new_for_xml (g_bytes_get_data (data, NULL), error);
805}
806
Richard Hughesf0a799e2017-01-17 20:13:30 +0000807static gboolean
808fu_main_perhaps_own_name (gpointer user_data)
809{
810 FuMainPrivate *priv = (FuMainPrivate *) user_data;
811 g_autoptr(GError) error = NULL;
812
813 /* are any plugins pending */
Richard Hughes9945edb2017-06-19 10:03:55 +0100814 if (!fu_engine_check_plugins_pending (priv->engine, &error)) {
Richard Hughesf0a799e2017-01-17 20:13:30 +0000815 g_debug ("trying again: %s", error->message);
816 return G_SOURCE_CONTINUE;
817 }
818
819 /* own the object */
820 g_debug ("registering D-Bus service");
821 priv->owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
822 FWUPD_DBUS_SERVICE,
823 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
824 G_BUS_NAME_OWNER_FLAGS_REPLACE,
825 fu_main_on_bus_acquired_cb,
826 fu_main_on_name_acquired_cb,
827 fu_main_on_name_lost_cb,
828 priv, NULL);
829 return G_SOURCE_REMOVE;
830}
831
Richard Hughesf29a6ee2017-06-02 19:50:37 +0100832static void
833fu_main_private_free (FuMainPrivate *priv)
834{
835 if (priv->loop != NULL)
836 g_main_loop_unref (priv->loop);
837 if (priv->owner_id > 0)
838 g_bus_unown_name (priv->owner_id);
839 if (priv->proxy_uid != NULL)
840 g_object_unref (priv->proxy_uid);
Richard Hughes9945edb2017-06-19 10:03:55 +0100841 if (priv->engine != NULL)
842 g_object_unref (priv->engine);
Richard Hughesf29a6ee2017-06-02 19:50:37 +0100843 if (priv->connection != NULL)
844 g_object_unref (priv->connection);
845 if (priv->authority != NULL)
846 g_object_unref (priv->authority);
Richard Hughesf29a6ee2017-06-02 19:50:37 +0100847 if (priv->introspection_daemon != NULL)
848 g_dbus_node_info_unref (priv->introspection_daemon);
Richard Hughesf29a6ee2017-06-02 19:50:37 +0100849 g_free (priv);
850}
851
852G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuMainPrivate, fu_main_private_free)
853
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000854int
855main (int argc, char *argv[])
856{
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000857 gboolean immediate_exit = FALSE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000858 gboolean timed_exit = FALSE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000859 const GOptionEntry options[] = {
860 { "timed-exit", '\0', 0, G_OPTION_ARG_NONE, &timed_exit,
861 /* TRANSLATORS: exit after we've started up, used for user profiling */
862 _("Exit after a small delay"), NULL },
863 { "immediate-exit", '\0', 0, G_OPTION_ARG_NONE, &immediate_exit,
864 /* TRANSLATORS: exit straight away, used for automatic profiling */
865 _("Exit after the engine has loaded"), NULL },
866 { NULL}
867 };
Richard Hughesf29a6ee2017-06-02 19:50:37 +0100868 g_autoptr(FuMainPrivate) priv = NULL;
Richard Hughes46832432015-09-11 13:43:15 +0100869 g_autoptr(GError) error = NULL;
Richard Hughesf29a6ee2017-06-02 19:50:37 +0100870 g_autoptr(GOptionContext) context = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000871
872 setlocale (LC_ALL, "");
873
874 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
875 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
876 textdomain (GETTEXT_PACKAGE);
877
878 /* TRANSLATORS: program name */
Richard Hughes63a407a2015-07-22 08:54:14 +0100879 g_set_application_name (_("Firmware Update Daemon"));
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000880 context = g_option_context_new (NULL);
881 g_option_context_add_main_entries (context, options, NULL);
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000882 g_option_context_add_group (context, fu_debug_get_option_group ());
Richard Hughes8ded6ca2015-03-16 12:51:36 +0000883 /* TRANSLATORS: program summary */
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000884 g_option_context_set_summary (context, _("Firmware Update D-Bus Service"));
Richard Hughesf29a6ee2017-06-02 19:50:37 +0100885 if (!g_option_context_parse (context, &argc, &argv, &error)) {
886 g_printerr ("Failed to parse command line: %s\n", error->message);
887 return EXIT_FAILURE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000888 }
889
890 /* create new objects */
891 priv = g_new0 (FuMainPrivate, 1);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000892 priv->loop = g_main_loop_new (NULL, FALSE);
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000893
Richard Hughes9945edb2017-06-19 10:03:55 +0100894 /* load engine */
895 priv->engine = fu_engine_new ();
896 g_signal_connect (priv->engine, "changed",
897 G_CALLBACK (fu_main_engine_changed_cb),
898 priv);
899 g_signal_connect (priv->engine, "device-added",
900 G_CALLBACK (fu_main_engine_device_added_cb),
901 priv);
902 g_signal_connect (priv->engine, "device-removed",
903 G_CALLBACK (fu_main_engine_device_removed_cb),
904 priv);
905 g_signal_connect (priv->engine, "device-changed",
906 G_CALLBACK (fu_main_engine_device_changed_cb),
907 priv);
908 g_signal_connect (priv->engine, "status-changed",
909 G_CALLBACK (fu_main_engine_status_changed_cb),
910 priv);
911 g_signal_connect (priv->engine, "percentage-changed",
912 G_CALLBACK (fu_main_engine_percentage_changed_cb),
913 priv);
914 if (!fu_engine_load (priv->engine, &error)) {
915 g_printerr ("Failed to load engine: %s\n", error->message);
Richard Hughesf29a6ee2017-06-02 19:50:37 +0100916 return EXIT_FAILURE;
Richard Hughes804c0752015-08-04 14:53:52 +0100917 }
918
Richard Hughes9945edb2017-06-19 10:03:55 +0100919 /* keep polling until all the plugins are ready */
920 g_timeout_add (200, fu_main_perhaps_own_name, priv);
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000921
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000922 /* load introspection from file */
923 priv->introspection_daemon = fu_main_load_introspection (FWUPD_DBUS_INTERFACE ".xml",
924 &error);
925 if (priv->introspection_daemon == NULL) {
Richard Hughesf29a6ee2017-06-02 19:50:37 +0100926 g_printerr ("Failed to load introspection: %s\n", error->message);
927 return EXIT_FAILURE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000928 }
929
Richard Hughesf508e762015-02-27 12:49:36 +0000930 /* get authority */
931 priv->authority = polkit_authority_get_sync (NULL, &error);
932 if (priv->authority == NULL) {
Richard Hughesf29a6ee2017-06-02 19:50:37 +0100933 g_printerr ("Failed to load authority: %s\n", error->message);
934 return EXIT_FAILURE;
Richard Hughesf508e762015-02-27 12:49:36 +0000935 }
936
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000937 /* Only timeout and close the mainloop if we have specified it
938 * on the command line */
939 if (immediate_exit)
940 g_idle_add (fu_main_timed_exit_cb, priv->loop);
941 else if (timed_exit)
942 g_timeout_add_seconds (5, fu_main_timed_exit_cb, priv->loop);
943
944 /* wait */
Richard Hughes4619f9f2017-06-14 13:55:30 +0100945 g_message ("Daemon ready for requests");
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000946 g_main_loop_run (priv->loop);
947
948 /* success */
Richard Hughesf29a6ee2017-06-02 19:50:37 +0100949 return EXIT_SUCCESS;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000950}