blob: a0b92905ffae5afd1416dfd26fe026d9313b18c5 [file] [log] [blame]
Richard Hughesd0905142016-03-13 09:46:49 +00001/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2016 Richard Hughes <richard@hughsie.com>
4 *
5 * Licensed under the GNU General Public License Version 2
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22#include "config.h"
23
Richard Hughescff38bc2016-12-12 12:03:37 +000024#include <fwupd.h>
25#include <gmodule.h>
26#include <appstream-glib.h>
27#include <errno.h>
28#include <string.h>
29#include <gio/gunixinputstream.h>
Richard Hughesd0905142016-03-13 09:46:49 +000030
Richard Hughescff38bc2016-12-12 12:03:37 +000031#include "fu-plugin-private.h"
32#include "fu-pending.h"
Richard Hughesd0905142016-03-13 09:46:49 +000033
Richard Hughescff38bc2016-12-12 12:03:37 +000034static void fu_plugin_finalize (GObject *object);
35
36typedef struct {
37 GModule *module;
38 GUsbContext *usb_ctx;
39 gboolean enabled;
40 gchar *name;
41 GHashTable *devices; /* platform_id:GObject */
42 FuPluginData *data;
43} FuPluginPrivate;
44
45enum {
46 SIGNAL_DEVICE_ADDED,
47 SIGNAL_DEVICE_REMOVED,
48 SIGNAL_STATUS_CHANGED,
49 SIGNAL_PERCENTAGE_CHANGED,
50 SIGNAL_LAST
51};
52
53static guint signals[SIGNAL_LAST] = { 0 };
54
55G_DEFINE_TYPE_WITH_PRIVATE (FuPlugin, fu_plugin, G_TYPE_OBJECT)
56#define GET_PRIVATE(o) (fu_plugin_get_instance_private (o))
57
58typedef const gchar *(*FuPluginGetNameFunc) (void);
59typedef void (*FuPluginInitFunc) (FuPlugin *plugin);
60typedef gboolean (*FuPluginStartupFunc) (FuPlugin *plugin,
61 GError **error);
62typedef gboolean (*FuPluginDeviceFunc) (FuPlugin *plugin,
63 FuDevice *device,
64 GError **error);
65typedef gboolean (*FuPluginVerifyFunc) (FuPlugin *plugin,
66 FuDevice *device,
67 FuPluginVerifyFlags flags,
68 GError **error);
69typedef gboolean (*FuPluginUpdateFunc) (FuPlugin *plugin,
70 FuDevice *device,
71 GBytes *blob_fw,
72 FwupdInstallFlags flags,
73 GError **error);
74
75const gchar *
76fu_plugin_get_name (FuPlugin *plugin)
Richard Hughesd0905142016-03-13 09:46:49 +000077{
Richard Hughescff38bc2016-12-12 12:03:37 +000078 FuPluginPrivate *priv = GET_PRIVATE (plugin);
79 return priv->name;
80}
Richard Hughesd0905142016-03-13 09:46:49 +000081
Richard Hughescff38bc2016-12-12 12:03:37 +000082void
83fu_plugin_set_name (FuPlugin *plugin, const gchar *name)
84{
85 FuPluginPrivate *priv = GET_PRIVATE (plugin);
86 g_free (priv->name);
87 priv->name = g_strdup (name);
88}
Richard Hughesd0905142016-03-13 09:46:49 +000089
Richard Hughescff38bc2016-12-12 12:03:37 +000090gpointer
91fu_plugin_cache_lookup (FuPlugin *plugin, const gchar *id)
92{
93 FuPluginPrivate *priv = GET_PRIVATE (plugin);
94 return g_hash_table_lookup (priv->devices, id);
95}
Richard Hughesd0905142016-03-13 09:46:49 +000096
Richard Hughescff38bc2016-12-12 12:03:37 +000097void
98fu_plugin_cache_add (FuPlugin *plugin, const gchar *id, gpointer dev)
99{
100 FuPluginPrivate *priv = GET_PRIVATE (plugin);
101 g_hash_table_insert (priv->devices, g_strdup (id), g_object_ref (dev));
102}
103
104void
105fu_plugin_cache_remove (FuPlugin *plugin, const gchar *id)
106{
107 FuPluginPrivate *priv = GET_PRIVATE (plugin);
108 g_hash_table_remove (priv->devices, id);
109}
110
111FuPluginData *
112fu_plugin_get_data (FuPlugin *plugin)
113{
114 FuPluginPrivate *priv = GET_PRIVATE (plugin);
115 return priv->data;
116}
117
118FuPluginData *
119fu_plugin_alloc_data (FuPlugin *plugin, gsize data_sz)
120{
121 FuPluginPrivate *priv = GET_PRIVATE (plugin);
122 priv->data = g_malloc0 (data_sz);
123 return priv->data;
Richard Hughesd0905142016-03-13 09:46:49 +0000124}
125
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000126GUsbContext *
127fu_plugin_get_usb_context (FuPlugin *plugin)
128{
Richard Hughescff38bc2016-12-12 12:03:37 +0000129 FuPluginPrivate *priv = GET_PRIVATE (plugin);
130 return priv->usb_ctx;
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000131}
132
133void
134fu_plugin_set_usb_context (FuPlugin *plugin, GUsbContext *usb_ctx)
135{
Richard Hughescff38bc2016-12-12 12:03:37 +0000136 FuPluginPrivate *priv = GET_PRIVATE (plugin);
137 g_set_object (&priv->usb_ctx, usb_ctx);
138}
139
140gboolean
141fu_plugin_get_enabled (FuPlugin *plugin)
142{
143 FuPluginPrivate *priv = GET_PRIVATE (plugin);
144 return priv->enabled;
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000145}
146
Richard Hughesd0905142016-03-13 09:46:49 +0000147void
Richard Hughescff38bc2016-12-12 12:03:37 +0000148fu_plugin_set_enabled (FuPlugin *plugin, gboolean enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000149{
Richard Hughescff38bc2016-12-12 12:03:37 +0000150 FuPluginPrivate *priv = GET_PRIVATE (plugin);
151 priv->enabled = enabled;
152}
153
154gboolean
155fu_plugin_open (FuPlugin *plugin, const gchar *filename, GError **error)
156{
157 FuPluginPrivate *priv = GET_PRIVATE (plugin);
158 FuPluginInitFunc func = NULL;
159 gchar *str;
160
161 priv->module = g_module_open (filename, 0);
162 if (priv->module == NULL) {
163 g_set_error (error,
164 G_IO_ERROR,
165 G_IO_ERROR_FAILED,
166 "failed to open plugin: %s",
167 g_module_error ());
168 return FALSE;
169 }
170
171 /* set automatically */
172 str = g_strstr_len (filename, -1, "libfu_plugin_");
173 if (str != NULL) {
174 priv->name = g_strdup (str + 13);
175 g_strdelimit (priv->name, ".", '\0');
176 }
Richard Hughesd0905142016-03-13 09:46:49 +0000177
178 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000179 g_module_symbol (priv->module, "fu_plugin_init", (gpointer *) &func);
180 if (func != NULL) {
181 g_debug ("performing init() on %s", filename);
Richard Hughesd0905142016-03-13 09:46:49 +0000182 func (plugin);
183 }
184
Richard Hughescff38bc2016-12-12 12:03:37 +0000185 return TRUE;
186}
187
188void
189fu_plugin_device_add (FuPlugin *plugin, FuDevice *device)
190{
191 g_debug ("emit added from %s: %s",
192 fu_plugin_get_name (plugin),
193 fu_device_get_id (device));
194 fu_device_set_created (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
195 fu_device_set_plugin (device, fu_plugin_get_name (plugin));
196 g_signal_emit (plugin, signals[SIGNAL_DEVICE_ADDED], 0, device);
197}
198
199void
200fu_plugin_device_remove (FuPlugin *plugin, FuDevice *device)
201{
202 g_debug ("emit removed from %s: %s",
203 fu_plugin_get_name (plugin),
204 fu_device_get_id (device));
205 g_signal_emit (plugin, signals[SIGNAL_DEVICE_REMOVED], 0, device);
206}
207
208void
209fu_plugin_set_status (FuPlugin *plugin, FwupdStatus status)
210{
211 g_signal_emit (plugin, signals[SIGNAL_STATUS_CHANGED], 0, status);
212}
213
214void
215fu_plugin_set_percentage (FuPlugin *plugin, guint percentage)
216{
217 g_signal_emit (plugin, signals[SIGNAL_PERCENTAGE_CHANGED], 0,
218 percentage);
Richard Hughesd0905142016-03-13 09:46:49 +0000219}
220
Richard Hughesd0905142016-03-13 09:46:49 +0000221gboolean
Richard Hughescff38bc2016-12-12 12:03:37 +0000222fu_plugin_runner_startup (FuPlugin *plugin, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +0000223{
Richard Hughescff38bc2016-12-12 12:03:37 +0000224 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000225 FuPluginStartupFunc func = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +0000226
227 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +0000228 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000229 return TRUE;
230
231 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000232 g_module_symbol (priv->module, "fu_plugin_startup", (gpointer *) &func);
233 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +0000234 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +0000235 g_debug ("performing startup() on %s", priv->name);
Richard Hughesd0905142016-03-13 09:46:49 +0000236 if (!func (plugin, error)) {
Richard Hughescff38bc2016-12-12 12:03:37 +0000237 g_prefix_error (error, "failed to startup %s: ", priv->name);
238 return FALSE;
239 }
240 return TRUE;
241}
242
243static gboolean
244fu_plugin_runner_offline_invalidate (GError **error)
245{
246 g_autoptr(GError) error_local = NULL;
247 g_autoptr(GFile) file1 = NULL;
248
249 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
250
251 file1 = g_file_new_for_path (FU_OFFLINE_TRIGGER_FILENAME);
252 if (!g_file_query_exists (file1, NULL))
253 return TRUE;
254 if (!g_file_delete (file1, NULL, &error_local)) {
255 g_set_error (error,
256 FWUPD_ERROR,
257 FWUPD_ERROR_INTERNAL,
258 "Cannot delete %s: %s",
259 FU_OFFLINE_TRIGGER_FILENAME,
260 error_local->message);
261 return FALSE;
262 }
263 return TRUE;
264}
265
266static gboolean
267fu_plugin_runner_offline_setup (GError **error)
268{
269 gint rc;
270
271 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
272
273 /* create symlink for the systemd-system-update-generator */
274 rc = symlink ("/var/lib/fwupd", FU_OFFLINE_TRIGGER_FILENAME);
275 if (rc < 0) {
276 g_set_error (error,
277 FWUPD_ERROR,
278 FWUPD_ERROR_INTERNAL,
279 "Failed to create symlink %s to %s: %s",
280 FU_OFFLINE_TRIGGER_FILENAME,
281 "/var/lib", strerror (errno));
Richard Hughesd0905142016-03-13 09:46:49 +0000282 return FALSE;
283 }
284 return TRUE;
285}
286
Richard Hughesd0905142016-03-13 09:46:49 +0000287gboolean
Richard Hughescff38bc2016-12-12 12:03:37 +0000288fu_plugin_runner_coldplug (FuPlugin *plugin, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +0000289{
Richard Hughescff38bc2016-12-12 12:03:37 +0000290 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000291 FuPluginStartupFunc func = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +0000292
293 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +0000294 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000295 return TRUE;
296
297 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000298 g_module_symbol (priv->module, "fu_plugin_coldplug", (gpointer *) &func);
299 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +0000300 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +0000301 g_debug ("performing coldplug() on %s", priv->name);
302 if (!func (plugin, error)) {
303 g_prefix_error (error, "failed to coldplug %s: ", priv->name);
304 return FALSE;
305 }
306 return TRUE;
307}
308
Richard Hughes7b8b2022016-12-12 16:15:03 +0000309gboolean
310fu_plugin_runner_update_prepare (FuPlugin *plugin, FuDevice *device, GError **error)
311{
312 FuPluginPrivate *priv = GET_PRIVATE (plugin);
313 FuPluginDeviceFunc func = NULL;
314
315 /* not enabled */
316 if (!priv->enabled)
317 return TRUE;
318
319 /* optional */
320 g_module_symbol (priv->module, "fu_plugin_update_prepare", (gpointer *) &func);
321 if (func == NULL)
322 return TRUE;
323 g_debug ("performing update_prepare() on %s", priv->name);
324 if (!func (plugin, device, error)) {
325 g_prefix_error (error, "failed to prepare for update %s: ", priv->name);
326 return FALSE;
327 }
328 return TRUE;
329}
330
331gboolean
332fu_plugin_runner_update_cleanup (FuPlugin *plugin, FuDevice *device, GError **error)
333{
334 FuPluginPrivate *priv = GET_PRIVATE (plugin);
335 FuPluginDeviceFunc func = NULL;
336
337 /* not enabled */
338 if (!priv->enabled)
339 return TRUE;
340
341 /* optional */
342 g_module_symbol (priv->module, "fu_plugin_update_cleanup", (gpointer *) &func);
343 if (func == NULL)
344 return TRUE;
345 g_debug ("performing update_cleanup() on %s", priv->name);
346 if (!func (plugin, device, error)) {
347 g_prefix_error (error, "failed to cleanup update %s: ", priv->name);
348 return FALSE;
349 }
350 return TRUE;
351}
352
Richard Hughescff38bc2016-12-12 12:03:37 +0000353static gboolean
354fu_plugin_runner_schedule_update (FuPlugin *plugin,
355 FuDevice *device,
356 GBytes *blob_cab,
357 GError **error)
358{
359 gchar tmpname[] = {"XXXXXX.cap"};
360 g_autofree gchar *dirname = NULL;
361 g_autofree gchar *filename = NULL;
362 g_autoptr(FwupdResult) res_tmp = NULL;
363 g_autoptr(FuPending) pending = NULL;
364 g_autoptr(GFile) file = NULL;
365
366 /* id already exists */
367 pending = fu_pending_new ();
368 res_tmp = fu_pending_get_device (pending, fu_device_get_id (device), NULL);
369 if (res_tmp != NULL) {
370 g_set_error (error,
371 FWUPD_ERROR,
372 FWUPD_ERROR_ALREADY_PENDING,
373 "%s is already scheduled to be updated",
374 fu_device_get_id (device));
375 return FALSE;
376 }
377
378 /* create directory */
379 dirname = g_build_filename (LOCALSTATEDIR, "lib", "fwupd", NULL);
380 file = g_file_new_for_path (dirname);
381 if (!g_file_query_exists (file, NULL)) {
382 if (!g_file_make_directory_with_parents (file, NULL, error))
383 return FALSE;
384 }
385
386 /* get a random filename */
387 for (guint i = 0; i < 6; i++)
388 tmpname[i] = (gchar) g_random_int_range ('A', 'Z');
389 filename = g_build_filename (dirname, tmpname, NULL);
390
391 /* just copy to the temp file */
392 fu_plugin_set_status (plugin, FWUPD_STATUS_SCHEDULING);
393 if (!g_file_set_contents (filename,
394 g_bytes_get_data (blob_cab, NULL),
395 (gssize) g_bytes_get_size (blob_cab),
396 error))
397 return FALSE;
398
399 /* schedule for next boot */
400 g_debug ("schedule %s to be installed to %s on next boot",
401 filename, fu_device_get_id (device));
402 fu_device_set_update_filename (device, filename);
403
404 /* add to database */
405 if (!fu_pending_add_device (pending, FWUPD_RESULT (device), error))
406 return FALSE;
407
408 /* next boot we run offline */
409 return fu_plugin_runner_offline_setup (error);
410}
411
412gboolean
413fu_plugin_runner_verify (FuPlugin *plugin,
414 FuDevice *device,
415 FuPluginVerifyFlags flags,
416 GError **error)
417{
418 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000419 FuPluginVerifyFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000420
421 /* not enabled */
422 if (!priv->enabled)
423 return TRUE;
424
425 /* optional */
426 g_module_symbol (priv->module, "fu_plugin_verify", (gpointer *) &func);
427 if (func == NULL)
428 return TRUE;
429 g_debug ("performing verify() on %s", priv->name);
430 if (!func (plugin, device, flags, error)) {
431 g_prefix_error (error, "failed to verify %s: ", priv->name);
Richard Hughesd0905142016-03-13 09:46:49 +0000432 return FALSE;
433 }
434 return TRUE;
435}
436
Richard Hughesd0905142016-03-13 09:46:49 +0000437gboolean
Richard Hughescff38bc2016-12-12 12:03:37 +0000438fu_plugin_runner_unlock (FuPlugin *plugin, FuDevice *device, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +0000439{
Richard Hughescff38bc2016-12-12 12:03:37 +0000440 guint64 flags;
441 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000442 FuPluginDeviceFunc func = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +0000443
444 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +0000445 if (!priv->enabled)
446 return TRUE;
447
448 /* final check */
449 flags = fu_device_get_flags (device);
450 if ((flags & FWUPD_DEVICE_FLAG_LOCKED) == 0) {
451 g_set_error (error,
452 FWUPD_ERROR,
453 FWUPD_ERROR_NOT_SUPPORTED,
454 "Device %s is not locked",
455 fu_device_get_id (device));
456 return FALSE;
457 }
458
459 /* optional */
460 g_module_symbol (priv->module, "fu_plugin_unlock", (gpointer *) &func);
461 if (func != NULL) {
462 g_debug ("performing unlock() on %s", priv->name);
463 if (!func (plugin, device, error)) {
Richard Hughes7b8b2022016-12-12 16:15:03 +0000464 g_prefix_error (error, "failed to unlock %s: ", priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +0000465 return FALSE;
466 }
467 }
468
469 /* update with correct flags */
470 flags = fu_device_get_flags (device);
471 fu_device_set_flags (device, flags &= ~FWUPD_DEVICE_FLAG_LOCKED);
472 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
473 return TRUE;
474}
475
476gboolean
477fu_plugin_runner_update (FuPlugin *plugin,
478 FuDevice *device,
479 GBytes *blob_cab,
480 GBytes *blob_fw,
481 FwupdInstallFlags flags,
482 GError **error)
483{
484 FuPluginPrivate *priv = GET_PRIVATE (plugin);
485 FuPluginUpdateFunc func_online;
486 FuPluginUpdateFunc func_offline;
487 g_autoptr(FuPending) pending = NULL;
488 g_autoptr(FwupdResult) res_pending = NULL;
489 GError *error_update = NULL;
490
491 /* not enabled */
492 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000493 return TRUE;
494
495 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000496 g_module_symbol (priv->module, "fu_plugin_update_online", (gpointer *) &func_online);
497 g_module_symbol (priv->module, "fu_plugin_update_offline", (gpointer *) &func_offline);
Richard Hughesd0905142016-03-13 09:46:49 +0000498
Richard Hughescff38bc2016-12-12 12:03:37 +0000499 /* schedule for next reboot, or handle in the plugin */
500 if (flags & FWUPD_INSTALL_FLAG_OFFLINE) {
501 if (func_offline == NULL) {
502 return fu_plugin_runner_schedule_update (plugin,
503 device,
504 blob_cab,
505 error);
506 }
507 return func_offline (plugin, device, blob_fw, flags, error);
508 }
509
510 /* cancel the pending action */
511 if (!fu_plugin_runner_offline_invalidate (error))
512 return FALSE;
513
514 /* online */
515 if (func_online == NULL) {
516 g_set_error_literal (error,
517 FWUPD_ERROR,
518 FWUPD_ERROR_NOT_SUPPORTED,
519 "No online update possible");
Richard Hughesd0905142016-03-13 09:46:49 +0000520 return FALSE;
521 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000522 pending = fu_pending_new ();
523 res_pending = fu_pending_get_device (pending, fu_device_get_id (device), NULL);
524 if (!func_online (plugin, device, blob_fw, flags, &error_update)) {
525 /* save the error to the database */
526 if (res_pending != NULL) {
527 fu_pending_set_error_msg (pending, FWUPD_RESULT (device),
528 error_update->message, NULL);
529 }
530 g_propagate_error (error, error_update);
531 return FALSE;
532 }
533
534 /* cleanup */
535 if (res_pending != NULL) {
536 const gchar *tmp;
537
538 /* update pending database */
539 fu_pending_set_state (pending, FWUPD_RESULT (device),
540 FWUPD_UPDATE_STATE_SUCCESS, NULL);
541
542 /* delete cab file */
543 tmp = fwupd_result_get_update_filename (res_pending);
544 if (tmp != NULL && g_str_has_prefix (tmp, LIBEXECDIR)) {
545 g_autoptr(GError) error_local = NULL;
546 g_autoptr(GFile) file = NULL;
547 file = g_file_new_for_path (tmp);
548 if (!g_file_delete (file, NULL, &error_local)) {
549 g_set_error (error,
550 FWUPD_ERROR,
551 FWUPD_ERROR_INVALID_FILE,
552 "Failed to delete %s: %s",
553 tmp, error_local->message);
554 return FALSE;
555 }
556 }
557 }
Richard Hughesd0905142016-03-13 09:46:49 +0000558 return TRUE;
559}
Richard Hughescff38bc2016-12-12 12:03:37 +0000560
561gboolean
562fu_plugin_runner_clear_results (FuPlugin *plugin, FuDevice *device, GError **error)
563{
564 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000565 FuPluginDeviceFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000566 g_autoptr(GError) error_local = NULL;
567 g_autoptr(FwupdResult) res_pending = NULL;
568 g_autoptr(FuPending) pending = NULL;
569
570 /* not enabled */
571 if (!priv->enabled)
572 return TRUE;
573
574 /* use the plugin if the vfunc is provided */
575 g_module_symbol (priv->module, "fu_plugin_clear_result", (gpointer *) &func);
576 if (func != NULL) {
577 g_debug ("performing clear_result() on %s", priv->name);
578 if (!func (plugin, device, error)) {
579 g_prefix_error (error, "failed to clear_result %s: ", priv->name);
580 return FALSE;
581 }
582 return TRUE;
583 }
584
585 /* handled using the database */
586 pending = fu_pending_new ();
587 res_pending = fu_pending_get_device (pending,
588 fu_device_get_id (device),
589 &error_local);
590 if (res_pending == NULL) {
591 g_set_error (error,
592 FWUPD_ERROR,
593 FWUPD_ERROR_INVALID_FILE,
594 "Failed to find %s in pending database: %s",
595 fu_device_get_id (device),
596 error_local->message);
597 return FALSE;
598 }
599
600 /* remove from pending database */
601 return fu_pending_remove_device (pending, FWUPD_RESULT (device), error);
602}
603
604gboolean
605fu_plugin_runner_get_results (FuPlugin *plugin, FuDevice *device, GError **error)
606{
607 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000608 FuPluginDeviceFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000609 FwupdUpdateState update_state;
610 const gchar *tmp;
611 g_autoptr(GError) error_local = NULL;
612 g_autoptr(FwupdResult) res_pending = NULL;
613 g_autoptr(FuPending) pending = NULL;
614
615 /* not enabled */
616 if (!priv->enabled)
617 return TRUE;
618
619 /* use the plugin if the vfunc is provided */
620 g_module_symbol (priv->module, "fu_plugin_get_results", (gpointer *) &func);
621 if (func != NULL) {
622 g_debug ("performing get_results() on %s", priv->name);
623 if (!func (plugin, device, error)) {
624 g_prefix_error (error, "failed to get_results %s: ", priv->name);
625 return FALSE;
626 }
627 return TRUE;
628 }
629
630 /* handled using the database */
631 pending = fu_pending_new ();
632 res_pending = fu_pending_get_device (pending,
633 fu_device_get_id (device),
634 &error_local);
635 if (res_pending == NULL) {
636 g_set_error (error,
637 FWUPD_ERROR,
638 FWUPD_ERROR_NOTHING_TO_DO,
639 "Failed to find %s in pending database: %s",
640 fu_device_get_id (device),
641 error_local->message);
642 return FALSE;
643 }
644
645 /* copy the important parts from the pending device to the real one */
646 update_state = fwupd_result_get_update_state (res_pending);
647 if (update_state == FWUPD_UPDATE_STATE_UNKNOWN ||
648 update_state == FWUPD_UPDATE_STATE_PENDING) {
649 g_set_error (error,
650 FWUPD_ERROR,
651 FWUPD_ERROR_NOTHING_TO_DO,
652 "Device %s has not been updated offline yet",
653 fu_device_get_id (device));
654 return FALSE;
655 }
656
657 /* copy */
658 fu_device_set_update_state (device, update_state);
659 tmp = fwupd_result_get_update_error (res_pending);
660 if (tmp != NULL)
661 fu_device_set_update_error (device, tmp);
662 tmp = fwupd_result_get_device_version (res_pending);
663 if (tmp != NULL)
664 fu_device_set_version (device, tmp);
665 tmp = fwupd_result_get_update_version (res_pending);
666 if (tmp != NULL)
667 fu_device_set_update_version (device, tmp);
668 return TRUE;
669}
670
671static void
672fu_plugin_class_init (FuPluginClass *klass)
673{
674 GObjectClass *object_class = G_OBJECT_CLASS (klass);
675 object_class->finalize = fu_plugin_finalize;
676 signals[SIGNAL_DEVICE_ADDED] =
677 g_signal_new ("device-added",
678 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
679 G_STRUCT_OFFSET (FuPluginClass, device_added),
680 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
681 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
682 signals[SIGNAL_DEVICE_REMOVED] =
683 g_signal_new ("device-removed",
684 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
685 G_STRUCT_OFFSET (FuPluginClass, device_removed),
686 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
687 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
688 signals[SIGNAL_STATUS_CHANGED] =
689 g_signal_new ("status-changed",
690 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
691 G_STRUCT_OFFSET (FuPluginClass, status_changed),
692 NULL, NULL, g_cclosure_marshal_VOID__UINT,
693 G_TYPE_NONE, 1, G_TYPE_UINT);
694 signals[SIGNAL_PERCENTAGE_CHANGED] =
695 g_signal_new ("percentage-changed",
696 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
697 G_STRUCT_OFFSET (FuPluginClass, percentage_changed),
698 NULL, NULL, g_cclosure_marshal_VOID__UINT,
699 G_TYPE_NONE, 1, G_TYPE_UINT);
700}
701
702static void
703fu_plugin_init (FuPlugin *plugin)
704{
705 FuPluginPrivate *priv = GET_PRIVATE (plugin);
706 priv->enabled = TRUE;
707 priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal,
708 g_free, (GDestroyNotify) g_object_unref);
709}
710
711static void
712fu_plugin_finalize (GObject *object)
713{
714 FuPlugin *plugin = FU_PLUGIN (object);
715 FuPluginPrivate *priv = GET_PRIVATE (plugin);
716 FuPluginInitFunc func = NULL;
717
718 /* optional */
719 if (priv->module != NULL) {
720 g_module_symbol (priv->module, "fu_plugin_destroy", (gpointer *) &func);
721 if (func != NULL) {
722 g_debug ("performing destroy() on %s", priv->name);
723 func (plugin);
724 }
725 }
726
727 if (priv->usb_ctx != NULL)
728 g_object_unref (priv->usb_ctx);
729 if (priv->module != NULL)
730 g_module_close (priv->module);
731 g_hash_table_unref (priv->devices);
732 g_free (priv->name);
733 g_free (priv->data);
734
735 G_OBJECT_CLASS (fu_plugin_parent_class)->finalize (object);
736}
737
738FuPlugin *
739fu_plugin_new (void)
740{
741 FuPlugin *plugin;
742 plugin = g_object_new (FU_TYPE_PLUGIN, NULL);
743 return plugin;
744}
745
746GChecksumType
747fu_plugin_get_checksum_type (FuPluginVerifyFlags flags)
748{
749 if (flags & FU_PLUGIN_VERIFY_FLAG_USE_SHA256)
750 return G_CHECKSUM_SHA256;
751 return G_CHECKSUM_SHA1;
752}