blob: 11eb8b2f029fdadbbc143ade064c7ee4c5095564 [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>
Mario Limonciello6d0aa3d2017-02-28 08:22:27 -060030#ifdef HAVE_VALGRIND
Richard Hughes576c0122017-02-24 09:47:00 +000031#include <valgrind.h>
Mario Limonciello6d0aa3d2017-02-28 08:22:27 -060032#endif /* HAVE_VALGRIND */
Richard Hughesd0905142016-03-13 09:46:49 +000033
Richard Hughescff38bc2016-12-12 12:03:37 +000034#include "fu-plugin-private.h"
35#include "fu-pending.h"
Richard Hughesd0905142016-03-13 09:46:49 +000036
Richard Hughesb0829032017-01-10 09:27:08 +000037#define FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM 3000u /* ms */
38
Richard Hughescff38bc2016-12-12 12:03:37 +000039static void fu_plugin_finalize (GObject *object);
40
41typedef struct {
42 GModule *module;
43 GUsbContext *usb_ctx;
44 gboolean enabled;
45 gchar *name;
46 GHashTable *devices; /* platform_id:GObject */
Richard Hughesae3d65f2016-12-16 09:38:01 +000047 GHashTable *devices_delay; /* FuDevice:FuPluginHelper */
Richard Hughescff38bc2016-12-12 12:03:37 +000048 FuPluginData *data;
49} FuPluginPrivate;
50
51enum {
52 SIGNAL_DEVICE_ADDED,
53 SIGNAL_DEVICE_REMOVED,
54 SIGNAL_STATUS_CHANGED,
55 SIGNAL_PERCENTAGE_CHANGED,
Richard Hughes362d6d72017-01-07 21:42:14 +000056 SIGNAL_RECOLDPLUG,
Richard Hughesb0829032017-01-10 09:27:08 +000057 SIGNAL_SET_COLDPLUG_DELAY,
Richard Hughescff38bc2016-12-12 12:03:37 +000058 SIGNAL_LAST
59};
60
61static guint signals[SIGNAL_LAST] = { 0 };
62
63G_DEFINE_TYPE_WITH_PRIVATE (FuPlugin, fu_plugin, G_TYPE_OBJECT)
64#define GET_PRIVATE(o) (fu_plugin_get_instance_private (o))
65
66typedef const gchar *(*FuPluginGetNameFunc) (void);
67typedef void (*FuPluginInitFunc) (FuPlugin *plugin);
68typedef gboolean (*FuPluginStartupFunc) (FuPlugin *plugin,
69 GError **error);
70typedef gboolean (*FuPluginDeviceFunc) (FuPlugin *plugin,
71 FuDevice *device,
72 GError **error);
73typedef gboolean (*FuPluginVerifyFunc) (FuPlugin *plugin,
74 FuDevice *device,
75 FuPluginVerifyFlags flags,
76 GError **error);
77typedef gboolean (*FuPluginUpdateFunc) (FuPlugin *plugin,
78 FuDevice *device,
79 GBytes *blob_fw,
80 FwupdInstallFlags flags,
81 GError **error);
82
Richard Hughes57d18222017-01-10 16:02:59 +000083/**
84 * fu_plugin_get_name:
85 * @plugin: A #FuPlugin
86 *
87 * Gets the plugin name.
88 *
89 * Returns: a plugin name, or %NULL for unknown.
90 *
91 * Since: 0.8.0
92 **/
Richard Hughescff38bc2016-12-12 12:03:37 +000093const gchar *
94fu_plugin_get_name (FuPlugin *plugin)
Richard Hughesd0905142016-03-13 09:46:49 +000095{
Richard Hughescff38bc2016-12-12 12:03:37 +000096 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughesccd78a92017-01-11 16:57:41 +000097 g_return_val_if_fail (FU_IS_PLUGIN (plugin), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +000098 return priv->name;
99}
Richard Hughesd0905142016-03-13 09:46:49 +0000100
Richard Hughes57d18222017-01-10 16:02:59 +0000101/**
102 * fu_plugin_cache_lookup:
103 * @plugin: A #FuPlugin
104 * @id: the key
105 *
106 * Finds an object in the per-plugin cache.
107 *
108 * Returns: (transfer none): a #GObject, or %NULL for unfound.
109 *
110 * Since: 0.8.0
111 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000112gpointer
113fu_plugin_cache_lookup (FuPlugin *plugin, const gchar *id)
114{
115 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughesccd78a92017-01-11 16:57:41 +0000116 g_return_val_if_fail (FU_IS_PLUGIN (plugin), NULL);
117 g_return_val_if_fail (id != NULL, NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000118 return g_hash_table_lookup (priv->devices, id);
119}
Richard Hughesd0905142016-03-13 09:46:49 +0000120
Richard Hughes57d18222017-01-10 16:02:59 +0000121/**
122 * fu_plugin_cache_add:
123 * @plugin: A #FuPlugin
124 * @id: the key
125 * @dev: a #GObject, typically a #FuDevice
126 *
127 * Adds an object to the per-plugin cache.
128 *
129 * Since: 0.8.0
130 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000131void
132fu_plugin_cache_add (FuPlugin *plugin, const gchar *id, gpointer dev)
133{
134 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughesccd78a92017-01-11 16:57:41 +0000135 g_return_if_fail (FU_IS_PLUGIN (plugin));
136 g_return_if_fail (id != NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000137 g_hash_table_insert (priv->devices, g_strdup (id), g_object_ref (dev));
138}
139
Richard Hughes57d18222017-01-10 16:02:59 +0000140/**
141 * fu_plugin_cache_remove:
142 * @plugin: A #FuPlugin
143 * @id: the key
144 *
145 * Removes an object from the per-plugin cache.
146 *
147 * Since: 0.8.0
148 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000149void
150fu_plugin_cache_remove (FuPlugin *plugin, const gchar *id)
151{
152 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughesccd78a92017-01-11 16:57:41 +0000153 g_return_if_fail (FU_IS_PLUGIN (plugin));
154 g_return_if_fail (id != NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000155 g_hash_table_remove (priv->devices, id);
156}
157
Richard Hughes57d18222017-01-10 16:02:59 +0000158/**
159 * fu_plugin_get_data:
160 * @plugin: A #FuPlugin
161 *
162 * Gets the per-plugin allocated private data.
163 *
164 * Returns: (transfer full): a pointer to a structure, or %NULL for unset.
165 *
166 * Since: 0.8.0
167 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000168FuPluginData *
169fu_plugin_get_data (FuPlugin *plugin)
170{
171 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughesccd78a92017-01-11 16:57:41 +0000172 g_return_val_if_fail (FU_IS_PLUGIN (plugin), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000173 return priv->data;
174}
175
Richard Hughes57d18222017-01-10 16:02:59 +0000176/**
177 * fu_plugin_alloc_data:
178 * @plugin: A #FuPlugin
179 * @data_sz: the size to allocate
180 *
181 * Allocates the per-plugin allocated private data.
182 *
183 * Returns: (transfer full): a pointer to a structure, or %NULL for unset.
184 *
185 * Since: 0.8.0
186 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000187FuPluginData *
188fu_plugin_alloc_data (FuPlugin *plugin, gsize data_sz)
189{
190 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughesccd78a92017-01-11 16:57:41 +0000191 g_return_val_if_fail (FU_IS_PLUGIN (plugin), NULL);
Richard Hughes44dee882017-01-11 08:31:10 +0000192 if (priv->data != NULL) {
193 g_critical ("fu_plugin_alloc_data() already used by plugin");
194 return priv->data;
195 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000196 priv->data = g_malloc0 (data_sz);
197 return priv->data;
Richard Hughesd0905142016-03-13 09:46:49 +0000198}
199
Richard Hughes57d18222017-01-10 16:02:59 +0000200/**
201 * fu_plugin_get_usb_context:
202 * @plugin: A #FuPlugin
203 *
204 * Gets the shared USB context that all plugins can use.
205 *
206 * Returns: (transfer none): a #GUsbContext.
207 *
208 * Since: 0.8.0
209 **/
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000210GUsbContext *
211fu_plugin_get_usb_context (FuPlugin *plugin)
212{
Richard Hughescff38bc2016-12-12 12:03:37 +0000213 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughesccd78a92017-01-11 16:57:41 +0000214 g_return_val_if_fail (FU_IS_PLUGIN (plugin), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000215 return priv->usb_ctx;
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000216}
217
218void
219fu_plugin_set_usb_context (FuPlugin *plugin, GUsbContext *usb_ctx)
220{
Richard Hughescff38bc2016-12-12 12:03:37 +0000221 FuPluginPrivate *priv = GET_PRIVATE (plugin);
222 g_set_object (&priv->usb_ctx, usb_ctx);
223}
224
Richard Hughes57d18222017-01-10 16:02:59 +0000225/**
226 * fu_plugin_get_enabled:
227 * @plugin: A #FuPlugin
228 *
229 * Returns if the plugin is enabled.
230 *
231 * Returns: %TRUE if the plugin is currently enabled.
232 *
233 * Since: 0.8.0
234 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000235gboolean
236fu_plugin_get_enabled (FuPlugin *plugin)
237{
238 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughesccd78a92017-01-11 16:57:41 +0000239 g_return_val_if_fail (FU_IS_PLUGIN (plugin), FALSE);
Richard Hughescff38bc2016-12-12 12:03:37 +0000240 return priv->enabled;
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000241}
242
Richard Hughes57d18222017-01-10 16:02:59 +0000243/**
244 * fu_plugin_set_enabled:
245 * @plugin: A #FuPlugin
246 * @enabled: the enabled value
247 *
248 * Enables or disables a plugin. Plugins can self-disable at any point.
249 *
250 * Since: 0.8.0
251 **/
Richard Hughesd0905142016-03-13 09:46:49 +0000252void
Richard Hughescff38bc2016-12-12 12:03:37 +0000253fu_plugin_set_enabled (FuPlugin *plugin, gboolean enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000254{
Richard Hughescff38bc2016-12-12 12:03:37 +0000255 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughesccd78a92017-01-11 16:57:41 +0000256 g_return_if_fail (FU_IS_PLUGIN (plugin));
Richard Hughescff38bc2016-12-12 12:03:37 +0000257 priv->enabled = enabled;
258}
259
260gboolean
261fu_plugin_open (FuPlugin *plugin, const gchar *filename, GError **error)
262{
263 FuPluginPrivate *priv = GET_PRIVATE (plugin);
264 FuPluginInitFunc func = NULL;
265 gchar *str;
266
267 priv->module = g_module_open (filename, 0);
268 if (priv->module == NULL) {
269 g_set_error (error,
270 G_IO_ERROR,
271 G_IO_ERROR_FAILED,
272 "failed to open plugin: %s",
273 g_module_error ());
274 return FALSE;
275 }
276
277 /* set automatically */
278 str = g_strstr_len (filename, -1, "libfu_plugin_");
279 if (str != NULL) {
280 priv->name = g_strdup (str + 13);
281 g_strdelimit (priv->name, ".", '\0');
282 }
Richard Hughesd0905142016-03-13 09:46:49 +0000283
284 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000285 g_module_symbol (priv->module, "fu_plugin_init", (gpointer *) &func);
286 if (func != NULL) {
287 g_debug ("performing init() on %s", filename);
Richard Hughesd0905142016-03-13 09:46:49 +0000288 func (plugin);
289 }
290
Richard Hughescff38bc2016-12-12 12:03:37 +0000291 return TRUE;
292}
293
Richard Hughes57d18222017-01-10 16:02:59 +0000294/**
295 * fu_plugin_device_add:
296 * @plugin: A #FuPlugin
297 * @device: A #FuDevice
298 *
299 * Asks the daemon to add a device to the exported list. If this device ID
300 * has already been added by a different plugin then this request will be
301 * ignored.
302 *
303 * Plugins should use fu_plugin_device_add_delay() if they are not capable of
304 * actually flashing an image to the hardware so that higher-priority plugins
305 * can add the device themselves.
306 *
307 * Since: 0.8.0
308 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000309void
310fu_plugin_device_add (FuPlugin *plugin, FuDevice *device)
311{
Richard Hughesccd78a92017-01-11 16:57:41 +0000312 g_return_if_fail (FU_IS_PLUGIN (plugin));
313 g_return_if_fail (FU_IS_DEVICE (device));
314
Richard Hughescff38bc2016-12-12 12:03:37 +0000315 g_debug ("emit added from %s: %s",
316 fu_plugin_get_name (plugin),
317 fu_device_get_id (device));
318 fu_device_set_created (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
319 fu_device_set_plugin (device, fu_plugin_get_name (plugin));
320 g_signal_emit (plugin, signals[SIGNAL_DEVICE_ADDED], 0, device);
321}
322
Richard Hughesae3d65f2016-12-16 09:38:01 +0000323typedef struct {
324 FuPlugin *plugin;
325 FuDevice *device;
326 guint timeout_id;
Richard Hughesd4184cf2016-12-21 16:05:17 +0000327 GHashTable *devices;
Richard Hughesae3d65f2016-12-16 09:38:01 +0000328} FuPluginHelper;
329
330static void
331fu_plugin_helper_free (FuPluginHelper *helper)
332{
333 g_object_unref (helper->plugin);
334 g_object_unref (helper->device);
Richard Hughesd4184cf2016-12-21 16:05:17 +0000335 g_hash_table_unref (helper->devices);
Richard Hughesae3d65f2016-12-16 09:38:01 +0000336 g_free (helper);
337}
338
339static gboolean
340fu_plugin_device_add_delay_cb (gpointer user_data)
341{
342 FuPluginHelper *helper = (FuPluginHelper *) user_data;
Richard Hughesf0a799e2017-01-17 20:13:30 +0000343 g_hash_table_remove (helper->devices, helper->device);
Richard Hughesae3d65f2016-12-16 09:38:01 +0000344 fu_plugin_device_add (helper->plugin, helper->device);
345 fu_plugin_helper_free (helper);
346 return FALSE;
347}
348
Richard Hughes57d18222017-01-10 16:02:59 +0000349/**
Richard Hughesf0a799e2017-01-17 20:13:30 +0000350 * fu_plugin_has_device_delay:
351 * @plugin: A #FuPlugin
352 *
353 * Returns if the device has a pending device that is waiting to be added.
354 *
355 * Returns: %TRUE if a device is waiting to be added
356 *
357 * Since: 0.8.0
358 **/
359gboolean
360fu_plugin_has_device_delay (FuPlugin *plugin)
361{
362 FuPluginPrivate *priv = GET_PRIVATE (plugin);
363 return g_hash_table_size (priv->devices_delay) > 0;
364}
365
366/**
Richard Hughes57d18222017-01-10 16:02:59 +0000367 * fu_plugin_device_add_delay:
368 * @plugin: A #FuPlugin
369 * @device: A #FuDevice
370 *
371 * Asks the daemon to add a device to the exported list after a small delay.
372 *
373 * Since: 0.8.0
374 **/
Richard Hughesae3d65f2016-12-16 09:38:01 +0000375void
376fu_plugin_device_add_delay (FuPlugin *plugin, FuDevice *device)
377{
378 FuPluginPrivate *priv = GET_PRIVATE (plugin);
379 FuPluginHelper *helper;
Richard Hughesccd78a92017-01-11 16:57:41 +0000380
381 g_return_if_fail (FU_IS_PLUGIN (plugin));
382 g_return_if_fail (FU_IS_DEVICE (device));
383
Richard Hughes6ad951d2017-02-03 10:12:12 +0000384 /* already waiting for add */
385 helper = g_hash_table_lookup (priv->devices_delay, device);
386 if (helper != NULL) {
387 g_warning ("ignoring add-delay as device %s already pending",
388 fu_device_get_id (device));
389 return;
390 }
391
392 /* add after a small delay */
Richard Hughesae3d65f2016-12-16 09:38:01 +0000393 g_debug ("waiting a small time for other plugins");
394 helper = g_new0 (FuPluginHelper, 1);
395 helper->plugin = g_object_ref (plugin);
396 helper->device = g_object_ref (device);
397 helper->timeout_id = g_timeout_add (500, fu_plugin_device_add_delay_cb, helper);
Richard Hughesd4184cf2016-12-21 16:05:17 +0000398 helper->devices = g_hash_table_ref (priv->devices_delay);
399 g_hash_table_insert (helper->devices, device, helper);
Richard Hughesae3d65f2016-12-16 09:38:01 +0000400}
401
Richard Hughes57d18222017-01-10 16:02:59 +0000402/**
403 * fu_plugin_device_add:
404 * @plugin: A #FuPlugin
405 * @device: A #FuDevice
406 *
407 * Asks the daemon to remove a device from the exported list.
408 *
409 * Since: 0.8.0
410 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000411void
412fu_plugin_device_remove (FuPlugin *plugin, FuDevice *device)
413{
Richard Hughesae3d65f2016-12-16 09:38:01 +0000414 FuPluginPrivate *priv = GET_PRIVATE (plugin);
415 FuPluginHelper *helper;
416
Richard Hughesccd78a92017-01-11 16:57:41 +0000417 g_return_if_fail (FU_IS_PLUGIN (plugin));
418 g_return_if_fail (FU_IS_DEVICE (device));
419
Richard Hughesae3d65f2016-12-16 09:38:01 +0000420 /* waiting for add */
421 helper = g_hash_table_lookup (priv->devices_delay, device);
422 if (helper != NULL) {
423 g_debug ("ignoring remove from delayed addition");
424 g_source_remove (helper->timeout_id);
Richard Hughesd4184cf2016-12-21 16:05:17 +0000425 g_hash_table_remove (priv->devices_delay, helper->device);
Richard Hughesae3d65f2016-12-16 09:38:01 +0000426 fu_plugin_helper_free (helper);
427 return;
428 }
429
Richard Hughescff38bc2016-12-12 12:03:37 +0000430 g_debug ("emit removed from %s: %s",
431 fu_plugin_get_name (plugin),
432 fu_device_get_id (device));
433 g_signal_emit (plugin, signals[SIGNAL_DEVICE_REMOVED], 0, device);
434}
435
Richard Hughes57d18222017-01-10 16:02:59 +0000436/**
437 * fu_plugin_set_status:
438 * @plugin: A #FuPlugin
439 * @status: A #FwupdStatus, e.g. #FWUPD_STATUS_DECOMPRESSING
440 *
441 * Sets the global state of the daemon according to the current plugin action.
442 *
443 * Since: 0.8.0
444 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000445void
446fu_plugin_set_status (FuPlugin *plugin, FwupdStatus status)
447{
Richard Hughesccd78a92017-01-11 16:57:41 +0000448 g_return_if_fail (FU_IS_PLUGIN (plugin));
Richard Hughescff38bc2016-12-12 12:03:37 +0000449 g_signal_emit (plugin, signals[SIGNAL_STATUS_CHANGED], 0, status);
450}
451
Richard Hughes57d18222017-01-10 16:02:59 +0000452/**
453 * fu_plugin_set_percentage:
454 * @plugin: A #FuPlugin
455 * @percentage: the percentage complete
456 *
457 * Sets the global completion of the daemon according to the current plugin
458 * action.
459 *
460 * Since: 0.8.0
461 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000462void
463fu_plugin_set_percentage (FuPlugin *plugin, guint percentage)
464{
Richard Hughesccd78a92017-01-11 16:57:41 +0000465 g_return_if_fail (FU_IS_PLUGIN (plugin));
466 g_return_if_fail (percentage <= 100);
Richard Hughescff38bc2016-12-12 12:03:37 +0000467 g_signal_emit (plugin, signals[SIGNAL_PERCENTAGE_CHANGED], 0,
468 percentage);
Richard Hughesd0905142016-03-13 09:46:49 +0000469}
470
Richard Hughes362d6d72017-01-07 21:42:14 +0000471/**
472 * fu_plugin_recoldplug:
473 * @plugin: A #FuPlugin
474 *
475 * Ask all the plugins to coldplug all devices, which will include the prepare()
476 * and cleanup() phases. Duplicate devices added will be ignored.
477 *
478 * Since: 0.8.0
479 **/
480void
481fu_plugin_recoldplug (FuPlugin *plugin)
482{
Richard Hughesccd78a92017-01-11 16:57:41 +0000483 g_return_if_fail (FU_IS_PLUGIN (plugin));
Richard Hughes362d6d72017-01-07 21:42:14 +0000484 g_signal_emit (plugin, signals[SIGNAL_RECOLDPLUG], 0);
485}
486
Richard Hughesb0829032017-01-10 09:27:08 +0000487/**
488 * fu_plugin_set_coldplug_delay:
489 * @plugin: A #FuPlugin
490 * @duration: A delay in milliseconds
491 *
492 * Set the minimum time that should be waited inbetween the call to
493 * fu_plugin_coldplug_prepare() and fu_plugin_coldplug(). This is usually going
494 * to be the minimum hardware initialisation time from a datasheet.
495 *
496 * It is better to use this function rather than using a sleep() in the plugin
497 * itself as then only one delay is done in the daemon rather than waiting for
498 * each coldplug prepare in a serial way.
499 *
500 * Additionally, very long delays should be avoided as the daemon will be
501 * blocked from processing requests whilst the coldplug delay is being
502 * performed.
503 *
504 * Since: 0.8.0
505 **/
506void
507fu_plugin_set_coldplug_delay (FuPlugin *plugin, guint duration)
508{
509 g_return_if_fail (FU_IS_PLUGIN (plugin));
510 g_return_if_fail (duration > 0);
511
512 /* check sanity */
513 if (duration > FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM) {
514 g_warning ("duration of %ums is crazy, truncating to %ums",
515 duration,
516 FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM);
517 duration = FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM;
518 }
519
520 /* emit */
521 g_signal_emit (plugin, signals[SIGNAL_SET_COLDPLUG_DELAY], 0, duration);
522}
523
Richard Hughesd0905142016-03-13 09:46:49 +0000524gboolean
Richard Hughescff38bc2016-12-12 12:03:37 +0000525fu_plugin_runner_startup (FuPlugin *plugin, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +0000526{
Richard Hughescff38bc2016-12-12 12:03:37 +0000527 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000528 FuPluginStartupFunc func = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +0000529
530 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +0000531 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000532 return TRUE;
533
534 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000535 g_module_symbol (priv->module, "fu_plugin_startup", (gpointer *) &func);
536 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +0000537 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +0000538 g_debug ("performing startup() on %s", priv->name);
Richard Hughesd0905142016-03-13 09:46:49 +0000539 if (!func (plugin, error)) {
Richard Hughescff38bc2016-12-12 12:03:37 +0000540 g_prefix_error (error, "failed to startup %s: ", priv->name);
541 return FALSE;
542 }
543 return TRUE;
544}
545
546static gboolean
547fu_plugin_runner_offline_invalidate (GError **error)
548{
549 g_autoptr(GError) error_local = NULL;
550 g_autoptr(GFile) file1 = NULL;
551
552 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
553
554 file1 = g_file_new_for_path (FU_OFFLINE_TRIGGER_FILENAME);
555 if (!g_file_query_exists (file1, NULL))
556 return TRUE;
557 if (!g_file_delete (file1, NULL, &error_local)) {
558 g_set_error (error,
559 FWUPD_ERROR,
560 FWUPD_ERROR_INTERNAL,
561 "Cannot delete %s: %s",
562 FU_OFFLINE_TRIGGER_FILENAME,
563 error_local->message);
564 return FALSE;
565 }
566 return TRUE;
567}
568
569static gboolean
570fu_plugin_runner_offline_setup (GError **error)
571{
572 gint rc;
573
574 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
575
576 /* create symlink for the systemd-system-update-generator */
577 rc = symlink ("/var/lib/fwupd", FU_OFFLINE_TRIGGER_FILENAME);
578 if (rc < 0) {
579 g_set_error (error,
580 FWUPD_ERROR,
581 FWUPD_ERROR_INTERNAL,
582 "Failed to create symlink %s to %s: %s",
583 FU_OFFLINE_TRIGGER_FILENAME,
584 "/var/lib", strerror (errno));
Richard Hughesd0905142016-03-13 09:46:49 +0000585 return FALSE;
586 }
587 return TRUE;
588}
589
Richard Hughesd0905142016-03-13 09:46:49 +0000590gboolean
Richard Hughescff38bc2016-12-12 12:03:37 +0000591fu_plugin_runner_coldplug (FuPlugin *plugin, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +0000592{
Richard Hughescff38bc2016-12-12 12:03:37 +0000593 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000594 FuPluginStartupFunc func = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +0000595
596 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +0000597 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000598 return TRUE;
599
600 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000601 g_module_symbol (priv->module, "fu_plugin_coldplug", (gpointer *) &func);
602 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +0000603 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +0000604 g_debug ("performing coldplug() on %s", priv->name);
605 if (!func (plugin, error)) {
606 g_prefix_error (error, "failed to coldplug %s: ", priv->name);
607 return FALSE;
608 }
609 return TRUE;
610}
611
Richard Hughes7b8b2022016-12-12 16:15:03 +0000612gboolean
Richard Hughes46487c92017-01-07 21:26:34 +0000613fu_plugin_runner_coldplug_prepare (FuPlugin *plugin, GError **error)
614{
615 FuPluginPrivate *priv = GET_PRIVATE (plugin);
616 FuPluginStartupFunc func = NULL;
617
618 /* not enabled */
619 if (!priv->enabled)
620 return TRUE;
621
622 /* optional */
623 g_module_symbol (priv->module, "fu_plugin_coldplug_prepare", (gpointer *) &func);
624 if (func == NULL)
625 return TRUE;
626 g_debug ("performing coldplug_prepare() on %s", priv->name);
627 if (!func (plugin, error)) {
628 g_prefix_error (error, "failed to prepare for coldplug %s: ", priv->name);
629 return FALSE;
630 }
631 return TRUE;
632}
633
634gboolean
635fu_plugin_runner_coldplug_cleanup (FuPlugin *plugin, GError **error)
636{
637 FuPluginPrivate *priv = GET_PRIVATE (plugin);
638 FuPluginStartupFunc func = NULL;
639
640 /* not enabled */
641 if (!priv->enabled)
642 return TRUE;
643
644 /* optional */
645 g_module_symbol (priv->module, "fu_plugin_coldplug_cleanup", (gpointer *) &func);
646 if (func == NULL)
647 return TRUE;
648 g_debug ("performing coldplug_cleanup() on %s", priv->name);
649 if (!func (plugin, error)) {
650 g_prefix_error (error, "failed to cleanup coldplug %s: ", priv->name);
651 return FALSE;
652 }
653 return TRUE;
654}
655
656gboolean
Richard Hughes7b8b2022016-12-12 16:15:03 +0000657fu_plugin_runner_update_prepare (FuPlugin *plugin, FuDevice *device, GError **error)
658{
659 FuPluginPrivate *priv = GET_PRIVATE (plugin);
660 FuPluginDeviceFunc func = NULL;
661
662 /* not enabled */
663 if (!priv->enabled)
664 return TRUE;
665
666 /* optional */
667 g_module_symbol (priv->module, "fu_plugin_update_prepare", (gpointer *) &func);
668 if (func == NULL)
669 return TRUE;
670 g_debug ("performing update_prepare() on %s", priv->name);
671 if (!func (plugin, device, error)) {
672 g_prefix_error (error, "failed to prepare for update %s: ", priv->name);
673 return FALSE;
674 }
675 return TRUE;
676}
677
678gboolean
679fu_plugin_runner_update_cleanup (FuPlugin *plugin, FuDevice *device, GError **error)
680{
681 FuPluginPrivate *priv = GET_PRIVATE (plugin);
682 FuPluginDeviceFunc func = NULL;
683
684 /* not enabled */
685 if (!priv->enabled)
686 return TRUE;
687
688 /* optional */
689 g_module_symbol (priv->module, "fu_plugin_update_cleanup", (gpointer *) &func);
690 if (func == NULL)
691 return TRUE;
692 g_debug ("performing update_cleanup() on %s", priv->name);
693 if (!func (plugin, device, error)) {
694 g_prefix_error (error, "failed to cleanup update %s: ", priv->name);
695 return FALSE;
696 }
697 return TRUE;
698}
699
Richard Hughescff38bc2016-12-12 12:03:37 +0000700static gboolean
701fu_plugin_runner_schedule_update (FuPlugin *plugin,
702 FuDevice *device,
703 GBytes *blob_cab,
704 GError **error)
705{
706 gchar tmpname[] = {"XXXXXX.cap"};
707 g_autofree gchar *dirname = NULL;
708 g_autofree gchar *filename = NULL;
709 g_autoptr(FwupdResult) res_tmp = NULL;
710 g_autoptr(FuPending) pending = NULL;
711 g_autoptr(GFile) file = NULL;
712
713 /* id already exists */
714 pending = fu_pending_new ();
715 res_tmp = fu_pending_get_device (pending, fu_device_get_id (device), NULL);
716 if (res_tmp != NULL) {
717 g_set_error (error,
718 FWUPD_ERROR,
719 FWUPD_ERROR_ALREADY_PENDING,
720 "%s is already scheduled to be updated",
721 fu_device_get_id (device));
722 return FALSE;
723 }
724
725 /* create directory */
726 dirname = g_build_filename (LOCALSTATEDIR, "lib", "fwupd", NULL);
727 file = g_file_new_for_path (dirname);
728 if (!g_file_query_exists (file, NULL)) {
729 if (!g_file_make_directory_with_parents (file, NULL, error))
730 return FALSE;
731 }
732
733 /* get a random filename */
734 for (guint i = 0; i < 6; i++)
735 tmpname[i] = (gchar) g_random_int_range ('A', 'Z');
736 filename = g_build_filename (dirname, tmpname, NULL);
737
738 /* just copy to the temp file */
739 fu_plugin_set_status (plugin, FWUPD_STATUS_SCHEDULING);
740 if (!g_file_set_contents (filename,
741 g_bytes_get_data (blob_cab, NULL),
742 (gssize) g_bytes_get_size (blob_cab),
743 error))
744 return FALSE;
745
746 /* schedule for next boot */
747 g_debug ("schedule %s to be installed to %s on next boot",
748 filename, fu_device_get_id (device));
749 fu_device_set_update_filename (device, filename);
750
751 /* add to database */
752 if (!fu_pending_add_device (pending, FWUPD_RESULT (device), error))
753 return FALSE;
754
755 /* next boot we run offline */
756 return fu_plugin_runner_offline_setup (error);
757}
758
759gboolean
760fu_plugin_runner_verify (FuPlugin *plugin,
761 FuDevice *device,
762 FuPluginVerifyFlags flags,
763 GError **error)
764{
765 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000766 FuPluginVerifyFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000767
768 /* not enabled */
769 if (!priv->enabled)
770 return TRUE;
771
772 /* optional */
773 g_module_symbol (priv->module, "fu_plugin_verify", (gpointer *) &func);
774 if (func == NULL)
775 return TRUE;
776 g_debug ("performing verify() on %s", priv->name);
777 if (!func (plugin, device, flags, error)) {
778 g_prefix_error (error, "failed to verify %s: ", priv->name);
Richard Hughesd0905142016-03-13 09:46:49 +0000779 return FALSE;
780 }
781 return TRUE;
782}
783
Richard Hughesd0905142016-03-13 09:46:49 +0000784gboolean
Richard Hughescff38bc2016-12-12 12:03:37 +0000785fu_plugin_runner_unlock (FuPlugin *plugin, FuDevice *device, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +0000786{
Richard Hughescff38bc2016-12-12 12:03:37 +0000787 guint64 flags;
788 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000789 FuPluginDeviceFunc func = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +0000790
791 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +0000792 if (!priv->enabled)
793 return TRUE;
794
795 /* final check */
796 flags = fu_device_get_flags (device);
797 if ((flags & FWUPD_DEVICE_FLAG_LOCKED) == 0) {
798 g_set_error (error,
799 FWUPD_ERROR,
800 FWUPD_ERROR_NOT_SUPPORTED,
801 "Device %s is not locked",
802 fu_device_get_id (device));
803 return FALSE;
804 }
805
806 /* optional */
807 g_module_symbol (priv->module, "fu_plugin_unlock", (gpointer *) &func);
808 if (func != NULL) {
809 g_debug ("performing unlock() on %s", priv->name);
810 if (!func (plugin, device, error)) {
Richard Hughes7b8b2022016-12-12 16:15:03 +0000811 g_prefix_error (error, "failed to unlock %s: ", priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +0000812 return FALSE;
813 }
814 }
815
816 /* update with correct flags */
817 flags = fu_device_get_flags (device);
818 fu_device_set_flags (device, flags &= ~FWUPD_DEVICE_FLAG_LOCKED);
819 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
820 return TRUE;
821}
822
823gboolean
824fu_plugin_runner_update (FuPlugin *plugin,
825 FuDevice *device,
826 GBytes *blob_cab,
827 GBytes *blob_fw,
828 FwupdInstallFlags flags,
829 GError **error)
830{
831 FuPluginPrivate *priv = GET_PRIVATE (plugin);
832 FuPluginUpdateFunc func_online;
833 FuPluginUpdateFunc func_offline;
834 g_autoptr(FuPending) pending = NULL;
835 g_autoptr(FwupdResult) res_pending = NULL;
836 GError *error_update = NULL;
837
838 /* not enabled */
839 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000840 return TRUE;
841
842 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000843 g_module_symbol (priv->module, "fu_plugin_update_online", (gpointer *) &func_online);
844 g_module_symbol (priv->module, "fu_plugin_update_offline", (gpointer *) &func_offline);
Richard Hughesd0905142016-03-13 09:46:49 +0000845
Richard Hughescff38bc2016-12-12 12:03:37 +0000846 /* schedule for next reboot, or handle in the plugin */
847 if (flags & FWUPD_INSTALL_FLAG_OFFLINE) {
848 if (func_offline == NULL) {
849 return fu_plugin_runner_schedule_update (plugin,
850 device,
851 blob_cab,
852 error);
853 }
854 return func_offline (plugin, device, blob_fw, flags, error);
855 }
856
857 /* cancel the pending action */
858 if (!fu_plugin_runner_offline_invalidate (error))
859 return FALSE;
860
861 /* online */
862 if (func_online == NULL) {
863 g_set_error_literal (error,
864 FWUPD_ERROR,
865 FWUPD_ERROR_NOT_SUPPORTED,
866 "No online update possible");
Richard Hughesd0905142016-03-13 09:46:49 +0000867 return FALSE;
868 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000869 pending = fu_pending_new ();
870 res_pending = fu_pending_get_device (pending, fu_device_get_id (device), NULL);
871 if (!func_online (plugin, device, blob_fw, flags, &error_update)) {
872 /* save the error to the database */
873 if (res_pending != NULL) {
874 fu_pending_set_error_msg (pending, FWUPD_RESULT (device),
875 error_update->message, NULL);
876 }
877 g_propagate_error (error, error_update);
878 return FALSE;
879 }
880
881 /* cleanup */
882 if (res_pending != NULL) {
883 const gchar *tmp;
884
885 /* update pending database */
886 fu_pending_set_state (pending, FWUPD_RESULT (device),
887 FWUPD_UPDATE_STATE_SUCCESS, NULL);
888
889 /* delete cab file */
890 tmp = fwupd_result_get_update_filename (res_pending);
891 if (tmp != NULL && g_str_has_prefix (tmp, LIBEXECDIR)) {
892 g_autoptr(GError) error_local = NULL;
893 g_autoptr(GFile) file = NULL;
894 file = g_file_new_for_path (tmp);
895 if (!g_file_delete (file, NULL, &error_local)) {
896 g_set_error (error,
897 FWUPD_ERROR,
898 FWUPD_ERROR_INVALID_FILE,
899 "Failed to delete %s: %s",
900 tmp, error_local->message);
901 return FALSE;
902 }
903 }
904 }
Richard Hughesd0905142016-03-13 09:46:49 +0000905 return TRUE;
906}
Richard Hughescff38bc2016-12-12 12:03:37 +0000907
908gboolean
909fu_plugin_runner_clear_results (FuPlugin *plugin, FuDevice *device, GError **error)
910{
911 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000912 FuPluginDeviceFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000913 g_autoptr(GError) error_local = NULL;
914 g_autoptr(FwupdResult) res_pending = NULL;
915 g_autoptr(FuPending) pending = NULL;
916
917 /* not enabled */
918 if (!priv->enabled)
919 return TRUE;
920
921 /* use the plugin if the vfunc is provided */
922 g_module_symbol (priv->module, "fu_plugin_clear_result", (gpointer *) &func);
923 if (func != NULL) {
924 g_debug ("performing clear_result() on %s", priv->name);
925 if (!func (plugin, device, error)) {
926 g_prefix_error (error, "failed to clear_result %s: ", priv->name);
927 return FALSE;
928 }
929 return TRUE;
930 }
931
932 /* handled using the database */
933 pending = fu_pending_new ();
934 res_pending = fu_pending_get_device (pending,
935 fu_device_get_id (device),
936 &error_local);
937 if (res_pending == NULL) {
938 g_set_error (error,
939 FWUPD_ERROR,
940 FWUPD_ERROR_INVALID_FILE,
941 "Failed to find %s in pending database: %s",
942 fu_device_get_id (device),
943 error_local->message);
944 return FALSE;
945 }
946
947 /* remove from pending database */
948 return fu_pending_remove_device (pending, FWUPD_RESULT (device), error);
949}
950
951gboolean
952fu_plugin_runner_get_results (FuPlugin *plugin, FuDevice *device, GError **error)
953{
954 FuPluginPrivate *priv = GET_PRIVATE (plugin);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000955 FuPluginDeviceFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000956 FwupdUpdateState update_state;
957 const gchar *tmp;
958 g_autoptr(GError) error_local = NULL;
959 g_autoptr(FwupdResult) res_pending = NULL;
960 g_autoptr(FuPending) pending = NULL;
961
962 /* not enabled */
963 if (!priv->enabled)
964 return TRUE;
965
966 /* use the plugin if the vfunc is provided */
967 g_module_symbol (priv->module, "fu_plugin_get_results", (gpointer *) &func);
968 if (func != NULL) {
969 g_debug ("performing get_results() on %s", priv->name);
970 if (!func (plugin, device, error)) {
971 g_prefix_error (error, "failed to get_results %s: ", priv->name);
972 return FALSE;
973 }
974 return TRUE;
975 }
976
977 /* handled using the database */
978 pending = fu_pending_new ();
979 res_pending = fu_pending_get_device (pending,
980 fu_device_get_id (device),
981 &error_local);
982 if (res_pending == NULL) {
983 g_set_error (error,
984 FWUPD_ERROR,
985 FWUPD_ERROR_NOTHING_TO_DO,
986 "Failed to find %s in pending database: %s",
987 fu_device_get_id (device),
988 error_local->message);
989 return FALSE;
990 }
991
992 /* copy the important parts from the pending device to the real one */
993 update_state = fwupd_result_get_update_state (res_pending);
994 if (update_state == FWUPD_UPDATE_STATE_UNKNOWN ||
995 update_state == FWUPD_UPDATE_STATE_PENDING) {
996 g_set_error (error,
997 FWUPD_ERROR,
998 FWUPD_ERROR_NOTHING_TO_DO,
999 "Device %s has not been updated offline yet",
1000 fu_device_get_id (device));
1001 return FALSE;
1002 }
1003
1004 /* copy */
1005 fu_device_set_update_state (device, update_state);
1006 tmp = fwupd_result_get_update_error (res_pending);
1007 if (tmp != NULL)
1008 fu_device_set_update_error (device, tmp);
1009 tmp = fwupd_result_get_device_version (res_pending);
1010 if (tmp != NULL)
1011 fu_device_set_version (device, tmp);
1012 tmp = fwupd_result_get_update_version (res_pending);
1013 if (tmp != NULL)
1014 fu_device_set_update_version (device, tmp);
1015 return TRUE;
1016}
1017
1018static void
1019fu_plugin_class_init (FuPluginClass *klass)
1020{
1021 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1022 object_class->finalize = fu_plugin_finalize;
1023 signals[SIGNAL_DEVICE_ADDED] =
1024 g_signal_new ("device-added",
1025 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
1026 G_STRUCT_OFFSET (FuPluginClass, device_added),
1027 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
1028 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
1029 signals[SIGNAL_DEVICE_REMOVED] =
1030 g_signal_new ("device-removed",
1031 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
1032 G_STRUCT_OFFSET (FuPluginClass, device_removed),
1033 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
1034 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
1035 signals[SIGNAL_STATUS_CHANGED] =
1036 g_signal_new ("status-changed",
1037 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
1038 G_STRUCT_OFFSET (FuPluginClass, status_changed),
1039 NULL, NULL, g_cclosure_marshal_VOID__UINT,
1040 G_TYPE_NONE, 1, G_TYPE_UINT);
1041 signals[SIGNAL_PERCENTAGE_CHANGED] =
1042 g_signal_new ("percentage-changed",
1043 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
1044 G_STRUCT_OFFSET (FuPluginClass, percentage_changed),
1045 NULL, NULL, g_cclosure_marshal_VOID__UINT,
1046 G_TYPE_NONE, 1, G_TYPE_UINT);
Richard Hughes362d6d72017-01-07 21:42:14 +00001047 signals[SIGNAL_RECOLDPLUG] =
1048 g_signal_new ("recoldplug",
1049 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
1050 G_STRUCT_OFFSET (FuPluginClass, recoldplug),
1051 NULL, NULL, g_cclosure_marshal_VOID__VOID,
1052 G_TYPE_NONE, 0);
Richard Hughesb0829032017-01-10 09:27:08 +00001053 signals[SIGNAL_SET_COLDPLUG_DELAY] =
1054 g_signal_new ("set-coldplug-delay",
1055 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
1056 G_STRUCT_OFFSET (FuPluginClass, set_coldplug_delay),
1057 NULL, NULL, g_cclosure_marshal_VOID__UINT,
1058 G_TYPE_NONE, 1, G_TYPE_UINT);
Richard Hughescff38bc2016-12-12 12:03:37 +00001059}
1060
1061static void
1062fu_plugin_init (FuPlugin *plugin)
1063{
1064 FuPluginPrivate *priv = GET_PRIVATE (plugin);
1065 priv->enabled = TRUE;
1066 priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal,
1067 g_free, (GDestroyNotify) g_object_unref);
Richard Hughesae3d65f2016-12-16 09:38:01 +00001068 priv->devices_delay = g_hash_table_new (g_str_hash, g_str_equal);
Richard Hughescff38bc2016-12-12 12:03:37 +00001069}
1070
1071static void
1072fu_plugin_finalize (GObject *object)
1073{
1074 FuPlugin *plugin = FU_PLUGIN (object);
1075 FuPluginPrivate *priv = GET_PRIVATE (plugin);
1076 FuPluginInitFunc func = NULL;
1077
1078 /* optional */
1079 if (priv->module != NULL) {
1080 g_module_symbol (priv->module, "fu_plugin_destroy", (gpointer *) &func);
1081 if (func != NULL) {
1082 g_debug ("performing destroy() on %s", priv->name);
1083 func (plugin);
1084 }
1085 }
1086
1087 if (priv->usb_ctx != NULL)
1088 g_object_unref (priv->usb_ctx);
Richard Hughes576c0122017-02-24 09:47:00 +00001089#ifndef RUNNING_ON_VALGRIND
Richard Hughescff38bc2016-12-12 12:03:37 +00001090 if (priv->module != NULL)
1091 g_module_close (priv->module);
Richard Hughes576c0122017-02-24 09:47:00 +00001092#endif
Richard Hughescff38bc2016-12-12 12:03:37 +00001093 g_hash_table_unref (priv->devices);
Richard Hughesae3d65f2016-12-16 09:38:01 +00001094 g_hash_table_unref (priv->devices_delay);
Richard Hughescff38bc2016-12-12 12:03:37 +00001095 g_free (priv->name);
1096 g_free (priv->data);
1097
1098 G_OBJECT_CLASS (fu_plugin_parent_class)->finalize (object);
1099}
1100
1101FuPlugin *
1102fu_plugin_new (void)
1103{
1104 FuPlugin *plugin;
1105 plugin = g_object_new (FU_TYPE_PLUGIN, NULL);
1106 return plugin;
1107}
1108
1109GChecksumType
1110fu_plugin_get_checksum_type (FuPluginVerifyFlags flags)
1111{
1112 if (flags & FU_PLUGIN_VERIFY_FLAG_USE_SHA256)
1113 return G_CHECKSUM_SHA256;
1114 return G_CHECKSUM_SHA1;
1115}