blob: f4881c0891cb1825313111aaf2896da18a1d6f9d [file] [log] [blame]
Richard Hughes02c90d82018-08-09 12:13:03 +01001/*
Richard Hughes2de8f132018-01-17 09:12:02 +00002 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
Richard Hughesd0905142016-03-13 09:46:49 +00003 *
Mario Limonciello51308e62018-05-28 20:05:46 -05004 * SPDX-License-Identifier: LGPL-2.1+
Richard Hughesd0905142016-03-13 09:46:49 +00005 */
6
Richard Hughesb08e7bc2018-09-11 10:51:13 +01007#define G_LOG_DOMAIN "FuPlugin"
8
Richard Hughesd0905142016-03-13 09:46:49 +00009#include "config.h"
10
Richard Hughescff38bc2016-12-12 12:03:37 +000011#include <fwupd.h>
12#include <gmodule.h>
Richard Hughescff38bc2016-12-12 12:03:37 +000013#include <errno.h>
14#include <string.h>
Richard Hughes68f12dd2018-08-09 14:43:31 +010015#include <unistd.h>
Mario Limonciello6d0aa3d2017-02-28 08:22:27 -060016#ifdef HAVE_VALGRIND
Richard Hughes576c0122017-02-24 09:47:00 +000017#include <valgrind.h>
Mario Limonciello6d0aa3d2017-02-28 08:22:27 -060018#endif /* HAVE_VALGRIND */
Richard Hughesd0905142016-03-13 09:46:49 +000019
Richard Hughes9dde04f2017-09-13 12:07:15 +010020#include "fu-device-private.h"
Richard Hughescff38bc2016-12-12 12:03:37 +000021#include "fu-plugin-private.h"
Richard Hughes37d09432018-09-09 10:39:45 +010022#include "fu-mutex.h"
Richard Hughesd0905142016-03-13 09:46:49 +000023
Richard Hughes4eada342017-10-03 21:20:32 +010024/**
25 * SECTION:fu-plugin
26 * @short_description: a daemon plugin
27 *
28 * An object that represents a plugin run by the daemon.
29 *
30 * See also: #FuDevice
31 */
32
Richard Hughesb0829032017-01-10 09:27:08 +000033#define FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM 3000u /* ms */
34
Richard Hughescff38bc2016-12-12 12:03:37 +000035static void fu_plugin_finalize (GObject *object);
36
37typedef struct {
38 GModule *module;
39 GUsbContext *usb_ctx;
40 gboolean enabled;
Richard Hughes08a37992017-09-12 12:57:43 +010041 guint order;
Richard Hughes81c427c2018-08-06 15:20:17 +010042 guint priority;
Richard Hughes08a37992017-09-12 12:57:43 +010043 GPtrArray *rules[FU_PLUGIN_RULE_LAST];
Richard Hughescff38bc2016-12-12 12:03:37 +000044 gchar *name;
Richard Hughesf425d292019-01-18 17:57:39 +000045 gchar *build_hash;
Richard Hughesd7704d42017-08-08 20:29:09 +010046 FuHwids *hwids;
Richard Hughes9c028f02017-10-28 21:14:28 +010047 FuQuirks *quirks;
Richard Hughes0eb123b2018-04-19 12:00:04 +010048 GHashTable *runtime_versions;
Richard Hughes34e0dab2018-04-20 16:43:00 +010049 GHashTable *compile_versions;
Richard Hughes9d6e0e72018-08-24 20:20:17 +010050 GPtrArray *udev_subsystems;
Richard Hughes1354ea92017-09-19 15:58:31 +010051 FuSmbios *smbios;
Richard Hughes989acf12019-10-05 20:16:47 +010052 GType device_gtype;
Richard Hughes371f6b22020-06-22 15:21:17 +010053 GHashTable *devices; /* (nullable): platform_id:GObject */
Richard Hughes161e9b52019-06-12 14:22:45 +010054 GRWLock devices_mutex;
Richard Hughes1d900f72020-06-22 15:17:39 +010055 GHashTable *report_metadata; /* (nullable): key:value */
Richard Hughescff38bc2016-12-12 12:03:37 +000056 FuPluginData *data;
57} FuPluginPrivate;
58
59enum {
60 SIGNAL_DEVICE_ADDED,
61 SIGNAL_DEVICE_REMOVED,
Richard Hughese1fd34d2017-08-24 14:19:51 +010062 SIGNAL_DEVICE_REGISTER,
Richard Hughes75b965d2018-11-15 13:51:21 +000063 SIGNAL_RULES_CHANGED,
Richard Hughes362d6d72017-01-07 21:42:14 +000064 SIGNAL_RECOLDPLUG,
Richard Hughesb0829032017-01-10 09:27:08 +000065 SIGNAL_SET_COLDPLUG_DELAY,
Richard Hughesaabdc372018-11-14 10:11:08 +000066 SIGNAL_CHECK_SUPPORTED,
Richard Hughes95c98a92019-10-22 16:03:15 +010067 SIGNAL_ADD_FIRMWARE_GTYPE,
Richard Hughes399859e2020-05-11 19:44:03 +010068 SIGNAL_SECURITY_CHANGED,
Richard Hughescff38bc2016-12-12 12:03:37 +000069 SIGNAL_LAST
70};
71
72static guint signals[SIGNAL_LAST] = { 0 };
73
74G_DEFINE_TYPE_WITH_PRIVATE (FuPlugin, fu_plugin, G_TYPE_OBJECT)
75#define GET_PRIVATE(o) (fu_plugin_get_instance_private (o))
76
77typedef const gchar *(*FuPluginGetNameFunc) (void);
Richard Hughes12724852018-09-04 13:53:44 +010078typedef void (*FuPluginInitFunc) (FuPlugin *self);
79typedef gboolean (*FuPluginStartupFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000080 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010081typedef void (*FuPluginDeviceRegisterFunc) (FuPlugin *self,
Richard Hughese1fd34d2017-08-24 14:19:51 +010082 FuDevice *device);
Richard Hughes12724852018-09-04 13:53:44 +010083typedef gboolean (*FuPluginDeviceFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000084 FuDevice *device,
85 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010086typedef gboolean (*FuPluginFlaggedDeviceFunc) (FuPlugin *self,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -050087 FwupdInstallFlags flags,
88 FuDevice *device,
89 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010090typedef gboolean (*FuPluginDeviceArrayFunc) (FuPlugin *self,
Richard Hughesdbd8c762018-06-15 20:31:40 +010091 GPtrArray *devices,
92 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010093typedef gboolean (*FuPluginVerifyFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000094 FuDevice *device,
95 FuPluginVerifyFlags flags,
96 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010097typedef gboolean (*FuPluginUpdateFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000098 FuDevice *device,
99 GBytes *blob_fw,
100 FwupdInstallFlags flags,
101 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +0100102typedef gboolean (*FuPluginUsbDeviceAddedFunc) (FuPlugin *self,
Richard Hughesff704412018-09-04 11:28:32 +0100103 FuUsbDevice *device,
Richard Hughes104f6512017-11-24 11:44:57 +0000104 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +0100105typedef gboolean (*FuPluginUdevDeviceAddedFunc) (FuPlugin *self,
Richard Hughesff704412018-09-04 11:28:32 +0100106 FuUdevDevice *device,
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100107 GError **error);
Richard Hughesf58ac732020-05-12 15:23:44 +0100108typedef void (*FuPluginSecurityAttrsFunc) (FuPlugin *self,
109 FuSecurityAttrs *attrs);
Richard Hughescff38bc2016-12-12 12:03:37 +0000110
Richard Hughes57d18222017-01-10 16:02:59 +0000111/**
Mario Limonciello52e75ba2019-11-22 13:21:19 -0600112 * fu_plugin_is_open:
113 * @self: A #FuPlugin
114 *
115 * Determines if the plugin is opened
116 *
117 * Returns: TRUE for opened, FALSE for not
118 *
119 * Since: 1.3.5
120 **/
121gboolean
122fu_plugin_is_open (FuPlugin *self)
123{
124 FuPluginPrivate *priv = GET_PRIVATE (self);
125 return priv->module != NULL;
126}
127
128/**
Richard Hughes57d18222017-01-10 16:02:59 +0000129 * fu_plugin_get_name:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100130 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000131 *
132 * Gets the plugin name.
133 *
134 * Returns: a plugin name, or %NULL for unknown.
135 *
136 * Since: 0.8.0
137 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000138const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100139fu_plugin_get_name (FuPlugin *self)
Richard Hughesd0905142016-03-13 09:46:49 +0000140{
Richard Hughes12724852018-09-04 13:53:44 +0100141 FuPluginPrivate *priv = GET_PRIVATE (self);
142 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000143 return priv->name;
144}
Richard Hughesd0905142016-03-13 09:46:49 +0000145
Mario Limonciello1a680f32019-11-25 19:44:53 -0600146/**
147 * fu_plugin_set_name:
148 * @self: A #FuPlugin
149 * @name: A string
150 *
151 * Sets the plugin name.
152 *
153 * Since: 0.8.0
154 **/
Richard Hughes34834102017-11-21 21:55:00 +0000155void
Richard Hughes12724852018-09-04 13:53:44 +0100156fu_plugin_set_name (FuPlugin *self, const gchar *name)
Richard Hughes34834102017-11-21 21:55:00 +0000157{
Richard Hughes12724852018-09-04 13:53:44 +0100158 FuPluginPrivate *priv = GET_PRIVATE (self);
159 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughes34834102017-11-21 21:55:00 +0000160 g_return_if_fail (name != NULL);
161 g_free (priv->name);
162 priv->name = g_strdup (name);
163}
164
Richard Hughes57d18222017-01-10 16:02:59 +0000165/**
Richard Hughesf425d292019-01-18 17:57:39 +0000166 * fu_plugin_set_build_hash:
167 * @self: A #FuPlugin
168 * @build_hash: A checksum
169 *
170 * Sets the plugin build hash, typically a SHA256 checksum. All plugins must
171 * set the correct checksum to avoid the daemon being marked as tainted.
172 *
173 * Since: 1.2.4
174 **/
175void
176fu_plugin_set_build_hash (FuPlugin *self, const gchar *build_hash)
177{
178 FuPluginPrivate *priv = GET_PRIVATE (self);
179 g_return_if_fail (FU_IS_PLUGIN (self));
180 g_return_if_fail (build_hash != NULL);
181 g_free (priv->build_hash);
182 priv->build_hash = g_strdup (build_hash);
183}
184
Mario Limonciello1a680f32019-11-25 19:44:53 -0600185/**
186 * fu_plugin_get_build_hash:
187 * @self: A #FuPlugin
188 *
189 * Gets the build hash a plugin was generated with.
190 *
191 * Returns: (transfer none): a #gchar, or %NULL for unset.
192 *
193 * Since: 1.2.4
194 **/
Richard Hughesf425d292019-01-18 17:57:39 +0000195const gchar *
196fu_plugin_get_build_hash (FuPlugin *self)
197{
198 FuPluginPrivate *priv = GET_PRIVATE (self);
199 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
200 return priv->build_hash;
201}
202
203/**
Richard Hughes57d18222017-01-10 16:02:59 +0000204 * fu_plugin_cache_lookup:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100205 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000206 * @id: the key
207 *
208 * Finds an object in the per-plugin cache.
209 *
210 * Returns: (transfer none): a #GObject, or %NULL for unfound.
211 *
212 * Since: 0.8.0
213 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000214gpointer
Richard Hughes12724852018-09-04 13:53:44 +0100215fu_plugin_cache_lookup (FuPlugin *self, const gchar *id)
Richard Hughescff38bc2016-12-12 12:03:37 +0000216{
Richard Hughes12724852018-09-04 13:53:44 +0100217 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes161e9b52019-06-12 14:22:45 +0100218 g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100219 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughesccd78a92017-01-11 16:57:41 +0000220 g_return_val_if_fail (id != NULL, NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100221 g_return_val_if_fail (locker != NULL, NULL);
Richard Hughes371f6b22020-06-22 15:21:17 +0100222 if (priv->devices == NULL)
223 return NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000224 return g_hash_table_lookup (priv->devices, id);
225}
Richard Hughesd0905142016-03-13 09:46:49 +0000226
Richard Hughes57d18222017-01-10 16:02:59 +0000227/**
228 * fu_plugin_cache_add:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100229 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000230 * @id: the key
231 * @dev: a #GObject, typically a #FuDevice
232 *
233 * Adds an object to the per-plugin cache.
234 *
235 * Since: 0.8.0
236 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000237void
Richard Hughes12724852018-09-04 13:53:44 +0100238fu_plugin_cache_add (FuPlugin *self, const gchar *id, gpointer dev)
Richard Hughescff38bc2016-12-12 12:03:37 +0000239{
Richard Hughes12724852018-09-04 13:53:44 +0100240 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0fe49142019-11-22 16:56:38 +0000241 g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100242 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000243 g_return_if_fail (id != NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100244 g_return_if_fail (locker != NULL);
Richard Hughes371f6b22020-06-22 15:21:17 +0100245 if (priv->devices == NULL) {
246 priv->devices = g_hash_table_new_full (g_str_hash,
247 g_str_equal,
248 g_free,
249 (GDestroyNotify) g_object_unref);
250 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000251 g_hash_table_insert (priv->devices, g_strdup (id), g_object_ref (dev));
252}
253
Richard Hughes57d18222017-01-10 16:02:59 +0000254/**
255 * fu_plugin_cache_remove:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100256 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000257 * @id: the key
258 *
259 * Removes an object from the per-plugin cache.
260 *
261 * Since: 0.8.0
262 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000263void
Richard Hughes12724852018-09-04 13:53:44 +0100264fu_plugin_cache_remove (FuPlugin *self, const gchar *id)
Richard Hughescff38bc2016-12-12 12:03:37 +0000265{
Richard Hughes12724852018-09-04 13:53:44 +0100266 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0fe49142019-11-22 16:56:38 +0000267 g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100268 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000269 g_return_if_fail (id != NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100270 g_return_if_fail (locker != NULL);
Richard Hughes371f6b22020-06-22 15:21:17 +0100271 if (priv->devices == NULL)
272 return;
Richard Hughescff38bc2016-12-12 12:03:37 +0000273 g_hash_table_remove (priv->devices, id);
274}
275
Richard Hughes57d18222017-01-10 16:02:59 +0000276/**
277 * fu_plugin_get_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100278 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000279 *
Richard Hughes4eada342017-10-03 21:20:32 +0100280 * Gets the per-plugin allocated private data. This will return %NULL unless
281 * fu_plugin_alloc_data() has been called by the plugin.
Richard Hughes57d18222017-01-10 16:02:59 +0000282 *
Richard Hughes4eada342017-10-03 21:20:32 +0100283 * Returns: (transfer none): a pointer to a structure, or %NULL for unset.
Richard Hughes57d18222017-01-10 16:02:59 +0000284 *
285 * Since: 0.8.0
286 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000287FuPluginData *
Richard Hughes12724852018-09-04 13:53:44 +0100288fu_plugin_get_data (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +0000289{
Richard Hughes12724852018-09-04 13:53:44 +0100290 FuPluginPrivate *priv = GET_PRIVATE (self);
291 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000292 return priv->data;
293}
294
Richard Hughes57d18222017-01-10 16:02:59 +0000295/**
Richard Hughes00f66f62019-11-27 11:42:53 +0000296 * fu_plugin_alloc_data: (skip):
Richard Hughes2c0635a2018-09-04 14:52:46 +0100297 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000298 * @data_sz: the size to allocate
299 *
300 * Allocates the per-plugin allocated private data.
301 *
302 * Returns: (transfer full): a pointer to a structure, or %NULL for unset.
303 *
304 * Since: 0.8.0
305 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000306FuPluginData *
Richard Hughes12724852018-09-04 13:53:44 +0100307fu_plugin_alloc_data (FuPlugin *self, gsize data_sz)
Richard Hughescff38bc2016-12-12 12:03:37 +0000308{
Richard Hughes12724852018-09-04 13:53:44 +0100309 FuPluginPrivate *priv = GET_PRIVATE (self);
310 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes44dee882017-01-11 08:31:10 +0000311 if (priv->data != NULL) {
312 g_critical ("fu_plugin_alloc_data() already used by plugin");
313 return priv->data;
314 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000315 priv->data = g_malloc0 (data_sz);
316 return priv->data;
Richard Hughesd0905142016-03-13 09:46:49 +0000317}
318
Richard Hughes57d18222017-01-10 16:02:59 +0000319/**
320 * fu_plugin_get_usb_context:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100321 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000322 *
323 * Gets the shared USB context that all plugins can use.
324 *
325 * Returns: (transfer none): a #GUsbContext.
326 *
327 * Since: 0.8.0
328 **/
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000329GUsbContext *
Richard Hughes12724852018-09-04 13:53:44 +0100330fu_plugin_get_usb_context (FuPlugin *self)
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000331{
Richard Hughes12724852018-09-04 13:53:44 +0100332 FuPluginPrivate *priv = GET_PRIVATE (self);
333 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000334 return priv->usb_ctx;
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000335}
336
Mario Limonciello1a680f32019-11-25 19:44:53 -0600337/**
338 * fu_plugin_set_usb_context:
339 * @self: A #FuPlugin
340 * @usb_ctx: A #FGUsbContext
341 *
342 * Sets the shared USB context for a plugin
343 *
344 * Since: 0.8.0
345 **/
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000346void
Richard Hughes12724852018-09-04 13:53:44 +0100347fu_plugin_set_usb_context (FuPlugin *self, GUsbContext *usb_ctx)
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000348{
Richard Hughes12724852018-09-04 13:53:44 +0100349 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +0000350 g_set_object (&priv->usb_ctx, usb_ctx);
351}
352
Richard Hughes57d18222017-01-10 16:02:59 +0000353/**
354 * fu_plugin_get_enabled:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100355 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000356 *
Richard Hughes4eada342017-10-03 21:20:32 +0100357 * Returns if the plugin is enabled. Plugins may self-disable using
358 * fu_plugin_set_enabled() or can be disabled by the daemon.
Richard Hughes57d18222017-01-10 16:02:59 +0000359 *
360 * Returns: %TRUE if the plugin is currently enabled.
361 *
362 * Since: 0.8.0
363 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000364gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100365fu_plugin_get_enabled (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +0000366{
Richard Hughes12724852018-09-04 13:53:44 +0100367 FuPluginPrivate *priv = GET_PRIVATE (self);
368 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
Richard Hughescff38bc2016-12-12 12:03:37 +0000369 return priv->enabled;
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000370}
371
Richard Hughes57d18222017-01-10 16:02:59 +0000372/**
373 * fu_plugin_set_enabled:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100374 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000375 * @enabled: the enabled value
376 *
377 * Enables or disables a plugin. Plugins can self-disable at any point.
378 *
379 * Since: 0.8.0
380 **/
Richard Hughesd0905142016-03-13 09:46:49 +0000381void
Richard Hughes12724852018-09-04 13:53:44 +0100382fu_plugin_set_enabled (FuPlugin *self, gboolean enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000383{
Richard Hughes12724852018-09-04 13:53:44 +0100384 FuPluginPrivate *priv = GET_PRIVATE (self);
385 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughescff38bc2016-12-12 12:03:37 +0000386 priv->enabled = enabled;
387}
388
Mario Limonciello1a680f32019-11-25 19:44:53 -0600389/**
390 * fu_plugin_guess_name_from_fn:
391 * @filename: filename to guess
392 *
393 * Tries to guess the name of the plugin from a filename
394 *
395 * Returns: (transfer full): the guessed name of the plugin
396 *
397 * Since: 1.0.8
398 **/
Richard Hughes1e456bc2018-05-10 20:16:16 +0100399gchar *
400fu_plugin_guess_name_from_fn (const gchar *filename)
401{
402 const gchar *prefix = "libfu_plugin_";
403 gchar *name;
404 gchar *str = g_strstr_len (filename, -1, prefix);
405 if (str == NULL)
406 return NULL;
407 name = g_strdup (str + strlen (prefix));
408 g_strdelimit (name, ".", '\0');
409 return name;
410}
411
Mario Limonciello1a680f32019-11-25 19:44:53 -0600412/**
413 * fu_plugin_open:
414 * @self: A #FuPlugin
415 * @filename: The shared object filename to open
416 * @error: A #GError or NULL
417 *
418 * Opens the plugin module
419 *
420 * Returns: TRUE for success, FALSE for fail
421 *
422 * Since: 0.8.0
423 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000424gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100425fu_plugin_open (FuPlugin *self, const gchar *filename, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +0000426{
Richard Hughes12724852018-09-04 13:53:44 +0100427 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +0000428 FuPluginInitFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000429
430 priv->module = g_module_open (filename, 0);
431 if (priv->module == NULL) {
432 g_set_error (error,
433 G_IO_ERROR,
434 G_IO_ERROR_FAILED,
Mario Limonciellof5605532019-11-04 07:49:50 -0600435 "failed to open plugin %s: %s",
436 filename, g_module_error ());
Richard Hughescff38bc2016-12-12 12:03:37 +0000437 return FALSE;
438 }
439
440 /* set automatically */
Richard Hughes1e456bc2018-05-10 20:16:16 +0100441 if (priv->name == NULL)
442 priv->name = fu_plugin_guess_name_from_fn (filename);
Richard Hughesd0905142016-03-13 09:46:49 +0000443
444 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000445 g_module_symbol (priv->module, "fu_plugin_init", (gpointer *) &func);
446 if (func != NULL) {
447 g_debug ("performing init() on %s", filename);
Richard Hughes12724852018-09-04 13:53:44 +0100448 func (self);
Richard Hughesd0905142016-03-13 09:46:49 +0000449 }
450
Richard Hughescff38bc2016-12-12 12:03:37 +0000451 return TRUE;
452}
453
Richard Hughes57d18222017-01-10 16:02:59 +0000454/**
455 * fu_plugin_device_add:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100456 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000457 * @device: A #FuDevice
458 *
459 * Asks the daemon to add a device to the exported list. If this device ID
460 * has already been added by a different plugin then this request will be
461 * ignored.
462 *
463 * Plugins should use fu_plugin_device_add_delay() if they are not capable of
464 * actually flashing an image to the hardware so that higher-priority plugins
465 * can add the device themselves.
466 *
467 * Since: 0.8.0
468 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000469void
Richard Hughes12724852018-09-04 13:53:44 +0100470fu_plugin_device_add (FuPlugin *self, FuDevice *device)
Richard Hughescff38bc2016-12-12 12:03:37 +0000471{
Richard Hughes5e447292018-04-27 14:25:54 +0100472 GPtrArray *children;
Richard Hughesc125ec02018-09-05 19:35:17 +0100473 g_autoptr(GError) error = NULL;
Richard Hughes5e447292018-04-27 14:25:54 +0100474
Richard Hughes12724852018-09-04 13:53:44 +0100475 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000476 g_return_if_fail (FU_IS_DEVICE (device));
477
Richard Hughesc125ec02018-09-05 19:35:17 +0100478 /* ensure the device ID is set from the physical and logical IDs */
479 if (!fu_device_ensure_id (device, &error)) {
480 g_warning ("ignoring add: %s", error->message);
481 return;
482 }
483
Richard Hughescff38bc2016-12-12 12:03:37 +0000484 g_debug ("emit added from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100485 fu_plugin_get_name (self),
Richard Hughescff38bc2016-12-12 12:03:37 +0000486 fu_device_get_id (device));
487 fu_device_set_created (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
Richard Hughes12724852018-09-04 13:53:44 +0100488 fu_device_set_plugin (device, fu_plugin_get_name (self));
489 g_signal_emit (self, signals[SIGNAL_DEVICE_ADDED], 0, device);
Richard Hughes5e447292018-04-27 14:25:54 +0100490
Richard Hughes128c0162018-08-10 11:00:29 +0100491 /* add children if they have not already been added */
Richard Hughes5e447292018-04-27 14:25:54 +0100492 children = fu_device_get_children (device);
493 for (guint i = 0; i < children->len; i++) {
494 FuDevice *child = g_ptr_array_index (children, i);
Richard Hughes128c0162018-08-10 11:00:29 +0100495 if (fu_device_get_created (child) == 0)
Richard Hughes12724852018-09-04 13:53:44 +0100496 fu_plugin_device_add (self, child);
Richard Hughes5e447292018-04-27 14:25:54 +0100497 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000498}
499
Richard Hughese1fd34d2017-08-24 14:19:51 +0100500/**
501 * fu_plugin_device_register:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100502 * @self: A #FuPlugin
Richard Hughese1fd34d2017-08-24 14:19:51 +0100503 * @device: A #FuDevice
504 *
505 * Registers the device with other plugins so they can set metadata.
506 *
507 * Plugins do not have to call this manually as this is done automatically
508 * when using fu_plugin_device_add(). They may wish to use this manually
Richard Hughes21eaeef2020-01-14 12:10:01 +0000509 * if for instance the coldplug should be ignored based on the metadata
Richard Hughese1fd34d2017-08-24 14:19:51 +0100510 * set from other plugins.
511 *
512 * Since: 0.9.7
513 **/
514void
Richard Hughes12724852018-09-04 13:53:44 +0100515fu_plugin_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +0100516{
Richard Hughesc125ec02018-09-05 19:35:17 +0100517 g_autoptr(GError) error = NULL;
518
Richard Hughes12724852018-09-04 13:53:44 +0100519 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughese1fd34d2017-08-24 14:19:51 +0100520 g_return_if_fail (FU_IS_DEVICE (device));
521
Richard Hughesc125ec02018-09-05 19:35:17 +0100522 /* ensure the device ID is set from the physical and logical IDs */
523 if (!fu_device_ensure_id (device, &error)) {
524 g_warning ("ignoring registration: %s", error->message);
525 return;
526 }
527
Richard Hughese1fd34d2017-08-24 14:19:51 +0100528 g_debug ("emit device-register from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100529 fu_plugin_get_name (self),
Richard Hughese1fd34d2017-08-24 14:19:51 +0100530 fu_device_get_id (device));
Richard Hughes12724852018-09-04 13:53:44 +0100531 g_signal_emit (self, signals[SIGNAL_DEVICE_REGISTER], 0, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +0100532}
533
Richard Hughes57d18222017-01-10 16:02:59 +0000534/**
Richard Hughes4eada342017-10-03 21:20:32 +0100535 * fu_plugin_device_remove:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100536 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000537 * @device: A #FuDevice
538 *
539 * Asks the daemon to remove a device from the exported list.
540 *
541 * Since: 0.8.0
542 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000543void
Richard Hughes12724852018-09-04 13:53:44 +0100544fu_plugin_device_remove (FuPlugin *self, FuDevice *device)
Richard Hughescff38bc2016-12-12 12:03:37 +0000545{
Richard Hughes12724852018-09-04 13:53:44 +0100546 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000547 g_return_if_fail (FU_IS_DEVICE (device));
548
Richard Hughescff38bc2016-12-12 12:03:37 +0000549 g_debug ("emit removed from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100550 fu_plugin_get_name (self),
Richard Hughescff38bc2016-12-12 12:03:37 +0000551 fu_device_get_id (device));
Richard Hughes12724852018-09-04 13:53:44 +0100552 g_signal_emit (self, signals[SIGNAL_DEVICE_REMOVED], 0, device);
Richard Hughescff38bc2016-12-12 12:03:37 +0000553}
554
Richard Hughes57d18222017-01-10 16:02:59 +0000555/**
Richard Hughes2de8f132018-01-17 09:12:02 +0000556 * fu_plugin_request_recoldplug:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100557 * @self: A #FuPlugin
Richard Hughes362d6d72017-01-07 21:42:14 +0000558 *
559 * Ask all the plugins to coldplug all devices, which will include the prepare()
560 * and cleanup() phases. Duplicate devices added will be ignored.
561 *
562 * Since: 0.8.0
563 **/
564void
Richard Hughes12724852018-09-04 13:53:44 +0100565fu_plugin_request_recoldplug (FuPlugin *self)
Richard Hughes362d6d72017-01-07 21:42:14 +0000566{
Richard Hughes12724852018-09-04 13:53:44 +0100567 g_return_if_fail (FU_IS_PLUGIN (self));
568 g_signal_emit (self, signals[SIGNAL_RECOLDPLUG], 0);
Richard Hughes362d6d72017-01-07 21:42:14 +0000569}
570
Richard Hughesb0829032017-01-10 09:27:08 +0000571/**
Richard Hughes399859e2020-05-11 19:44:03 +0100572 * fu_plugin_security_changed:
573 * @self: A #FuPlugin
574 *
575 * Informs the daemon that the HSI state may have changed.
576 *
577 * Since: 1.5.0
578 **/
579void
580fu_plugin_security_changed (FuPlugin *self)
581{
582 g_return_if_fail (FU_IS_PLUGIN (self));
583 g_signal_emit (self, signals[SIGNAL_SECURITY_CHANGED], 0);
584}
585
586/**
Richard Hughesb8f8db22017-04-25 15:56:00 +0100587 * fu_plugin_check_hwid:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100588 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100589 * @hwid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
Richard Hughesb8f8db22017-04-25 15:56:00 +0100590 *
Richard Hughesd7704d42017-08-08 20:29:09 +0100591 * Checks to see if a specific GUID exists. All hardware IDs on a
Richard Hughesb8f8db22017-04-25 15:56:00 +0100592 * specific system can be shown using the `fwupdmgr hwids` command.
593 *
Richard Hughes4eada342017-10-03 21:20:32 +0100594 * Returns: %TRUE if the HwId is found on the system.
595 *
Richard Hughesb8f8db22017-04-25 15:56:00 +0100596 * Since: 0.9.1
597 **/
598gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100599fu_plugin_check_hwid (FuPlugin *self, const gchar *hwid)
Richard Hughesb8f8db22017-04-25 15:56:00 +0100600{
Richard Hughes12724852018-09-04 13:53:44 +0100601 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100602 if (priv->hwids == NULL)
603 return FALSE;
Richard Hughesd7704d42017-08-08 20:29:09 +0100604 return fu_hwids_has_guid (priv->hwids, hwid);
605}
606
607/**
Patrick Rudolpha60b5472019-10-16 10:43:03 +0200608 * fu_plugin_get_hwid_replace_value:
609 * @self: A #FuPlugin
610 * @keys: A key, e.g. `HardwareID-3` or %FU_HWIDS_KEY_PRODUCT_SKU
611 * @error: A #GError or %NULL
612 *
613 * Gets the replacement value for a specific key. All hardware IDs on a
614 * specific system can be shown using the `fwupdmgr hwids` command.
615 *
616 * Returns: (transfer full): a string, or %NULL for error.
617 *
618 * Since: 1.3.3
619 **/
620gchar *
621fu_plugin_get_hwid_replace_value (FuPlugin *self, const gchar *keys, GError **error)
622{
623 FuPluginPrivate *priv = GET_PRIVATE (self);
624 if (priv->hwids == NULL)
625 return NULL;
626
627 return fu_hwids_get_replace_values (priv->hwids, keys, error);
628}
629
630/**
Richard Hughes69a5f352018-08-08 11:58:15 +0100631 * fu_plugin_get_hwids:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100632 * @self: A #FuPlugin
Richard Hughes69a5f352018-08-08 11:58:15 +0100633 *
634 * Returns all the HWIDs defined in the system. All hardware IDs on a
635 * specific system can be shown using the `fwupdmgr hwids` command.
636 *
Mario Limonciello1a680f32019-11-25 19:44:53 -0600637 * Returns: (transfer none) (element-type utf8): An array of GUIDs
Richard Hughes69a5f352018-08-08 11:58:15 +0100638 *
639 * Since: 1.1.1
640 **/
641GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +0100642fu_plugin_get_hwids (FuPlugin *self)
Richard Hughes69a5f352018-08-08 11:58:15 +0100643{
Richard Hughes12724852018-09-04 13:53:44 +0100644 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes69a5f352018-08-08 11:58:15 +0100645 if (priv->hwids == NULL)
646 return NULL;
647 return fu_hwids_get_guids (priv->hwids);
648}
649
650/**
Richard Hughes19841802019-09-10 16:48:00 +0100651 * fu_plugin_has_custom_flag:
652 * @self: A #FuPlugin
653 * @flag: A custom text flag, specific to the plugin, e.g. `uefi-force-enable`
654 *
655 * Returns if a per-plugin HwId custom flag exists, typically added from a DMI quirk.
656 *
657 * Returns: %TRUE if the quirk entry exists
658 *
659 * Since: 1.3.1
660 **/
661gboolean
662fu_plugin_has_custom_flag (FuPlugin *self, const gchar *flag)
663{
664 FuPluginPrivate *priv = GET_PRIVATE (self);
665 GPtrArray *hwids = fu_plugin_get_hwids (self);
666
667 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
668 g_return_val_if_fail (flag != NULL, FALSE);
669
670 /* never set up, e.g. in tests */
671 if (hwids == NULL)
672 return FALSE;
673
674 /* search each hwid */
675 for (guint i = 0; i < hwids->len; i++) {
676 const gchar *hwid = g_ptr_array_index (hwids, i);
677 const gchar *value;
678 g_autofree gchar *key = g_strdup_printf ("HwId=%s", hwid);
679
680 /* does prefixed quirk exist */
681 value = fu_quirks_lookup_by_id (priv->quirks, key, FU_QUIRKS_FLAGS);
682 if (value != NULL) {
683 g_auto(GStrv) quirks = g_strsplit (value, ",", -1);
684 if (g_strv_contains ((const gchar * const *) quirks, flag))
685 return TRUE;
686 }
687 }
688 return FALSE;
689}
690
691/**
Richard Hughes1354ea92017-09-19 15:58:31 +0100692 * fu_plugin_check_supported:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100693 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100694 * @guid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
Richard Hughes1354ea92017-09-19 15:58:31 +0100695 *
696 * Checks to see if a specific device GUID is supported, i.e. available in the
697 * AppStream metadata.
698 *
Richard Hughes4eada342017-10-03 21:20:32 +0100699 * Returns: %TRUE if the device is supported.
700 *
Richard Hughes1354ea92017-09-19 15:58:31 +0100701 * Since: 1.0.0
702 **/
Richard Hughesd8a8d5e2019-10-08 13:05:02 +0100703static gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100704fu_plugin_check_supported (FuPlugin *self, const gchar *guid)
Richard Hughes1354ea92017-09-19 15:58:31 +0100705{
Richard Hughesaabdc372018-11-14 10:11:08 +0000706 gboolean retval = FALSE;
707 g_signal_emit (self, signals[SIGNAL_CHECK_SUPPORTED], 0, guid, &retval);
708 return retval;
Richard Hughes1354ea92017-09-19 15:58:31 +0100709}
710
711/**
Richard Hughesd7704d42017-08-08 20:29:09 +0100712 * fu_plugin_get_dmi_value:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100713 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100714 * @dmi_id: A DMI ID, e.g. `BiosVersion`
Richard Hughesd7704d42017-08-08 20:29:09 +0100715 *
716 * Gets a hardware DMI value.
717 *
Richard Hughes4eada342017-10-03 21:20:32 +0100718 * Returns: The string, or %NULL
719 *
Richard Hughesd7704d42017-08-08 20:29:09 +0100720 * Since: 0.9.7
721 **/
722const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100723fu_plugin_get_dmi_value (FuPlugin *self, const gchar *dmi_id)
Richard Hughesd7704d42017-08-08 20:29:09 +0100724{
Richard Hughes12724852018-09-04 13:53:44 +0100725 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd7704d42017-08-08 20:29:09 +0100726 if (priv->hwids == NULL)
Richard Hughes7ef96b82017-08-23 18:28:24 +0100727 return NULL;
Richard Hughesd7704d42017-08-08 20:29:09 +0100728 return fu_hwids_get_value (priv->hwids, dmi_id);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100729}
730
Richard Hughes49e5e052017-09-03 12:15:41 +0100731/**
732 * fu_plugin_get_smbios_string:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100733 * @self: A #FuPlugin
Richard Hughes49e5e052017-09-03 12:15:41 +0100734 * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
735 * @offset: A SMBIOS offset
736 *
737 * Gets a hardware SMBIOS string.
738 *
739 * The @type and @offset can be referenced from the DMTF SMBIOS specification:
740 * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.1.1.pdf
741 *
Richard Hughes4eada342017-10-03 21:20:32 +0100742 * Returns: A string, or %NULL
743 *
Richard Hughes49e5e052017-09-03 12:15:41 +0100744 * Since: 0.9.8
745 **/
746const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100747fu_plugin_get_smbios_string (FuPlugin *self, guint8 structure_type, guint8 offset)
Richard Hughes49e5e052017-09-03 12:15:41 +0100748{
Richard Hughes12724852018-09-04 13:53:44 +0100749 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100750 if (priv->smbios == NULL)
751 return NULL;
752 return fu_smbios_get_string (priv->smbios, structure_type, offset, NULL);
753}
754
755/**
756 * fu_plugin_get_smbios_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100757 * @self: A #FuPlugin
Richard Hughes49e5e052017-09-03 12:15:41 +0100758 * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
759 *
760 * Gets a hardware SMBIOS data.
761 *
Richard Hughesdfaca2d2019-08-01 08:08:03 +0100762 * Returns: (transfer full): A #GBytes, or %NULL
Richard Hughes4eada342017-10-03 21:20:32 +0100763 *
Richard Hughes49e5e052017-09-03 12:15:41 +0100764 * Since: 0.9.8
765 **/
766GBytes *
Richard Hughes12724852018-09-04 13:53:44 +0100767fu_plugin_get_smbios_data (FuPlugin *self, guint8 structure_type)
Richard Hughes49e5e052017-09-03 12:15:41 +0100768{
Richard Hughes12724852018-09-04 13:53:44 +0100769 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100770 if (priv->smbios == NULL)
771 return NULL;
772 return fu_smbios_get_data (priv->smbios, structure_type, NULL);
773}
774
Mario Limonciello1a680f32019-11-25 19:44:53 -0600775/**
776 * fu_plugin_set_hwids:
777 * @self: A #FuPlugin
778 * @hwids: A #FuHwids
779 *
780 * Sets the hwids for a plugin
781 *
782 * Since: 0.9.7
783 **/
Richard Hughesb8f8db22017-04-25 15:56:00 +0100784void
Richard Hughes12724852018-09-04 13:53:44 +0100785fu_plugin_set_hwids (FuPlugin *self, FuHwids *hwids)
Richard Hughesb8f8db22017-04-25 15:56:00 +0100786{
Richard Hughes12724852018-09-04 13:53:44 +0100787 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd7704d42017-08-08 20:29:09 +0100788 g_set_object (&priv->hwids, hwids);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100789}
790
Mario Limonciello1a680f32019-11-25 19:44:53 -0600791/**
792 * fu_plugin_set_udev_subsystems:
793 * @self: A #FuPlugin
Richard Hughesa0d81c72019-11-27 11:41:54 +0000794 * @udev_subsystems: (element-type utf8): A #GPtrArray
Mario Limonciello1a680f32019-11-25 19:44:53 -0600795 *
796 * Sets the udev subsystems used by a plugin
797 *
798 * Since: 1.1.2
799 **/
Richard Hughes49e5e052017-09-03 12:15:41 +0100800void
Richard Hughes12724852018-09-04 13:53:44 +0100801fu_plugin_set_udev_subsystems (FuPlugin *self, GPtrArray *udev_subsystems)
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100802{
Richard Hughes12724852018-09-04 13:53:44 +0100803 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100804 if (priv->udev_subsystems != NULL)
805 g_ptr_array_unref (priv->udev_subsystems);
806 priv->udev_subsystems = g_ptr_array_ref (udev_subsystems);
807}
808
Mario Limonciello1a680f32019-11-25 19:44:53 -0600809/**
810 * fu_plugin_set_quirks:
811 * @self: A #FuPlugin
812 * @quirks: A #FuQuirks
813 *
814 * Sets the quirks for a plugin
815 *
816 * Since: 1.0.1
817 **/
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100818void
Richard Hughes12724852018-09-04 13:53:44 +0100819fu_plugin_set_quirks (FuPlugin *self, FuQuirks *quirks)
Richard Hughes9c028f02017-10-28 21:14:28 +0100820{
Richard Hughes12724852018-09-04 13:53:44 +0100821 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9c028f02017-10-28 21:14:28 +0100822 g_set_object (&priv->quirks, quirks);
823}
824
825/**
826 * fu_plugin_get_quirks:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100827 * @self: A #FuPlugin
Richard Hughes9c028f02017-10-28 21:14:28 +0100828 *
829 * Returns the hardware database object. This can be used to discover device
830 * quirks or other device-specific settings.
831 *
832 * Returns: (transfer none): a #FuQuirks, or %NULL if not set
833 *
834 * Since: 1.0.1
835 **/
836FuQuirks *
Richard Hughes12724852018-09-04 13:53:44 +0100837fu_plugin_get_quirks (FuPlugin *self)
Richard Hughes9c028f02017-10-28 21:14:28 +0100838{
Richard Hughes12724852018-09-04 13:53:44 +0100839 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9c028f02017-10-28 21:14:28 +0100840 return priv->quirks;
841}
842
Mario Limonciello1a680f32019-11-25 19:44:53 -0600843/**
844 * fu_plugin_set_runtime_versions:
845 * @self: A #FuPlugin
846 * @runtime_versions: A #GHashTables
847 *
848 * Sets the runtime versions for a plugin
849 *
850 * Since: 1.0.7
851 **/
Richard Hughes0eb123b2018-04-19 12:00:04 +0100852void
Richard Hughes12724852018-09-04 13:53:44 +0100853fu_plugin_set_runtime_versions (FuPlugin *self, GHashTable *runtime_versions)
Richard Hughes0eb123b2018-04-19 12:00:04 +0100854{
Richard Hughes12724852018-09-04 13:53:44 +0100855 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0eb123b2018-04-19 12:00:04 +0100856 priv->runtime_versions = g_hash_table_ref (runtime_versions);
857}
858
859/**
860 * fu_plugin_add_runtime_version:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100861 * @self: A #FuPlugin
Richard Hughes0eb123b2018-04-19 12:00:04 +0100862 * @component_id: An AppStream component id, e.g. "org.gnome.Software"
863 * @version: A version string, e.g. "1.2.3"
864 *
Richard Hughesdce91202019-04-08 12:47:45 +0100865 * Sets a runtime version of a specific dependency.
Richard Hughes0eb123b2018-04-19 12:00:04 +0100866 *
867 * Since: 1.0.7
868 **/
869void
Richard Hughes12724852018-09-04 13:53:44 +0100870fu_plugin_add_runtime_version (FuPlugin *self,
Richard Hughes0eb123b2018-04-19 12:00:04 +0100871 const gchar *component_id,
872 const gchar *version)
873{
Richard Hughes12724852018-09-04 13:53:44 +0100874 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesb01b4862018-04-20 16:39:48 +0100875 if (priv->runtime_versions == NULL)
876 return;
Richard Hughes0eb123b2018-04-19 12:00:04 +0100877 g_hash_table_insert (priv->runtime_versions,
878 g_strdup (component_id),
879 g_strdup (version));
880}
881
Mario Limonciello1a680f32019-11-25 19:44:53 -0600882/**
883 * fu_plugin_set_compile_versions:
884 * @self: A #FuPlugin
885 * @compile_versions: A #GHashTables
886 *
887 * Sets the compile time versions for a plugin
888 *
889 * Since: 1.0.7
890 **/
Richard Hughes34e0dab2018-04-20 16:43:00 +0100891void
Richard Hughes12724852018-09-04 13:53:44 +0100892fu_plugin_set_compile_versions (FuPlugin *self, GHashTable *compile_versions)
Richard Hughes34e0dab2018-04-20 16:43:00 +0100893{
Richard Hughes12724852018-09-04 13:53:44 +0100894 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes34e0dab2018-04-20 16:43:00 +0100895 priv->compile_versions = g_hash_table_ref (compile_versions);
896}
897
898/**
899 * fu_plugin_add_compile_version:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100900 * @self: A #FuPlugin
Richard Hughes34e0dab2018-04-20 16:43:00 +0100901 * @component_id: An AppStream component id, e.g. "org.gnome.Software"
902 * @version: A version string, e.g. "1.2.3"
903 *
Richard Hughesdce91202019-04-08 12:47:45 +0100904 * Sets a compile-time version of a specific dependency.
Richard Hughes34e0dab2018-04-20 16:43:00 +0100905 *
906 * Since: 1.0.7
907 **/
908void
Richard Hughes12724852018-09-04 13:53:44 +0100909fu_plugin_add_compile_version (FuPlugin *self,
Richard Hughes34e0dab2018-04-20 16:43:00 +0100910 const gchar *component_id,
911 const gchar *version)
912{
Richard Hughes12724852018-09-04 13:53:44 +0100913 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes34e0dab2018-04-20 16:43:00 +0100914 if (priv->compile_versions == NULL)
915 return;
916 g_hash_table_insert (priv->compile_versions,
917 g_strdup (component_id),
918 g_strdup (version));
919}
920
Richard Hughes9c028f02017-10-28 21:14:28 +0100921/**
922 * fu_plugin_lookup_quirk_by_id:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100923 * @self: A #FuPlugin
Richard Hughes87fb9ff2018-06-28 12:55:59 +0100924 * @group: A string, e.g. "DfuFlags"
925 * @key: An ID to match the entry, e.g. "Summary"
Richard Hughes9c028f02017-10-28 21:14:28 +0100926 *
927 * Looks up an entry in the hardware database using a string value.
928 *
929 * Returns: (transfer none): values from the database, or %NULL if not found
930 *
931 * Since: 1.0.1
932 **/
933const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100934fu_plugin_lookup_quirk_by_id (FuPlugin *self, const gchar *group, const gchar *key)
Richard Hughes9c028f02017-10-28 21:14:28 +0100935{
Richard Hughes12724852018-09-04 13:53:44 +0100936 FuPluginPrivate *priv = GET_PRIVATE (self);
937 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes9c028f02017-10-28 21:14:28 +0100938
Richard Hughes9c028f02017-10-28 21:14:28 +0100939 /* exact ID */
Richard Hughes87fb9ff2018-06-28 12:55:59 +0100940 return fu_quirks_lookup_by_id (priv->quirks, group, key);
Richard Hughes9c028f02017-10-28 21:14:28 +0100941}
942
943/**
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100944 * fu_plugin_lookup_quirk_by_id_as_uint64:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100945 * @self: A #FuPlugin
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100946 * @group: A string, e.g. "DfuFlags"
947 * @key: An ID to match the entry, e.g. "Size"
948 *
949 * Looks up an entry in the hardware database using a string key, returning
950 * an integer value. Values are assumed base 10, unless prefixed with "0x"
951 * where they are parsed as base 16.
952 *
Mario Limonciello1a680f32019-11-25 19:44:53 -0600953 * Returns: guint64 id or 0 if not found
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100954 *
955 * Since: 1.1.2
956 **/
957guint64
Richard Hughes12724852018-09-04 13:53:44 +0100958fu_plugin_lookup_quirk_by_id_as_uint64 (FuPlugin *self, const gchar *group, const gchar *key)
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100959{
Richard Hughes12724852018-09-04 13:53:44 +0100960 return fu_common_strtoull (fu_plugin_lookup_quirk_by_id (self, group, key));
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100961}
962
Mario Limonciello1a680f32019-11-25 19:44:53 -0600963/**
964 * fu_plugin_set_smbios:
965 * @self: A #FuPlugin
966 * @smbios: A #FuSmbios
967 *
968 * Sets the smbios for a plugin
969 *
970 * Since: 1.0.0
971 **/
Richard Hughes1354ea92017-09-19 15:58:31 +0100972void
Richard Hughes12724852018-09-04 13:53:44 +0100973fu_plugin_set_smbios (FuPlugin *self, FuSmbios *smbios)
Richard Hughes49e5e052017-09-03 12:15:41 +0100974{
Richard Hughes12724852018-09-04 13:53:44 +0100975 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100976 g_set_object (&priv->smbios, smbios);
977}
978
Richard Hughesb8f8db22017-04-25 15:56:00 +0100979/**
Richard Hughesb0829032017-01-10 09:27:08 +0000980 * fu_plugin_set_coldplug_delay:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100981 * @self: A #FuPlugin
Richard Hughesb0829032017-01-10 09:27:08 +0000982 * @duration: A delay in milliseconds
983 *
Richard Hughes21eaeef2020-01-14 12:10:01 +0000984 * Set the minimum time that should be waited in-between the call to
Richard Hughesb0829032017-01-10 09:27:08 +0000985 * fu_plugin_coldplug_prepare() and fu_plugin_coldplug(). This is usually going
986 * to be the minimum hardware initialisation time from a datasheet.
987 *
988 * It is better to use this function rather than using a sleep() in the plugin
989 * itself as then only one delay is done in the daemon rather than waiting for
990 * each coldplug prepare in a serial way.
991 *
992 * Additionally, very long delays should be avoided as the daemon will be
993 * blocked from processing requests whilst the coldplug delay is being
994 * performed.
995 *
996 * Since: 0.8.0
997 **/
998void
Richard Hughes12724852018-09-04 13:53:44 +0100999fu_plugin_set_coldplug_delay (FuPlugin *self, guint duration)
Richard Hughesb0829032017-01-10 09:27:08 +00001000{
Richard Hughes12724852018-09-04 13:53:44 +01001001 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesb0829032017-01-10 09:27:08 +00001002 g_return_if_fail (duration > 0);
1003
1004 /* check sanity */
1005 if (duration > FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM) {
1006 g_warning ("duration of %ums is crazy, truncating to %ums",
1007 duration,
1008 FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM);
1009 duration = FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM;
1010 }
1011
1012 /* emit */
Richard Hughes12724852018-09-04 13:53:44 +01001013 g_signal_emit (self, signals[SIGNAL_SET_COLDPLUG_DELAY], 0, duration);
Richard Hughesb0829032017-01-10 09:27:08 +00001014}
1015
Richard Hughes4b303802019-10-04 13:22:51 +01001016static gboolean
1017fu_plugin_device_attach (FuPlugin *self, FuDevice *device, GError **error)
1018{
1019 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughes4b303802019-10-04 13:22:51 +01001020 locker = fu_device_locker_new (device, error);
1021 if (locker == NULL)
1022 return FALSE;
1023 return fu_device_attach (device, error);
1024}
1025
1026static gboolean
1027fu_plugin_device_detach (FuPlugin *self, FuDevice *device, GError **error)
1028{
1029 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughes4b303802019-10-04 13:22:51 +01001030 locker = fu_device_locker_new (device, error);
1031 if (locker == NULL)
1032 return FALSE;
1033 return fu_device_detach (device, error);
1034}
1035
1036static gboolean
Richard Hughes4b303802019-10-04 13:22:51 +01001037fu_plugin_device_activate (FuPlugin *self, FuDevice *device, GError **error)
1038{
1039 g_autoptr(FuDeviceLocker) locker = NULL;
1040 locker = fu_device_locker_new (device, error);
1041 if (locker == NULL)
1042 return FALSE;
1043 return fu_device_activate (device, error);
1044}
1045
1046static gboolean
1047fu_plugin_device_write_firmware (FuPlugin *self, FuDevice *device,
1048 GBytes *fw, FwupdInstallFlags flags,
1049 GError **error)
1050{
1051 g_autoptr(FuDeviceLocker) locker = NULL;
1052 locker = fu_device_locker_new (device, error);
1053 if (locker == NULL)
1054 return FALSE;
1055 return fu_device_write_firmware (device, fw, flags, error);
1056}
1057
Richard Hughes7f677212019-10-05 16:19:40 +01001058static gboolean
1059fu_plugin_device_read_firmware (FuPlugin *self, FuDevice *device, GError **error)
1060{
1061 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughesf0eb0912019-10-10 11:37:22 +01001062 g_autoptr(FuFirmware) firmware = NULL;
Richard Hughes7f677212019-10-05 16:19:40 +01001063 g_autoptr(GBytes) fw = NULL;
1064 GChecksumType checksum_types[] = {
1065 G_CHECKSUM_SHA1,
1066 G_CHECKSUM_SHA256,
1067 0 };
1068 locker = fu_device_locker_new (device, error);
1069 if (locker == NULL)
1070 return FALSE;
1071 if (!fu_device_detach (device, error))
1072 return FALSE;
Richard Hughesf0eb0912019-10-10 11:37:22 +01001073 firmware = fu_device_read_firmware (device, error);
1074 if (firmware == NULL) {
1075 g_autoptr(GError) error_local = NULL;
1076 if (!fu_device_attach (device, &error_local))
1077 g_debug ("ignoring attach failure: %s", error_local->message);
1078 g_prefix_error (error, "failed to read firmware: ");
1079 return FALSE;
1080 }
1081 fw = fu_firmware_write (firmware, error);
Richard Hughes7f677212019-10-05 16:19:40 +01001082 if (fw == NULL) {
1083 g_autoptr(GError) error_local = NULL;
1084 if (!fu_device_attach (device, &error_local))
Richard Hughesf0eb0912019-10-10 11:37:22 +01001085 g_debug ("ignoring attach failure: %s", error_local->message);
1086 g_prefix_error (error, "failed to write firmware: ");
Richard Hughes7f677212019-10-05 16:19:40 +01001087 return FALSE;
1088 }
1089 for (guint i = 0; checksum_types[i] != 0; i++) {
1090 g_autofree gchar *hash = NULL;
1091 hash = g_compute_checksum_for_bytes (checksum_types[i], fw);
1092 fu_device_add_checksum (device, hash);
1093 }
1094 return fu_device_attach (device, error);
1095}
1096
Mario Limonciello1a680f32019-11-25 19:44:53 -06001097/**
1098 * fu_plugin_runner_startup:
1099 * @self: a #FuPlugin
1100 * @error: a #GError or NULL
1101 *
1102 * Runs the startup routine for the plugin
1103 *
1104 * Returns: #TRUE for success, #FALSE for failure
1105 *
1106 * Since: 0.8.0
1107 **/
Richard Hughesd0905142016-03-13 09:46:49 +00001108gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001109fu_plugin_runner_startup (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00001110{
Richard Hughes12724852018-09-04 13:53:44 +01001111 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001112 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001113 g_autoptr(GError) error_local = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +00001114
1115 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +00001116 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +00001117 return TRUE;
1118
Richard Hughes639da472018-01-06 22:35:04 +00001119 /* no object loaded */
1120 if (priv->module == NULL)
1121 return TRUE;
1122
Richard Hughesd0905142016-03-13 09:46:49 +00001123 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00001124 g_module_symbol (priv->module, "fu_plugin_startup", (gpointer *) &func);
1125 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +00001126 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001127 g_debug ("performing startup() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001128 if (!func (self, &error_local)) {
1129 if (error_local == NULL) {
1130 g_critical ("unset error in plugin %s for startup()",
1131 priv->name);
1132 g_set_error_literal (&error_local,
1133 FWUPD_ERROR,
1134 FWUPD_ERROR_INTERNAL,
1135 "unspecified error");
1136 }
1137 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1138 "failed to startup using %s: ",
1139 priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00001140 return FALSE;
1141 }
1142 return TRUE;
1143}
1144
1145static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001146fu_plugin_runner_device_generic (FuPlugin *self, FuDevice *device,
Richard Hughes4b303802019-10-04 13:22:51 +01001147 const gchar *symbol_name,
1148 FuPluginDeviceFunc device_func,
1149 GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001150{
Richard Hughes12724852018-09-04 13:53:44 +01001151 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001152 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001153 g_autoptr(GError) error_local = NULL;
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001154
1155 /* not enabled */
1156 if (!priv->enabled)
1157 return TRUE;
1158
Richard Hughesd3d96cc2017-11-14 11:34:33 +00001159 /* no object loaded */
1160 if (priv->module == NULL)
1161 return TRUE;
1162
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001163 /* optional */
1164 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
Richard Hughes4b303802019-10-04 13:22:51 +01001165 if (func == NULL) {
1166 if (device_func != NULL) {
1167 g_debug ("running superclassed %s() on %s",
1168 symbol_name + 10, priv->name);
1169 return device_func (self, device, error);
1170 }
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001171 return TRUE;
Richard Hughes4b303802019-10-04 13:22:51 +01001172 }
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001173 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001174 if (!func (self, device, &error_local)) {
1175 if (error_local == NULL) {
1176 g_critical ("unset error in plugin %s for %s()",
1177 priv->name, symbol_name + 10);
1178 g_set_error_literal (&error_local,
1179 FWUPD_ERROR,
1180 FWUPD_ERROR_INTERNAL,
1181 "unspecified error");
1182 }
1183 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1184 "failed to %s using %s: ",
1185 symbol_name + 10, priv->name);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001186 return FALSE;
1187 }
1188 return TRUE;
1189}
1190
Richard Hughesdbd8c762018-06-15 20:31:40 +01001191static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001192fu_plugin_runner_flagged_device_generic (FuPlugin *self, FwupdInstallFlags flags,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001193 FuDevice *device,
1194 const gchar *symbol_name, GError **error)
1195{
Richard Hughes12724852018-09-04 13:53:44 +01001196 FuPluginPrivate *priv = GET_PRIVATE (self);
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001197 FuPluginFlaggedDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001198 g_autoptr(GError) error_local = NULL;
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001199
1200 /* not enabled */
1201 if (!priv->enabled)
1202 return TRUE;
1203
1204 /* no object loaded */
1205 if (priv->module == NULL)
1206 return TRUE;
1207
1208 /* optional */
1209 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1210 if (func == NULL)
1211 return TRUE;
1212 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001213 if (!func (self, flags, device, &error_local)) {
1214 if (error_local == NULL) {
1215 g_critical ("unset error in plugin %s for %s()",
1216 priv->name, symbol_name + 10);
1217 g_set_error_literal (&error_local,
1218 FWUPD_ERROR,
1219 FWUPD_ERROR_INTERNAL,
1220 "unspecified error");
1221 }
1222 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1223 "failed to %s using %s: ",
1224 symbol_name + 10, priv->name);
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001225 return FALSE;
1226 }
1227 return TRUE;
1228
1229}
1230
1231static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001232fu_plugin_runner_device_array_generic (FuPlugin *self, GPtrArray *devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001233 const gchar *symbol_name, GError **error)
1234{
Richard Hughes12724852018-09-04 13:53:44 +01001235 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesdbd8c762018-06-15 20:31:40 +01001236 FuPluginDeviceArrayFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001237 g_autoptr(GError) error_local = NULL;
Richard Hughesdbd8c762018-06-15 20:31:40 +01001238
1239 /* not enabled */
1240 if (!priv->enabled)
1241 return TRUE;
1242
1243 /* no object loaded */
1244 if (priv->module == NULL)
1245 return TRUE;
1246
1247 /* optional */
1248 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1249 if (func == NULL)
1250 return TRUE;
1251 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001252 if (!func (self, devices, &error_local)) {
1253 if (error_local == NULL) {
1254 g_critical ("unset error in plugin %s for %s()",
1255 priv->name, symbol_name + 10);
1256 g_set_error_literal (&error_local,
1257 FWUPD_ERROR,
1258 FWUPD_ERROR_INTERNAL,
1259 "unspecified error");
1260 }
1261 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1262 "failed to %s using %s: ",
1263 symbol_name + 10, priv->name);
Richard Hughesdbd8c762018-06-15 20:31:40 +01001264 return FALSE;
1265 }
1266 return TRUE;
1267}
1268
Mario Limonciello1a680f32019-11-25 19:44:53 -06001269/**
1270 * fu_plugin_runner_coldplug:
1271 * @self: a #FuPlugin
1272 * @error: a #GError or NULL
1273 *
1274 * Runs the coldplug routine for the plugin
1275 *
1276 * Returns: #TRUE for success, #FALSE for failure
1277 *
1278 * Since: 0.8.0
1279 **/
Richard Hughesd0905142016-03-13 09:46:49 +00001280gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001281fu_plugin_runner_coldplug (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00001282{
Richard Hughes12724852018-09-04 13:53:44 +01001283 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001284 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001285 g_autoptr(GError) error_local = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +00001286
1287 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +00001288 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +00001289 return TRUE;
1290
Richard Hughes639da472018-01-06 22:35:04 +00001291 /* no object loaded */
1292 if (priv->module == NULL)
1293 return TRUE;
1294
Richard Hughesd0905142016-03-13 09:46:49 +00001295 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00001296 g_module_symbol (priv->module, "fu_plugin_coldplug", (gpointer *) &func);
1297 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +00001298 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001299 g_debug ("performing coldplug() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001300 if (!func (self, &error_local)) {
1301 if (error_local == NULL) {
1302 g_critical ("unset error in plugin %s for coldplug()",
1303 priv->name);
1304 g_set_error_literal (&error_local,
1305 FWUPD_ERROR,
1306 FWUPD_ERROR_INTERNAL,
1307 "unspecified error");
1308 }
1309 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1310 "failed to coldplug using %s: ", priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00001311 return FALSE;
1312 }
1313 return TRUE;
1314}
1315
Mario Limonciello1a680f32019-11-25 19:44:53 -06001316/**
1317 * fu_plugin_runner_recoldplug:
1318 * @self: a #FuPlugin
1319 * @error: a #GError or NULL
1320 *
1321 * Runs the recoldplug routine for the plugin
1322 *
1323 * Returns: #TRUE for success, #FALSE for failure
1324 *
1325 * Since: 1.0.4
1326 **/
Richard Hughes7b8b2022016-12-12 16:15:03 +00001327gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001328fu_plugin_runner_recoldplug (FuPlugin *self, GError **error)
Richard Hughes2de8f132018-01-17 09:12:02 +00001329{
Richard Hughes12724852018-09-04 13:53:44 +01001330 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes2de8f132018-01-17 09:12:02 +00001331 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001332 g_autoptr(GError) error_local = NULL;
Richard Hughes2de8f132018-01-17 09:12:02 +00001333
1334 /* not enabled */
1335 if (!priv->enabled)
1336 return TRUE;
1337
1338 /* no object loaded */
1339 if (priv->module == NULL)
1340 return TRUE;
1341
1342 /* optional */
1343 g_module_symbol (priv->module, "fu_plugin_recoldplug", (gpointer *) &func);
1344 if (func == NULL)
1345 return TRUE;
1346 g_debug ("performing recoldplug() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001347 if (!func (self, &error_local)) {
1348 if (error_local == NULL) {
1349 g_critical ("unset error in plugin %s for recoldplug()",
1350 priv->name);
1351 g_set_error_literal (&error_local,
1352 FWUPD_ERROR,
1353 FWUPD_ERROR_INTERNAL,
1354 "unspecified error");
1355 }
1356 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1357 "failed to recoldplug using %s: ",
1358 priv->name);
Richard Hughes2de8f132018-01-17 09:12:02 +00001359 return FALSE;
1360 }
1361 return TRUE;
1362}
1363
Mario Limonciello1a680f32019-11-25 19:44:53 -06001364/**
1365 * fu_plugin_runner_coldplug_prepare:
1366 * @self: a #FuPlugin
1367 * @error: a #GError or NULL
1368 *
1369 * Runs the coldplug_prepare routine for the plugin
1370 *
1371 * Returns: #TRUE for success, #FALSE for failure
1372 *
1373 * Since: 0.8.0
1374 **/
Richard Hughes2de8f132018-01-17 09:12:02 +00001375gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001376fu_plugin_runner_coldplug_prepare (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001377{
Richard Hughes12724852018-09-04 13:53:44 +01001378 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001379 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001380 g_autoptr(GError) error_local = NULL;
Richard Hughes46487c92017-01-07 21:26:34 +00001381
1382 /* not enabled */
1383 if (!priv->enabled)
1384 return TRUE;
1385
Richard Hughes639da472018-01-06 22:35:04 +00001386 /* no object loaded */
1387 if (priv->module == NULL)
1388 return TRUE;
1389
Richard Hughes46487c92017-01-07 21:26:34 +00001390 /* optional */
1391 g_module_symbol (priv->module, "fu_plugin_coldplug_prepare", (gpointer *) &func);
1392 if (func == NULL)
1393 return TRUE;
1394 g_debug ("performing coldplug_prepare() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001395 if (!func (self, &error_local)) {
1396 if (error_local == NULL) {
1397 g_critical ("unset error in plugin %s for coldplug_prepare()",
1398 priv->name);
1399 g_set_error_literal (&error_local,
1400 FWUPD_ERROR,
1401 FWUPD_ERROR_INTERNAL,
1402 "unspecified error");
1403 }
1404 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1405 "failed to coldplug_prepare using %s: ",
1406 priv->name);
Richard Hughes46487c92017-01-07 21:26:34 +00001407 return FALSE;
1408 }
1409 return TRUE;
1410}
1411
Mario Limonciello1a680f32019-11-25 19:44:53 -06001412/**
1413 * fu_plugin_runner_coldplug_cleanup:
1414 * @self: a #FuPlugin
1415 * @error: a #GError or NULL
1416 *
1417 * Runs the coldplug_cleanup routine for the plugin
1418 *
1419 * Returns: #TRUE for success, #FALSE for failure
1420 *
1421 * Since: 0.8.0
1422 **/
Richard Hughes46487c92017-01-07 21:26:34 +00001423gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001424fu_plugin_runner_coldplug_cleanup (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001425{
Richard Hughes12724852018-09-04 13:53:44 +01001426 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001427 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001428 g_autoptr(GError) error_local = NULL;
Richard Hughes46487c92017-01-07 21:26:34 +00001429
1430 /* not enabled */
1431 if (!priv->enabled)
1432 return TRUE;
1433
Richard Hughes639da472018-01-06 22:35:04 +00001434 /* no object loaded */
1435 if (priv->module == NULL)
1436 return TRUE;
1437
Richard Hughes46487c92017-01-07 21:26:34 +00001438 /* optional */
1439 g_module_symbol (priv->module, "fu_plugin_coldplug_cleanup", (gpointer *) &func);
1440 if (func == NULL)
1441 return TRUE;
1442 g_debug ("performing coldplug_cleanup() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001443 if (!func (self, &error_local)) {
1444 if (error_local == NULL) {
1445 g_critical ("unset error in plugin %s for coldplug_cleanup()",
1446 priv->name);
1447 g_set_error_literal (&error_local,
1448 FWUPD_ERROR,
1449 FWUPD_ERROR_INTERNAL,
1450 "unspecified error");
1451 }
1452 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1453 "failed to coldplug_cleanup using %s: ",
1454 priv->name);
Richard Hughes46487c92017-01-07 21:26:34 +00001455 return FALSE;
1456 }
1457 return TRUE;
1458}
1459
Mario Limonciello1a680f32019-11-25 19:44:53 -06001460/**
1461 * fu_plugin_runner_composite_prepare:
1462 * @self: a #FuPlugin
Richard Hughesa0d81c72019-11-27 11:41:54 +00001463 * @devices: (element-type FuDevice): a #GPtrArray of devices
Mario Limonciello1a680f32019-11-25 19:44:53 -06001464 * @error: a #GError or NULL
1465 *
1466 * Runs the composite_prepare routine for the plugin
1467 *
1468 * Returns: #TRUE for success, #FALSE for failure
1469 *
1470 * Since: 1.0.9
1471 **/
Richard Hughes46487c92017-01-07 21:26:34 +00001472gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001473fu_plugin_runner_composite_prepare (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001474{
Richard Hughes12724852018-09-04 13:53:44 +01001475 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001476 "fu_plugin_composite_prepare",
1477 error);
1478}
1479
Mario Limonciello1a680f32019-11-25 19:44:53 -06001480/**
1481 * fu_plugin_runner_composite_cleanup:
1482 * @self: a #FuPlugin
Richard Hughesa0d81c72019-11-27 11:41:54 +00001483 * @devices: (element-type FuDevice): a #GPtrArray of devices
Mario Limonciello1a680f32019-11-25 19:44:53 -06001484 * @error: a #GError or NULL
1485 *
1486 * Runs the composite_cleanup routine for the plugin
1487 *
1488 * Returns: #TRUE for success, #FALSE for failure
1489 *
1490 * Since: 1.0.9
1491 **/
Richard Hughesdbd8c762018-06-15 20:31:40 +01001492gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001493fu_plugin_runner_composite_cleanup (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001494{
Richard Hughes12724852018-09-04 13:53:44 +01001495 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001496 "fu_plugin_composite_cleanup",
1497 error);
1498}
1499
Mario Limonciello1a680f32019-11-25 19:44:53 -06001500/**
1501 * fu_plugin_runner_update_prepare:
1502 * @self: a #FuPlugin
1503 * @error: a #GError or NULL
1504 *
1505 * Runs the update_prepare routine for the plugin
1506 *
1507 * Returns: #TRUE for success, #FALSE for failure
1508 *
1509 * Since: 1.1.2
1510 **/
Richard Hughesdbd8c762018-06-15 20:31:40 +01001511gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001512fu_plugin_runner_update_prepare (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001513 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001514{
Richard Hughes12724852018-09-04 13:53:44 +01001515 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001516 "fu_plugin_update_prepare",
1517 error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001518}
1519
Mario Limonciello1a680f32019-11-25 19:44:53 -06001520/**
1521 * fu_plugin_runner_update_cleanup:
1522 * @self: a #FuPlugin
1523 * @error: a #GError or NULL
1524 *
1525 * Runs the update_cleanup routine for the plugin
1526 *
1527 * Returns: #TRUE for success, #FALSE for failure
1528 *
1529 * Since: 1.1.2
1530 **/
Richard Hughes7b8b2022016-12-12 16:15:03 +00001531gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001532fu_plugin_runner_update_cleanup (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001533 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001534{
Richard Hughes12724852018-09-04 13:53:44 +01001535 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001536 "fu_plugin_update_cleanup",
1537 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001538}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001539
Mario Limonciello1a680f32019-11-25 19:44:53 -06001540/**
1541 * fu_plugin_runner_update_attach:
1542 * @self: a #FuPlugin
1543 * @device: a #FuDevice
1544 * @error: a #GError or NULL
1545 *
1546 * Runs the update_attach routine for the plugin
1547 *
1548 * Returns: #TRUE for success, #FALSE for failure
1549 *
1550 * Since: 1.1.2
1551 **/
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001552gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001553fu_plugin_runner_update_attach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001554{
Richard Hughes12724852018-09-04 13:53:44 +01001555 return fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001556 "fu_plugin_update_attach",
1557 fu_plugin_device_attach,
1558 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001559}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001560
Mario Limonciello1a680f32019-11-25 19:44:53 -06001561/**
1562 * fu_plugin_runner_update_detach:
1563 * @self: a #FuPlugin
1564 * @device: A #FuDevice
1565 * @error: a #GError or NULL
1566 *
1567 * Runs the update_detach routine for the plugin
1568 *
1569 * Returns: #TRUE for success, #FALSE for failure
1570 *
1571 * Since: 1.1.2
1572 **/
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001573gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001574fu_plugin_runner_update_detach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001575{
Richard Hughes12724852018-09-04 13:53:44 +01001576 return fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001577 "fu_plugin_update_detach",
1578 fu_plugin_device_detach,
1579 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001580}
1581
Mario Limonciello1a680f32019-11-25 19:44:53 -06001582/**
1583 * fu_plugin_runner_update_reload:
1584 * @self: a #FuPlugin
1585 * @error: a #GError or NULL
1586 *
1587 * Runs reload routine for a device
1588 *
1589 * Returns: #TRUE for success, #FALSE for failure
1590 *
1591 * Since: 1.1.2
1592 **/
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001593gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001594fu_plugin_runner_update_reload (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001595{
Richard Hughes42f33df2019-10-05 20:52:33 +01001596 FuPluginPrivate *priv = GET_PRIVATE (self);
1597 g_autoptr(FuDeviceLocker) locker = NULL;
1598
1599 /* not enabled */
1600 if (!priv->enabled)
1601 return TRUE;
1602
1603 /* no object loaded */
1604 locker = fu_device_locker_new (device, error);
1605 if (locker == NULL)
1606 return FALSE;
1607 return fu_device_reload (device, error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001608}
1609
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001610/**
Richard Hughes196c6c62020-05-11 19:42:47 +01001611 * fu_plugin_runner_add_security_attrs:
1612 * @self: a #FuPlugin
Richard Hughes3ecd22c2020-05-19 20:13:47 +01001613 * @attrs: a #FuSecurityAttrs
Richard Hughes196c6c62020-05-11 19:42:47 +01001614 *
Richard Hughes3ecd22c2020-05-19 20:13:47 +01001615 * Runs the `add_security_attrs()` routine for the plugin
Richard Hughes196c6c62020-05-11 19:42:47 +01001616 *
1617 * Since: 1.5.0
1618 **/
Richard Hughesf58ac732020-05-12 15:23:44 +01001619void
1620fu_plugin_runner_add_security_attrs (FuPlugin *self, FuSecurityAttrs *attrs)
Richard Hughes196c6c62020-05-11 19:42:47 +01001621{
Richard Hughesf58ac732020-05-12 15:23:44 +01001622 FuPluginPrivate *priv = GET_PRIVATE (self);
1623 FuPluginSecurityAttrsFunc func = NULL;
1624 const gchar *symbol_name = "fu_plugin_add_security_attrs";
1625
1626 /* no object loaded */
1627 if (priv->module == NULL)
1628 return;
1629
1630 /* optional, but gets called even for disabled plugins */
1631 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1632 if (func == NULL)
1633 return;
1634 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
1635 func (self, attrs);
Richard Hughes196c6c62020-05-11 19:42:47 +01001636}
1637
1638/**
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001639 * fu_plugin_add_udev_subsystem:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001640 * @self: a #FuPlugin
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001641 * @subsystem: a subsystem name, e.g. `pciport`
1642 *
1643 * Registers the udev subsystem to be watched by the daemon.
1644 *
1645 * Plugins can use this method only in fu_plugin_init()
Mario Limonciello1a680f32019-11-25 19:44:53 -06001646 *
1647 * Since: 1.1.2
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001648 **/
1649void
Richard Hughes12724852018-09-04 13:53:44 +01001650fu_plugin_add_udev_subsystem (FuPlugin *self, const gchar *subsystem)
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001651{
Richard Hughes12724852018-09-04 13:53:44 +01001652 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesea327fc2020-06-22 15:23:29 +01001653 if (priv->udev_subsystems == NULL)
1654 priv->udev_subsystems = g_ptr_array_new_with_free_func (g_free);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001655 for (guint i = 0; i < priv->udev_subsystems->len; i++) {
1656 const gchar *subsystem_tmp = g_ptr_array_index (priv->udev_subsystems, i);
1657 if (g_strcmp0 (subsystem_tmp, subsystem) == 0)
1658 return;
1659 }
1660 g_debug ("added udev subsystem watch of %s", subsystem);
1661 g_ptr_array_add (priv->udev_subsystems, g_strdup (subsystem));
1662}
1663
Richard Hughes989acf12019-10-05 20:16:47 +01001664/**
1665 * fu_plugin_set_device_gtype:
1666 * @self: a #FuPlugin
1667 * @device_gtype: a #GType `FU_TYPE_DEVICE`
1668 *
1669 * Sets the device #GType which is used when creating devices.
1670 *
1671 * If this method is used then fu_plugin_usb_device_added() is not called, and
1672 * instead the object is created in the daemon for the plugin.
1673 *
1674 * Plugins can use this method only in fu_plugin_init()
1675 *
1676 * Since: 1.3.3
1677 **/
1678void
1679fu_plugin_set_device_gtype (FuPlugin *self, GType device_gtype)
1680{
1681 FuPluginPrivate *priv = GET_PRIVATE (self);
1682 priv->device_gtype = device_gtype;
1683}
1684
Mario Limonciello1a680f32019-11-25 19:44:53 -06001685/**
1686 * fu_plugin_add_firmware_gtype:
1687 * @self: a #FuPlugin
1688 * @id: A string describing the type
1689 * @gtype: a #GType `FU_TYPE_DEVICE`
1690 *
1691 * Adds a firmware #GType which is used when creating devices.
1692 * *
1693 * Plugins can use this method only in fu_plugin_init()
1694 *
1695 * Since: 1.3.3
1696 **/
Richard Hughes95c98a92019-10-22 16:03:15 +01001697void
1698fu_plugin_add_firmware_gtype (FuPlugin *self, const gchar *id, GType gtype)
1699{
1700 g_signal_emit (self, signals[SIGNAL_ADD_FIRMWARE_GTYPE], 0, id, gtype);
1701}
1702
Richard Hughes989acf12019-10-05 20:16:47 +01001703static gboolean
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001704fu_plugin_check_supported_device (FuPlugin *self, FuDevice *device)
1705{
1706 GPtrArray *instance_ids = fu_device_get_instance_ids (device);
1707 for (guint i = 0; i < instance_ids->len; i++) {
1708 const gchar *instance_id = g_ptr_array_index (instance_ids, i);
1709 g_autofree gchar *guid = fwupd_guid_hash_string (instance_id);
1710 if (fu_plugin_check_supported (self, guid))
1711 return TRUE;
1712 }
1713 return FALSE;
1714}
1715
1716static gboolean
Richard Hughes989acf12019-10-05 20:16:47 +01001717fu_plugin_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error)
1718{
1719 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001720 GType device_gtype = fu_device_get_specialized_gtype (FU_DEVICE (device));
Richard Hughes989acf12019-10-05 20:16:47 +01001721 g_autoptr(FuDevice) dev = NULL;
1722 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001723
1724 /* fall back to plugin default */
1725 if (device_gtype == G_TYPE_INVALID)
1726 device_gtype = priv->device_gtype;
1727
1728 /* create new device and incorporate existing properties */
1729 dev = g_object_new (device_gtype, NULL);
1730 fu_device_incorporate (dev, FU_DEVICE (device));
Richard Hughes0f66a022020-02-19 18:54:38 +00001731 if (!fu_plugin_runner_device_created (self, dev, error))
1732 return FALSE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001733
1734 /* there are a lot of different devices that match, but not all respond
1735 * well to opening -- so limit some ones with issued updates */
1736 if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_ONLY_SUPPORTED)) {
1737 if (!fu_device_probe (dev, error))
1738 return FALSE;
1739 fu_device_convert_instance_ids (dev);
1740 if (!fu_plugin_check_supported_device (self, dev)) {
1741 g_autofree gchar *guids = fu_device_get_guids_as_str (dev);
1742 g_debug ("%s has no updates, so ignoring device", guids);
1743 return TRUE;
1744 }
1745 }
1746
1747 /* open and add */
1748 locker = fu_device_locker_new (dev, error);
1749 if (locker == NULL)
1750 return FALSE;
1751 fu_plugin_device_add (self, dev);
Richard Hughes6a078702020-05-09 20:36:33 +01001752 fu_plugin_runner_device_added (self, dev);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001753 return TRUE;
1754}
1755
1756static gboolean
Mario Limonciello096e3cf2020-04-28 15:01:33 -05001757fu_plugin_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GError **error)
1758{
1759 g_autoptr(FuDeviceLocker) locker = NULL;
1760
1761 /* open */
1762 locker = fu_device_locker_new (FU_DEVICE (device), error);
1763 if (locker == NULL)
1764 return FALSE;
1765 return fu_device_rescan (FU_DEVICE (device), error);
1766}
1767
1768static gboolean
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001769fu_plugin_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error)
1770{
1771 FuPluginPrivate *priv = GET_PRIVATE (self);
1772 GType device_gtype = fu_device_get_specialized_gtype (FU_DEVICE (device));
1773 g_autoptr(FuDevice) dev = NULL;
1774 g_autoptr(FuDeviceLocker) locker = NULL;
1775
1776 /* fall back to plugin default */
1777 if (device_gtype == G_TYPE_INVALID)
1778 device_gtype = priv->device_gtype;
1779
1780 /* create new device and incorporate existing properties */
1781 dev = g_object_new (device_gtype, NULL);
Richard Hughes989acf12019-10-05 20:16:47 +01001782 fu_device_incorporate (FU_DEVICE (dev), FU_DEVICE (device));
Richard Hughes0f66a022020-02-19 18:54:38 +00001783 if (!fu_plugin_runner_device_created (self, dev, error))
1784 return FALSE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001785
1786 /* there are a lot of different devices that match, but not all respond
1787 * well to opening -- so limit some ones with issued updates */
1788 if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_ONLY_SUPPORTED)) {
1789 if (!fu_device_probe (dev, error))
1790 return FALSE;
1791 fu_device_convert_instance_ids (dev);
1792 if (!fu_plugin_check_supported_device (self, dev)) {
1793 g_autofree gchar *guids = fu_device_get_guids_as_str (dev);
1794 g_debug ("%s has no updates, so ignoring device", guids);
1795 return TRUE;
1796 }
1797 }
1798
1799 /* open and add */
Richard Hughes989acf12019-10-05 20:16:47 +01001800 locker = fu_device_locker_new (dev, error);
1801 if (locker == NULL)
1802 return FALSE;
1803 fu_plugin_device_add (self, FU_DEVICE (dev));
Richard Hughes6a078702020-05-09 20:36:33 +01001804 fu_plugin_runner_device_added (self, dev);
Richard Hughes989acf12019-10-05 20:16:47 +01001805 return TRUE;
1806}
1807
Mario Limonciello1a680f32019-11-25 19:44:53 -06001808/**
1809 * fu_plugin_runner_usb_device_added:
1810 * @self: a #FuPlugin
1811 * @device: a #FuUsbDevice
1812 * @error: a #GError or NULL
1813 *
1814 * Call the usb_device_added routine for the plugin
1815 *
1816 * Returns: #TRUE for success, #FALSE for failure
1817 *
1818 * Since: 1.0.2
1819 **/
Richard Hughes104f6512017-11-24 11:44:57 +00001820gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001821fu_plugin_runner_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error)
Richard Hughes104f6512017-11-24 11:44:57 +00001822{
Richard Hughes12724852018-09-04 13:53:44 +01001823 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes104f6512017-11-24 11:44:57 +00001824 FuPluginUsbDeviceAddedFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001825 g_autoptr(GError) error_local = NULL;
Richard Hughes104f6512017-11-24 11:44:57 +00001826
1827 /* not enabled */
1828 if (!priv->enabled)
1829 return TRUE;
Richard Hughes639da472018-01-06 22:35:04 +00001830
1831 /* no object loaded */
Richard Hughes104f6512017-11-24 11:44:57 +00001832 if (priv->module == NULL)
1833 return TRUE;
1834
1835 /* optional */
1836 g_module_symbol (priv->module, "fu_plugin_usb_device_added", (gpointer *) &func);
Richard Hughes989acf12019-10-05 20:16:47 +01001837 if (func == NULL) {
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001838 if (priv->device_gtype != G_TYPE_INVALID ||
1839 fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) {
Mario Limonciello0e500322019-10-17 18:41:04 -05001840 if (!fu_plugin_usb_device_added (self, device, error))
Mario Limoncielloa9be5362019-10-12 13:17:45 -05001841 return FALSE;
Richard Hughes989acf12019-10-05 20:16:47 +01001842 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001843 return TRUE;
Richard Hughes989acf12019-10-05 20:16:47 +01001844 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001845 g_debug ("performing usb_device_added() on %s", priv->name);
1846 if (!func (self, device, &error_local)) {
1847 if (error_local == NULL) {
1848 g_critical ("unset error in plugin %s for usb_device_added()",
1849 priv->name);
1850 g_set_error_literal (&error_local,
1851 FWUPD_ERROR,
1852 FWUPD_ERROR_INTERNAL,
1853 "unspecified error");
1854 }
1855 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1856 "failed to add device using on %s: ",
1857 priv->name);
1858 return FALSE;
Richard Hughes104f6512017-11-24 11:44:57 +00001859 }
1860 return TRUE;
1861}
1862
Mario Limonciello1a680f32019-11-25 19:44:53 -06001863/**
1864 * fu_plugin_runner_udev_device_added:
1865 * @self: a #FuPlugin
1866 * @device: a #FuUdevDevice
1867 * @error: a #GError or NULL
1868 *
1869 * Call the udev_device_added routine for the plugin
1870 *
1871 * Returns: #TRUE for success, #FALSE for failure
1872 *
1873 * Since: 1.0.2
1874 **/
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001875gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001876fu_plugin_runner_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error)
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001877{
Richard Hughes12724852018-09-04 13:53:44 +01001878 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001879 FuPluginUdevDeviceAddedFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001880 g_autoptr(GError) error_local = NULL;
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001881
1882 /* not enabled */
1883 if (!priv->enabled)
1884 return TRUE;
1885
1886 /* no object loaded */
1887 if (priv->module == NULL)
1888 return TRUE;
1889
1890 /* optional */
1891 g_module_symbol (priv->module, "fu_plugin_udev_device_added", (gpointer *) &func);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001892 if (func == NULL) {
1893 if (priv->device_gtype != G_TYPE_INVALID ||
1894 fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) {
Mario Limonciello0e500322019-10-17 18:41:04 -05001895 if (!fu_plugin_udev_device_added (self, device, error))
Mario Limoncielloa9be5362019-10-12 13:17:45 -05001896 return FALSE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001897 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001898 return TRUE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001899 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001900 g_debug ("performing udev_device_added() on %s", priv->name);
1901 if (!func (self, device, &error_local)) {
1902 if (error_local == NULL) {
1903 g_critical ("unset error in plugin %s for udev_device_added()",
1904 priv->name);
1905 g_set_error_literal (&error_local,
1906 FWUPD_ERROR,
1907 FWUPD_ERROR_INTERNAL,
1908 "unspecified error");
1909 }
1910 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1911 "failed to add device using on %s: ",
1912 priv->name);
1913 return FALSE;
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001914 }
1915 return TRUE;
1916}
1917
Mario Limonciello1a680f32019-11-25 19:44:53 -06001918/**
1919 * fu_plugin_runner_udev_device_changed:
1920 * @self: a #FuPlugin
1921 * @device: a #FuUdevDevice
1922 * @error: a #GError or NULL
1923 *
1924 * Call the udev_device_changed routine for the plugin
1925 *
1926 * Returns: #TRUE for success, #FALSE for failure
1927 *
1928 * Since: 1.0.2
1929 **/
Richard Hughes5e952ce2019-08-26 11:09:46 +01001930gboolean
1931fu_plugin_runner_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GError **error)
1932{
1933 FuPluginPrivate *priv = GET_PRIVATE (self);
1934 FuPluginUdevDeviceAddedFunc func = NULL;
1935 g_autoptr(GError) error_local = NULL;
1936
1937 /* not enabled */
1938 if (!priv->enabled)
1939 return TRUE;
1940
1941 /* no object loaded */
1942 if (priv->module == NULL)
1943 return TRUE;
1944
1945 /* optional */
1946 g_module_symbol (priv->module, "fu_plugin_udev_device_changed", (gpointer *) &func);
Mario Limonciello096e3cf2020-04-28 15:01:33 -05001947 if (func == NULL) {
1948 if (priv->device_gtype != G_TYPE_INVALID ||
1949 fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) {
1950 if (!fu_plugin_udev_device_changed (self, device, error))
1951 return FALSE;
1952 }
Richard Hughes5e952ce2019-08-26 11:09:46 +01001953 return TRUE;
Mario Limonciello096e3cf2020-04-28 15:01:33 -05001954 }
Richard Hughes5e952ce2019-08-26 11:09:46 +01001955 g_debug ("performing udev_device_changed() on %s", priv->name);
1956 if (!func (self, device, &error_local)) {
1957 if (error_local == NULL) {
1958 g_critical ("unset error in plugin %s for udev_device_changed()",
1959 priv->name);
1960 g_set_error_literal (&error_local,
1961 FWUPD_ERROR,
1962 FWUPD_ERROR_INTERNAL,
1963 "unspecified error");
1964 }
1965 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1966 "failed to change device on %s: ",
1967 priv->name);
1968 return FALSE;
1969 }
1970 return TRUE;
1971}
1972
Mario Limonciello1a680f32019-11-25 19:44:53 -06001973/**
Richard Hughes6a078702020-05-09 20:36:33 +01001974 * fu_plugin_runner_device_added:
1975 * @self: a #FuPlugin
1976 * @device: a #FuDevice
1977 *
1978 * Call the device_added routine for the plugin
1979 *
1980 * Since: 1.5.0
1981 **/
1982void
1983fu_plugin_runner_device_added (FuPlugin *self, FuDevice *device)
1984{
1985 FuPluginPrivate *priv = GET_PRIVATE (self);
1986 FuPluginDeviceRegisterFunc func = NULL;
1987
1988 /* not enabled */
1989 if (!priv->enabled)
1990 return;
1991 if (priv->module == NULL)
1992 return;
1993
1994 /* optional */
1995 g_module_symbol (priv->module, "fu_plugin_device_added", (gpointer *) &func);
1996 if (func == NULL)
1997 return;
1998 g_debug ("performing fu_plugin_device_added() on %s", priv->name);
1999 func (self, device);
2000}
2001
2002/**
Mario Limonciello1a680f32019-11-25 19:44:53 -06002003 * fu_plugin_runner_device_removed:
2004 * @self: a #FuPlugin
2005 * @device: a #FuDevice
2006 *
2007 * Call the device_removed routine for the plugin
2008 *
2009 * Since: 1.1.2
2010 **/
Richard Hughese1fd34d2017-08-24 14:19:51 +01002011void
Richard Hughes12724852018-09-04 13:53:44 +01002012fu_plugin_runner_device_removed (FuPlugin *self, FuDevice *device)
Mario Limoncielloe260ead2018-09-01 09:19:24 -05002013{
2014 g_autoptr(GError) error_local= NULL;
2015
Richard Hughes12724852018-09-04 13:53:44 +01002016 if (!fu_plugin_runner_device_generic (self, device,
Mario Limoncielloe260ead2018-09-01 09:19:24 -05002017 "fu_plugin_device_removed",
Richard Hughes4b303802019-10-04 13:22:51 +01002018 NULL,
Mario Limoncielloe260ead2018-09-01 09:19:24 -05002019 &error_local))
2020 g_warning ("%s", error_local->message);
2021}
2022
Mario Limonciello1a680f32019-11-25 19:44:53 -06002023/**
2024 * fu_plugin_runner_device_register:
2025 * @self: a #FuPlugin
2026 * @device: a #FuDevice
2027 *
2028 * Call the device_registered routine for the plugin
2029 *
2030 * Since: 0.9.7
2031 **/
Mario Limoncielloe260ead2018-09-01 09:19:24 -05002032void
Richard Hughes12724852018-09-04 13:53:44 +01002033fu_plugin_runner_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +01002034{
Richard Hughes12724852018-09-04 13:53:44 +01002035 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughese1fd34d2017-08-24 14:19:51 +01002036 FuPluginDeviceRegisterFunc func = NULL;
2037
2038 /* not enabled */
2039 if (!priv->enabled)
2040 return;
Richard Hughes34834102017-11-21 21:55:00 +00002041 if (priv->module == NULL)
2042 return;
Richard Hughese1fd34d2017-08-24 14:19:51 +01002043
Mario Limonciello4910b242018-06-22 15:04:21 -05002044 /* don't notify plugins on their own devices */
Richard Hughes12724852018-09-04 13:53:44 +01002045 if (g_strcmp0 (fu_device_get_plugin (device), fu_plugin_get_name (self)) == 0)
Mario Limonciello4910b242018-06-22 15:04:21 -05002046 return;
2047
Richard Hughese1fd34d2017-08-24 14:19:51 +01002048 /* optional */
2049 g_module_symbol (priv->module, "fu_plugin_device_registered", (gpointer *) &func);
2050 if (func != NULL) {
Richard Hughes1bf7ff92018-08-24 20:21:35 +01002051 g_debug ("performing fu_plugin_device_registered() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01002052 func (self, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +01002053 }
2054}
2055
Mario Limonciello1a680f32019-11-25 19:44:53 -06002056/**
Richard Hughes0f66a022020-02-19 18:54:38 +00002057 * fu_plugin_runner_device_created:
2058 * @self: a #FuPlugin
2059 * @device: a #FuDevice
2060 * @error: a #GError or NULL
2061 *
2062 * Call the device_created routine for the plugin
2063 *
2064 * Returns: #TRUE for success, #FALSE for failure
2065 *
Mario Limonciello96117d12020-02-28 10:17:56 -06002066 * Since: 1.4.0
Richard Hughes0f66a022020-02-19 18:54:38 +00002067 **/
2068gboolean
2069fu_plugin_runner_device_created (FuPlugin *self, FuDevice *device, GError **error)
2070{
2071 FuPluginPrivate *priv = GET_PRIVATE (self);
2072 FuPluginDeviceFunc func = NULL;
2073
2074 /* not enabled */
2075 if (!priv->enabled)
2076 return TRUE;
2077 if (priv->module == NULL)
2078 return TRUE;
2079
2080 /* optional */
2081 g_module_symbol (priv->module, "fu_plugin_device_created", (gpointer *) &func);
2082 if (func == NULL)
2083 return TRUE;
2084 g_debug ("performing fu_plugin_device_created() on %s", priv->name);
2085 return func (self, device, error);
2086}
2087
2088/**
Mario Limonciello1a680f32019-11-25 19:44:53 -06002089 * fu_plugin_runner_verify:
2090 * @self: a #FuPlugin
2091 * @device: a #FuDevice
2092 * @flags: #FuPluginVerifyFlags
2093 * @error: A #GError or NULL
2094 *
2095 * Call into the plugin's verify routine
2096 *
2097 * Returns: #TRUE for success, #FALSE for failure
2098 *
2099 * Since: 0.8.0
2100 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002101gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002102fu_plugin_runner_verify (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +00002103 FuDevice *device,
2104 FuPluginVerifyFlags flags,
2105 GError **error)
2106{
Richard Hughes12724852018-09-04 13:53:44 +01002107 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00002108 FuPluginVerifyFunc func = NULL;
Richard Hughesababbb72017-06-15 20:18:36 +01002109 GPtrArray *checksums;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002110 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002111
2112 /* not enabled */
2113 if (!priv->enabled)
2114 return TRUE;
2115
Richard Hughes639da472018-01-06 22:35:04 +00002116 /* no object loaded */
2117 if (priv->module == NULL)
2118 return TRUE;
2119
Richard Hughescff38bc2016-12-12 12:03:37 +00002120 /* optional */
2121 g_module_symbol (priv->module, "fu_plugin_verify", (gpointer *) &func);
Richard Hughes7f677212019-10-05 16:19:40 +01002122 if (func == NULL) {
Richard Hughes7f677212019-10-05 16:19:40 +01002123 return fu_plugin_device_read_firmware (self, device, error);
2124 }
Richard Hughes1812fc72018-12-14 11:37:54 +00002125
2126 /* clear any existing verification checksums */
2127 checksums = fu_device_get_checksums (device);
2128 g_ptr_array_set_size (checksums, 0);
2129
Richard Hughesc9223be2019-03-18 08:46:42 +00002130 /* run additional detach */
2131 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01002132 "fu_plugin_update_detach",
Richard Hughes4b303802019-10-04 13:22:51 +01002133 fu_plugin_device_detach,
Richard Hughesc9223be2019-03-18 08:46:42 +00002134 error))
2135 return FALSE;
2136
Richard Hughes1812fc72018-12-14 11:37:54 +00002137 /* run vfunc */
Richard Hughescff38bc2016-12-12 12:03:37 +00002138 g_debug ("performing verify() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002139 if (!func (self, device, flags, &error_local)) {
Richard Hughesc9223be2019-03-18 08:46:42 +00002140 g_autoptr(GError) error_attach = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002141 if (error_local == NULL) {
2142 g_critical ("unset error in plugin %s for verify()",
2143 priv->name);
2144 g_set_error_literal (&error_local,
2145 FWUPD_ERROR,
2146 FWUPD_ERROR_INTERNAL,
2147 "unspecified error");
2148 }
2149 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2150 "failed to verify using %s: ",
2151 priv->name);
Richard Hughesc9223be2019-03-18 08:46:42 +00002152 /* make the device "work" again, but don't prefix the error */
2153 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01002154 "fu_plugin_update_attach",
Richard Hughes4b303802019-10-04 13:22:51 +01002155 fu_plugin_device_attach,
Richard Hughesc9223be2019-03-18 08:46:42 +00002156 &error_attach)) {
2157 g_warning ("failed to attach whilst aborting verify(): %s",
2158 error_attach->message);
2159 }
Richard Hughesd0905142016-03-13 09:46:49 +00002160 return FALSE;
2161 }
Richard Hughesc9223be2019-03-18 08:46:42 +00002162
2163 /* run optional attach */
2164 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01002165 "fu_plugin_update_attach",
Richard Hughes4b303802019-10-04 13:22:51 +01002166 fu_plugin_device_attach,
Richard Hughesc9223be2019-03-18 08:46:42 +00002167 error))
2168 return FALSE;
2169
2170 /* success */
Richard Hughesd0905142016-03-13 09:46:49 +00002171 return TRUE;
2172}
2173
Mario Limonciello1a680f32019-11-25 19:44:53 -06002174/**
2175 * fu_plugin_runner_activate:
2176 * @self: a #FuPlugin
2177 * @device: a #FuDevice
2178 * @error: A #GError or NULL
2179 *
2180 * Call into the plugin's activate routine
2181 *
2182 * Returns: #TRUE for success, #FALSE for failure
2183 *
2184 * Since: 1.2.6
2185 **/
Richard Hughesd0905142016-03-13 09:46:49 +00002186gboolean
Mario Limonciello96a0dd52019-02-25 13:50:03 -06002187fu_plugin_runner_activate (FuPlugin *self, FuDevice *device, GError **error)
2188{
2189 guint64 flags;
2190
2191 /* final check */
2192 flags = fu_device_get_flags (device);
2193 if ((flags & FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION) == 0) {
2194 g_set_error (error,
2195 FWUPD_ERROR,
2196 FWUPD_ERROR_NOT_SUPPORTED,
2197 "Device %s does not need activation",
2198 fu_device_get_id (device));
2199 return FALSE;
2200 }
2201
2202 /* run vfunc */
2203 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01002204 "fu_plugin_activate",
2205 fu_plugin_device_activate,
2206 error))
Mario Limonciello96a0dd52019-02-25 13:50:03 -06002207 return FALSE;
2208
2209 /* update with correct flags */
2210 fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION);
2211 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
2212 return TRUE;
2213}
2214
Mario Limonciello1a680f32019-11-25 19:44:53 -06002215/**
2216 * fu_plugin_runner_unlock:
2217 * @self: a #FuPlugin
2218 * @device: a #FuDevice
2219 * @error: A #GError or NULL
2220 *
2221 * Call into the plugin's unlock routine
2222 *
2223 * Returns: #TRUE for success, #FALSE for failure
2224 *
2225 * Since: 0.8.0
2226 **/
Mario Limonciello96a0dd52019-02-25 13:50:03 -06002227gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002228fu_plugin_runner_unlock (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00002229{
Richard Hughescff38bc2016-12-12 12:03:37 +00002230 guint64 flags;
Richard Hughescff38bc2016-12-12 12:03:37 +00002231
2232 /* final check */
2233 flags = fu_device_get_flags (device);
2234 if ((flags & FWUPD_DEVICE_FLAG_LOCKED) == 0) {
2235 g_set_error (error,
2236 FWUPD_ERROR,
2237 FWUPD_ERROR_NOT_SUPPORTED,
2238 "Device %s is not locked",
2239 fu_device_get_id (device));
2240 return FALSE;
2241 }
2242
Richard Hughes9c4b5312017-11-14 11:34:53 +00002243 /* run vfunc */
Richard Hughes12724852018-09-04 13:53:44 +01002244 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01002245 "fu_plugin_unlock",
2246 NULL,
2247 error))
Richard Hughes9c4b5312017-11-14 11:34:53 +00002248 return FALSE;
Richard Hughescff38bc2016-12-12 12:03:37 +00002249
2250 /* update with correct flags */
2251 flags = fu_device_get_flags (device);
2252 fu_device_set_flags (device, flags &= ~FWUPD_DEVICE_FLAG_LOCKED);
2253 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
2254 return TRUE;
2255}
2256
Mario Limonciello1a680f32019-11-25 19:44:53 -06002257/**
2258 * fu_plugin_runner_update:
2259 * @self: a #FuPlugin
2260 * @device: a #FuDevice
2261 * @blob_fw: A #GBytes
2262 * @flags: A #FwupdInstallFlags
2263 * @error: A #GError or NULL
2264 *
2265 * Call into the plugin's update routine
2266 *
2267 * Returns: #TRUE for success, #FALSE for failure
2268 *
2269 * Since: 0.8.0
2270 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002271gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002272fu_plugin_runner_update (FuPlugin *self,
Richard Hughesa785a1c2017-08-25 16:00:58 +01002273 FuDevice *device,
Richard Hughesa785a1c2017-08-25 16:00:58 +01002274 GBytes *blob_fw,
2275 FwupdInstallFlags flags,
2276 GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00002277{
Richard Hughes12724852018-09-04 13:53:44 +01002278 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesa785a1c2017-08-25 16:00:58 +01002279 FuPluginUpdateFunc update_func;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002280 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002281
2282 /* not enabled */
Richard Hughes41c15482018-02-01 22:07:21 +00002283 if (!priv->enabled) {
2284 g_debug ("plugin not enabled, skipping");
Richard Hughesd0905142016-03-13 09:46:49 +00002285 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00002286 }
Richard Hughesd0905142016-03-13 09:46:49 +00002287
Richard Hughes639da472018-01-06 22:35:04 +00002288 /* no object loaded */
Richard Hughes41c15482018-02-01 22:07:21 +00002289 if (priv->module == NULL) {
2290 g_debug ("module not enabled, skipping");
Richard Hughes639da472018-01-06 22:35:04 +00002291 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00002292 }
Richard Hughes639da472018-01-06 22:35:04 +00002293
Richard Hughesd0905142016-03-13 09:46:49 +00002294 /* optional */
Richard Hughesa785a1c2017-08-25 16:00:58 +01002295 g_module_symbol (priv->module, "fu_plugin_update", (gpointer *) &update_func);
2296 if (update_func == NULL) {
Richard Hughes4b303802019-10-04 13:22:51 +01002297 g_debug ("running superclassed write_firmware() on %s", priv->name);
2298 return fu_plugin_device_write_firmware (self, device, blob_fw, flags, error);
Richard Hughesa785a1c2017-08-25 16:00:58 +01002299 }
Richard Hughesd0905142016-03-13 09:46:49 +00002300
Richard Hughescff38bc2016-12-12 12:03:37 +00002301 /* online */
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002302 if (!update_func (self, device, blob_fw, flags, &error_local)) {
2303 if (error_local == NULL) {
2304 g_critical ("unset error in plugin %s for update()",
2305 priv->name);
2306 g_set_error_literal (&error_local,
Richard Hughes3c8ada32018-10-12 10:08:58 +01002307 FWUPD_ERROR,
2308 FWUPD_ERROR_INTERNAL,
2309 "unspecified error");
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002310 return FALSE;
Richard Hughes3c8ada32018-10-12 10:08:58 +01002311 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002312 fu_device_set_update_error (device, error_local->message);
2313 g_propagate_error (error, g_steal_pointer (&error_local));
Richard Hughescff38bc2016-12-12 12:03:37 +00002314 return FALSE;
2315 }
2316
Richard Hughesf556d372017-06-15 19:49:18 +01002317 /* no longer valid */
Richard Hughesf8039642019-01-16 12:22:22 +00002318 if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT) &&
2319 !fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) {
Richard Hughes08435162018-12-12 10:34:16 +00002320 GPtrArray *checksums = fu_device_get_checksums (device);
2321 g_ptr_array_set_size (checksums, 0);
2322 }
Richard Hughesf556d372017-06-15 19:49:18 +01002323
Richard Hughes019a1bc2019-11-26 10:19:33 +00002324 /* success */
Richard Hughesd0905142016-03-13 09:46:49 +00002325 return TRUE;
2326}
Richard Hughescff38bc2016-12-12 12:03:37 +00002327
Mario Limonciello1a680f32019-11-25 19:44:53 -06002328/**
2329 * fu_plugin_runner_clear_results:
2330 * @self: a #FuPlugin
2331 * @device: a #FuDevice
2332 * @error: A #GError or NULL
2333 *
2334 * Call into the plugin's clear results routine
2335 *
2336 * Returns: #TRUE for success, #FALSE for failure
2337 *
2338 * Since: 0.8.0
2339 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002340gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002341fu_plugin_runner_clear_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00002342{
Richard Hughes12724852018-09-04 13:53:44 +01002343 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00002344 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002345 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002346
2347 /* not enabled */
2348 if (!priv->enabled)
2349 return TRUE;
2350
Richard Hughes639da472018-01-06 22:35:04 +00002351 /* no object loaded */
2352 if (priv->module == NULL)
2353 return TRUE;
2354
Richard Hughes65e44ca2018-01-30 17:26:30 +00002355 /* optional */
Richard Hughescd644902019-11-01 12:35:17 +00002356 g_module_symbol (priv->module, "fu_plugin_clear_results", (gpointer *) &func);
Richard Hughes65e44ca2018-01-30 17:26:30 +00002357 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00002358 return TRUE;
Richard Hughes65e44ca2018-01-30 17:26:30 +00002359 g_debug ("performing clear_result() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002360 if (!func (self, device, &error_local)) {
2361 if (error_local == NULL) {
2362 g_critical ("unset error in plugin %s for clear_result()",
2363 priv->name);
2364 g_set_error_literal (&error_local,
2365 FWUPD_ERROR,
2366 FWUPD_ERROR_INTERNAL,
2367 "unspecified error");
2368 }
2369 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2370 "failed to clear_result using %s: ",
2371 priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00002372 return FALSE;
2373 }
Richard Hughes65e44ca2018-01-30 17:26:30 +00002374 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00002375}
2376
Mario Limonciello1a680f32019-11-25 19:44:53 -06002377/**
2378 * fu_plugin_runner_get_results:
2379 * @self: a #FuPlugin
2380 * @device: a #FuDevice
2381 * @error: A #GError or NULL
2382 *
2383 * Call into the plugin's get results routine
2384 *
2385 * Returns: #TRUE for success, #FALSE for failure
2386 *
2387 * Since: 0.8.0
2388 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002389gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002390fu_plugin_runner_get_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00002391{
Richard Hughes12724852018-09-04 13:53:44 +01002392 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00002393 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002394 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002395
2396 /* not enabled */
2397 if (!priv->enabled)
2398 return TRUE;
2399
Richard Hughes639da472018-01-06 22:35:04 +00002400 /* no object loaded */
2401 if (priv->module == NULL)
2402 return TRUE;
2403
Richard Hughes65e44ca2018-01-30 17:26:30 +00002404 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00002405 g_module_symbol (priv->module, "fu_plugin_get_results", (gpointer *) &func);
Richard Hughes65e44ca2018-01-30 17:26:30 +00002406 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00002407 return TRUE;
Richard Hughes65e44ca2018-01-30 17:26:30 +00002408 g_debug ("performing get_results() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002409 if (!func (self, device, &error_local)) {
2410 if (error_local == NULL) {
2411 g_critical ("unset error in plugin %s for get_results()",
2412 priv->name);
2413 g_set_error_literal (&error_local,
2414 FWUPD_ERROR,
2415 FWUPD_ERROR_INTERNAL,
2416 "unspecified error");
2417 }
2418 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2419 "failed to get_results using %s: ",
2420 priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00002421 return FALSE;
2422 }
Richard Hughescff38bc2016-12-12 12:03:37 +00002423 return TRUE;
2424}
2425
Richard Hughes08a37992017-09-12 12:57:43 +01002426/**
2427 * fu_plugin_get_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002428 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002429 *
2430 * Gets the plugin order, where higher numbers are run after lower
2431 * numbers.
2432 *
2433 * Returns: the integer value
Mario Limonciello1a680f32019-11-25 19:44:53 -06002434 *
2435 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002436 **/
2437guint
Richard Hughes12724852018-09-04 13:53:44 +01002438fu_plugin_get_order (FuPlugin *self)
Richard Hughes08a37992017-09-12 12:57:43 +01002439{
Richard Hughes12724852018-09-04 13:53:44 +01002440 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002441 return priv->order;
2442}
2443
2444/**
2445 * fu_plugin_set_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002446 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002447 * @order: a integer value
2448 *
2449 * Sets the plugin order, where higher numbers are run after lower
2450 * numbers.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002451 *
2452 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002453 **/
2454void
Richard Hughes12724852018-09-04 13:53:44 +01002455fu_plugin_set_order (FuPlugin *self, guint order)
Richard Hughes08a37992017-09-12 12:57:43 +01002456{
Richard Hughes12724852018-09-04 13:53:44 +01002457 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002458 priv->order = order;
2459}
2460
2461/**
Richard Hughes81c427c2018-08-06 15:20:17 +01002462 * fu_plugin_get_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002463 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01002464 *
2465 * Gets the plugin priority, where higher numbers are better.
2466 *
2467 * Returns: the integer value
Mario Limonciello1a680f32019-11-25 19:44:53 -06002468 *
2469 * Since: 1.1.1
Richard Hughes81c427c2018-08-06 15:20:17 +01002470 **/
2471guint
Richard Hughes12724852018-09-04 13:53:44 +01002472fu_plugin_get_priority (FuPlugin *self)
Richard Hughes81c427c2018-08-06 15:20:17 +01002473{
Richard Hughes12724852018-09-04 13:53:44 +01002474 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01002475 return priv->priority;
2476}
2477
2478/**
2479 * fu_plugin_set_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002480 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01002481 * @priority: a integer value
2482 *
2483 * Sets the plugin priority, where higher numbers are better.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002484 *
2485 * Since: 1.0.0
Richard Hughes81c427c2018-08-06 15:20:17 +01002486 **/
2487void
Richard Hughes12724852018-09-04 13:53:44 +01002488fu_plugin_set_priority (FuPlugin *self, guint priority)
Richard Hughes81c427c2018-08-06 15:20:17 +01002489{
Richard Hughes12724852018-09-04 13:53:44 +01002490 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01002491 priv->priority = priority;
2492}
2493
2494/**
Richard Hughes08a37992017-09-12 12:57:43 +01002495 * fu_plugin_add_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002496 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002497 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
Richard Hughes4eada342017-10-03 21:20:32 +01002498 * @name: a plugin name, e.g. `upower`
Richard Hughes08a37992017-09-12 12:57:43 +01002499 *
2500 * If the plugin name is found, the rule will be used to sort the plugin list,
2501 * for example the plugin specified by @name will be ordered after this plugin
2502 * when %FU_PLUGIN_RULE_RUN_AFTER is used.
2503 *
2504 * NOTE: The depsolver is iterative and may not solve overly-complicated rules;
2505 * If depsolving fails then fwupd will not start.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002506 *
2507 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002508 **/
2509void
Richard Hughes12724852018-09-04 13:53:44 +01002510fu_plugin_add_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes08a37992017-09-12 12:57:43 +01002511{
Richard Hughes12724852018-09-04 13:53:44 +01002512 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes11c59412020-06-22 15:29:48 +01002513 if (priv->rules[rule] == NULL)
2514 priv->rules[rule] = g_ptr_array_new_with_free_func (g_free);
Richard Hughes08a37992017-09-12 12:57:43 +01002515 g_ptr_array_add (priv->rules[rule], g_strdup (name));
Richard Hughes75b965d2018-11-15 13:51:21 +00002516 g_signal_emit (self, signals[SIGNAL_RULES_CHANGED], 0);
Richard Hughes08a37992017-09-12 12:57:43 +01002517}
2518
2519/**
2520 * fu_plugin_get_rules:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002521 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002522 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
2523 *
2524 * Gets the plugin IDs that should be run after this plugin.
2525 *
Richard Hughes11c59412020-06-22 15:29:48 +01002526 * Returns: (element-type utf8) (transfer none) (nullable): the list of plugin names, e.g. ['appstream']
Mario Limonciello1a680f32019-11-25 19:44:53 -06002527 *
2528 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002529 **/
2530GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +01002531fu_plugin_get_rules (FuPlugin *self, FuPluginRule rule)
Richard Hughes08a37992017-09-12 12:57:43 +01002532{
Richard Hughes12724852018-09-04 13:53:44 +01002533 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughesdad35972019-12-06 11:00:25 +00002534 g_return_val_if_fail (rule < FU_PLUGIN_RULE_LAST, NULL);
Richard Hughes08a37992017-09-12 12:57:43 +01002535 return priv->rules[rule];
2536}
2537
Richard Hughes80b79bb2018-01-11 21:11:06 +00002538/**
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002539 * fu_plugin_has_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002540 * @self: a #FuPlugin
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002541 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
2542 * @name: a plugin name, e.g. `upower`
2543 *
Richard Hughes87fb9ff2018-06-28 12:55:59 +01002544 * Gets the plugin IDs that should be run after this plugin.
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002545 *
2546 * Returns: %TRUE if the name exists for the specific rule
Mario Limonciello1a680f32019-11-25 19:44:53 -06002547 *
2548 * Since: 1.0.0
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002549 **/
2550gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002551fu_plugin_has_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002552{
Richard Hughes12724852018-09-04 13:53:44 +01002553 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes11c59412020-06-22 15:29:48 +01002554 if (priv->rules[rule] == NULL)
2555 return FALSE;
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002556 for (guint i = 0; i < priv->rules[rule]->len; i++) {
2557 const gchar *tmp = g_ptr_array_index (priv->rules[rule], i);
2558 if (g_strcmp0 (tmp, name) == 0)
2559 return TRUE;
2560 }
2561 return FALSE;
2562}
2563
2564/**
Richard Hughes80b79bb2018-01-11 21:11:06 +00002565 * fu_plugin_add_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002566 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00002567 * @key: a string, e.g. `FwupdateVersion`
2568 * @value: a string, e.g. `10`
2569 *
2570 * Sets any additional metadata to be included in the firmware report to aid
2571 * debugging problems.
2572 *
2573 * Any data included here will be sent to the metadata server after user
2574 * confirmation.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002575 *
2576 * Since: 1.0.4
Richard Hughes80b79bb2018-01-11 21:11:06 +00002577 **/
2578void
Richard Hughes12724852018-09-04 13:53:44 +01002579fu_plugin_add_report_metadata (FuPlugin *self, const gchar *key, const gchar *value)
Richard Hughes80b79bb2018-01-11 21:11:06 +00002580{
Richard Hughes12724852018-09-04 13:53:44 +01002581 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes1d900f72020-06-22 15:17:39 +01002582 if (priv->report_metadata == NULL) {
2583 priv->report_metadata = g_hash_table_new_full (g_str_hash,
2584 g_str_equal,
2585 g_free,
2586 g_free);
2587 }
Richard Hughes80b79bb2018-01-11 21:11:06 +00002588 g_hash_table_insert (priv->report_metadata, g_strdup (key), g_strdup (value));
2589}
2590
2591/**
2592 * fu_plugin_get_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002593 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00002594 *
2595 * Returns the list of additional metadata to be added when filing a report.
2596 *
Richard Hughes1d900f72020-06-22 15:17:39 +01002597 * Returns: (transfer none) (nullable): the map of report metadata
Mario Limonciello1a680f32019-11-25 19:44:53 -06002598 *
2599 * Since: 1.0.4
Richard Hughes80b79bb2018-01-11 21:11:06 +00002600 **/
2601GHashTable *
Richard Hughes12724852018-09-04 13:53:44 +01002602fu_plugin_get_report_metadata (FuPlugin *self)
Richard Hughes80b79bb2018-01-11 21:11:06 +00002603{
Richard Hughes12724852018-09-04 13:53:44 +01002604 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002605 return priv->report_metadata;
2606}
2607
Mario Limonciello963dc422018-02-27 14:26:58 -06002608/**
2609 * fu_plugin_get_config_value:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002610 * @self: a #FuPlugin
Mario Limonciello963dc422018-02-27 14:26:58 -06002611 * @key: A settings key
2612 *
2613 * Return the value of a key if it's been configured
2614 *
2615 * Since: 1.0.6
2616 **/
2617gchar *
Richard Hughes12724852018-09-04 13:53:44 +01002618fu_plugin_get_config_value (FuPlugin *self, const gchar *key)
Mario Limonciello963dc422018-02-27 14:26:58 -06002619{
Richard Hughes4be17d12018-05-30 20:36:29 +01002620 g_autofree gchar *conf_dir = NULL;
Mario Limonciello963dc422018-02-27 14:26:58 -06002621 g_autofree gchar *conf_file = NULL;
2622 g_autofree gchar *conf_path = NULL;
2623 g_autoptr(GKeyFile) keyfile = NULL;
2624 const gchar *plugin_name;
2625
Richard Hughes4be17d12018-05-30 20:36:29 +01002626 conf_dir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR_PKG);
Richard Hughes12724852018-09-04 13:53:44 +01002627 plugin_name = fu_plugin_get_name (self);
Mario Limonciello963dc422018-02-27 14:26:58 -06002628 conf_file = g_strdup_printf ("%s.conf", plugin_name);
Richard Hughes4be17d12018-05-30 20:36:29 +01002629 conf_path = g_build_filename (conf_dir, conf_file, NULL);
Mario Limonciello963dc422018-02-27 14:26:58 -06002630 if (!g_file_test (conf_path, G_FILE_TEST_IS_REGULAR))
2631 return NULL;
2632 keyfile = g_key_file_new ();
2633 if (!g_key_file_load_from_file (keyfile, conf_path,
2634 G_KEY_FILE_NONE, NULL))
2635 return NULL;
2636 return g_key_file_get_string (keyfile, plugin_name, key, NULL);
2637}
2638
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002639/**
Richard Hughes334ba792020-02-19 20:44:56 +00002640 * fu_plugin_get_config_value_boolean:
2641 * @self: a #FuPlugin
2642 * @key: A settings key
2643 *
2644 * Return the boolean value of a key if it's been configured
2645 *
2646 * Returns: %TRUE if the value is `true` (case insensitive), %FALSE otherwise
2647 *
Mario Limonciello96117d12020-02-28 10:17:56 -06002648 * Since: 1.4.0
Richard Hughes334ba792020-02-19 20:44:56 +00002649 **/
2650gboolean
2651fu_plugin_get_config_value_boolean (FuPlugin *self, const gchar *key)
2652{
2653 g_autofree gchar *tmp = fu_plugin_get_config_value (self, key);
2654 if (tmp == NULL)
2655 return FALSE;
Richard Hughes5337a432020-02-21 12:04:32 +00002656 return g_ascii_strcasecmp (tmp, "true") == 0;
Richard Hughes334ba792020-02-19 20:44:56 +00002657}
2658
2659/**
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002660 * fu_plugin_name_compare:
2661 * @plugin1: first #FuPlugin to compare.
2662 * @plugin2: second #FuPlugin to compare.
2663 *
2664 * Compares two plugins by their names.
2665 *
2666 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002667 *
2668 * Since: 1.0.8
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002669 **/
2670gint
2671fu_plugin_name_compare (FuPlugin *plugin1, FuPlugin *plugin2)
2672{
2673 FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1);
2674 FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2);
2675 return g_strcmp0 (priv1->name, priv2->name);
2676}
2677
2678/**
2679 * fu_plugin_order_compare:
2680 * @plugin1: first #FuPlugin to compare.
2681 * @plugin2: second #FuPlugin to compare.
2682 *
2683 * Compares two plugins by their depsolved order.
2684 *
2685 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002686 *
2687 * Since: 1.0.8
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002688 **/
2689gint
2690fu_plugin_order_compare (FuPlugin *plugin1, FuPlugin *plugin2)
2691{
2692 FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1);
2693 FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2);
2694 if (priv1->order < priv2->order)
2695 return -1;
2696 if (priv1->order > priv2->order)
2697 return 1;
2698 return 0;
2699}
2700
Richard Hughescff38bc2016-12-12 12:03:37 +00002701static void
2702fu_plugin_class_init (FuPluginClass *klass)
2703{
2704 GObjectClass *object_class = G_OBJECT_CLASS (klass);
2705 object_class->finalize = fu_plugin_finalize;
2706 signals[SIGNAL_DEVICE_ADDED] =
2707 g_signal_new ("device-added",
2708 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2709 G_STRUCT_OFFSET (FuPluginClass, device_added),
2710 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2711 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
2712 signals[SIGNAL_DEVICE_REMOVED] =
2713 g_signal_new ("device-removed",
2714 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2715 G_STRUCT_OFFSET (FuPluginClass, device_removed),
2716 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2717 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughese1fd34d2017-08-24 14:19:51 +01002718 signals[SIGNAL_DEVICE_REGISTER] =
2719 g_signal_new ("device-register",
2720 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2721 G_STRUCT_OFFSET (FuPluginClass, device_register),
2722 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2723 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughes362d6d72017-01-07 21:42:14 +00002724 signals[SIGNAL_RECOLDPLUG] =
2725 g_signal_new ("recoldplug",
2726 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2727 G_STRUCT_OFFSET (FuPluginClass, recoldplug),
2728 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2729 G_TYPE_NONE, 0);
Richard Hughes399859e2020-05-11 19:44:03 +01002730 signals[SIGNAL_SECURITY_CHANGED] =
2731 g_signal_new ("security-changed",
2732 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2733 G_STRUCT_OFFSET (FuPluginClass, security_changed),
2734 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2735 G_TYPE_NONE, 0);
Richard Hughesb0829032017-01-10 09:27:08 +00002736 signals[SIGNAL_SET_COLDPLUG_DELAY] =
2737 g_signal_new ("set-coldplug-delay",
2738 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2739 G_STRUCT_OFFSET (FuPluginClass, set_coldplug_delay),
2740 NULL, NULL, g_cclosure_marshal_VOID__UINT,
2741 G_TYPE_NONE, 1, G_TYPE_UINT);
Richard Hughesaabdc372018-11-14 10:11:08 +00002742 signals[SIGNAL_CHECK_SUPPORTED] =
2743 g_signal_new ("check-supported",
2744 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2745 G_STRUCT_OFFSET (FuPluginClass, check_supported),
2746 NULL, NULL, g_cclosure_marshal_generic,
2747 G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
Richard Hughes75b965d2018-11-15 13:51:21 +00002748 signals[SIGNAL_RULES_CHANGED] =
2749 g_signal_new ("rules-changed",
2750 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2751 G_STRUCT_OFFSET (FuPluginClass, rules_changed),
2752 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2753 G_TYPE_NONE, 0);
Richard Hughes95c98a92019-10-22 16:03:15 +01002754 signals[SIGNAL_ADD_FIRMWARE_GTYPE] =
2755 g_signal_new ("add-firmware-gtype",
2756 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2757 G_STRUCT_OFFSET (FuPluginClass, add_firmware_gtype),
2758 NULL, NULL, g_cclosure_marshal_generic,
2759 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_GTYPE);
Richard Hughescff38bc2016-12-12 12:03:37 +00002760}
2761
2762static void
Richard Hughes12724852018-09-04 13:53:44 +01002763fu_plugin_init (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +00002764{
Richard Hughes12724852018-09-04 13:53:44 +01002765 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002766 priv->enabled = TRUE;
Richard Hughes161e9b52019-06-12 14:22:45 +01002767 g_rw_lock_init (&priv->devices_mutex);
Richard Hughescff38bc2016-12-12 12:03:37 +00002768}
2769
2770static void
2771fu_plugin_finalize (GObject *object)
2772{
Richard Hughes12724852018-09-04 13:53:44 +01002773 FuPlugin *self = FU_PLUGIN (object);
2774 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002775 FuPluginInitFunc func = NULL;
2776
2777 /* optional */
2778 if (priv->module != NULL) {
2779 g_module_symbol (priv->module, "fu_plugin_destroy", (gpointer *) &func);
2780 if (func != NULL) {
2781 g_debug ("performing destroy() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01002782 func (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002783 }
2784 }
2785
Richard Hughes11c59412020-06-22 15:29:48 +01002786 for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++) {
2787 if (priv->rules[i] != NULL)
2788 g_ptr_array_unref (priv->rules[i]);
2789 }
Richard Hughescff38bc2016-12-12 12:03:37 +00002790 if (priv->usb_ctx != NULL)
2791 g_object_unref (priv->usb_ctx);
Richard Hughesb8f8db22017-04-25 15:56:00 +01002792 if (priv->hwids != NULL)
Richard Hughesd7704d42017-08-08 20:29:09 +01002793 g_object_unref (priv->hwids);
Richard Hughes9c028f02017-10-28 21:14:28 +01002794 if (priv->quirks != NULL)
2795 g_object_unref (priv->quirks);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01002796 if (priv->udev_subsystems != NULL)
2797 g_ptr_array_unref (priv->udev_subsystems);
Richard Hughes49e5e052017-09-03 12:15:41 +01002798 if (priv->smbios != NULL)
2799 g_object_unref (priv->smbios);
Richard Hughes275d3b42018-04-20 16:40:37 +01002800 if (priv->runtime_versions != NULL)
2801 g_hash_table_unref (priv->runtime_versions);
Richard Hughes34e0dab2018-04-20 16:43:00 +01002802 if (priv->compile_versions != NULL)
2803 g_hash_table_unref (priv->compile_versions);
Richard Hughes1d900f72020-06-22 15:17:39 +01002804 if (priv->report_metadata != NULL)
2805 g_hash_table_unref (priv->report_metadata);
Richard Hughes371f6b22020-06-22 15:21:17 +01002806 if (priv->devices != NULL)
2807 g_hash_table_unref (priv->devices);
Richard Hughes161e9b52019-06-12 14:22:45 +01002808 g_rw_lock_clear (&priv->devices_mutex);
Richard Hughes84999302019-05-02 10:18:32 +01002809 g_free (priv->build_hash);
Richard Hughescff38bc2016-12-12 12:03:37 +00002810 g_free (priv->name);
2811 g_free (priv->data);
Mario Limonciello3f9a1c12018-06-06 14:06:40 -05002812 /* Must happen as the last step to avoid prematurely
2813 * freeing memory held by the plugin */
Richard Hughes862ec5c2020-05-22 14:38:02 +01002814#ifdef RUNNING_ON_VALGRIND
2815 if (priv->module != NULL && RUNNING_ON_VALGRIND == 0)
2816#else
Mario Limonciello3f9a1c12018-06-06 14:06:40 -05002817 if (priv->module != NULL)
Mario Limonciello3f9a1c12018-06-06 14:06:40 -05002818#endif
Richard Hughes862ec5c2020-05-22 14:38:02 +01002819 g_module_close (priv->module);
Richard Hughescff38bc2016-12-12 12:03:37 +00002820
2821 G_OBJECT_CLASS (fu_plugin_parent_class)->finalize (object);
2822}
2823
Mario Limonciello1a680f32019-11-25 19:44:53 -06002824/**
2825 * fu_plugin_new:
2826 *
2827 * Creates a new #FuPlugin
2828 *
2829 * Since: 0.8.0
2830 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002831FuPlugin *
2832fu_plugin_new (void)
2833{
Richard Hughes12724852018-09-04 13:53:44 +01002834 return FU_PLUGIN (g_object_new (FU_TYPE_PLUGIN, NULL));
Richard Hughescff38bc2016-12-12 12:03:37 +00002835}