blob: 6236d03240755b432dbc453168472a18cf950da9 [file] [log] [blame]
Richard Hughes02c90d82018-08-09 12:13:03 +01001/*
Richard Hughes5c9b1fc2021-01-07 14:20:49 +00002 * Copyright (C) 2016 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;
Richard Hughes08a37992017-09-12 12:57:43 +010040 guint order;
Richard Hughes81c427c2018-08-06 15:20:17 +010041 guint priority;
Richard Hughes08a37992017-09-12 12:57:43 +010042 GPtrArray *rules[FU_PLUGIN_RULE_LAST];
Richard Hughes68ab1e42021-01-13 14:01:17 +000043 GPtrArray *devices; /* (nullable) (element-type FuDevice) */
Richard Hughesf425d292019-01-18 17:57:39 +000044 gchar *build_hash;
Richard Hughesd7704d42017-08-08 20:29:09 +010045 FuHwids *hwids;
Richard Hughes9c028f02017-10-28 21:14:28 +010046 FuQuirks *quirks;
Richard Hughes0eb123b2018-04-19 12:00:04 +010047 GHashTable *runtime_versions;
Richard Hughes34e0dab2018-04-20 16:43:00 +010048 GHashTable *compile_versions;
Richard Hughes9d6e0e72018-08-24 20:20:17 +010049 GPtrArray *udev_subsystems;
Richard Hughes1354ea92017-09-19 15:58:31 +010050 FuSmbios *smbios;
Richard Hughes989acf12019-10-05 20:16:47 +010051 GType device_gtype;
Richard Hughesfaf2afe2021-01-13 14:00:20 +000052 GHashTable *cache; /* (nullable): platform_id:GObject */
53 GRWLock cache_mutex;
Richard Hughes1d900f72020-06-22 15:17:39 +010054 GHashTable *report_metadata; /* (nullable): key:value */
Richard Hughescff38bc2016-12-12 12:03:37 +000055 FuPluginData *data;
56} FuPluginPrivate;
57
58enum {
59 SIGNAL_DEVICE_ADDED,
60 SIGNAL_DEVICE_REMOVED,
Richard Hughese1fd34d2017-08-24 14:19:51 +010061 SIGNAL_DEVICE_REGISTER,
Richard Hughes75b965d2018-11-15 13:51:21 +000062 SIGNAL_RULES_CHANGED,
Richard Hughes362d6d72017-01-07 21:42:14 +000063 SIGNAL_RECOLDPLUG,
Richard Hughesb0829032017-01-10 09:27:08 +000064 SIGNAL_SET_COLDPLUG_DELAY,
Richard Hughesaabdc372018-11-14 10:11:08 +000065 SIGNAL_CHECK_SUPPORTED,
Richard Hughes95c98a92019-10-22 16:03:15 +010066 SIGNAL_ADD_FIRMWARE_GTYPE,
Richard Hughes399859e2020-05-11 19:44:03 +010067 SIGNAL_SECURITY_CHANGED,
Richard Hughescff38bc2016-12-12 12:03:37 +000068 SIGNAL_LAST
69};
70
71static guint signals[SIGNAL_LAST] = { 0 };
72
Richard Hughes7bcb8d42020-10-08 15:47:47 +010073G_DEFINE_TYPE_WITH_PRIVATE (FuPlugin, fu_plugin, FWUPD_TYPE_PLUGIN)
Richard Hughescff38bc2016-12-12 12:03:37 +000074#define GET_PRIVATE(o) (fu_plugin_get_instance_private (o))
75
76typedef const gchar *(*FuPluginGetNameFunc) (void);
Richard Hughes12724852018-09-04 13:53:44 +010077typedef void (*FuPluginInitFunc) (FuPlugin *self);
78typedef gboolean (*FuPluginStartupFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000079 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010080typedef void (*FuPluginDeviceRegisterFunc) (FuPlugin *self,
Richard Hughese1fd34d2017-08-24 14:19:51 +010081 FuDevice *device);
Richard Hughes12724852018-09-04 13:53:44 +010082typedef gboolean (*FuPluginDeviceFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000083 FuDevice *device,
84 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010085typedef gboolean (*FuPluginFlaggedDeviceFunc) (FuPlugin *self,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -050086 FwupdInstallFlags flags,
87 FuDevice *device,
88 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010089typedef gboolean (*FuPluginDeviceArrayFunc) (FuPlugin *self,
Richard Hughesdbd8c762018-06-15 20:31:40 +010090 GPtrArray *devices,
91 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010092typedef gboolean (*FuPluginVerifyFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000093 FuDevice *device,
94 FuPluginVerifyFlags flags,
95 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010096typedef gboolean (*FuPluginUpdateFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000097 FuDevice *device,
98 GBytes *blob_fw,
99 FwupdInstallFlags flags,
100 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +0100101typedef gboolean (*FuPluginUsbDeviceAddedFunc) (FuPlugin *self,
Richard Hughesff704412018-09-04 11:28:32 +0100102 FuUsbDevice *device,
Richard Hughes104f6512017-11-24 11:44:57 +0000103 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +0100104typedef gboolean (*FuPluginUdevDeviceAddedFunc) (FuPlugin *self,
Richard Hughesff704412018-09-04 11:28:32 +0100105 FuUdevDevice *device,
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100106 GError **error);
Richard Hughesf58ac732020-05-12 15:23:44 +0100107typedef void (*FuPluginSecurityAttrsFunc) (FuPlugin *self,
108 FuSecurityAttrs *attrs);
Richard Hughescff38bc2016-12-12 12:03:37 +0000109
Richard Hughes57d18222017-01-10 16:02:59 +0000110/**
Mario Limonciello52e75ba2019-11-22 13:21:19 -0600111 * fu_plugin_is_open:
112 * @self: A #FuPlugin
113 *
114 * Determines if the plugin is opened
115 *
116 * Returns: TRUE for opened, FALSE for not
117 *
118 * Since: 1.3.5
119 **/
120gboolean
121fu_plugin_is_open (FuPlugin *self)
122{
123 FuPluginPrivate *priv = GET_PRIVATE (self);
124 return priv->module != NULL;
125}
126
127/**
Richard Hughes57d18222017-01-10 16:02:59 +0000128 * fu_plugin_get_name:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100129 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000130 *
131 * Gets the plugin name.
132 *
133 * Returns: a plugin name, or %NULL for unknown.
134 *
135 * Since: 0.8.0
136 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000137const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100138fu_plugin_get_name (FuPlugin *self)
Richard Hughesd0905142016-03-13 09:46:49 +0000139{
Richard Hughes12724852018-09-04 13:53:44 +0100140 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100141 return fwupd_plugin_get_name (FWUPD_PLUGIN (self));
Richard Hughescff38bc2016-12-12 12:03:37 +0000142}
Richard Hughesd0905142016-03-13 09:46:49 +0000143
Mario Limonciello1a680f32019-11-25 19:44:53 -0600144/**
145 * fu_plugin_set_name:
146 * @self: A #FuPlugin
147 * @name: A string
148 *
149 * Sets the plugin name.
150 *
151 * Since: 0.8.0
152 **/
Richard Hughes34834102017-11-21 21:55:00 +0000153void
Richard Hughes12724852018-09-04 13:53:44 +0100154fu_plugin_set_name (FuPlugin *self, const gchar *name)
Richard Hughes34834102017-11-21 21:55:00 +0000155{
Richard Hughes12724852018-09-04 13:53:44 +0100156 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100157 fwupd_plugin_set_name (FWUPD_PLUGIN (self), name);
Richard Hughes34834102017-11-21 21:55:00 +0000158}
159
Richard Hughes57d18222017-01-10 16:02:59 +0000160/**
Richard Hughesf425d292019-01-18 17:57:39 +0000161 * fu_plugin_set_build_hash:
162 * @self: A #FuPlugin
163 * @build_hash: A checksum
164 *
165 * Sets the plugin build hash, typically a SHA256 checksum. All plugins must
166 * set the correct checksum to avoid the daemon being marked as tainted.
167 *
168 * Since: 1.2.4
169 **/
170void
171fu_plugin_set_build_hash (FuPlugin *self, const gchar *build_hash)
172{
173 FuPluginPrivate *priv = GET_PRIVATE (self);
174 g_return_if_fail (FU_IS_PLUGIN (self));
175 g_return_if_fail (build_hash != NULL);
Richard Hughes382524d2021-01-28 13:14:35 +0000176
177 /* not changed */
178 if (g_strcmp0 (priv->build_hash, build_hash) == 0)
179 return;
180
Richard Hughesf425d292019-01-18 17:57:39 +0000181 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 Hughesfaf2afe2021-01-13 14:00:20 +0000218 g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&priv->cache_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 Hughesfaf2afe2021-01-13 14:00:20 +0000222 if (priv->cache == NULL)
Richard Hughes371f6b22020-06-22 15:21:17 +0100223 return NULL;
Richard Hughesfaf2afe2021-01-13 14:00:20 +0000224 return g_hash_table_lookup (priv->cache, id);
Richard Hughescff38bc2016-12-12 12:03:37 +0000225}
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 Hughesfaf2afe2021-01-13 14:00:20 +0000241 g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&priv->cache_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 Hughesfaf2afe2021-01-13 14:00:20 +0000245 if (priv->cache == NULL) {
246 priv->cache = g_hash_table_new_full (g_str_hash,
247 g_str_equal,
248 g_free,
249 (GDestroyNotify) g_object_unref);
Richard Hughes371f6b22020-06-22 15:21:17 +0100250 }
Richard Hughesfaf2afe2021-01-13 14:00:20 +0000251 g_hash_table_insert (priv->cache, g_strdup (id), g_object_ref (dev));
Richard Hughescff38bc2016-12-12 12:03:37 +0000252}
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 Hughesfaf2afe2021-01-13 14:00:20 +0000267 g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&priv->cache_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 Hughesfaf2afe2021-01-13 14:00:20 +0000271 if (priv->cache == NULL)
Richard Hughes371f6b22020-06-22 15:21:17 +0100272 return;
Richard Hughesfaf2afe2021-01-13 14:00:20 +0000273 g_hash_table_remove (priv->cache, id);
Richard Hughescff38bc2016-12-12 12:03:37 +0000274}
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 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100368 return !fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED);
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000369}
370
Richard Hughes57d18222017-01-10 16:02:59 +0000371/**
372 * fu_plugin_set_enabled:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100373 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000374 * @enabled: the enabled value
375 *
376 * Enables or disables a plugin. Plugins can self-disable at any point.
377 *
378 * Since: 0.8.0
379 **/
Richard Hughesd0905142016-03-13 09:46:49 +0000380void
Richard Hughes12724852018-09-04 13:53:44 +0100381fu_plugin_set_enabled (FuPlugin *self, gboolean enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000382{
Richard Hughes12724852018-09-04 13:53:44 +0100383 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100384 if (enabled) {
385 fwupd_plugin_remove_flag (FWUPD_PLUGIN (self),
386 FWUPD_PLUGIN_FLAG_DISABLED);
387 } else {
388 fu_plugin_add_flag (self, FWUPD_PLUGIN_FLAG_DISABLED);
389 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000390}
391
Mario Limonciello1a680f32019-11-25 19:44:53 -0600392/**
393 * fu_plugin_guess_name_from_fn:
394 * @filename: filename to guess
395 *
396 * Tries to guess the name of the plugin from a filename
397 *
398 * Returns: (transfer full): the guessed name of the plugin
399 *
400 * Since: 1.0.8
401 **/
Richard Hughes1e456bc2018-05-10 20:16:16 +0100402gchar *
403fu_plugin_guess_name_from_fn (const gchar *filename)
404{
405 const gchar *prefix = "libfu_plugin_";
406 gchar *name;
407 gchar *str = g_strstr_len (filename, -1, prefix);
408 if (str == NULL)
409 return NULL;
410 name = g_strdup (str + strlen (prefix));
411 g_strdelimit (name, ".", '\0');
412 return name;
413}
414
Mario Limonciello1a680f32019-11-25 19:44:53 -0600415/**
416 * fu_plugin_open:
417 * @self: A #FuPlugin
418 * @filename: The shared object filename to open
419 * @error: A #GError or NULL
420 *
421 * Opens the plugin module
422 *
423 * Returns: TRUE for success, FALSE for fail
424 *
425 * Since: 0.8.0
426 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000427gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100428fu_plugin_open (FuPlugin *self, const gchar *filename, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +0000429{
Richard Hughes12724852018-09-04 13:53:44 +0100430 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +0000431 FuPluginInitFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000432
Richard Hughes6a489a92020-12-22 10:32:06 +0000433 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
434 g_return_val_if_fail (filename != NULL, FALSE);
435 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
436
Richard Hughescff38bc2016-12-12 12:03:37 +0000437 priv->module = g_module_open (filename, 0);
438 if (priv->module == NULL) {
439 g_set_error (error,
440 G_IO_ERROR,
441 G_IO_ERROR_FAILED,
Mario Limonciellof5605532019-11-04 07:49:50 -0600442 "failed to open plugin %s: %s",
443 filename, g_module_error ());
Mario Limoncielloc3a81732020-10-20 09:16:18 -0500444 fu_plugin_add_flag (self, FWUPD_PLUGIN_FLAG_FAILED_OPEN);
445 fu_plugin_add_flag (self, FWUPD_PLUGIN_FLAG_USER_WARNING);
Richard Hughescff38bc2016-12-12 12:03:37 +0000446 return FALSE;
447 }
448
449 /* set automatically */
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100450 if (fu_plugin_get_name (self) == NULL) {
451 g_autofree gchar *str = fu_plugin_guess_name_from_fn (filename);
452 fu_plugin_set_name (self, str);
453 }
Richard Hughesd0905142016-03-13 09:46:49 +0000454
455 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000456 g_module_symbol (priv->module, "fu_plugin_init", (gpointer *) &func);
457 if (func != NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -0500458 g_debug ("init(%s)", filename);
Richard Hughes12724852018-09-04 13:53:44 +0100459 func (self);
Richard Hughesd0905142016-03-13 09:46:49 +0000460 }
461
Richard Hughescff38bc2016-12-12 12:03:37 +0000462 return TRUE;
463}
464
Richard Hughes203ed842020-11-02 14:25:13 +0000465/* order of usefulness to the user */
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100466static const gchar *
467fu_plugin_build_device_update_error (FuPlugin *self)
468{
469 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_NO_HARDWARE))
470 return "Not updatable as required hardware was not found";
471 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_LEGACY_BIOS))
472 return "Not updatable in legacy BIOS mode";
473 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED))
Mario Limonciello797da4f2021-01-12 12:38:51 -0600474 return "Not updatable as UEFI capsule updates not enabled in firmware setup";
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100475 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_UNLOCK_REQUIRED))
476 return "Not updatable as requires unlock";
477 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_EFIVAR_NOT_MOUNTED))
478 return "Not updatable as efivarfs was not found";
479 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND))
480 return "Not updatable as UEFI ESP partition not detected";
481 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
482 return "Not updatable as plugin was disabled";
483 return NULL;
484}
485
Richard Hughes68ab1e42021-01-13 14:01:17 +0000486static void
487fu_plugin_ensure_devices (FuPlugin *self)
488{
489 FuPluginPrivate *priv = GET_PRIVATE (self);
490 if (priv->devices != NULL)
491 return;
492 priv->devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
493}
494
Richard Hughes57d18222017-01-10 16:02:59 +0000495/**
496 * fu_plugin_device_add:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100497 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000498 * @device: A #FuDevice
499 *
500 * Asks the daemon to add a device to the exported list. If this device ID
501 * has already been added by a different plugin then this request will be
502 * ignored.
503 *
504 * Plugins should use fu_plugin_device_add_delay() if they are not capable of
505 * actually flashing an image to the hardware so that higher-priority plugins
506 * can add the device themselves.
507 *
508 * Since: 0.8.0
509 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000510void
Richard Hughes12724852018-09-04 13:53:44 +0100511fu_plugin_device_add (FuPlugin *self, FuDevice *device)
Richard Hughescff38bc2016-12-12 12:03:37 +0000512{
Richard Hughes68ab1e42021-01-13 14:01:17 +0000513 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes5e447292018-04-27 14:25:54 +0100514 GPtrArray *children;
Richard Hughesc125ec02018-09-05 19:35:17 +0100515 g_autoptr(GError) error = NULL;
Richard Hughes5e447292018-04-27 14:25:54 +0100516
Richard Hughes12724852018-09-04 13:53:44 +0100517 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000518 g_return_if_fail (FU_IS_DEVICE (device));
519
Richard Hughesc125ec02018-09-05 19:35:17 +0100520 /* ensure the device ID is set from the physical and logical IDs */
521 if (!fu_device_ensure_id (device, &error)) {
522 g_warning ("ignoring add: %s", error->message);
523 return;
524 }
525
Richard Hughes68ab1e42021-01-13 14:01:17 +0000526 /* add to array */
527 fu_plugin_ensure_devices (self);
528 g_ptr_array_add (priv->devices, g_object_ref (device));
529
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100530 /* proxy to device where required */
531 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE)) {
532 g_debug ("plugin %s has _CLEAR_UPDATABLE, so removing from %s",
533 fu_plugin_get_name (self),
534 fu_device_get_id (device));
535 fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE);
536 }
537 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_USER_WARNING) &&
538 fu_device_get_update_error (device) == NULL) {
539 const gchar *tmp = fu_plugin_build_device_update_error (self);
540 g_debug ("setting %s update error to '%s' from %s",
541 fu_device_get_id (device), tmp, fu_plugin_get_name (self));
542 fu_device_set_update_error (device, tmp);
543 }
544
Richard Hughescff38bc2016-12-12 12:03:37 +0000545 g_debug ("emit added from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100546 fu_plugin_get_name (self),
Richard Hughescff38bc2016-12-12 12:03:37 +0000547 fu_device_get_id (device));
548 fu_device_set_created (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
Richard Hughes12724852018-09-04 13:53:44 +0100549 fu_device_set_plugin (device, fu_plugin_get_name (self));
550 g_signal_emit (self, signals[SIGNAL_DEVICE_ADDED], 0, device);
Richard Hughes5e447292018-04-27 14:25:54 +0100551
Richard Hughes128c0162018-08-10 11:00:29 +0100552 /* add children if they have not already been added */
Richard Hughes5e447292018-04-27 14:25:54 +0100553 children = fu_device_get_children (device);
554 for (guint i = 0; i < children->len; i++) {
555 FuDevice *child = g_ptr_array_index (children, i);
Richard Hughes128c0162018-08-10 11:00:29 +0100556 if (fu_device_get_created (child) == 0)
Richard Hughes12724852018-09-04 13:53:44 +0100557 fu_plugin_device_add (self, child);
Richard Hughes5e447292018-04-27 14:25:54 +0100558 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000559}
560
Richard Hughese1fd34d2017-08-24 14:19:51 +0100561/**
Richard Hughes68ab1e42021-01-13 14:01:17 +0000562 * fu_plugin_get_devices:
563 * @self: A #FuPlugin
564 *
565 * Returns all devices added by the plugin using fu_plugin_device_add() and
566 * not yet removed with fu_plugin_device_remove().
567 *
568 * Returns: (transfer none) (element-type FuDevice): devices
569 *
570 * Since: 1.5.6
571 **/
572GPtrArray *
573fu_plugin_get_devices (FuPlugin *self)
574{
575 FuPluginPrivate *priv = GET_PRIVATE (self);
576 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
577 fu_plugin_ensure_devices (self);
578 return priv->devices;
579}
580
581/**
Richard Hughese1fd34d2017-08-24 14:19:51 +0100582 * fu_plugin_device_register:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100583 * @self: A #FuPlugin
Richard Hughese1fd34d2017-08-24 14:19:51 +0100584 * @device: A #FuDevice
585 *
586 * Registers the device with other plugins so they can set metadata.
587 *
588 * Plugins do not have to call this manually as this is done automatically
589 * when using fu_plugin_device_add(). They may wish to use this manually
Richard Hughes21eaeef2020-01-14 12:10:01 +0000590 * if for instance the coldplug should be ignored based on the metadata
Richard Hughese1fd34d2017-08-24 14:19:51 +0100591 * set from other plugins.
592 *
593 * Since: 0.9.7
594 **/
595void
Richard Hughes12724852018-09-04 13:53:44 +0100596fu_plugin_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +0100597{
Richard Hughesc125ec02018-09-05 19:35:17 +0100598 g_autoptr(GError) error = NULL;
599
Richard Hughes12724852018-09-04 13:53:44 +0100600 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughese1fd34d2017-08-24 14:19:51 +0100601 g_return_if_fail (FU_IS_DEVICE (device));
602
Richard Hughesc125ec02018-09-05 19:35:17 +0100603 /* ensure the device ID is set from the physical and logical IDs */
604 if (!fu_device_ensure_id (device, &error)) {
605 g_warning ("ignoring registration: %s", error->message);
606 return;
607 }
608
Richard Hughese1fd34d2017-08-24 14:19:51 +0100609 g_debug ("emit device-register from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100610 fu_plugin_get_name (self),
Richard Hughese1fd34d2017-08-24 14:19:51 +0100611 fu_device_get_id (device));
Richard Hughes12724852018-09-04 13:53:44 +0100612 g_signal_emit (self, signals[SIGNAL_DEVICE_REGISTER], 0, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +0100613}
614
Richard Hughes57d18222017-01-10 16:02:59 +0000615/**
Richard Hughes4eada342017-10-03 21:20:32 +0100616 * fu_plugin_device_remove:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100617 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000618 * @device: A #FuDevice
619 *
620 * Asks the daemon to remove a device from the exported list.
621 *
622 * Since: 0.8.0
623 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000624void
Richard Hughes12724852018-09-04 13:53:44 +0100625fu_plugin_device_remove (FuPlugin *self, FuDevice *device)
Richard Hughescff38bc2016-12-12 12:03:37 +0000626{
Richard Hughes68ab1e42021-01-13 14:01:17 +0000627 FuPluginPrivate *priv = GET_PRIVATE (self);
628
Richard Hughes12724852018-09-04 13:53:44 +0100629 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000630 g_return_if_fail (FU_IS_DEVICE (device));
631
Richard Hughes68ab1e42021-01-13 14:01:17 +0000632 /* remove from array */
633 if (priv->devices != NULL)
634 g_ptr_array_remove (priv->devices, device);
635
Richard Hughescff38bc2016-12-12 12:03:37 +0000636 g_debug ("emit removed from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100637 fu_plugin_get_name (self),
Richard Hughescff38bc2016-12-12 12:03:37 +0000638 fu_device_get_id (device));
Richard Hughes12724852018-09-04 13:53:44 +0100639 g_signal_emit (self, signals[SIGNAL_DEVICE_REMOVED], 0, device);
Richard Hughescff38bc2016-12-12 12:03:37 +0000640}
641
Richard Hughes57d18222017-01-10 16:02:59 +0000642/**
Richard Hughes2de8f132018-01-17 09:12:02 +0000643 * fu_plugin_request_recoldplug:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100644 * @self: A #FuPlugin
Richard Hughes362d6d72017-01-07 21:42:14 +0000645 *
646 * Ask all the plugins to coldplug all devices, which will include the prepare()
647 * and cleanup() phases. Duplicate devices added will be ignored.
648 *
649 * Since: 0.8.0
650 **/
651void
Richard Hughes12724852018-09-04 13:53:44 +0100652fu_plugin_request_recoldplug (FuPlugin *self)
Richard Hughes362d6d72017-01-07 21:42:14 +0000653{
Richard Hughes12724852018-09-04 13:53:44 +0100654 g_return_if_fail (FU_IS_PLUGIN (self));
655 g_signal_emit (self, signals[SIGNAL_RECOLDPLUG], 0);
Richard Hughes362d6d72017-01-07 21:42:14 +0000656}
657
Richard Hughesb0829032017-01-10 09:27:08 +0000658/**
Richard Hughes399859e2020-05-11 19:44:03 +0100659 * fu_plugin_security_changed:
660 * @self: A #FuPlugin
661 *
662 * Informs the daemon that the HSI state may have changed.
663 *
664 * Since: 1.5.0
665 **/
666void
667fu_plugin_security_changed (FuPlugin *self)
668{
669 g_return_if_fail (FU_IS_PLUGIN (self));
670 g_signal_emit (self, signals[SIGNAL_SECURITY_CHANGED], 0);
671}
672
673/**
Richard Hughesb8f8db22017-04-25 15:56:00 +0100674 * fu_plugin_check_hwid:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100675 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100676 * @hwid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
Richard Hughesb8f8db22017-04-25 15:56:00 +0100677 *
Richard Hughesd7704d42017-08-08 20:29:09 +0100678 * Checks to see if a specific GUID exists. All hardware IDs on a
Richard Hughesb8f8db22017-04-25 15:56:00 +0100679 * specific system can be shown using the `fwupdmgr hwids` command.
680 *
Richard Hughes4eada342017-10-03 21:20:32 +0100681 * Returns: %TRUE if the HwId is found on the system.
682 *
Richard Hughesb8f8db22017-04-25 15:56:00 +0100683 * Since: 0.9.1
684 **/
685gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100686fu_plugin_check_hwid (FuPlugin *self, const gchar *hwid)
Richard Hughesb8f8db22017-04-25 15:56:00 +0100687{
Richard Hughes12724852018-09-04 13:53:44 +0100688 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100689 if (priv->hwids == NULL)
690 return FALSE;
Richard Hughesd7704d42017-08-08 20:29:09 +0100691 return fu_hwids_has_guid (priv->hwids, hwid);
692}
693
694/**
Patrick Rudolpha60b5472019-10-16 10:43:03 +0200695 * fu_plugin_get_hwid_replace_value:
696 * @self: A #FuPlugin
697 * @keys: A key, e.g. `HardwareID-3` or %FU_HWIDS_KEY_PRODUCT_SKU
698 * @error: A #GError or %NULL
699 *
700 * Gets the replacement value for a specific key. All hardware IDs on a
701 * specific system can be shown using the `fwupdmgr hwids` command.
702 *
703 * Returns: (transfer full): a string, or %NULL for error.
704 *
705 * Since: 1.3.3
706 **/
707gchar *
708fu_plugin_get_hwid_replace_value (FuPlugin *self, const gchar *keys, GError **error)
709{
710 FuPluginPrivate *priv = GET_PRIVATE (self);
711 if (priv->hwids == NULL)
712 return NULL;
713
714 return fu_hwids_get_replace_values (priv->hwids, keys, error);
715}
716
717/**
Richard Hughes69a5f352018-08-08 11:58:15 +0100718 * fu_plugin_get_hwids:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100719 * @self: A #FuPlugin
Richard Hughes69a5f352018-08-08 11:58:15 +0100720 *
721 * Returns all the HWIDs defined in the system. All hardware IDs on a
722 * specific system can be shown using the `fwupdmgr hwids` command.
723 *
Mario Limonciello1a680f32019-11-25 19:44:53 -0600724 * Returns: (transfer none) (element-type utf8): An array of GUIDs
Richard Hughes69a5f352018-08-08 11:58:15 +0100725 *
726 * Since: 1.1.1
727 **/
728GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +0100729fu_plugin_get_hwids (FuPlugin *self)
Richard Hughes69a5f352018-08-08 11:58:15 +0100730{
Richard Hughes12724852018-09-04 13:53:44 +0100731 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes69a5f352018-08-08 11:58:15 +0100732 if (priv->hwids == NULL)
733 return NULL;
734 return fu_hwids_get_guids (priv->hwids);
735}
736
737/**
Richard Hughes19841802019-09-10 16:48:00 +0100738 * fu_plugin_has_custom_flag:
739 * @self: A #FuPlugin
740 * @flag: A custom text flag, specific to the plugin, e.g. `uefi-force-enable`
741 *
742 * Returns if a per-plugin HwId custom flag exists, typically added from a DMI quirk.
743 *
744 * Returns: %TRUE if the quirk entry exists
745 *
746 * Since: 1.3.1
747 **/
748gboolean
749fu_plugin_has_custom_flag (FuPlugin *self, const gchar *flag)
750{
751 FuPluginPrivate *priv = GET_PRIVATE (self);
752 GPtrArray *hwids = fu_plugin_get_hwids (self);
753
754 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
755 g_return_val_if_fail (flag != NULL, FALSE);
756
757 /* never set up, e.g. in tests */
758 if (hwids == NULL)
759 return FALSE;
760
761 /* search each hwid */
762 for (guint i = 0; i < hwids->len; i++) {
763 const gchar *hwid = g_ptr_array_index (hwids, i);
764 const gchar *value;
765 g_autofree gchar *key = g_strdup_printf ("HwId=%s", hwid);
766
767 /* does prefixed quirk exist */
768 value = fu_quirks_lookup_by_id (priv->quirks, key, FU_QUIRKS_FLAGS);
769 if (value != NULL) {
770 g_auto(GStrv) quirks = g_strsplit (value, ",", -1);
771 if (g_strv_contains ((const gchar * const *) quirks, flag))
772 return TRUE;
773 }
774 }
775 return FALSE;
776}
777
778/**
Richard Hughes1354ea92017-09-19 15:58:31 +0100779 * fu_plugin_check_supported:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100780 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100781 * @guid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
Richard Hughes1354ea92017-09-19 15:58:31 +0100782 *
783 * Checks to see if a specific device GUID is supported, i.e. available in the
784 * AppStream metadata.
785 *
Richard Hughes4eada342017-10-03 21:20:32 +0100786 * Returns: %TRUE if the device is supported.
787 *
Richard Hughes1354ea92017-09-19 15:58:31 +0100788 * Since: 1.0.0
789 **/
Richard Hughesd8a8d5e2019-10-08 13:05:02 +0100790static gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100791fu_plugin_check_supported (FuPlugin *self, const gchar *guid)
Richard Hughes1354ea92017-09-19 15:58:31 +0100792{
Richard Hughesaabdc372018-11-14 10:11:08 +0000793 gboolean retval = FALSE;
794 g_signal_emit (self, signals[SIGNAL_CHECK_SUPPORTED], 0, guid, &retval);
795 return retval;
Richard Hughes1354ea92017-09-19 15:58:31 +0100796}
797
798/**
Richard Hughesd7704d42017-08-08 20:29:09 +0100799 * fu_plugin_get_dmi_value:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100800 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100801 * @dmi_id: A DMI ID, e.g. `BiosVersion`
Richard Hughesd7704d42017-08-08 20:29:09 +0100802 *
803 * Gets a hardware DMI value.
804 *
Richard Hughes4eada342017-10-03 21:20:32 +0100805 * Returns: The string, or %NULL
806 *
Richard Hughesd7704d42017-08-08 20:29:09 +0100807 * Since: 0.9.7
808 **/
809const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100810fu_plugin_get_dmi_value (FuPlugin *self, const gchar *dmi_id)
Richard Hughesd7704d42017-08-08 20:29:09 +0100811{
Richard Hughes12724852018-09-04 13:53:44 +0100812 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd7704d42017-08-08 20:29:09 +0100813 if (priv->hwids == NULL)
Richard Hughes7ef96b82017-08-23 18:28:24 +0100814 return NULL;
Richard Hughesd7704d42017-08-08 20:29:09 +0100815 return fu_hwids_get_value (priv->hwids, dmi_id);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100816}
817
Richard Hughes49e5e052017-09-03 12:15:41 +0100818/**
819 * fu_plugin_get_smbios_string:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100820 * @self: A #FuPlugin
Richard Hughes49e5e052017-09-03 12:15:41 +0100821 * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
822 * @offset: A SMBIOS offset
823 *
824 * Gets a hardware SMBIOS string.
825 *
826 * The @type and @offset can be referenced from the DMTF SMBIOS specification:
827 * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.1.1.pdf
828 *
Richard Hughes4eada342017-10-03 21:20:32 +0100829 * Returns: A string, or %NULL
830 *
Richard Hughes49e5e052017-09-03 12:15:41 +0100831 * Since: 0.9.8
832 **/
833const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100834fu_plugin_get_smbios_string (FuPlugin *self, guint8 structure_type, guint8 offset)
Richard Hughes49e5e052017-09-03 12:15:41 +0100835{
Richard Hughes12724852018-09-04 13:53:44 +0100836 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100837 if (priv->smbios == NULL)
838 return NULL;
839 return fu_smbios_get_string (priv->smbios, structure_type, offset, NULL);
840}
841
842/**
843 * fu_plugin_get_smbios_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100844 * @self: A #FuPlugin
Richard Hughes49e5e052017-09-03 12:15:41 +0100845 * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
846 *
847 * Gets a hardware SMBIOS data.
848 *
Richard Hughesdfaca2d2019-08-01 08:08:03 +0100849 * Returns: (transfer full): A #GBytes, or %NULL
Richard Hughes4eada342017-10-03 21:20:32 +0100850 *
Richard Hughes49e5e052017-09-03 12:15:41 +0100851 * Since: 0.9.8
852 **/
853GBytes *
Richard Hughes12724852018-09-04 13:53:44 +0100854fu_plugin_get_smbios_data (FuPlugin *self, guint8 structure_type)
Richard Hughes49e5e052017-09-03 12:15:41 +0100855{
Richard Hughes12724852018-09-04 13:53:44 +0100856 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100857 if (priv->smbios == NULL)
858 return NULL;
859 return fu_smbios_get_data (priv->smbios, structure_type, NULL);
860}
861
Mario Limonciello1a680f32019-11-25 19:44:53 -0600862/**
863 * fu_plugin_set_hwids:
864 * @self: A #FuPlugin
865 * @hwids: A #FuHwids
866 *
867 * Sets the hwids for a plugin
868 *
869 * Since: 0.9.7
870 **/
Richard Hughesb8f8db22017-04-25 15:56:00 +0100871void
Richard Hughes12724852018-09-04 13:53:44 +0100872fu_plugin_set_hwids (FuPlugin *self, FuHwids *hwids)
Richard Hughesb8f8db22017-04-25 15:56:00 +0100873{
Richard Hughes12724852018-09-04 13:53:44 +0100874 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd7704d42017-08-08 20:29:09 +0100875 g_set_object (&priv->hwids, hwids);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100876}
877
Mario Limonciello1a680f32019-11-25 19:44:53 -0600878/**
879 * fu_plugin_set_udev_subsystems:
880 * @self: A #FuPlugin
Richard Hughesa0d81c72019-11-27 11:41:54 +0000881 * @udev_subsystems: (element-type utf8): A #GPtrArray
Mario Limonciello1a680f32019-11-25 19:44:53 -0600882 *
883 * Sets the udev subsystems used by a plugin
884 *
885 * Since: 1.1.2
886 **/
Richard Hughes49e5e052017-09-03 12:15:41 +0100887void
Richard Hughes12724852018-09-04 13:53:44 +0100888fu_plugin_set_udev_subsystems (FuPlugin *self, GPtrArray *udev_subsystems)
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100889{
Richard Hughes12724852018-09-04 13:53:44 +0100890 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100891 if (priv->udev_subsystems != NULL)
892 g_ptr_array_unref (priv->udev_subsystems);
893 priv->udev_subsystems = g_ptr_array_ref (udev_subsystems);
894}
895
Mario Limonciello1a680f32019-11-25 19:44:53 -0600896/**
897 * fu_plugin_set_quirks:
898 * @self: A #FuPlugin
899 * @quirks: A #FuQuirks
900 *
901 * Sets the quirks for a plugin
902 *
903 * Since: 1.0.1
904 **/
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100905void
Richard Hughes12724852018-09-04 13:53:44 +0100906fu_plugin_set_quirks (FuPlugin *self, FuQuirks *quirks)
Richard Hughes9c028f02017-10-28 21:14:28 +0100907{
Richard Hughes12724852018-09-04 13:53:44 +0100908 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9c028f02017-10-28 21:14:28 +0100909 g_set_object (&priv->quirks, quirks);
910}
911
912/**
913 * fu_plugin_get_quirks:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100914 * @self: A #FuPlugin
Richard Hughes9c028f02017-10-28 21:14:28 +0100915 *
916 * Returns the hardware database object. This can be used to discover device
917 * quirks or other device-specific settings.
918 *
919 * Returns: (transfer none): a #FuQuirks, or %NULL if not set
920 *
921 * Since: 1.0.1
922 **/
923FuQuirks *
Richard Hughes12724852018-09-04 13:53:44 +0100924fu_plugin_get_quirks (FuPlugin *self)
Richard Hughes9c028f02017-10-28 21:14:28 +0100925{
Richard Hughes12724852018-09-04 13:53:44 +0100926 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9c028f02017-10-28 21:14:28 +0100927 return priv->quirks;
928}
929
Mario Limonciello1a680f32019-11-25 19:44:53 -0600930/**
931 * fu_plugin_set_runtime_versions:
932 * @self: A #FuPlugin
933 * @runtime_versions: A #GHashTables
934 *
935 * Sets the runtime versions for a plugin
936 *
937 * Since: 1.0.7
938 **/
Richard Hughes0eb123b2018-04-19 12:00:04 +0100939void
Richard Hughes12724852018-09-04 13:53:44 +0100940fu_plugin_set_runtime_versions (FuPlugin *self, GHashTable *runtime_versions)
Richard Hughes0eb123b2018-04-19 12:00:04 +0100941{
Richard Hughes12724852018-09-04 13:53:44 +0100942 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0eb123b2018-04-19 12:00:04 +0100943 priv->runtime_versions = g_hash_table_ref (runtime_versions);
944}
945
946/**
947 * fu_plugin_add_runtime_version:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100948 * @self: A #FuPlugin
Richard Hughes0eb123b2018-04-19 12:00:04 +0100949 * @component_id: An AppStream component id, e.g. "org.gnome.Software"
950 * @version: A version string, e.g. "1.2.3"
951 *
Richard Hughesdce91202019-04-08 12:47:45 +0100952 * Sets a runtime version of a specific dependency.
Richard Hughes0eb123b2018-04-19 12:00:04 +0100953 *
954 * Since: 1.0.7
955 **/
956void
Richard Hughes12724852018-09-04 13:53:44 +0100957fu_plugin_add_runtime_version (FuPlugin *self,
Richard Hughes0eb123b2018-04-19 12:00:04 +0100958 const gchar *component_id,
959 const gchar *version)
960{
Richard Hughes12724852018-09-04 13:53:44 +0100961 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesb01b4862018-04-20 16:39:48 +0100962 if (priv->runtime_versions == NULL)
963 return;
Richard Hughes0eb123b2018-04-19 12:00:04 +0100964 g_hash_table_insert (priv->runtime_versions,
965 g_strdup (component_id),
966 g_strdup (version));
967}
968
Mario Limonciello1a680f32019-11-25 19:44:53 -0600969/**
970 * fu_plugin_set_compile_versions:
971 * @self: A #FuPlugin
972 * @compile_versions: A #GHashTables
973 *
974 * Sets the compile time versions for a plugin
975 *
976 * Since: 1.0.7
977 **/
Richard Hughes34e0dab2018-04-20 16:43:00 +0100978void
Richard Hughes12724852018-09-04 13:53:44 +0100979fu_plugin_set_compile_versions (FuPlugin *self, GHashTable *compile_versions)
Richard Hughes34e0dab2018-04-20 16:43:00 +0100980{
Richard Hughes12724852018-09-04 13:53:44 +0100981 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes34e0dab2018-04-20 16:43:00 +0100982 priv->compile_versions = g_hash_table_ref (compile_versions);
983}
984
985/**
986 * fu_plugin_add_compile_version:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100987 * @self: A #FuPlugin
Richard Hughes34e0dab2018-04-20 16:43:00 +0100988 * @component_id: An AppStream component id, e.g. "org.gnome.Software"
989 * @version: A version string, e.g. "1.2.3"
990 *
Richard Hughesdce91202019-04-08 12:47:45 +0100991 * Sets a compile-time version of a specific dependency.
Richard Hughes34e0dab2018-04-20 16:43:00 +0100992 *
993 * Since: 1.0.7
994 **/
995void
Richard Hughes12724852018-09-04 13:53:44 +0100996fu_plugin_add_compile_version (FuPlugin *self,
Richard Hughes34e0dab2018-04-20 16:43:00 +0100997 const gchar *component_id,
998 const gchar *version)
999{
Richard Hughes12724852018-09-04 13:53:44 +01001000 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes34e0dab2018-04-20 16:43:00 +01001001 if (priv->compile_versions == NULL)
1002 return;
1003 g_hash_table_insert (priv->compile_versions,
1004 g_strdup (component_id),
1005 g_strdup (version));
1006}
1007
Richard Hughes9c028f02017-10-28 21:14:28 +01001008/**
1009 * fu_plugin_lookup_quirk_by_id:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001010 * @self: A #FuPlugin
Richard Hughes87fb9ff2018-06-28 12:55:59 +01001011 * @group: A string, e.g. "DfuFlags"
1012 * @key: An ID to match the entry, e.g. "Summary"
Richard Hughes9c028f02017-10-28 21:14:28 +01001013 *
1014 * Looks up an entry in the hardware database using a string value.
1015 *
1016 * Returns: (transfer none): values from the database, or %NULL if not found
1017 *
1018 * Since: 1.0.1
1019 **/
1020const gchar *
Richard Hughes12724852018-09-04 13:53:44 +01001021fu_plugin_lookup_quirk_by_id (FuPlugin *self, const gchar *group, const gchar *key)
Richard Hughes9c028f02017-10-28 21:14:28 +01001022{
Richard Hughes12724852018-09-04 13:53:44 +01001023 FuPluginPrivate *priv = GET_PRIVATE (self);
1024 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes9c028f02017-10-28 21:14:28 +01001025
Richard Hughes9c028f02017-10-28 21:14:28 +01001026 /* exact ID */
Richard Hughes87fb9ff2018-06-28 12:55:59 +01001027 return fu_quirks_lookup_by_id (priv->quirks, group, key);
Richard Hughes9c028f02017-10-28 21:14:28 +01001028}
1029
1030/**
Richard Hughes8fe7cdd2018-08-23 10:02:44 +01001031 * fu_plugin_lookup_quirk_by_id_as_uint64:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001032 * @self: A #FuPlugin
Richard Hughes8fe7cdd2018-08-23 10:02:44 +01001033 * @group: A string, e.g. "DfuFlags"
1034 * @key: An ID to match the entry, e.g. "Size"
1035 *
1036 * Looks up an entry in the hardware database using a string key, returning
1037 * an integer value. Values are assumed base 10, unless prefixed with "0x"
1038 * where they are parsed as base 16.
1039 *
Mario Limonciello1a680f32019-11-25 19:44:53 -06001040 * Returns: guint64 id or 0 if not found
Richard Hughes8fe7cdd2018-08-23 10:02:44 +01001041 *
1042 * Since: 1.1.2
1043 **/
1044guint64
Richard Hughes12724852018-09-04 13:53:44 +01001045fu_plugin_lookup_quirk_by_id_as_uint64 (FuPlugin *self, const gchar *group, const gchar *key)
Richard Hughes8fe7cdd2018-08-23 10:02:44 +01001046{
Richard Hughes12724852018-09-04 13:53:44 +01001047 return fu_common_strtoull (fu_plugin_lookup_quirk_by_id (self, group, key));
Richard Hughes8fe7cdd2018-08-23 10:02:44 +01001048}
1049
Mario Limonciello1a680f32019-11-25 19:44:53 -06001050/**
1051 * fu_plugin_set_smbios:
1052 * @self: A #FuPlugin
1053 * @smbios: A #FuSmbios
1054 *
1055 * Sets the smbios for a plugin
1056 *
1057 * Since: 1.0.0
1058 **/
Richard Hughes1354ea92017-09-19 15:58:31 +01001059void
Richard Hughes12724852018-09-04 13:53:44 +01001060fu_plugin_set_smbios (FuPlugin *self, FuSmbios *smbios)
Richard Hughes49e5e052017-09-03 12:15:41 +01001061{
Richard Hughes12724852018-09-04 13:53:44 +01001062 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +01001063 g_set_object (&priv->smbios, smbios);
1064}
1065
Richard Hughesb8f8db22017-04-25 15:56:00 +01001066/**
Richard Hughesb0829032017-01-10 09:27:08 +00001067 * fu_plugin_set_coldplug_delay:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001068 * @self: A #FuPlugin
Richard Hughesb0829032017-01-10 09:27:08 +00001069 * @duration: A delay in milliseconds
1070 *
Richard Hughes21eaeef2020-01-14 12:10:01 +00001071 * Set the minimum time that should be waited in-between the call to
Richard Hughesb0829032017-01-10 09:27:08 +00001072 * fu_plugin_coldplug_prepare() and fu_plugin_coldplug(). This is usually going
Richard Hughes203ed842020-11-02 14:25:13 +00001073 * to be the minimum hardware initialization time from a datasheet.
Richard Hughesb0829032017-01-10 09:27:08 +00001074 *
1075 * It is better to use this function rather than using a sleep() in the plugin
1076 * itself as then only one delay is done in the daemon rather than waiting for
1077 * each coldplug prepare in a serial way.
1078 *
1079 * Additionally, very long delays should be avoided as the daemon will be
1080 * blocked from processing requests whilst the coldplug delay is being
1081 * performed.
1082 *
1083 * Since: 0.8.0
1084 **/
1085void
Richard Hughes12724852018-09-04 13:53:44 +01001086fu_plugin_set_coldplug_delay (FuPlugin *self, guint duration)
Richard Hughesb0829032017-01-10 09:27:08 +00001087{
Richard Hughes12724852018-09-04 13:53:44 +01001088 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesb0829032017-01-10 09:27:08 +00001089 g_return_if_fail (duration > 0);
1090
1091 /* check sanity */
1092 if (duration > FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM) {
1093 g_warning ("duration of %ums is crazy, truncating to %ums",
1094 duration,
1095 FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM);
1096 duration = FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM;
1097 }
1098
1099 /* emit */
Richard Hughes12724852018-09-04 13:53:44 +01001100 g_signal_emit (self, signals[SIGNAL_SET_COLDPLUG_DELAY], 0, duration);
Richard Hughesb0829032017-01-10 09:27:08 +00001101}
1102
Richard Hughes4b303802019-10-04 13:22:51 +01001103static gboolean
1104fu_plugin_device_attach (FuPlugin *self, FuDevice *device, GError **error)
1105{
1106 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughes4b303802019-10-04 13:22:51 +01001107 locker = fu_device_locker_new (device, error);
1108 if (locker == NULL)
1109 return FALSE;
1110 return fu_device_attach (device, error);
1111}
1112
1113static gboolean
1114fu_plugin_device_detach (FuPlugin *self, FuDevice *device, GError **error)
1115{
1116 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughes4b303802019-10-04 13:22:51 +01001117 locker = fu_device_locker_new (device, error);
1118 if (locker == NULL)
1119 return FALSE;
1120 return fu_device_detach (device, error);
1121}
1122
1123static gboolean
Richard Hughes4b303802019-10-04 13:22:51 +01001124fu_plugin_device_activate (FuPlugin *self, FuDevice *device, GError **error)
1125{
1126 g_autoptr(FuDeviceLocker) locker = NULL;
1127 locker = fu_device_locker_new (device, error);
1128 if (locker == NULL)
1129 return FALSE;
1130 return fu_device_activate (device, error);
1131}
1132
1133static gboolean
1134fu_plugin_device_write_firmware (FuPlugin *self, FuDevice *device,
1135 GBytes *fw, FwupdInstallFlags flags,
1136 GError **error)
1137{
1138 g_autoptr(FuDeviceLocker) locker = NULL;
1139 locker = fu_device_locker_new (device, error);
1140 if (locker == NULL)
1141 return FALSE;
Richard Hughes1a612582020-09-29 19:39:38 +01001142
1143 /* back the old firmware up to /var/lib/fwupd */
1144 if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL)) {
1145 g_autoptr(GBytes) fw_old = NULL;
1146 g_autofree gchar *path = NULL;
1147 g_autofree gchar *fn = NULL;
1148 g_autofree gchar *localstatedir = NULL;
1149
1150 fw_old = fu_device_dump_firmware (device, error);
1151 if (fw_old == NULL) {
1152 g_prefix_error (error, "failed to backup old firmware: ");
1153 return FALSE;
1154 }
1155 localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG);
1156 fn = g_strdup_printf ("%s.bin", fu_device_get_version (device));
1157 path = g_build_filename (localstatedir,
1158 "backup",
1159 fu_device_get_id (device),
1160 fu_device_get_serial (device) != NULL ?
1161 fu_device_get_serial (device) :
1162 "default",
1163 fn, NULL);
1164 if (!fu_common_set_contents_bytes (path, fw_old, error))
1165 return FALSE;
1166 }
1167
Richard Hughes4b303802019-10-04 13:22:51 +01001168 return fu_device_write_firmware (device, fw, flags, error);
1169}
1170
Richard Hughes7f677212019-10-05 16:19:40 +01001171static gboolean
1172fu_plugin_device_read_firmware (FuPlugin *self, FuDevice *device, GError **error)
1173{
1174 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughesf0eb0912019-10-10 11:37:22 +01001175 g_autoptr(FuFirmware) firmware = NULL;
Richard Hughes7f677212019-10-05 16:19:40 +01001176 g_autoptr(GBytes) fw = NULL;
1177 GChecksumType checksum_types[] = {
1178 G_CHECKSUM_SHA1,
1179 G_CHECKSUM_SHA256,
1180 0 };
1181 locker = fu_device_locker_new (device, error);
1182 if (locker == NULL)
1183 return FALSE;
1184 if (!fu_device_detach (device, error))
1185 return FALSE;
Richard Hughesf0eb0912019-10-10 11:37:22 +01001186 firmware = fu_device_read_firmware (device, error);
1187 if (firmware == NULL) {
1188 g_autoptr(GError) error_local = NULL;
1189 if (!fu_device_attach (device, &error_local))
1190 g_debug ("ignoring attach failure: %s", error_local->message);
1191 g_prefix_error (error, "failed to read firmware: ");
1192 return FALSE;
1193 }
1194 fw = fu_firmware_write (firmware, error);
Richard Hughes7f677212019-10-05 16:19:40 +01001195 if (fw == NULL) {
1196 g_autoptr(GError) error_local = NULL;
1197 if (!fu_device_attach (device, &error_local))
Richard Hughesf0eb0912019-10-10 11:37:22 +01001198 g_debug ("ignoring attach failure: %s", error_local->message);
1199 g_prefix_error (error, "failed to write firmware: ");
Richard Hughes7f677212019-10-05 16:19:40 +01001200 return FALSE;
1201 }
1202 for (guint i = 0; checksum_types[i] != 0; i++) {
1203 g_autofree gchar *hash = NULL;
1204 hash = g_compute_checksum_for_bytes (checksum_types[i], fw);
1205 fu_device_add_checksum (device, hash);
1206 }
1207 return fu_device_attach (device, error);
1208}
1209
Mario Limonciello1a680f32019-11-25 19:44:53 -06001210/**
1211 * fu_plugin_runner_startup:
1212 * @self: a #FuPlugin
1213 * @error: a #GError or NULL
1214 *
1215 * Runs the startup routine for the plugin
1216 *
1217 * Returns: #TRUE for success, #FALSE for failure
1218 *
1219 * Since: 0.8.0
1220 **/
Richard Hughesd0905142016-03-13 09:46:49 +00001221gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001222fu_plugin_runner_startup (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00001223{
Richard Hughes12724852018-09-04 13:53:44 +01001224 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001225 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001226 g_autoptr(GError) error_local = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +00001227
1228 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001229 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughesd0905142016-03-13 09:46:49 +00001230 return TRUE;
1231
Richard Hughes639da472018-01-06 22:35:04 +00001232 /* no object loaded */
1233 if (priv->module == NULL)
1234 return TRUE;
1235
Richard Hughesd0905142016-03-13 09:46:49 +00001236 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00001237 g_module_symbol (priv->module, "fu_plugin_startup", (gpointer *) &func);
1238 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +00001239 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001240 g_debug ("startup(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001241 if (!func (self, &error_local)) {
1242 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001243 g_critical ("unset plugin error in startup(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001244 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001245 g_set_error_literal (&error_local,
1246 FWUPD_ERROR,
1247 FWUPD_ERROR_INTERNAL,
1248 "unspecified error");
1249 }
1250 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1251 "failed to startup using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001252 fu_plugin_get_name (self));
Richard Hughescff38bc2016-12-12 12:03:37 +00001253 return FALSE;
1254 }
1255 return TRUE;
1256}
1257
1258static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001259fu_plugin_runner_device_generic (FuPlugin *self, FuDevice *device,
Richard Hughes4b303802019-10-04 13:22:51 +01001260 const gchar *symbol_name,
1261 FuPluginDeviceFunc device_func,
1262 GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001263{
Richard Hughes12724852018-09-04 13:53:44 +01001264 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001265 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001266 g_autoptr(GError) error_local = NULL;
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001267
1268 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001269 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001270 return TRUE;
1271
Richard Hughesd3d96cc2017-11-14 11:34:33 +00001272 /* no object loaded */
1273 if (priv->module == NULL)
1274 return TRUE;
1275
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001276 /* optional */
1277 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
Richard Hughes4b303802019-10-04 13:22:51 +01001278 if (func == NULL) {
1279 if (device_func != NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001280 g_debug ("running superclassed %s(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001281 symbol_name + 10, fu_plugin_get_name (self));
Richard Hughes4b303802019-10-04 13:22:51 +01001282 return device_func (self, device, error);
1283 }
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001284 return TRUE;
Richard Hughes4b303802019-10-04 13:22:51 +01001285 }
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001286 g_debug ("%s(%s)", symbol_name + 10, fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001287 if (!func (self, device, &error_local)) {
1288 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001289 g_critical ("unset plugin error in %s(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001290 fu_plugin_get_name (self), symbol_name + 10);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001291 g_set_error_literal (&error_local,
1292 FWUPD_ERROR,
1293 FWUPD_ERROR_INTERNAL,
1294 "unspecified error");
1295 }
1296 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1297 "failed to %s using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001298 symbol_name + 10, fu_plugin_get_name (self));
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001299 return FALSE;
1300 }
1301 return TRUE;
1302}
1303
Richard Hughesdbd8c762018-06-15 20:31:40 +01001304static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001305fu_plugin_runner_flagged_device_generic (FuPlugin *self, FwupdInstallFlags flags,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001306 FuDevice *device,
1307 const gchar *symbol_name, GError **error)
1308{
Richard Hughes12724852018-09-04 13:53:44 +01001309 FuPluginPrivate *priv = GET_PRIVATE (self);
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001310 FuPluginFlaggedDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001311 g_autoptr(GError) error_local = NULL;
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001312
1313 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001314 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001315 return TRUE;
1316
1317 /* no object loaded */
1318 if (priv->module == NULL)
1319 return TRUE;
1320
1321 /* optional */
1322 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1323 if (func == NULL)
1324 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001325 g_debug ("%s(%s)", symbol_name + 10, fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001326 if (!func (self, flags, device, &error_local)) {
1327 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001328 g_critical ("unset plugin error in %s(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001329 fu_plugin_get_name (self), symbol_name + 10);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001330 g_set_error_literal (&error_local,
1331 FWUPD_ERROR,
1332 FWUPD_ERROR_INTERNAL,
1333 "unspecified error");
1334 }
1335 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1336 "failed to %s using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001337 symbol_name + 10, fu_plugin_get_name (self));
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001338 return FALSE;
1339 }
1340 return TRUE;
1341
1342}
1343
1344static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001345fu_plugin_runner_device_array_generic (FuPlugin *self, GPtrArray *devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001346 const gchar *symbol_name, GError **error)
1347{
Richard Hughes12724852018-09-04 13:53:44 +01001348 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesdbd8c762018-06-15 20:31:40 +01001349 FuPluginDeviceArrayFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001350 g_autoptr(GError) error_local = NULL;
Richard Hughesdbd8c762018-06-15 20:31:40 +01001351
1352 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001353 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughesdbd8c762018-06-15 20:31:40 +01001354 return TRUE;
1355
1356 /* no object loaded */
1357 if (priv->module == NULL)
1358 return TRUE;
1359
1360 /* optional */
1361 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1362 if (func == NULL)
1363 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001364 g_debug ("%s(%s)", symbol_name + 10, fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001365 if (!func (self, devices, &error_local)) {
1366 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001367 g_critical ("unset plugin error in for %s(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001368 fu_plugin_get_name (self), symbol_name + 10);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001369 g_set_error_literal (&error_local,
1370 FWUPD_ERROR,
1371 FWUPD_ERROR_INTERNAL,
1372 "unspecified error");
1373 }
1374 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1375 "failed to %s using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001376 symbol_name + 10, fu_plugin_get_name (self));
Richard Hughesdbd8c762018-06-15 20:31:40 +01001377 return FALSE;
1378 }
1379 return TRUE;
1380}
1381
Mario Limonciello1a680f32019-11-25 19:44:53 -06001382/**
1383 * fu_plugin_runner_coldplug:
1384 * @self: a #FuPlugin
1385 * @error: a #GError or NULL
1386 *
1387 * Runs the coldplug routine for the plugin
1388 *
1389 * Returns: #TRUE for success, #FALSE for failure
1390 *
1391 * Since: 0.8.0
1392 **/
Richard Hughesd0905142016-03-13 09:46:49 +00001393gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001394fu_plugin_runner_coldplug (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00001395{
Richard Hughes12724852018-09-04 13:53:44 +01001396 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001397 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001398 g_autoptr(GError) error_local = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +00001399
1400 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001401 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughesd0905142016-03-13 09:46:49 +00001402 return TRUE;
1403
Richard Hughes639da472018-01-06 22:35:04 +00001404 /* no object loaded */
1405 if (priv->module == NULL)
1406 return TRUE;
1407
Richard Hughesd0905142016-03-13 09:46:49 +00001408 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00001409 g_module_symbol (priv->module, "fu_plugin_coldplug", (gpointer *) &func);
1410 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +00001411 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001412 g_debug ("coldplug(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001413 if (!func (self, &error_local)) {
1414 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001415 g_critical ("unset plugin error in coldplug(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001416 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001417 g_set_error_literal (&error_local,
1418 FWUPD_ERROR,
1419 FWUPD_ERROR_INTERNAL,
1420 "unspecified error");
1421 }
1422 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001423 "failed to coldplug using %s: ", fu_plugin_get_name (self));
Richard Hughescff38bc2016-12-12 12:03:37 +00001424 return FALSE;
1425 }
1426 return TRUE;
1427}
1428
Mario Limonciello1a680f32019-11-25 19:44:53 -06001429/**
1430 * fu_plugin_runner_recoldplug:
1431 * @self: a #FuPlugin
1432 * @error: a #GError or NULL
1433 *
1434 * Runs the recoldplug routine for the plugin
1435 *
1436 * Returns: #TRUE for success, #FALSE for failure
1437 *
1438 * Since: 1.0.4
1439 **/
Richard Hughes7b8b2022016-12-12 16:15:03 +00001440gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001441fu_plugin_runner_recoldplug (FuPlugin *self, GError **error)
Richard Hughes2de8f132018-01-17 09:12:02 +00001442{
Richard Hughes12724852018-09-04 13:53:44 +01001443 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes2de8f132018-01-17 09:12:02 +00001444 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001445 g_autoptr(GError) error_local = NULL;
Richard Hughes2de8f132018-01-17 09:12:02 +00001446
1447 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001448 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes2de8f132018-01-17 09:12:02 +00001449 return TRUE;
1450
1451 /* no object loaded */
1452 if (priv->module == NULL)
1453 return TRUE;
1454
1455 /* optional */
1456 g_module_symbol (priv->module, "fu_plugin_recoldplug", (gpointer *) &func);
1457 if (func == NULL)
1458 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001459 g_debug ("recoldplug(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001460 if (!func (self, &error_local)) {
1461 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001462 g_critical ("unset plugin error in recoldplug(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001463 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001464 g_set_error_literal (&error_local,
1465 FWUPD_ERROR,
1466 FWUPD_ERROR_INTERNAL,
1467 "unspecified error");
1468 }
1469 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1470 "failed to recoldplug using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001471 fu_plugin_get_name (self));
Richard Hughes2de8f132018-01-17 09:12:02 +00001472 return FALSE;
1473 }
1474 return TRUE;
1475}
1476
Mario Limonciello1a680f32019-11-25 19:44:53 -06001477/**
1478 * fu_plugin_runner_coldplug_prepare:
1479 * @self: a #FuPlugin
1480 * @error: a #GError or NULL
1481 *
1482 * Runs the coldplug_prepare routine for the plugin
1483 *
1484 * Returns: #TRUE for success, #FALSE for failure
1485 *
1486 * Since: 0.8.0
1487 **/
Richard Hughes2de8f132018-01-17 09:12:02 +00001488gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001489fu_plugin_runner_coldplug_prepare (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001490{
Richard Hughes12724852018-09-04 13:53:44 +01001491 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001492 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001493 g_autoptr(GError) error_local = NULL;
Richard Hughes46487c92017-01-07 21:26:34 +00001494
1495 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001496 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes46487c92017-01-07 21:26:34 +00001497 return TRUE;
1498
Richard Hughes639da472018-01-06 22:35:04 +00001499 /* no object loaded */
1500 if (priv->module == NULL)
1501 return TRUE;
1502
Richard Hughes46487c92017-01-07 21:26:34 +00001503 /* optional */
1504 g_module_symbol (priv->module, "fu_plugin_coldplug_prepare", (gpointer *) &func);
1505 if (func == NULL)
1506 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001507 g_debug ("coldplug_prepare(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001508 if (!func (self, &error_local)) {
1509 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001510 g_critical ("unset plugin error in coldplug_prepare(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001511 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001512 g_set_error_literal (&error_local,
1513 FWUPD_ERROR,
1514 FWUPD_ERROR_INTERNAL,
1515 "unspecified error");
1516 }
1517 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1518 "failed to coldplug_prepare using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001519 fu_plugin_get_name (self));
Richard Hughes46487c92017-01-07 21:26:34 +00001520 return FALSE;
1521 }
1522 return TRUE;
1523}
1524
Mario Limonciello1a680f32019-11-25 19:44:53 -06001525/**
1526 * fu_plugin_runner_coldplug_cleanup:
1527 * @self: a #FuPlugin
1528 * @error: a #GError or NULL
1529 *
1530 * Runs the coldplug_cleanup routine for the plugin
1531 *
1532 * Returns: #TRUE for success, #FALSE for failure
1533 *
1534 * Since: 0.8.0
1535 **/
Richard Hughes46487c92017-01-07 21:26:34 +00001536gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001537fu_plugin_runner_coldplug_cleanup (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001538{
Richard Hughes12724852018-09-04 13:53:44 +01001539 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001540 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001541 g_autoptr(GError) error_local = NULL;
Richard Hughes46487c92017-01-07 21:26:34 +00001542
1543 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001544 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes46487c92017-01-07 21:26:34 +00001545 return TRUE;
1546
Richard Hughes639da472018-01-06 22:35:04 +00001547 /* no object loaded */
1548 if (priv->module == NULL)
1549 return TRUE;
1550
Richard Hughes46487c92017-01-07 21:26:34 +00001551 /* optional */
1552 g_module_symbol (priv->module, "fu_plugin_coldplug_cleanup", (gpointer *) &func);
1553 if (func == NULL)
1554 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001555 g_debug ("coldplug_cleanup(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001556 if (!func (self, &error_local)) {
1557 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001558 g_critical ("unset plugin error in coldplug_cleanup(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001559 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001560 g_set_error_literal (&error_local,
1561 FWUPD_ERROR,
1562 FWUPD_ERROR_INTERNAL,
1563 "unspecified error");
1564 }
1565 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1566 "failed to coldplug_cleanup using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001567 fu_plugin_get_name (self));
Richard Hughes46487c92017-01-07 21:26:34 +00001568 return FALSE;
1569 }
1570 return TRUE;
1571}
1572
Mario Limonciello1a680f32019-11-25 19:44:53 -06001573/**
1574 * fu_plugin_runner_composite_prepare:
1575 * @self: a #FuPlugin
Richard Hughesa0d81c72019-11-27 11:41:54 +00001576 * @devices: (element-type FuDevice): a #GPtrArray of devices
Mario Limonciello1a680f32019-11-25 19:44:53 -06001577 * @error: a #GError or NULL
1578 *
1579 * Runs the composite_prepare routine for the plugin
1580 *
1581 * Returns: #TRUE for success, #FALSE for failure
1582 *
1583 * Since: 1.0.9
1584 **/
Richard Hughes46487c92017-01-07 21:26:34 +00001585gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001586fu_plugin_runner_composite_prepare (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001587{
Richard Hughes12724852018-09-04 13:53:44 +01001588 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001589 "fu_plugin_composite_prepare",
1590 error);
1591}
1592
Mario Limonciello1a680f32019-11-25 19:44:53 -06001593/**
1594 * fu_plugin_runner_composite_cleanup:
1595 * @self: a #FuPlugin
Richard Hughesa0d81c72019-11-27 11:41:54 +00001596 * @devices: (element-type FuDevice): a #GPtrArray of devices
Mario Limonciello1a680f32019-11-25 19:44:53 -06001597 * @error: a #GError or NULL
1598 *
1599 * Runs the composite_cleanup routine for the plugin
1600 *
1601 * Returns: #TRUE for success, #FALSE for failure
1602 *
1603 * Since: 1.0.9
1604 **/
Richard Hughesdbd8c762018-06-15 20:31:40 +01001605gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001606fu_plugin_runner_composite_cleanup (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001607{
Richard Hughes12724852018-09-04 13:53:44 +01001608 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001609 "fu_plugin_composite_cleanup",
1610 error);
1611}
1612
Mario Limonciello1a680f32019-11-25 19:44:53 -06001613/**
1614 * fu_plugin_runner_update_prepare:
1615 * @self: a #FuPlugin
Richard Hughes2bbb7d22020-11-30 09:18:45 +00001616 * @flags: #FwupdInstallFlags
1617 * @device: a #FuDevice
Mario Limonciello1a680f32019-11-25 19:44:53 -06001618 * @error: a #GError or NULL
1619 *
1620 * Runs the update_prepare routine for the plugin
1621 *
1622 * Returns: #TRUE for success, #FALSE for failure
1623 *
1624 * Since: 1.1.2
1625 **/
Richard Hughesdbd8c762018-06-15 20:31:40 +01001626gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001627fu_plugin_runner_update_prepare (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001628 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001629{
Richard Hughes12724852018-09-04 13:53:44 +01001630 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001631 "fu_plugin_update_prepare",
1632 error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001633}
1634
Mario Limonciello1a680f32019-11-25 19:44:53 -06001635/**
1636 * fu_plugin_runner_update_cleanup:
1637 * @self: a #FuPlugin
Richard Hughes2bbb7d22020-11-30 09:18:45 +00001638 * @flags: #FwupdInstallFlags
1639 * @device: a #FuDevice
Mario Limonciello1a680f32019-11-25 19:44:53 -06001640 * @error: a #GError or NULL
1641 *
1642 * Runs the update_cleanup routine for the plugin
1643 *
1644 * Returns: #TRUE for success, #FALSE for failure
1645 *
1646 * Since: 1.1.2
1647 **/
Richard Hughes7b8b2022016-12-12 16:15:03 +00001648gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001649fu_plugin_runner_update_cleanup (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001650 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001651{
Richard Hughes12724852018-09-04 13:53:44 +01001652 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001653 "fu_plugin_update_cleanup",
1654 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001655}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001656
Mario Limonciello1a680f32019-11-25 19:44:53 -06001657/**
1658 * fu_plugin_runner_update_attach:
1659 * @self: a #FuPlugin
1660 * @device: a #FuDevice
1661 * @error: a #GError or NULL
1662 *
1663 * Runs the update_attach routine for the plugin
1664 *
1665 * Returns: #TRUE for success, #FALSE for failure
1666 *
1667 * Since: 1.1.2
1668 **/
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001669gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001670fu_plugin_runner_update_attach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001671{
Richard Hughes12724852018-09-04 13:53:44 +01001672 return fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001673 "fu_plugin_update_attach",
1674 fu_plugin_device_attach,
1675 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001676}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001677
Mario Limonciello1a680f32019-11-25 19:44:53 -06001678/**
1679 * fu_plugin_runner_update_detach:
1680 * @self: a #FuPlugin
1681 * @device: A #FuDevice
1682 * @error: a #GError or NULL
1683 *
1684 * Runs the update_detach routine for the plugin
1685 *
1686 * Returns: #TRUE for success, #FALSE for failure
1687 *
1688 * Since: 1.1.2
1689 **/
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001690gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001691fu_plugin_runner_update_detach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001692{
Richard Hughes12724852018-09-04 13:53:44 +01001693 return fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001694 "fu_plugin_update_detach",
1695 fu_plugin_device_detach,
1696 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001697}
1698
Mario Limonciello1a680f32019-11-25 19:44:53 -06001699/**
1700 * fu_plugin_runner_update_reload:
1701 * @self: a #FuPlugin
Richard Hughes2bbb7d22020-11-30 09:18:45 +00001702 * @device: A #FuDevice
Mario Limonciello1a680f32019-11-25 19:44:53 -06001703 * @error: a #GError or NULL
1704 *
1705 * Runs reload routine for a device
1706 *
1707 * Returns: #TRUE for success, #FALSE for failure
1708 *
1709 * Since: 1.1.2
1710 **/
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001711gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001712fu_plugin_runner_update_reload (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001713{
Richard Hughes42f33df2019-10-05 20:52:33 +01001714 g_autoptr(FuDeviceLocker) locker = NULL;
1715
1716 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001717 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes42f33df2019-10-05 20:52:33 +01001718 return TRUE;
1719
1720 /* no object loaded */
1721 locker = fu_device_locker_new (device, error);
1722 if (locker == NULL)
1723 return FALSE;
1724 return fu_device_reload (device, error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001725}
1726
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001727/**
Richard Hughes196c6c62020-05-11 19:42:47 +01001728 * fu_plugin_runner_add_security_attrs:
1729 * @self: a #FuPlugin
Richard Hughes3ecd22c2020-05-19 20:13:47 +01001730 * @attrs: a #FuSecurityAttrs
Richard Hughes196c6c62020-05-11 19:42:47 +01001731 *
Richard Hughes3ecd22c2020-05-19 20:13:47 +01001732 * Runs the `add_security_attrs()` routine for the plugin
Richard Hughes196c6c62020-05-11 19:42:47 +01001733 *
1734 * Since: 1.5.0
1735 **/
Richard Hughesf58ac732020-05-12 15:23:44 +01001736void
1737fu_plugin_runner_add_security_attrs (FuPlugin *self, FuSecurityAttrs *attrs)
Richard Hughes196c6c62020-05-11 19:42:47 +01001738{
Richard Hughesf58ac732020-05-12 15:23:44 +01001739 FuPluginPrivate *priv = GET_PRIVATE (self);
1740 FuPluginSecurityAttrsFunc func = NULL;
1741 const gchar *symbol_name = "fu_plugin_add_security_attrs";
1742
1743 /* no object loaded */
1744 if (priv->module == NULL)
1745 return;
1746
1747 /* optional, but gets called even for disabled plugins */
1748 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1749 if (func == NULL)
1750 return;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001751 g_debug ("%s(%s)", symbol_name + 10, fu_plugin_get_name (self));
Richard Hughesf58ac732020-05-12 15:23:44 +01001752 func (self, attrs);
Richard Hughes196c6c62020-05-11 19:42:47 +01001753}
1754
1755/**
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001756 * fu_plugin_add_udev_subsystem:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001757 * @self: a #FuPlugin
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001758 * @subsystem: a subsystem name, e.g. `pciport`
1759 *
1760 * Registers the udev subsystem to be watched by the daemon.
1761 *
1762 * Plugins can use this method only in fu_plugin_init()
Mario Limonciello1a680f32019-11-25 19:44:53 -06001763 *
1764 * Since: 1.1.2
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001765 **/
1766void
Richard Hughes12724852018-09-04 13:53:44 +01001767fu_plugin_add_udev_subsystem (FuPlugin *self, const gchar *subsystem)
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001768{
Richard Hughes12724852018-09-04 13:53:44 +01001769 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesea327fc2020-06-22 15:23:29 +01001770 if (priv->udev_subsystems == NULL)
1771 priv->udev_subsystems = g_ptr_array_new_with_free_func (g_free);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001772 for (guint i = 0; i < priv->udev_subsystems->len; i++) {
1773 const gchar *subsystem_tmp = g_ptr_array_index (priv->udev_subsystems, i);
1774 if (g_strcmp0 (subsystem_tmp, subsystem) == 0)
1775 return;
1776 }
1777 g_debug ("added udev subsystem watch of %s", subsystem);
1778 g_ptr_array_add (priv->udev_subsystems, g_strdup (subsystem));
1779}
1780
Richard Hughes989acf12019-10-05 20:16:47 +01001781/**
1782 * fu_plugin_set_device_gtype:
1783 * @self: a #FuPlugin
1784 * @device_gtype: a #GType `FU_TYPE_DEVICE`
1785 *
1786 * Sets the device #GType which is used when creating devices.
1787 *
1788 * If this method is used then fu_plugin_usb_device_added() is not called, and
1789 * instead the object is created in the daemon for the plugin.
1790 *
1791 * Plugins can use this method only in fu_plugin_init()
1792 *
1793 * Since: 1.3.3
1794 **/
1795void
1796fu_plugin_set_device_gtype (FuPlugin *self, GType device_gtype)
1797{
1798 FuPluginPrivate *priv = GET_PRIVATE (self);
1799 priv->device_gtype = device_gtype;
1800}
1801
Richard Hughes9f71fe32021-01-03 20:35:36 +00001802static gchar *
1803fu_common_string_uncamelcase (const gchar *str)
1804{
1805 GString *tmp = g_string_new (NULL);
1806 for (guint i = 0; str[i] != '\0'; i++) {
1807 if (g_ascii_islower (str[i]) ||
1808 g_ascii_isdigit (str[i])) {
1809 g_string_append_c (tmp, str[i]);
1810 continue;
1811 }
1812 if (i > 0)
1813 g_string_append_c (tmp, '-');
1814 g_string_append_c (tmp, g_ascii_tolower (str[i]));
1815 }
1816 return g_string_free (tmp, FALSE);
1817}
1818
Mario Limonciello1a680f32019-11-25 19:44:53 -06001819/**
1820 * fu_plugin_add_firmware_gtype:
1821 * @self: a #FuPlugin
Richard Hughes9f71fe32021-01-03 20:35:36 +00001822 * @id: (nullable): An optional string describing the type, e.g. "ihex"
1823 * @gtype: a #GType e.g. `FU_TYPE_FOO_FIRMWARE`
Mario Limonciello1a680f32019-11-25 19:44:53 -06001824 *
Richard Hughes9f71fe32021-01-03 20:35:36 +00001825 * Adds a firmware #GType which is used when creating devices. If @id is not
1826 * specified then it is guessed using the #GType name.
1827 *
Mario Limonciello1a680f32019-11-25 19:44:53 -06001828 * Plugins can use this method only in fu_plugin_init()
1829 *
1830 * Since: 1.3.3
1831 **/
Richard Hughes95c98a92019-10-22 16:03:15 +01001832void
1833fu_plugin_add_firmware_gtype (FuPlugin *self, const gchar *id, GType gtype)
1834{
Richard Hughes9f71fe32021-01-03 20:35:36 +00001835 g_autofree gchar *id_safe = NULL;
1836 if (id != NULL) {
1837 id_safe = g_strdup (id);
1838 } else {
Richard Hughesebb10a52021-01-05 13:34:39 +00001839 g_autoptr(GString) str = g_string_new (g_type_name (gtype));
Richard Hughes9f71fe32021-01-03 20:35:36 +00001840 if (g_str_has_prefix (str->str, "Fu"))
1841 g_string_erase (str, 0, 2);
1842 fu_common_string_replace (str, "Firmware", "");
1843 id_safe = fu_common_string_uncamelcase (str->str);
1844 }
1845 g_signal_emit (self, signals[SIGNAL_ADD_FIRMWARE_GTYPE], 0, id_safe, gtype);
Richard Hughes95c98a92019-10-22 16:03:15 +01001846}
1847
Richard Hughes989acf12019-10-05 20:16:47 +01001848static gboolean
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001849fu_plugin_check_supported_device (FuPlugin *self, FuDevice *device)
1850{
1851 GPtrArray *instance_ids = fu_device_get_instance_ids (device);
1852 for (guint i = 0; i < instance_ids->len; i++) {
1853 const gchar *instance_id = g_ptr_array_index (instance_ids, i);
1854 g_autofree gchar *guid = fwupd_guid_hash_string (instance_id);
1855 if (fu_plugin_check_supported (self, guid))
1856 return TRUE;
1857 }
1858 return FALSE;
1859}
1860
1861static gboolean
Richard Hughes989acf12019-10-05 20:16:47 +01001862fu_plugin_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error)
1863{
1864 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001865 GType device_gtype = fu_device_get_specialized_gtype (FU_DEVICE (device));
Richard Hughes989acf12019-10-05 20:16:47 +01001866 g_autoptr(FuDevice) dev = NULL;
1867 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001868
1869 /* fall back to plugin default */
1870 if (device_gtype == G_TYPE_INVALID)
1871 device_gtype = priv->device_gtype;
1872
1873 /* create new device and incorporate existing properties */
1874 dev = g_object_new (device_gtype, NULL);
1875 fu_device_incorporate (dev, FU_DEVICE (device));
Richard Hughes0f66a022020-02-19 18:54:38 +00001876 if (!fu_plugin_runner_device_created (self, dev, error))
1877 return FALSE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001878
1879 /* there are a lot of different devices that match, but not all respond
1880 * well to opening -- so limit some ones with issued updates */
Richard Hughescf100292021-01-04 10:36:37 +00001881 if (fu_device_has_internal_flag (dev, FU_DEVICE_INTERNAL_FLAG_ONLY_SUPPORTED)) {
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001882 if (!fu_device_probe (dev, error))
1883 return FALSE;
1884 fu_device_convert_instance_ids (dev);
1885 if (!fu_plugin_check_supported_device (self, dev)) {
1886 g_autofree gchar *guids = fu_device_get_guids_as_str (dev);
1887 g_debug ("%s has no updates, so ignoring device", guids);
1888 return TRUE;
1889 }
1890 }
1891
1892 /* open and add */
1893 locker = fu_device_locker_new (dev, error);
1894 if (locker == NULL)
1895 return FALSE;
1896 fu_plugin_device_add (self, dev);
Richard Hughes6a078702020-05-09 20:36:33 +01001897 fu_plugin_runner_device_added (self, dev);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001898 return TRUE;
1899}
1900
1901static gboolean
1902fu_plugin_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error)
1903{
1904 FuPluginPrivate *priv = GET_PRIVATE (self);
1905 GType device_gtype = fu_device_get_specialized_gtype (FU_DEVICE (device));
1906 g_autoptr(FuDevice) dev = NULL;
1907 g_autoptr(FuDeviceLocker) locker = NULL;
1908
1909 /* fall back to plugin default */
1910 if (device_gtype == G_TYPE_INVALID)
1911 device_gtype = priv->device_gtype;
1912
1913 /* create new device and incorporate existing properties */
1914 dev = g_object_new (device_gtype, NULL);
Richard Hughes989acf12019-10-05 20:16:47 +01001915 fu_device_incorporate (FU_DEVICE (dev), FU_DEVICE (device));
Richard Hughes0f66a022020-02-19 18:54:38 +00001916 if (!fu_plugin_runner_device_created (self, dev, error))
1917 return FALSE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001918
1919 /* there are a lot of different devices that match, but not all respond
1920 * well to opening -- so limit some ones with issued updates */
Richard Hughescf100292021-01-04 10:36:37 +00001921 if (fu_device_has_internal_flag (dev, FU_DEVICE_INTERNAL_FLAG_ONLY_SUPPORTED)) {
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001922 if (!fu_device_probe (dev, error))
1923 return FALSE;
1924 fu_device_convert_instance_ids (dev);
1925 if (!fu_plugin_check_supported_device (self, dev)) {
1926 g_autofree gchar *guids = fu_device_get_guids_as_str (dev);
1927 g_debug ("%s has no updates, so ignoring device", guids);
1928 return TRUE;
1929 }
1930 }
1931
1932 /* open and add */
Richard Hughes989acf12019-10-05 20:16:47 +01001933 locker = fu_device_locker_new (dev, error);
1934 if (locker == NULL)
1935 return FALSE;
1936 fu_plugin_device_add (self, FU_DEVICE (dev));
Richard Hughes6a078702020-05-09 20:36:33 +01001937 fu_plugin_runner_device_added (self, dev);
Richard Hughes989acf12019-10-05 20:16:47 +01001938 return TRUE;
1939}
1940
Mario Limonciello1a680f32019-11-25 19:44:53 -06001941/**
1942 * fu_plugin_runner_usb_device_added:
1943 * @self: a #FuPlugin
1944 * @device: a #FuUsbDevice
1945 * @error: a #GError or NULL
1946 *
1947 * Call the usb_device_added routine for the plugin
1948 *
1949 * Returns: #TRUE for success, #FALSE for failure
1950 *
1951 * Since: 1.0.2
1952 **/
Richard Hughes104f6512017-11-24 11:44:57 +00001953gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001954fu_plugin_runner_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error)
Richard Hughes104f6512017-11-24 11:44:57 +00001955{
Richard Hughes12724852018-09-04 13:53:44 +01001956 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes104f6512017-11-24 11:44:57 +00001957 FuPluginUsbDeviceAddedFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001958 g_autoptr(GError) error_local = NULL;
Richard Hughes104f6512017-11-24 11:44:57 +00001959
Richard Hughes6a489a92020-12-22 10:32:06 +00001960 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
1961 g_return_val_if_fail (FU_IS_USB_DEVICE (device), FALSE);
1962 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1963
Richard Hughes104f6512017-11-24 11:44:57 +00001964 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001965 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes104f6512017-11-24 11:44:57 +00001966 return TRUE;
Richard Hughes639da472018-01-06 22:35:04 +00001967
1968 /* no object loaded */
Richard Hughes104f6512017-11-24 11:44:57 +00001969 if (priv->module == NULL)
1970 return TRUE;
1971
1972 /* optional */
1973 g_module_symbol (priv->module, "fu_plugin_usb_device_added", (gpointer *) &func);
Richard Hughes989acf12019-10-05 20:16:47 +01001974 if (func == NULL) {
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001975 if (priv->device_gtype != G_TYPE_INVALID ||
1976 fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) {
Mario Limonciello0e500322019-10-17 18:41:04 -05001977 if (!fu_plugin_usb_device_added (self, device, error))
Mario Limoncielloa9be5362019-10-12 13:17:45 -05001978 return FALSE;
Richard Hughes989acf12019-10-05 20:16:47 +01001979 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001980 return TRUE;
Richard Hughes989acf12019-10-05 20:16:47 +01001981 }
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001982 g_debug ("usb_device_added(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001983 if (!func (self, device, &error_local)) {
1984 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001985 g_critical ("unset plugin error in usb_device_added(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001986 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001987 g_set_error_literal (&error_local,
1988 FWUPD_ERROR,
1989 FWUPD_ERROR_INTERNAL,
1990 "unspecified error");
1991 }
1992 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1993 "failed to add device using on %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001994 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001995 return FALSE;
Richard Hughes104f6512017-11-24 11:44:57 +00001996 }
1997 return TRUE;
1998}
1999
Mario Limonciello1a680f32019-11-25 19:44:53 -06002000/**
2001 * fu_plugin_runner_udev_device_added:
2002 * @self: a #FuPlugin
2003 * @device: a #FuUdevDevice
2004 * @error: a #GError or NULL
2005 *
2006 * Call the udev_device_added routine for the plugin
2007 *
2008 * Returns: #TRUE for success, #FALSE for failure
2009 *
2010 * Since: 1.0.2
2011 **/
Richard Hughes9d6e0e72018-08-24 20:20:17 +01002012gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002013fu_plugin_runner_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error)
Richard Hughes9d6e0e72018-08-24 20:20:17 +01002014{
Richard Hughes12724852018-09-04 13:53:44 +01002015 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01002016 FuPluginUdevDeviceAddedFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002017 g_autoptr(GError) error_local = NULL;
Richard Hughes9d6e0e72018-08-24 20:20:17 +01002018
Richard Hughes6a489a92020-12-22 10:32:06 +00002019 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
2020 g_return_val_if_fail (FU_IS_UDEV_DEVICE (device), FALSE);
2021 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2022
Richard Hughes9d6e0e72018-08-24 20:20:17 +01002023 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002024 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes9d6e0e72018-08-24 20:20:17 +01002025 return TRUE;
2026
2027 /* no object loaded */
2028 if (priv->module == NULL)
2029 return TRUE;
2030
2031 /* optional */
2032 g_module_symbol (priv->module, "fu_plugin_udev_device_added", (gpointer *) &func);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01002033 if (func == NULL) {
2034 if (priv->device_gtype != G_TYPE_INVALID ||
2035 fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) {
Richard Hughes6fca4692020-12-01 18:22:46 +00002036 return fu_plugin_udev_device_added (self, device, error);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01002037 }
Richard Hughesa21e0252020-12-01 12:21:33 +00002038 g_set_error_literal (error,
2039 FWUPD_ERROR,
2040 FWUPD_ERROR_INTERNAL,
2041 "No device GType set");
2042 return FALSE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01002043 }
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002044 g_debug ("udev_device_added(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002045 if (!func (self, device, &error_local)) {
2046 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05002047 g_critical ("unset plugin error in udev_device_added(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002048 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002049 g_set_error_literal (&error_local,
2050 FWUPD_ERROR,
2051 FWUPD_ERROR_INTERNAL,
2052 "unspecified error");
2053 }
2054 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2055 "failed to add device using on %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002056 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002057 return FALSE;
Richard Hughes9d6e0e72018-08-24 20:20:17 +01002058 }
2059 return TRUE;
2060}
2061
Mario Limonciello1a680f32019-11-25 19:44:53 -06002062/**
2063 * fu_plugin_runner_udev_device_changed:
2064 * @self: a #FuPlugin
2065 * @device: a #FuUdevDevice
2066 * @error: a #GError or NULL
2067 *
2068 * Call the udev_device_changed routine for the plugin
2069 *
2070 * Returns: #TRUE for success, #FALSE for failure
2071 *
2072 * Since: 1.0.2
2073 **/
Richard Hughes5e952ce2019-08-26 11:09:46 +01002074gboolean
2075fu_plugin_runner_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GError **error)
2076{
2077 FuPluginPrivate *priv = GET_PRIVATE (self);
2078 FuPluginUdevDeviceAddedFunc func = NULL;
2079 g_autoptr(GError) error_local = NULL;
2080
Richard Hughes6a489a92020-12-22 10:32:06 +00002081 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
2082 g_return_val_if_fail (FU_IS_UDEV_DEVICE (device), FALSE);
2083 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2084
Richard Hughes5e952ce2019-08-26 11:09:46 +01002085 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002086 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes5e952ce2019-08-26 11:09:46 +01002087 return TRUE;
2088
2089 /* no object loaded */
2090 if (priv->module == NULL)
2091 return TRUE;
2092
2093 /* optional */
2094 g_module_symbol (priv->module, "fu_plugin_udev_device_changed", (gpointer *) &func);
Mario Limonciello6d235142020-09-10 21:35:17 -05002095 if (func == NULL)
Richard Hughes5e952ce2019-08-26 11:09:46 +01002096 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002097 g_debug ("udev_device_changed(%s)", fu_plugin_get_name (self));
Richard Hughes5e952ce2019-08-26 11:09:46 +01002098 if (!func (self, device, &error_local)) {
2099 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05002100 g_critical ("unset plugin error in udev_device_changed(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002101 fu_plugin_get_name (self));
Richard Hughes5e952ce2019-08-26 11:09:46 +01002102 g_set_error_literal (&error_local,
2103 FWUPD_ERROR,
2104 FWUPD_ERROR_INTERNAL,
2105 "unspecified error");
2106 }
2107 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2108 "failed to change device on %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002109 fu_plugin_get_name (self));
Richard Hughes5e952ce2019-08-26 11:09:46 +01002110 return FALSE;
2111 }
2112 return TRUE;
2113}
2114
Mario Limonciello1a680f32019-11-25 19:44:53 -06002115/**
Richard Hughes6a078702020-05-09 20:36:33 +01002116 * fu_plugin_runner_device_added:
2117 * @self: a #FuPlugin
2118 * @device: a #FuDevice
2119 *
2120 * Call the device_added routine for the plugin
2121 *
2122 * Since: 1.5.0
2123 **/
2124void
2125fu_plugin_runner_device_added (FuPlugin *self, FuDevice *device)
2126{
2127 FuPluginPrivate *priv = GET_PRIVATE (self);
2128 FuPluginDeviceRegisterFunc func = NULL;
2129
2130 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002131 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes6a078702020-05-09 20:36:33 +01002132 return;
2133 if (priv->module == NULL)
2134 return;
2135
2136 /* optional */
2137 g_module_symbol (priv->module, "fu_plugin_device_added", (gpointer *) &func);
2138 if (func == NULL)
2139 return;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002140 g_debug ("fu_plugin_device_added(%s)", fu_plugin_get_name (self));
Richard Hughes6a078702020-05-09 20:36:33 +01002141 func (self, device);
2142}
2143
2144/**
Mario Limonciello1a680f32019-11-25 19:44:53 -06002145 * fu_plugin_runner_device_removed:
2146 * @self: a #FuPlugin
2147 * @device: a #FuDevice
2148 *
2149 * Call the device_removed routine for the plugin
2150 *
2151 * Since: 1.1.2
2152 **/
Richard Hughese1fd34d2017-08-24 14:19:51 +01002153void
Richard Hughes12724852018-09-04 13:53:44 +01002154fu_plugin_runner_device_removed (FuPlugin *self, FuDevice *device)
Mario Limoncielloe260ead2018-09-01 09:19:24 -05002155{
2156 g_autoptr(GError) error_local= NULL;
2157
Richard Hughes12724852018-09-04 13:53:44 +01002158 if (!fu_plugin_runner_device_generic (self, device,
Mario Limoncielloe260ead2018-09-01 09:19:24 -05002159 "fu_plugin_device_removed",
Richard Hughes4b303802019-10-04 13:22:51 +01002160 NULL,
Mario Limoncielloe260ead2018-09-01 09:19:24 -05002161 &error_local))
2162 g_warning ("%s", error_local->message);
2163}
2164
Mario Limonciello1a680f32019-11-25 19:44:53 -06002165/**
2166 * fu_plugin_runner_device_register:
2167 * @self: a #FuPlugin
2168 * @device: a #FuDevice
2169 *
2170 * Call the device_registered routine for the plugin
2171 *
2172 * Since: 0.9.7
2173 **/
Mario Limoncielloe260ead2018-09-01 09:19:24 -05002174void
Richard Hughes12724852018-09-04 13:53:44 +01002175fu_plugin_runner_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +01002176{
Richard Hughes12724852018-09-04 13:53:44 +01002177 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughese1fd34d2017-08-24 14:19:51 +01002178 FuPluginDeviceRegisterFunc func = NULL;
2179
2180 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002181 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughese1fd34d2017-08-24 14:19:51 +01002182 return;
Richard Hughes34834102017-11-21 21:55:00 +00002183 if (priv->module == NULL)
2184 return;
Richard Hughese1fd34d2017-08-24 14:19:51 +01002185
2186 /* optional */
2187 g_module_symbol (priv->module, "fu_plugin_device_registered", (gpointer *) &func);
2188 if (func != NULL) {
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002189 g_debug ("fu_plugin_device_registered(%s)", fu_plugin_get_name (self));
Richard Hughes12724852018-09-04 13:53:44 +01002190 func (self, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +01002191 }
2192}
2193
Mario Limonciello1a680f32019-11-25 19:44:53 -06002194/**
Richard Hughes0f66a022020-02-19 18:54:38 +00002195 * fu_plugin_runner_device_created:
2196 * @self: a #FuPlugin
2197 * @device: a #FuDevice
2198 * @error: a #GError or NULL
2199 *
2200 * Call the device_created routine for the plugin
2201 *
2202 * Returns: #TRUE for success, #FALSE for failure
2203 *
Mario Limonciello96117d12020-02-28 10:17:56 -06002204 * Since: 1.4.0
Richard Hughes0f66a022020-02-19 18:54:38 +00002205 **/
2206gboolean
2207fu_plugin_runner_device_created (FuPlugin *self, FuDevice *device, GError **error)
2208{
2209 FuPluginPrivate *priv = GET_PRIVATE (self);
2210 FuPluginDeviceFunc func = NULL;
2211
Richard Hughes6a489a92020-12-22 10:32:06 +00002212 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
2213 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
2214 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2215
Richard Hughes0f66a022020-02-19 18:54:38 +00002216 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002217 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes0f66a022020-02-19 18:54:38 +00002218 return TRUE;
2219 if (priv->module == NULL)
2220 return TRUE;
2221
2222 /* optional */
2223 g_module_symbol (priv->module, "fu_plugin_device_created", (gpointer *) &func);
2224 if (func == NULL)
2225 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002226 g_debug ("fu_plugin_device_created(%s)", fu_plugin_get_name (self));
Richard Hughes0f66a022020-02-19 18:54:38 +00002227 return func (self, device, error);
2228}
2229
2230/**
Mario Limonciello1a680f32019-11-25 19:44:53 -06002231 * fu_plugin_runner_verify:
2232 * @self: a #FuPlugin
2233 * @device: a #FuDevice
2234 * @flags: #FuPluginVerifyFlags
2235 * @error: A #GError or NULL
2236 *
2237 * Call into the plugin's verify routine
2238 *
2239 * Returns: #TRUE for success, #FALSE for failure
2240 *
2241 * Since: 0.8.0
2242 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002243gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002244fu_plugin_runner_verify (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +00002245 FuDevice *device,
2246 FuPluginVerifyFlags flags,
2247 GError **error)
2248{
Richard Hughes12724852018-09-04 13:53:44 +01002249 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00002250 FuPluginVerifyFunc func = NULL;
Richard Hughesababbb72017-06-15 20:18:36 +01002251 GPtrArray *checksums;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002252 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002253
Richard Hughes6a489a92020-12-22 10:32:06 +00002254 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
2255 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
2256 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2257
Richard Hughescff38bc2016-12-12 12:03:37 +00002258 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002259 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughescff38bc2016-12-12 12:03:37 +00002260 return TRUE;
2261
Richard Hughes639da472018-01-06 22:35:04 +00002262 /* no object loaded */
2263 if (priv->module == NULL)
2264 return TRUE;
2265
Richard Hughescff38bc2016-12-12 12:03:37 +00002266 /* optional */
2267 g_module_symbol (priv->module, "fu_plugin_verify", (gpointer *) &func);
Richard Hughes7f677212019-10-05 16:19:40 +01002268 if (func == NULL) {
Richard Hughes7f677212019-10-05 16:19:40 +01002269 return fu_plugin_device_read_firmware (self, device, error);
2270 }
Richard Hughes1812fc72018-12-14 11:37:54 +00002271
2272 /* clear any existing verification checksums */
2273 checksums = fu_device_get_checksums (device);
2274 g_ptr_array_set_size (checksums, 0);
2275
Richard Hughesc9223be2019-03-18 08:46:42 +00002276 /* run additional detach */
2277 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01002278 "fu_plugin_update_detach",
Richard Hughes4b303802019-10-04 13:22:51 +01002279 fu_plugin_device_detach,
Richard Hughesc9223be2019-03-18 08:46:42 +00002280 error))
2281 return FALSE;
2282
Richard Hughes1812fc72018-12-14 11:37:54 +00002283 /* run vfunc */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002284 g_debug ("verify(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002285 if (!func (self, device, flags, &error_local)) {
Richard Hughesc9223be2019-03-18 08:46:42 +00002286 g_autoptr(GError) error_attach = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002287 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05002288 g_critical ("unset plugin error in verify(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002289 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002290 g_set_error_literal (&error_local,
2291 FWUPD_ERROR,
2292 FWUPD_ERROR_INTERNAL,
2293 "unspecified error");
2294 }
2295 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2296 "failed to verify using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002297 fu_plugin_get_name (self));
Richard Hughesc9223be2019-03-18 08:46:42 +00002298 /* make the device "work" again, but don't prefix the error */
2299 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01002300 "fu_plugin_update_attach",
Richard Hughes4b303802019-10-04 13:22:51 +01002301 fu_plugin_device_attach,
Richard Hughesc9223be2019-03-18 08:46:42 +00002302 &error_attach)) {
2303 g_warning ("failed to attach whilst aborting verify(): %s",
2304 error_attach->message);
2305 }
Richard Hughesd0905142016-03-13 09:46:49 +00002306 return FALSE;
2307 }
Richard Hughesc9223be2019-03-18 08:46:42 +00002308
2309 /* run optional attach */
2310 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01002311 "fu_plugin_update_attach",
Richard Hughes4b303802019-10-04 13:22:51 +01002312 fu_plugin_device_attach,
Richard Hughesc9223be2019-03-18 08:46:42 +00002313 error))
2314 return FALSE;
2315
2316 /* success */
Richard Hughesd0905142016-03-13 09:46:49 +00002317 return TRUE;
2318}
2319
Mario Limonciello1a680f32019-11-25 19:44:53 -06002320/**
2321 * fu_plugin_runner_activate:
2322 * @self: a #FuPlugin
2323 * @device: a #FuDevice
2324 * @error: A #GError or NULL
2325 *
2326 * Call into the plugin's activate routine
2327 *
2328 * Returns: #TRUE for success, #FALSE for failure
2329 *
2330 * Since: 1.2.6
2331 **/
Richard Hughesd0905142016-03-13 09:46:49 +00002332gboolean
Mario Limonciello96a0dd52019-02-25 13:50:03 -06002333fu_plugin_runner_activate (FuPlugin *self, FuDevice *device, GError **error)
2334{
2335 guint64 flags;
2336
Richard Hughes6a489a92020-12-22 10:32:06 +00002337 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
2338 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
2339 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2340
Mario Limonciello96a0dd52019-02-25 13:50:03 -06002341 /* final check */
2342 flags = fu_device_get_flags (device);
2343 if ((flags & FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION) == 0) {
2344 g_set_error (error,
2345 FWUPD_ERROR,
2346 FWUPD_ERROR_NOT_SUPPORTED,
2347 "Device %s does not need activation",
2348 fu_device_get_id (device));
2349 return FALSE;
2350 }
2351
2352 /* run vfunc */
2353 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01002354 "fu_plugin_activate",
2355 fu_plugin_device_activate,
2356 error))
Mario Limonciello96a0dd52019-02-25 13:50:03 -06002357 return FALSE;
2358
2359 /* update with correct flags */
2360 fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION);
2361 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
2362 return TRUE;
2363}
2364
Mario Limonciello1a680f32019-11-25 19:44:53 -06002365/**
2366 * fu_plugin_runner_unlock:
2367 * @self: a #FuPlugin
2368 * @device: a #FuDevice
2369 * @error: A #GError or NULL
2370 *
2371 * Call into the plugin's unlock routine
2372 *
2373 * Returns: #TRUE for success, #FALSE for failure
2374 *
2375 * Since: 0.8.0
2376 **/
Mario Limonciello96a0dd52019-02-25 13:50:03 -06002377gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002378fu_plugin_runner_unlock (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00002379{
Richard Hughescff38bc2016-12-12 12:03:37 +00002380 guint64 flags;
Richard Hughescff38bc2016-12-12 12:03:37 +00002381
Richard Hughes6a489a92020-12-22 10:32:06 +00002382 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
2383 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
2384 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2385
Richard Hughescff38bc2016-12-12 12:03:37 +00002386 /* final check */
2387 flags = fu_device_get_flags (device);
2388 if ((flags & FWUPD_DEVICE_FLAG_LOCKED) == 0) {
2389 g_set_error (error,
2390 FWUPD_ERROR,
2391 FWUPD_ERROR_NOT_SUPPORTED,
2392 "Device %s is not locked",
2393 fu_device_get_id (device));
2394 return FALSE;
2395 }
2396
Richard Hughes9c4b5312017-11-14 11:34:53 +00002397 /* run vfunc */
Richard Hughes12724852018-09-04 13:53:44 +01002398 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01002399 "fu_plugin_unlock",
2400 NULL,
2401 error))
Richard Hughes9c4b5312017-11-14 11:34:53 +00002402 return FALSE;
Richard Hughescff38bc2016-12-12 12:03:37 +00002403
2404 /* update with correct flags */
2405 flags = fu_device_get_flags (device);
2406 fu_device_set_flags (device, flags &= ~FWUPD_DEVICE_FLAG_LOCKED);
2407 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
2408 return TRUE;
2409}
2410
Mario Limonciello1a680f32019-11-25 19:44:53 -06002411/**
2412 * fu_plugin_runner_update:
2413 * @self: a #FuPlugin
2414 * @device: a #FuDevice
2415 * @blob_fw: A #GBytes
2416 * @flags: A #FwupdInstallFlags
2417 * @error: A #GError or NULL
2418 *
2419 * Call into the plugin's update routine
2420 *
2421 * Returns: #TRUE for success, #FALSE for failure
2422 *
2423 * Since: 0.8.0
2424 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002425gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002426fu_plugin_runner_update (FuPlugin *self,
Richard Hughesa785a1c2017-08-25 16:00:58 +01002427 FuDevice *device,
Richard Hughesa785a1c2017-08-25 16:00:58 +01002428 GBytes *blob_fw,
2429 FwupdInstallFlags flags,
2430 GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00002431{
Richard Hughes12724852018-09-04 13:53:44 +01002432 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesa785a1c2017-08-25 16:00:58 +01002433 FuPluginUpdateFunc update_func;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002434 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002435
Richard Hughes6a489a92020-12-22 10:32:06 +00002436 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
2437 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
2438 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2439
Richard Hughescff38bc2016-12-12 12:03:37 +00002440 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002441 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) {
Richard Hughes41c15482018-02-01 22:07:21 +00002442 g_debug ("plugin not enabled, skipping");
Richard Hughesd0905142016-03-13 09:46:49 +00002443 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00002444 }
Richard Hughesd0905142016-03-13 09:46:49 +00002445
Richard Hughes639da472018-01-06 22:35:04 +00002446 /* no object loaded */
Richard Hughes41c15482018-02-01 22:07:21 +00002447 if (priv->module == NULL) {
2448 g_debug ("module not enabled, skipping");
Richard Hughes639da472018-01-06 22:35:04 +00002449 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00002450 }
Richard Hughes639da472018-01-06 22:35:04 +00002451
Richard Hughesd0905142016-03-13 09:46:49 +00002452 /* optional */
Richard Hughesa785a1c2017-08-25 16:00:58 +01002453 g_module_symbol (priv->module, "fu_plugin_update", (gpointer *) &update_func);
2454 if (update_func == NULL) {
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002455 g_debug ("superclassed write_firmware(%s)", fu_plugin_get_name (self));
Richard Hughes4b303802019-10-04 13:22:51 +01002456 return fu_plugin_device_write_firmware (self, device, blob_fw, flags, error);
Richard Hughesa785a1c2017-08-25 16:00:58 +01002457 }
Richard Hughesd0905142016-03-13 09:46:49 +00002458
Richard Hughescff38bc2016-12-12 12:03:37 +00002459 /* online */
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002460 if (!update_func (self, device, blob_fw, flags, &error_local)) {
2461 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05002462 g_critical ("unset plugin error in update(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002463 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002464 g_set_error_literal (&error_local,
Richard Hughes3c8ada32018-10-12 10:08:58 +01002465 FWUPD_ERROR,
2466 FWUPD_ERROR_INTERNAL,
2467 "unspecified error");
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002468 return FALSE;
Richard Hughes3c8ada32018-10-12 10:08:58 +01002469 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002470 fu_device_set_update_error (device, error_local->message);
2471 g_propagate_error (error, g_steal_pointer (&error_local));
Richard Hughescff38bc2016-12-12 12:03:37 +00002472 return FALSE;
2473 }
2474
Richard Hughesf556d372017-06-15 19:49:18 +01002475 /* no longer valid */
Richard Hughesf8039642019-01-16 12:22:22 +00002476 if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT) &&
2477 !fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) {
Richard Hughes08435162018-12-12 10:34:16 +00002478 GPtrArray *checksums = fu_device_get_checksums (device);
2479 g_ptr_array_set_size (checksums, 0);
2480 }
Richard Hughesf556d372017-06-15 19:49:18 +01002481
Richard Hughes019a1bc2019-11-26 10:19:33 +00002482 /* success */
Richard Hughesd0905142016-03-13 09:46:49 +00002483 return TRUE;
2484}
Richard Hughescff38bc2016-12-12 12:03:37 +00002485
Mario Limonciello1a680f32019-11-25 19:44:53 -06002486/**
2487 * fu_plugin_runner_clear_results:
2488 * @self: a #FuPlugin
2489 * @device: a #FuDevice
2490 * @error: A #GError or NULL
2491 *
2492 * Call into the plugin's clear results routine
2493 *
2494 * Returns: #TRUE for success, #FALSE for failure
2495 *
2496 * Since: 0.8.0
2497 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002498gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002499fu_plugin_runner_clear_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00002500{
Richard Hughes12724852018-09-04 13:53:44 +01002501 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00002502 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002503 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002504
Richard Hughes6a489a92020-12-22 10:32:06 +00002505 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
2506 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
2507 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2508
Richard Hughescff38bc2016-12-12 12:03:37 +00002509 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002510 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughescff38bc2016-12-12 12:03:37 +00002511 return TRUE;
2512
Richard Hughes639da472018-01-06 22:35:04 +00002513 /* no object loaded */
2514 if (priv->module == NULL)
2515 return TRUE;
2516
Richard Hughes65e44ca2018-01-30 17:26:30 +00002517 /* optional */
Richard Hughescd644902019-11-01 12:35:17 +00002518 g_module_symbol (priv->module, "fu_plugin_clear_results", (gpointer *) &func);
Richard Hughes65e44ca2018-01-30 17:26:30 +00002519 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00002520 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002521 g_debug ("clear_result(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002522 if (!func (self, device, &error_local)) {
2523 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05002524 g_critical ("unset plugin error in clear_result(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002525 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002526 g_set_error_literal (&error_local,
2527 FWUPD_ERROR,
2528 FWUPD_ERROR_INTERNAL,
2529 "unspecified error");
2530 }
2531 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2532 "failed to clear_result using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002533 fu_plugin_get_name (self));
Richard Hughescff38bc2016-12-12 12:03:37 +00002534 return FALSE;
2535 }
Richard Hughes65e44ca2018-01-30 17:26:30 +00002536 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00002537}
2538
Mario Limonciello1a680f32019-11-25 19:44:53 -06002539/**
2540 * fu_plugin_runner_get_results:
2541 * @self: a #FuPlugin
2542 * @device: a #FuDevice
2543 * @error: A #GError or NULL
2544 *
2545 * Call into the plugin's get results routine
2546 *
2547 * Returns: #TRUE for success, #FALSE for failure
2548 *
2549 * Since: 0.8.0
2550 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002551gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002552fu_plugin_runner_get_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00002553{
Richard Hughes12724852018-09-04 13:53:44 +01002554 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00002555 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002556 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002557
Richard Hughes6a489a92020-12-22 10:32:06 +00002558 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
2559 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
2560 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2561
Richard Hughescff38bc2016-12-12 12:03:37 +00002562 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002563 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughescff38bc2016-12-12 12:03:37 +00002564 return TRUE;
2565
Richard Hughes639da472018-01-06 22:35:04 +00002566 /* no object loaded */
2567 if (priv->module == NULL)
2568 return TRUE;
2569
Richard Hughes65e44ca2018-01-30 17:26:30 +00002570 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00002571 g_module_symbol (priv->module, "fu_plugin_get_results", (gpointer *) &func);
Richard Hughes65e44ca2018-01-30 17:26:30 +00002572 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00002573 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002574 g_debug ("get_results(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002575 if (!func (self, device, &error_local)) {
2576 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05002577 g_critical ("unset plugin error in get_results(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002578 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002579 g_set_error_literal (&error_local,
2580 FWUPD_ERROR,
2581 FWUPD_ERROR_INTERNAL,
2582 "unspecified error");
2583 }
2584 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2585 "failed to get_results using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002586 fu_plugin_get_name (self));
Richard Hughescff38bc2016-12-12 12:03:37 +00002587 return FALSE;
2588 }
Richard Hughescff38bc2016-12-12 12:03:37 +00002589 return TRUE;
2590}
2591
Richard Hughes08a37992017-09-12 12:57:43 +01002592/**
2593 * fu_plugin_get_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002594 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002595 *
2596 * Gets the plugin order, where higher numbers are run after lower
2597 * numbers.
2598 *
2599 * Returns: the integer value
Mario Limonciello1a680f32019-11-25 19:44:53 -06002600 *
2601 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002602 **/
2603guint
Richard Hughes12724852018-09-04 13:53:44 +01002604fu_plugin_get_order (FuPlugin *self)
Richard Hughes08a37992017-09-12 12:57:43 +01002605{
Richard Hughes12724852018-09-04 13:53:44 +01002606 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002607 return priv->order;
2608}
2609
2610/**
2611 * fu_plugin_set_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002612 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002613 * @order: a integer value
2614 *
2615 * Sets the plugin order, where higher numbers are run after lower
2616 * numbers.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002617 *
2618 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002619 **/
2620void
Richard Hughes12724852018-09-04 13:53:44 +01002621fu_plugin_set_order (FuPlugin *self, guint order)
Richard Hughes08a37992017-09-12 12:57:43 +01002622{
Richard Hughes12724852018-09-04 13:53:44 +01002623 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002624 priv->order = order;
2625}
2626
2627/**
Richard Hughes81c427c2018-08-06 15:20:17 +01002628 * fu_plugin_get_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002629 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01002630 *
2631 * Gets the plugin priority, where higher numbers are better.
2632 *
2633 * Returns: the integer value
Mario Limonciello1a680f32019-11-25 19:44:53 -06002634 *
2635 * Since: 1.1.1
Richard Hughes81c427c2018-08-06 15:20:17 +01002636 **/
2637guint
Richard Hughes12724852018-09-04 13:53:44 +01002638fu_plugin_get_priority (FuPlugin *self)
Richard Hughes81c427c2018-08-06 15:20:17 +01002639{
Richard Hughes12724852018-09-04 13:53:44 +01002640 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01002641 return priv->priority;
2642}
2643
2644/**
2645 * fu_plugin_set_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002646 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01002647 * @priority: a integer value
2648 *
2649 * Sets the plugin priority, where higher numbers are better.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002650 *
2651 * Since: 1.0.0
Richard Hughes81c427c2018-08-06 15:20:17 +01002652 **/
2653void
Richard Hughes12724852018-09-04 13:53:44 +01002654fu_plugin_set_priority (FuPlugin *self, guint priority)
Richard Hughes81c427c2018-08-06 15:20:17 +01002655{
Richard Hughes12724852018-09-04 13:53:44 +01002656 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01002657 priv->priority = priority;
2658}
2659
2660/**
Richard Hughes08a37992017-09-12 12:57:43 +01002661 * fu_plugin_add_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002662 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002663 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
Richard Hughes4eada342017-10-03 21:20:32 +01002664 * @name: a plugin name, e.g. `upower`
Richard Hughes08a37992017-09-12 12:57:43 +01002665 *
2666 * If the plugin name is found, the rule will be used to sort the plugin list,
2667 * for example the plugin specified by @name will be ordered after this plugin
2668 * when %FU_PLUGIN_RULE_RUN_AFTER is used.
2669 *
2670 * NOTE: The depsolver is iterative and may not solve overly-complicated rules;
2671 * If depsolving fails then fwupd will not start.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002672 *
2673 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002674 **/
2675void
Richard Hughes12724852018-09-04 13:53:44 +01002676fu_plugin_add_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes08a37992017-09-12 12:57:43 +01002677{
Richard Hughes12724852018-09-04 13:53:44 +01002678 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes11c59412020-06-22 15:29:48 +01002679 if (priv->rules[rule] == NULL)
2680 priv->rules[rule] = g_ptr_array_new_with_free_func (g_free);
Richard Hughes08a37992017-09-12 12:57:43 +01002681 g_ptr_array_add (priv->rules[rule], g_strdup (name));
Richard Hughes75b965d2018-11-15 13:51:21 +00002682 g_signal_emit (self, signals[SIGNAL_RULES_CHANGED], 0);
Richard Hughes08a37992017-09-12 12:57:43 +01002683}
2684
2685/**
2686 * fu_plugin_get_rules:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002687 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002688 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
2689 *
2690 * Gets the plugin IDs that should be run after this plugin.
2691 *
Richard Hughes11c59412020-06-22 15:29:48 +01002692 * Returns: (element-type utf8) (transfer none) (nullable): the list of plugin names, e.g. ['appstream']
Mario Limonciello1a680f32019-11-25 19:44:53 -06002693 *
2694 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002695 **/
2696GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +01002697fu_plugin_get_rules (FuPlugin *self, FuPluginRule rule)
Richard Hughes08a37992017-09-12 12:57:43 +01002698{
Richard Hughes12724852018-09-04 13:53:44 +01002699 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughesdad35972019-12-06 11:00:25 +00002700 g_return_val_if_fail (rule < FU_PLUGIN_RULE_LAST, NULL);
Richard Hughes08a37992017-09-12 12:57:43 +01002701 return priv->rules[rule];
2702}
2703
Richard Hughes80b79bb2018-01-11 21:11:06 +00002704/**
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002705 * fu_plugin_has_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002706 * @self: a #FuPlugin
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002707 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
2708 * @name: a plugin name, e.g. `upower`
2709 *
Richard Hughes87fb9ff2018-06-28 12:55:59 +01002710 * Gets the plugin IDs that should be run after this plugin.
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002711 *
2712 * Returns: %TRUE if the name exists for the specific rule
Mario Limonciello1a680f32019-11-25 19:44:53 -06002713 *
2714 * Since: 1.0.0
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002715 **/
2716gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002717fu_plugin_has_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002718{
Richard Hughes12724852018-09-04 13:53:44 +01002719 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes11c59412020-06-22 15:29:48 +01002720 if (priv->rules[rule] == NULL)
2721 return FALSE;
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002722 for (guint i = 0; i < priv->rules[rule]->len; i++) {
2723 const gchar *tmp = g_ptr_array_index (priv->rules[rule], i);
2724 if (g_strcmp0 (tmp, name) == 0)
2725 return TRUE;
2726 }
2727 return FALSE;
2728}
2729
2730/**
Richard Hughes80b79bb2018-01-11 21:11:06 +00002731 * fu_plugin_add_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002732 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00002733 * @key: a string, e.g. `FwupdateVersion`
2734 * @value: a string, e.g. `10`
2735 *
2736 * Sets any additional metadata to be included in the firmware report to aid
2737 * debugging problems.
2738 *
2739 * Any data included here will be sent to the metadata server after user
2740 * confirmation.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002741 *
2742 * Since: 1.0.4
Richard Hughes80b79bb2018-01-11 21:11:06 +00002743 **/
2744void
Richard Hughes12724852018-09-04 13:53:44 +01002745fu_plugin_add_report_metadata (FuPlugin *self, const gchar *key, const gchar *value)
Richard Hughes80b79bb2018-01-11 21:11:06 +00002746{
Richard Hughes12724852018-09-04 13:53:44 +01002747 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes1d900f72020-06-22 15:17:39 +01002748 if (priv->report_metadata == NULL) {
2749 priv->report_metadata = g_hash_table_new_full (g_str_hash,
2750 g_str_equal,
2751 g_free,
2752 g_free);
2753 }
Richard Hughes80b79bb2018-01-11 21:11:06 +00002754 g_hash_table_insert (priv->report_metadata, g_strdup (key), g_strdup (value));
2755}
2756
2757/**
2758 * fu_plugin_get_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002759 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00002760 *
2761 * Returns the list of additional metadata to be added when filing a report.
2762 *
Richard Hughes1d900f72020-06-22 15:17:39 +01002763 * Returns: (transfer none) (nullable): the map of report metadata
Mario Limonciello1a680f32019-11-25 19:44:53 -06002764 *
2765 * Since: 1.0.4
Richard Hughes80b79bb2018-01-11 21:11:06 +00002766 **/
2767GHashTable *
Richard Hughes12724852018-09-04 13:53:44 +01002768fu_plugin_get_report_metadata (FuPlugin *self)
Richard Hughes80b79bb2018-01-11 21:11:06 +00002769{
Richard Hughes12724852018-09-04 13:53:44 +01002770 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002771 return priv->report_metadata;
2772}
2773
Mario Limonciello963dc422018-02-27 14:26:58 -06002774/**
2775 * fu_plugin_get_config_value:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002776 * @self: a #FuPlugin
Mario Limonciello963dc422018-02-27 14:26:58 -06002777 * @key: A settings key
2778 *
2779 * Return the value of a key if it's been configured
2780 *
2781 * Since: 1.0.6
2782 **/
2783gchar *
Richard Hughes12724852018-09-04 13:53:44 +01002784fu_plugin_get_config_value (FuPlugin *self, const gchar *key)
Mario Limonciello963dc422018-02-27 14:26:58 -06002785{
Richard Hughes4be17d12018-05-30 20:36:29 +01002786 g_autofree gchar *conf_dir = NULL;
Mario Limonciello963dc422018-02-27 14:26:58 -06002787 g_autofree gchar *conf_file = NULL;
2788 g_autofree gchar *conf_path = NULL;
2789 g_autoptr(GKeyFile) keyfile = NULL;
2790 const gchar *plugin_name;
2791
Richard Hughes4be17d12018-05-30 20:36:29 +01002792 conf_dir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR_PKG);
Richard Hughes12724852018-09-04 13:53:44 +01002793 plugin_name = fu_plugin_get_name (self);
Mario Limonciello963dc422018-02-27 14:26:58 -06002794 conf_file = g_strdup_printf ("%s.conf", plugin_name);
Richard Hughes4be17d12018-05-30 20:36:29 +01002795 conf_path = g_build_filename (conf_dir, conf_file, NULL);
Mario Limonciello963dc422018-02-27 14:26:58 -06002796 if (!g_file_test (conf_path, G_FILE_TEST_IS_REGULAR))
2797 return NULL;
2798 keyfile = g_key_file_new ();
2799 if (!g_key_file_load_from_file (keyfile, conf_path,
2800 G_KEY_FILE_NONE, NULL))
2801 return NULL;
2802 return g_key_file_get_string (keyfile, plugin_name, key, NULL);
2803}
2804
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002805/**
Richard Hughes334ba792020-02-19 20:44:56 +00002806 * fu_plugin_get_config_value_boolean:
2807 * @self: a #FuPlugin
2808 * @key: A settings key
2809 *
2810 * Return the boolean value of a key if it's been configured
2811 *
2812 * Returns: %TRUE if the value is `true` (case insensitive), %FALSE otherwise
2813 *
Mario Limonciello96117d12020-02-28 10:17:56 -06002814 * Since: 1.4.0
Richard Hughes334ba792020-02-19 20:44:56 +00002815 **/
2816gboolean
2817fu_plugin_get_config_value_boolean (FuPlugin *self, const gchar *key)
2818{
2819 g_autofree gchar *tmp = fu_plugin_get_config_value (self, key);
2820 if (tmp == NULL)
2821 return FALSE;
Richard Hughes5337a432020-02-21 12:04:32 +00002822 return g_ascii_strcasecmp (tmp, "true") == 0;
Richard Hughes334ba792020-02-19 20:44:56 +00002823}
2824
2825/**
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002826 * fu_plugin_name_compare:
2827 * @plugin1: first #FuPlugin to compare.
2828 * @plugin2: second #FuPlugin to compare.
2829 *
2830 * Compares two plugins by their names.
2831 *
2832 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002833 *
2834 * Since: 1.0.8
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002835 **/
2836gint
2837fu_plugin_name_compare (FuPlugin *plugin1, FuPlugin *plugin2)
2838{
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002839 return g_strcmp0 (fu_plugin_get_name (plugin1), fu_plugin_get_name (plugin2));
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002840}
2841
2842/**
2843 * fu_plugin_order_compare:
2844 * @plugin1: first #FuPlugin to compare.
2845 * @plugin2: second #FuPlugin to compare.
2846 *
2847 * Compares two plugins by their depsolved order.
2848 *
2849 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002850 *
2851 * Since: 1.0.8
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002852 **/
2853gint
2854fu_plugin_order_compare (FuPlugin *plugin1, FuPlugin *plugin2)
2855{
2856 FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1);
2857 FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2);
2858 if (priv1->order < priv2->order)
2859 return -1;
2860 if (priv1->order > priv2->order)
2861 return 1;
2862 return 0;
2863}
2864
Richard Hughescff38bc2016-12-12 12:03:37 +00002865static void
2866fu_plugin_class_init (FuPluginClass *klass)
2867{
2868 GObjectClass *object_class = G_OBJECT_CLASS (klass);
2869 object_class->finalize = fu_plugin_finalize;
2870 signals[SIGNAL_DEVICE_ADDED] =
2871 g_signal_new ("device-added",
2872 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2873 G_STRUCT_OFFSET (FuPluginClass, device_added),
2874 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2875 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
2876 signals[SIGNAL_DEVICE_REMOVED] =
2877 g_signal_new ("device-removed",
2878 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2879 G_STRUCT_OFFSET (FuPluginClass, device_removed),
2880 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2881 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughese1fd34d2017-08-24 14:19:51 +01002882 signals[SIGNAL_DEVICE_REGISTER] =
2883 g_signal_new ("device-register",
2884 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2885 G_STRUCT_OFFSET (FuPluginClass, device_register),
2886 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2887 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughes362d6d72017-01-07 21:42:14 +00002888 signals[SIGNAL_RECOLDPLUG] =
2889 g_signal_new ("recoldplug",
2890 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2891 G_STRUCT_OFFSET (FuPluginClass, recoldplug),
2892 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2893 G_TYPE_NONE, 0);
Richard Hughes399859e2020-05-11 19:44:03 +01002894 signals[SIGNAL_SECURITY_CHANGED] =
2895 g_signal_new ("security-changed",
2896 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2897 G_STRUCT_OFFSET (FuPluginClass, security_changed),
2898 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2899 G_TYPE_NONE, 0);
Richard Hughesb0829032017-01-10 09:27:08 +00002900 signals[SIGNAL_SET_COLDPLUG_DELAY] =
2901 g_signal_new ("set-coldplug-delay",
2902 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2903 G_STRUCT_OFFSET (FuPluginClass, set_coldplug_delay),
2904 NULL, NULL, g_cclosure_marshal_VOID__UINT,
2905 G_TYPE_NONE, 1, G_TYPE_UINT);
Richard Hughesaabdc372018-11-14 10:11:08 +00002906 signals[SIGNAL_CHECK_SUPPORTED] =
2907 g_signal_new ("check-supported",
2908 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2909 G_STRUCT_OFFSET (FuPluginClass, check_supported),
2910 NULL, NULL, g_cclosure_marshal_generic,
2911 G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
Richard Hughes75b965d2018-11-15 13:51:21 +00002912 signals[SIGNAL_RULES_CHANGED] =
2913 g_signal_new ("rules-changed",
2914 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2915 G_STRUCT_OFFSET (FuPluginClass, rules_changed),
2916 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2917 G_TYPE_NONE, 0);
Richard Hughes95c98a92019-10-22 16:03:15 +01002918 signals[SIGNAL_ADD_FIRMWARE_GTYPE] =
2919 g_signal_new ("add-firmware-gtype",
2920 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2921 G_STRUCT_OFFSET (FuPluginClass, add_firmware_gtype),
2922 NULL, NULL, g_cclosure_marshal_generic,
2923 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_GTYPE);
Richard Hughescff38bc2016-12-12 12:03:37 +00002924}
2925
2926static void
Richard Hughes12724852018-09-04 13:53:44 +01002927fu_plugin_init (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +00002928{
Richard Hughes12724852018-09-04 13:53:44 +01002929 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesfaf2afe2021-01-13 14:00:20 +00002930 g_rw_lock_init (&priv->cache_mutex);
Richard Hughescff38bc2016-12-12 12:03:37 +00002931}
2932
2933static void
2934fu_plugin_finalize (GObject *object)
2935{
Richard Hughes12724852018-09-04 13:53:44 +01002936 FuPlugin *self = FU_PLUGIN (object);
2937 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002938 FuPluginInitFunc func = NULL;
2939
Richard Hughesfaf2afe2021-01-13 14:00:20 +00002940 g_rw_lock_clear (&priv->cache_mutex);
Richard Hughesaae22e42020-06-22 21:32:59 +01002941
Richard Hughescff38bc2016-12-12 12:03:37 +00002942 /* optional */
2943 if (priv->module != NULL) {
2944 g_module_symbol (priv->module, "fu_plugin_destroy", (gpointer *) &func);
2945 if (func != NULL) {
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002946 g_debug ("destroy(%s)", fu_plugin_get_name (self));
Richard Hughes12724852018-09-04 13:53:44 +01002947 func (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002948 }
2949 }
2950
Richard Hughes11c59412020-06-22 15:29:48 +01002951 for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++) {
2952 if (priv->rules[i] != NULL)
2953 g_ptr_array_unref (priv->rules[i]);
2954 }
Richard Hughes68ab1e42021-01-13 14:01:17 +00002955 if (priv->devices != NULL)
2956 g_ptr_array_unref (priv->devices);
Richard Hughescff38bc2016-12-12 12:03:37 +00002957 if (priv->usb_ctx != NULL)
2958 g_object_unref (priv->usb_ctx);
Richard Hughesb8f8db22017-04-25 15:56:00 +01002959 if (priv->hwids != NULL)
Richard Hughesd7704d42017-08-08 20:29:09 +01002960 g_object_unref (priv->hwids);
Richard Hughes9c028f02017-10-28 21:14:28 +01002961 if (priv->quirks != NULL)
2962 g_object_unref (priv->quirks);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01002963 if (priv->udev_subsystems != NULL)
2964 g_ptr_array_unref (priv->udev_subsystems);
Richard Hughes49e5e052017-09-03 12:15:41 +01002965 if (priv->smbios != NULL)
2966 g_object_unref (priv->smbios);
Richard Hughes275d3b42018-04-20 16:40:37 +01002967 if (priv->runtime_versions != NULL)
2968 g_hash_table_unref (priv->runtime_versions);
Richard Hughes34e0dab2018-04-20 16:43:00 +01002969 if (priv->compile_versions != NULL)
2970 g_hash_table_unref (priv->compile_versions);
Richard Hughes1d900f72020-06-22 15:17:39 +01002971 if (priv->report_metadata != NULL)
2972 g_hash_table_unref (priv->report_metadata);
Richard Hughesfaf2afe2021-01-13 14:00:20 +00002973 if (priv->cache != NULL)
2974 g_hash_table_unref (priv->cache);
Richard Hughes84999302019-05-02 10:18:32 +01002975 g_free (priv->build_hash);
Richard Hughescff38bc2016-12-12 12:03:37 +00002976 g_free (priv->data);
Mario Limonciello3f9a1c12018-06-06 14:06:40 -05002977 /* Must happen as the last step to avoid prematurely
2978 * freeing memory held by the plugin */
Richard Hughes862ec5c2020-05-22 14:38:02 +01002979#ifdef RUNNING_ON_VALGRIND
2980 if (priv->module != NULL && RUNNING_ON_VALGRIND == 0)
2981#else
Mario Limonciello3f9a1c12018-06-06 14:06:40 -05002982 if (priv->module != NULL)
Mario Limonciello3f9a1c12018-06-06 14:06:40 -05002983#endif
Richard Hughes862ec5c2020-05-22 14:38:02 +01002984 g_module_close (priv->module);
Richard Hughescff38bc2016-12-12 12:03:37 +00002985
2986 G_OBJECT_CLASS (fu_plugin_parent_class)->finalize (object);
2987}
2988
Mario Limonciello1a680f32019-11-25 19:44:53 -06002989/**
2990 * fu_plugin_new:
2991 *
2992 * Creates a new #FuPlugin
2993 *
2994 * Since: 0.8.0
2995 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002996FuPlugin *
2997fu_plugin_new (void)
2998{
Richard Hughes12724852018-09-04 13:53:44 +01002999 return FU_PLUGIN (g_object_new (FU_TYPE_PLUGIN, NULL));
Richard Hughescff38bc2016-12-12 12:03:37 +00003000}