blob: 039460bffda1835f9ccec988cf980503ae5e86bd [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;
Richard Hughes08a37992017-09-12 12:57:43 +010039 guint order;
Richard Hughes81c427c2018-08-06 15:20:17 +010040 guint priority;
Richard Hughes08a37992017-09-12 12:57:43 +010041 GPtrArray *rules[FU_PLUGIN_RULE_LAST];
Richard Hughes68ab1e42021-01-13 14:01:17 +000042 GPtrArray *devices; /* (nullable) (element-type FuDevice) */
Richard Hughesf425d292019-01-18 17:57:39 +000043 gchar *build_hash;
Richard Hughesd7704d42017-08-08 20:29:09 +010044 FuHwids *hwids;
Richard Hughes9c028f02017-10-28 21:14:28 +010045 FuQuirks *quirks;
Richard Hughes0eb123b2018-04-19 12:00:04 +010046 GHashTable *runtime_versions;
Richard Hughes34e0dab2018-04-20 16:43:00 +010047 GHashTable *compile_versions;
Richard Hughes9d6e0e72018-08-24 20:20:17 +010048 GPtrArray *udev_subsystems;
Richard Hughes1354ea92017-09-19 15:58:31 +010049 FuSmbios *smbios;
Richard Hughes989acf12019-10-05 20:16:47 +010050 GType device_gtype;
Richard Hughesfaf2afe2021-01-13 14:00:20 +000051 GHashTable *cache; /* (nullable): platform_id:GObject */
52 GRWLock cache_mutex;
Richard Hughes1d900f72020-06-22 15:17:39 +010053 GHashTable *report_metadata; /* (nullable): key:value */
Richard Hughescff38bc2016-12-12 12:03:37 +000054 FuPluginData *data;
55} FuPluginPrivate;
56
57enum {
58 SIGNAL_DEVICE_ADDED,
59 SIGNAL_DEVICE_REMOVED,
Richard Hughese1fd34d2017-08-24 14:19:51 +010060 SIGNAL_DEVICE_REGISTER,
Richard Hughes75b965d2018-11-15 13:51:21 +000061 SIGNAL_RULES_CHANGED,
Richard Hughes362d6d72017-01-07 21:42:14 +000062 SIGNAL_RECOLDPLUG,
Richard Hughesb0829032017-01-10 09:27:08 +000063 SIGNAL_SET_COLDPLUG_DELAY,
Richard Hughesaabdc372018-11-14 10:11:08 +000064 SIGNAL_CHECK_SUPPORTED,
Richard Hughes95c98a92019-10-22 16:03:15 +010065 SIGNAL_ADD_FIRMWARE_GTYPE,
Richard Hughes399859e2020-05-11 19:44:03 +010066 SIGNAL_SECURITY_CHANGED,
Richard Hughescff38bc2016-12-12 12:03:37 +000067 SIGNAL_LAST
68};
69
70static guint signals[SIGNAL_LAST] = { 0 };
71
Richard Hughes7bcb8d42020-10-08 15:47:47 +010072G_DEFINE_TYPE_WITH_PRIVATE (FuPlugin, fu_plugin, FWUPD_TYPE_PLUGIN)
Richard Hughescff38bc2016-12-12 12:03:37 +000073#define GET_PRIVATE(o) (fu_plugin_get_instance_private (o))
74
75typedef const gchar *(*FuPluginGetNameFunc) (void);
Richard Hughes12724852018-09-04 13:53:44 +010076typedef void (*FuPluginInitFunc) (FuPlugin *self);
77typedef gboolean (*FuPluginStartupFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000078 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010079typedef void (*FuPluginDeviceRegisterFunc) (FuPlugin *self,
Richard Hughese1fd34d2017-08-24 14:19:51 +010080 FuDevice *device);
Richard Hughes12724852018-09-04 13:53:44 +010081typedef gboolean (*FuPluginDeviceFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000082 FuDevice *device,
83 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010084typedef gboolean (*FuPluginFlaggedDeviceFunc) (FuPlugin *self,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -050085 FwupdInstallFlags flags,
86 FuDevice *device,
87 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010088typedef gboolean (*FuPluginDeviceArrayFunc) (FuPlugin *self,
Richard Hughesdbd8c762018-06-15 20:31:40 +010089 GPtrArray *devices,
90 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010091typedef gboolean (*FuPluginVerifyFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000092 FuDevice *device,
93 FuPluginVerifyFlags flags,
94 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010095typedef gboolean (*FuPluginUpdateFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000096 FuDevice *device,
97 GBytes *blob_fw,
98 FwupdInstallFlags flags,
99 GError **error);
Richard Hughesf58ac732020-05-12 15:23:44 +0100100typedef void (*FuPluginSecurityAttrsFunc) (FuPlugin *self,
101 FuSecurityAttrs *attrs);
Richard Hughescff38bc2016-12-12 12:03:37 +0000102
Richard Hughes57d18222017-01-10 16:02:59 +0000103/**
Mario Limonciello52e75ba2019-11-22 13:21:19 -0600104 * fu_plugin_is_open:
105 * @self: A #FuPlugin
106 *
107 * Determines if the plugin is opened
108 *
109 * Returns: TRUE for opened, FALSE for not
110 *
111 * Since: 1.3.5
112 **/
113gboolean
114fu_plugin_is_open (FuPlugin *self)
115{
116 FuPluginPrivate *priv = GET_PRIVATE (self);
117 return priv->module != NULL;
118}
119
120/**
Richard Hughes57d18222017-01-10 16:02:59 +0000121 * fu_plugin_get_name:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100122 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000123 *
124 * Gets the plugin name.
125 *
126 * Returns: a plugin name, or %NULL for unknown.
127 *
128 * Since: 0.8.0
129 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000130const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100131fu_plugin_get_name (FuPlugin *self)
Richard Hughesd0905142016-03-13 09:46:49 +0000132{
Richard Hughes12724852018-09-04 13:53:44 +0100133 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100134 return fwupd_plugin_get_name (FWUPD_PLUGIN (self));
Richard Hughescff38bc2016-12-12 12:03:37 +0000135}
Richard Hughesd0905142016-03-13 09:46:49 +0000136
Mario Limonciello1a680f32019-11-25 19:44:53 -0600137/**
138 * fu_plugin_set_name:
139 * @self: A #FuPlugin
140 * @name: A string
141 *
142 * Sets the plugin name.
143 *
144 * Since: 0.8.0
145 **/
Richard Hughes34834102017-11-21 21:55:00 +0000146void
Richard Hughes12724852018-09-04 13:53:44 +0100147fu_plugin_set_name (FuPlugin *self, const gchar *name)
Richard Hughes34834102017-11-21 21:55:00 +0000148{
Richard Hughes12724852018-09-04 13:53:44 +0100149 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100150 fwupd_plugin_set_name (FWUPD_PLUGIN (self), name);
Richard Hughes34834102017-11-21 21:55:00 +0000151}
152
Richard Hughes57d18222017-01-10 16:02:59 +0000153/**
Richard Hughesf425d292019-01-18 17:57:39 +0000154 * fu_plugin_set_build_hash:
155 * @self: A #FuPlugin
156 * @build_hash: A checksum
157 *
158 * Sets the plugin build hash, typically a SHA256 checksum. All plugins must
159 * set the correct checksum to avoid the daemon being marked as tainted.
160 *
161 * Since: 1.2.4
162 **/
163void
164fu_plugin_set_build_hash (FuPlugin *self, const gchar *build_hash)
165{
166 FuPluginPrivate *priv = GET_PRIVATE (self);
167 g_return_if_fail (FU_IS_PLUGIN (self));
168 g_return_if_fail (build_hash != NULL);
Richard Hughes382524d2021-01-28 13:14:35 +0000169
170 /* not changed */
171 if (g_strcmp0 (priv->build_hash, build_hash) == 0)
172 return;
173
Richard Hughesf425d292019-01-18 17:57:39 +0000174 g_free (priv->build_hash);
175 priv->build_hash = g_strdup (build_hash);
176}
177
Mario Limonciello1a680f32019-11-25 19:44:53 -0600178/**
179 * fu_plugin_get_build_hash:
180 * @self: A #FuPlugin
181 *
182 * Gets the build hash a plugin was generated with.
183 *
184 * Returns: (transfer none): a #gchar, or %NULL for unset.
185 *
186 * Since: 1.2.4
187 **/
Richard Hughesf425d292019-01-18 17:57:39 +0000188const gchar *
189fu_plugin_get_build_hash (FuPlugin *self)
190{
191 FuPluginPrivate *priv = GET_PRIVATE (self);
192 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
193 return priv->build_hash;
194}
195
196/**
Richard Hughes57d18222017-01-10 16:02:59 +0000197 * fu_plugin_cache_lookup:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100198 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000199 * @id: the key
200 *
201 * Finds an object in the per-plugin cache.
202 *
203 * Returns: (transfer none): a #GObject, or %NULL for unfound.
204 *
205 * Since: 0.8.0
206 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000207gpointer
Richard Hughes12724852018-09-04 13:53:44 +0100208fu_plugin_cache_lookup (FuPlugin *self, const gchar *id)
Richard Hughescff38bc2016-12-12 12:03:37 +0000209{
Richard Hughes12724852018-09-04 13:53:44 +0100210 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesfaf2afe2021-01-13 14:00:20 +0000211 g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&priv->cache_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100212 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughesccd78a92017-01-11 16:57:41 +0000213 g_return_val_if_fail (id != NULL, NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100214 g_return_val_if_fail (locker != NULL, NULL);
Richard Hughesfaf2afe2021-01-13 14:00:20 +0000215 if (priv->cache == NULL)
Richard Hughes371f6b22020-06-22 15:21:17 +0100216 return NULL;
Richard Hughesfaf2afe2021-01-13 14:00:20 +0000217 return g_hash_table_lookup (priv->cache, id);
Richard Hughescff38bc2016-12-12 12:03:37 +0000218}
Richard Hughesd0905142016-03-13 09:46:49 +0000219
Richard Hughes57d18222017-01-10 16:02:59 +0000220/**
221 * fu_plugin_cache_add:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100222 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000223 * @id: the key
224 * @dev: a #GObject, typically a #FuDevice
225 *
226 * Adds an object to the per-plugin cache.
227 *
228 * Since: 0.8.0
229 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000230void
Richard Hughes12724852018-09-04 13:53:44 +0100231fu_plugin_cache_add (FuPlugin *self, const gchar *id, gpointer dev)
Richard Hughescff38bc2016-12-12 12:03:37 +0000232{
Richard Hughes12724852018-09-04 13:53:44 +0100233 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesfaf2afe2021-01-13 14:00:20 +0000234 g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&priv->cache_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100235 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000236 g_return_if_fail (id != NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100237 g_return_if_fail (locker != NULL);
Richard Hughesfaf2afe2021-01-13 14:00:20 +0000238 if (priv->cache == NULL) {
239 priv->cache = g_hash_table_new_full (g_str_hash,
240 g_str_equal,
241 g_free,
242 (GDestroyNotify) g_object_unref);
Richard Hughes371f6b22020-06-22 15:21:17 +0100243 }
Richard Hughesfaf2afe2021-01-13 14:00:20 +0000244 g_hash_table_insert (priv->cache, g_strdup (id), g_object_ref (dev));
Richard Hughescff38bc2016-12-12 12:03:37 +0000245}
246
Richard Hughes57d18222017-01-10 16:02:59 +0000247/**
248 * fu_plugin_cache_remove:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100249 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000250 * @id: the key
251 *
252 * Removes an object from the per-plugin cache.
253 *
254 * Since: 0.8.0
255 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000256void
Richard Hughes12724852018-09-04 13:53:44 +0100257fu_plugin_cache_remove (FuPlugin *self, const gchar *id)
Richard Hughescff38bc2016-12-12 12:03:37 +0000258{
Richard Hughes12724852018-09-04 13:53:44 +0100259 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesfaf2afe2021-01-13 14:00:20 +0000260 g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&priv->cache_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100261 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000262 g_return_if_fail (id != NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100263 g_return_if_fail (locker != NULL);
Richard Hughesfaf2afe2021-01-13 14:00:20 +0000264 if (priv->cache == NULL)
Richard Hughes371f6b22020-06-22 15:21:17 +0100265 return;
Richard Hughesfaf2afe2021-01-13 14:00:20 +0000266 g_hash_table_remove (priv->cache, id);
Richard Hughescff38bc2016-12-12 12:03:37 +0000267}
268
Richard Hughes57d18222017-01-10 16:02:59 +0000269/**
270 * fu_plugin_get_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100271 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000272 *
Richard Hughes4eada342017-10-03 21:20:32 +0100273 * Gets the per-plugin allocated private data. This will return %NULL unless
274 * fu_plugin_alloc_data() has been called by the plugin.
Richard Hughes57d18222017-01-10 16:02:59 +0000275 *
Richard Hughes4eada342017-10-03 21:20:32 +0100276 * Returns: (transfer none): a pointer to a structure, or %NULL for unset.
Richard Hughes57d18222017-01-10 16:02:59 +0000277 *
278 * Since: 0.8.0
279 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000280FuPluginData *
Richard Hughes12724852018-09-04 13:53:44 +0100281fu_plugin_get_data (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +0000282{
Richard Hughes12724852018-09-04 13:53:44 +0100283 FuPluginPrivate *priv = GET_PRIVATE (self);
284 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000285 return priv->data;
286}
287
Richard Hughes57d18222017-01-10 16:02:59 +0000288/**
Richard Hughes00f66f62019-11-27 11:42:53 +0000289 * fu_plugin_alloc_data: (skip):
Richard Hughes2c0635a2018-09-04 14:52:46 +0100290 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000291 * @data_sz: the size to allocate
292 *
293 * Allocates the per-plugin allocated private data.
294 *
295 * Returns: (transfer full): a pointer to a structure, or %NULL for unset.
296 *
297 * Since: 0.8.0
298 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000299FuPluginData *
Richard Hughes12724852018-09-04 13:53:44 +0100300fu_plugin_alloc_data (FuPlugin *self, gsize data_sz)
Richard Hughescff38bc2016-12-12 12:03:37 +0000301{
Richard Hughes12724852018-09-04 13:53:44 +0100302 FuPluginPrivate *priv = GET_PRIVATE (self);
303 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes44dee882017-01-11 08:31:10 +0000304 if (priv->data != NULL) {
305 g_critical ("fu_plugin_alloc_data() already used by plugin");
306 return priv->data;
307 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000308 priv->data = g_malloc0 (data_sz);
309 return priv->data;
Richard Hughesd0905142016-03-13 09:46:49 +0000310}
311
Richard Hughes57d18222017-01-10 16:02:59 +0000312/**
313 * fu_plugin_get_usb_context:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100314 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000315 *
Richard Hughes9e9b73f2021-02-09 13:37:41 +0000316 * This used to get the shared USB context that all plugins can use; it now
317 * returns %NULL;
Richard Hughes57d18222017-01-10 16:02:59 +0000318 *
319 * Returns: (transfer none): a #GUsbContext.
320 *
321 * Since: 0.8.0
322 **/
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000323GUsbContext *
Richard Hughes12724852018-09-04 13:53:44 +0100324fu_plugin_get_usb_context (FuPlugin *self)
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000325{
Richard Hughes12724852018-09-04 13:53:44 +0100326 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes9e9b73f2021-02-09 13:37:41 +0000327 return NULL;
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000328}
329
Mario Limonciello1a680f32019-11-25 19:44:53 -0600330/**
331 * fu_plugin_set_usb_context:
332 * @self: A #FuPlugin
333 * @usb_ctx: A #FGUsbContext
334 *
Richard Hughes9e9b73f2021-02-09 13:37:41 +0000335 * This used to set the shared USB context for a plugin. It now does nothing.
Mario Limonciello1a680f32019-11-25 19:44:53 -0600336 *
337 * Since: 0.8.0
338 **/
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000339void
Richard Hughes12724852018-09-04 13:53:44 +0100340fu_plugin_set_usb_context (FuPlugin *self, GUsbContext *usb_ctx)
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000341{
Richard Hughescff38bc2016-12-12 12:03:37 +0000342}
343
Richard Hughes57d18222017-01-10 16:02:59 +0000344/**
345 * fu_plugin_get_enabled:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100346 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000347 *
Richard Hughes4eada342017-10-03 21:20:32 +0100348 * Returns if the plugin is enabled. Plugins may self-disable using
349 * fu_plugin_set_enabled() or can be disabled by the daemon.
Richard Hughes57d18222017-01-10 16:02:59 +0000350 *
351 * Returns: %TRUE if the plugin is currently enabled.
352 *
353 * Since: 0.8.0
354 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000355gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100356fu_plugin_get_enabled (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +0000357{
Richard Hughes12724852018-09-04 13:53:44 +0100358 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100359 return !fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED);
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000360}
361
Richard Hughes57d18222017-01-10 16:02:59 +0000362/**
363 * fu_plugin_set_enabled:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100364 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000365 * @enabled: the enabled value
366 *
367 * Enables or disables a plugin. Plugins can self-disable at any point.
368 *
369 * Since: 0.8.0
370 **/
Richard Hughesd0905142016-03-13 09:46:49 +0000371void
Richard Hughes12724852018-09-04 13:53:44 +0100372fu_plugin_set_enabled (FuPlugin *self, gboolean enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000373{
Richard Hughes12724852018-09-04 13:53:44 +0100374 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100375 if (enabled) {
376 fwupd_plugin_remove_flag (FWUPD_PLUGIN (self),
377 FWUPD_PLUGIN_FLAG_DISABLED);
378 } else {
379 fu_plugin_add_flag (self, FWUPD_PLUGIN_FLAG_DISABLED);
380 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000381}
382
Mario Limonciello1a680f32019-11-25 19:44:53 -0600383/**
384 * fu_plugin_guess_name_from_fn:
385 * @filename: filename to guess
386 *
387 * Tries to guess the name of the plugin from a filename
388 *
389 * Returns: (transfer full): the guessed name of the plugin
390 *
391 * Since: 1.0.8
392 **/
Richard Hughes1e456bc2018-05-10 20:16:16 +0100393gchar *
394fu_plugin_guess_name_from_fn (const gchar *filename)
395{
396 const gchar *prefix = "libfu_plugin_";
397 gchar *name;
398 gchar *str = g_strstr_len (filename, -1, prefix);
399 if (str == NULL)
400 return NULL;
401 name = g_strdup (str + strlen (prefix));
402 g_strdelimit (name, ".", '\0');
403 return name;
404}
405
Mario Limonciello1a680f32019-11-25 19:44:53 -0600406/**
407 * fu_plugin_open:
408 * @self: A #FuPlugin
409 * @filename: The shared object filename to open
410 * @error: A #GError or NULL
411 *
412 * Opens the plugin module
413 *
414 * Returns: TRUE for success, FALSE for fail
415 *
416 * Since: 0.8.0
417 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000418gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100419fu_plugin_open (FuPlugin *self, const gchar *filename, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +0000420{
Richard Hughes12724852018-09-04 13:53:44 +0100421 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +0000422 FuPluginInitFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000423
Richard Hughes6a489a92020-12-22 10:32:06 +0000424 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
425 g_return_val_if_fail (filename != NULL, FALSE);
426 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
427
Richard Hughescff38bc2016-12-12 12:03:37 +0000428 priv->module = g_module_open (filename, 0);
429 if (priv->module == NULL) {
430 g_set_error (error,
431 G_IO_ERROR,
432 G_IO_ERROR_FAILED,
Mario Limonciellof5605532019-11-04 07:49:50 -0600433 "failed to open plugin %s: %s",
434 filename, g_module_error ());
Mario Limoncielloc3a81732020-10-20 09:16:18 -0500435 fu_plugin_add_flag (self, FWUPD_PLUGIN_FLAG_FAILED_OPEN);
436 fu_plugin_add_flag (self, FWUPD_PLUGIN_FLAG_USER_WARNING);
Richard Hughescff38bc2016-12-12 12:03:37 +0000437 return FALSE;
438 }
439
440 /* set automatically */
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100441 if (fu_plugin_get_name (self) == NULL) {
442 g_autofree gchar *str = fu_plugin_guess_name_from_fn (filename);
443 fu_plugin_set_name (self, str);
444 }
Richard Hughesd0905142016-03-13 09:46:49 +0000445
446 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000447 g_module_symbol (priv->module, "fu_plugin_init", (gpointer *) &func);
448 if (func != NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -0500449 g_debug ("init(%s)", filename);
Richard Hughes12724852018-09-04 13:53:44 +0100450 func (self);
Richard Hughesd0905142016-03-13 09:46:49 +0000451 }
452
Richard Hughescff38bc2016-12-12 12:03:37 +0000453 return TRUE;
454}
455
Richard Hughes203ed842020-11-02 14:25:13 +0000456/* order of usefulness to the user */
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100457static const gchar *
458fu_plugin_build_device_update_error (FuPlugin *self)
459{
460 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_NO_HARDWARE))
461 return "Not updatable as required hardware was not found";
462 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_LEGACY_BIOS))
463 return "Not updatable in legacy BIOS mode";
464 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED))
Mario Limonciello797da4f2021-01-12 12:38:51 -0600465 return "Not updatable as UEFI capsule updates not enabled in firmware setup";
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100466 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_UNLOCK_REQUIRED))
467 return "Not updatable as requires unlock";
468 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_EFIVAR_NOT_MOUNTED))
469 return "Not updatable as efivarfs was not found";
470 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND))
471 return "Not updatable as UEFI ESP partition not detected";
472 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
473 return "Not updatable as plugin was disabled";
474 return NULL;
475}
476
Richard Hughes68ab1e42021-01-13 14:01:17 +0000477static void
478fu_plugin_ensure_devices (FuPlugin *self)
479{
480 FuPluginPrivate *priv = GET_PRIVATE (self);
481 if (priv->devices != NULL)
482 return;
483 priv->devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
484}
485
Richard Hughes57d18222017-01-10 16:02:59 +0000486/**
487 * fu_plugin_device_add:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100488 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000489 * @device: A #FuDevice
490 *
491 * Asks the daemon to add a device to the exported list. If this device ID
492 * has already been added by a different plugin then this request will be
493 * ignored.
494 *
495 * Plugins should use fu_plugin_device_add_delay() if they are not capable of
496 * actually flashing an image to the hardware so that higher-priority plugins
497 * can add the device themselves.
498 *
499 * Since: 0.8.0
500 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000501void
Richard Hughes12724852018-09-04 13:53:44 +0100502fu_plugin_device_add (FuPlugin *self, FuDevice *device)
Richard Hughescff38bc2016-12-12 12:03:37 +0000503{
Richard Hughes68ab1e42021-01-13 14:01:17 +0000504 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes5e447292018-04-27 14:25:54 +0100505 GPtrArray *children;
Richard Hughesc125ec02018-09-05 19:35:17 +0100506 g_autoptr(GError) error = NULL;
Richard Hughes5e447292018-04-27 14:25:54 +0100507
Richard Hughes12724852018-09-04 13:53:44 +0100508 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000509 g_return_if_fail (FU_IS_DEVICE (device));
510
Richard Hughesc125ec02018-09-05 19:35:17 +0100511 /* ensure the device ID is set from the physical and logical IDs */
512 if (!fu_device_ensure_id (device, &error)) {
513 g_warning ("ignoring add: %s", error->message);
514 return;
515 }
516
Richard Hughes68ab1e42021-01-13 14:01:17 +0000517 /* add to array */
518 fu_plugin_ensure_devices (self);
519 g_ptr_array_add (priv->devices, g_object_ref (device));
520
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100521 /* proxy to device where required */
522 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE)) {
523 g_debug ("plugin %s has _CLEAR_UPDATABLE, so removing from %s",
524 fu_plugin_get_name (self),
525 fu_device_get_id (device));
526 fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE);
527 }
528 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_USER_WARNING) &&
529 fu_device_get_update_error (device) == NULL) {
530 const gchar *tmp = fu_plugin_build_device_update_error (self);
531 g_debug ("setting %s update error to '%s' from %s",
532 fu_device_get_id (device), tmp, fu_plugin_get_name (self));
533 fu_device_set_update_error (device, tmp);
534 }
535
Richard Hughescff38bc2016-12-12 12:03:37 +0000536 g_debug ("emit added from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100537 fu_plugin_get_name (self),
Richard Hughescff38bc2016-12-12 12:03:37 +0000538 fu_device_get_id (device));
539 fu_device_set_created (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
Richard Hughes12724852018-09-04 13:53:44 +0100540 fu_device_set_plugin (device, fu_plugin_get_name (self));
541 g_signal_emit (self, signals[SIGNAL_DEVICE_ADDED], 0, device);
Richard Hughes5e447292018-04-27 14:25:54 +0100542
Richard Hughes128c0162018-08-10 11:00:29 +0100543 /* add children if they have not already been added */
Richard Hughes5e447292018-04-27 14:25:54 +0100544 children = fu_device_get_children (device);
545 for (guint i = 0; i < children->len; i++) {
546 FuDevice *child = g_ptr_array_index (children, i);
Richard Hughes128c0162018-08-10 11:00:29 +0100547 if (fu_device_get_created (child) == 0)
Richard Hughes12724852018-09-04 13:53:44 +0100548 fu_plugin_device_add (self, child);
Richard Hughes5e447292018-04-27 14:25:54 +0100549 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000550}
551
Richard Hughese1fd34d2017-08-24 14:19:51 +0100552/**
Richard Hughes68ab1e42021-01-13 14:01:17 +0000553 * fu_plugin_get_devices:
554 * @self: A #FuPlugin
555 *
556 * Returns all devices added by the plugin using fu_plugin_device_add() and
557 * not yet removed with fu_plugin_device_remove().
558 *
559 * Returns: (transfer none) (element-type FuDevice): devices
560 *
561 * Since: 1.5.6
562 **/
563GPtrArray *
564fu_plugin_get_devices (FuPlugin *self)
565{
566 FuPluginPrivate *priv = GET_PRIVATE (self);
567 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
568 fu_plugin_ensure_devices (self);
569 return priv->devices;
570}
571
572/**
Richard Hughese1fd34d2017-08-24 14:19:51 +0100573 * fu_plugin_device_register:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100574 * @self: A #FuPlugin
Richard Hughese1fd34d2017-08-24 14:19:51 +0100575 * @device: A #FuDevice
576 *
577 * Registers the device with other plugins so they can set metadata.
578 *
579 * Plugins do not have to call this manually as this is done automatically
580 * when using fu_plugin_device_add(). They may wish to use this manually
Richard Hughes21eaeef2020-01-14 12:10:01 +0000581 * if for instance the coldplug should be ignored based on the metadata
Richard Hughese1fd34d2017-08-24 14:19:51 +0100582 * set from other plugins.
583 *
584 * Since: 0.9.7
585 **/
586void
Richard Hughes12724852018-09-04 13:53:44 +0100587fu_plugin_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +0100588{
Richard Hughesc125ec02018-09-05 19:35:17 +0100589 g_autoptr(GError) error = NULL;
590
Richard Hughes12724852018-09-04 13:53:44 +0100591 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughese1fd34d2017-08-24 14:19:51 +0100592 g_return_if_fail (FU_IS_DEVICE (device));
593
Richard Hughesc125ec02018-09-05 19:35:17 +0100594 /* ensure the device ID is set from the physical and logical IDs */
595 if (!fu_device_ensure_id (device, &error)) {
596 g_warning ("ignoring registration: %s", error->message);
597 return;
598 }
599
Richard Hughese1fd34d2017-08-24 14:19:51 +0100600 g_debug ("emit device-register from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100601 fu_plugin_get_name (self),
Richard Hughese1fd34d2017-08-24 14:19:51 +0100602 fu_device_get_id (device));
Richard Hughes12724852018-09-04 13:53:44 +0100603 g_signal_emit (self, signals[SIGNAL_DEVICE_REGISTER], 0, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +0100604}
605
Richard Hughes57d18222017-01-10 16:02:59 +0000606/**
Richard Hughes4eada342017-10-03 21:20:32 +0100607 * fu_plugin_device_remove:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100608 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000609 * @device: A #FuDevice
610 *
611 * Asks the daemon to remove a device from the exported list.
612 *
613 * Since: 0.8.0
614 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000615void
Richard Hughes12724852018-09-04 13:53:44 +0100616fu_plugin_device_remove (FuPlugin *self, FuDevice *device)
Richard Hughescff38bc2016-12-12 12:03:37 +0000617{
Richard Hughes68ab1e42021-01-13 14:01:17 +0000618 FuPluginPrivate *priv = GET_PRIVATE (self);
619
Richard Hughes12724852018-09-04 13:53:44 +0100620 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000621 g_return_if_fail (FU_IS_DEVICE (device));
622
Richard Hughes68ab1e42021-01-13 14:01:17 +0000623 /* remove from array */
624 if (priv->devices != NULL)
625 g_ptr_array_remove (priv->devices, device);
626
Richard Hughescff38bc2016-12-12 12:03:37 +0000627 g_debug ("emit removed from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100628 fu_plugin_get_name (self),
Richard Hughescff38bc2016-12-12 12:03:37 +0000629 fu_device_get_id (device));
Richard Hughes12724852018-09-04 13:53:44 +0100630 g_signal_emit (self, signals[SIGNAL_DEVICE_REMOVED], 0, device);
Richard Hughescff38bc2016-12-12 12:03:37 +0000631}
632
Richard Hughes57d18222017-01-10 16:02:59 +0000633/**
Richard Hughes2de8f132018-01-17 09:12:02 +0000634 * fu_plugin_request_recoldplug:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100635 * @self: A #FuPlugin
Richard Hughes362d6d72017-01-07 21:42:14 +0000636 *
637 * Ask all the plugins to coldplug all devices, which will include the prepare()
638 * and cleanup() phases. Duplicate devices added will be ignored.
639 *
640 * Since: 0.8.0
641 **/
642void
Richard Hughes12724852018-09-04 13:53:44 +0100643fu_plugin_request_recoldplug (FuPlugin *self)
Richard Hughes362d6d72017-01-07 21:42:14 +0000644{
Richard Hughes12724852018-09-04 13:53:44 +0100645 g_return_if_fail (FU_IS_PLUGIN (self));
646 g_signal_emit (self, signals[SIGNAL_RECOLDPLUG], 0);
Richard Hughes362d6d72017-01-07 21:42:14 +0000647}
648
Richard Hughesb0829032017-01-10 09:27:08 +0000649/**
Richard Hughes399859e2020-05-11 19:44:03 +0100650 * fu_plugin_security_changed:
651 * @self: A #FuPlugin
652 *
653 * Informs the daemon that the HSI state may have changed.
654 *
655 * Since: 1.5.0
656 **/
657void
658fu_plugin_security_changed (FuPlugin *self)
659{
660 g_return_if_fail (FU_IS_PLUGIN (self));
661 g_signal_emit (self, signals[SIGNAL_SECURITY_CHANGED], 0);
662}
663
664/**
Richard Hughesb8f8db22017-04-25 15:56:00 +0100665 * fu_plugin_check_hwid:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100666 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100667 * @hwid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
Richard Hughesb8f8db22017-04-25 15:56:00 +0100668 *
Richard Hughesd7704d42017-08-08 20:29:09 +0100669 * Checks to see if a specific GUID exists. All hardware IDs on a
Richard Hughesb8f8db22017-04-25 15:56:00 +0100670 * specific system can be shown using the `fwupdmgr hwids` command.
671 *
Richard Hughes4eada342017-10-03 21:20:32 +0100672 * Returns: %TRUE if the HwId is found on the system.
673 *
Richard Hughesb8f8db22017-04-25 15:56:00 +0100674 * Since: 0.9.1
675 **/
676gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100677fu_plugin_check_hwid (FuPlugin *self, const gchar *hwid)
Richard Hughesb8f8db22017-04-25 15:56:00 +0100678{
Richard Hughes12724852018-09-04 13:53:44 +0100679 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100680 if (priv->hwids == NULL)
681 return FALSE;
Richard Hughesd7704d42017-08-08 20:29:09 +0100682 return fu_hwids_has_guid (priv->hwids, hwid);
683}
684
685/**
Patrick Rudolpha60b5472019-10-16 10:43:03 +0200686 * fu_plugin_get_hwid_replace_value:
687 * @self: A #FuPlugin
688 * @keys: A key, e.g. `HardwareID-3` or %FU_HWIDS_KEY_PRODUCT_SKU
689 * @error: A #GError or %NULL
690 *
691 * Gets the replacement value for a specific key. All hardware IDs on a
692 * specific system can be shown using the `fwupdmgr hwids` command.
693 *
694 * Returns: (transfer full): a string, or %NULL for error.
695 *
696 * Since: 1.3.3
697 **/
698gchar *
699fu_plugin_get_hwid_replace_value (FuPlugin *self, const gchar *keys, GError **error)
700{
701 FuPluginPrivate *priv = GET_PRIVATE (self);
702 if (priv->hwids == NULL)
703 return NULL;
704
705 return fu_hwids_get_replace_values (priv->hwids, keys, error);
706}
707
708/**
Richard Hughes69a5f352018-08-08 11:58:15 +0100709 * fu_plugin_get_hwids:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100710 * @self: A #FuPlugin
Richard Hughes69a5f352018-08-08 11:58:15 +0100711 *
712 * Returns all the HWIDs defined in the system. All hardware IDs on a
713 * specific system can be shown using the `fwupdmgr hwids` command.
714 *
Mario Limonciello1a680f32019-11-25 19:44:53 -0600715 * Returns: (transfer none) (element-type utf8): An array of GUIDs
Richard Hughes69a5f352018-08-08 11:58:15 +0100716 *
717 * Since: 1.1.1
718 **/
719GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +0100720fu_plugin_get_hwids (FuPlugin *self)
Richard Hughes69a5f352018-08-08 11:58:15 +0100721{
Richard Hughes12724852018-09-04 13:53:44 +0100722 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes69a5f352018-08-08 11:58:15 +0100723 if (priv->hwids == NULL)
724 return NULL;
725 return fu_hwids_get_guids (priv->hwids);
726}
727
728/**
Richard Hughes19841802019-09-10 16:48:00 +0100729 * fu_plugin_has_custom_flag:
730 * @self: A #FuPlugin
731 * @flag: A custom text flag, specific to the plugin, e.g. `uefi-force-enable`
732 *
733 * Returns if a per-plugin HwId custom flag exists, typically added from a DMI quirk.
734 *
735 * Returns: %TRUE if the quirk entry exists
736 *
737 * Since: 1.3.1
738 **/
739gboolean
740fu_plugin_has_custom_flag (FuPlugin *self, const gchar *flag)
741{
742 FuPluginPrivate *priv = GET_PRIVATE (self);
743 GPtrArray *hwids = fu_plugin_get_hwids (self);
744
745 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
746 g_return_val_if_fail (flag != NULL, FALSE);
747
748 /* never set up, e.g. in tests */
749 if (hwids == NULL)
750 return FALSE;
751
752 /* search each hwid */
753 for (guint i = 0; i < hwids->len; i++) {
754 const gchar *hwid = g_ptr_array_index (hwids, i);
755 const gchar *value;
756 g_autofree gchar *key = g_strdup_printf ("HwId=%s", hwid);
757
758 /* does prefixed quirk exist */
759 value = fu_quirks_lookup_by_id (priv->quirks, key, FU_QUIRKS_FLAGS);
760 if (value != NULL) {
761 g_auto(GStrv) quirks = g_strsplit (value, ",", -1);
762 if (g_strv_contains ((const gchar * const *) quirks, flag))
763 return TRUE;
764 }
765 }
766 return FALSE;
767}
768
769/**
Richard Hughes1354ea92017-09-19 15:58:31 +0100770 * fu_plugin_check_supported:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100771 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100772 * @guid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
Richard Hughes1354ea92017-09-19 15:58:31 +0100773 *
774 * Checks to see if a specific device GUID is supported, i.e. available in the
775 * AppStream metadata.
776 *
Richard Hughes4eada342017-10-03 21:20:32 +0100777 * Returns: %TRUE if the device is supported.
778 *
Richard Hughes1354ea92017-09-19 15:58:31 +0100779 * Since: 1.0.0
780 **/
Richard Hughesd8a8d5e2019-10-08 13:05:02 +0100781static gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100782fu_plugin_check_supported (FuPlugin *self, const gchar *guid)
Richard Hughes1354ea92017-09-19 15:58:31 +0100783{
Richard Hughesaabdc372018-11-14 10:11:08 +0000784 gboolean retval = FALSE;
785 g_signal_emit (self, signals[SIGNAL_CHECK_SUPPORTED], 0, guid, &retval);
786 return retval;
Richard Hughes1354ea92017-09-19 15:58:31 +0100787}
788
789/**
Richard Hughesd7704d42017-08-08 20:29:09 +0100790 * fu_plugin_get_dmi_value:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100791 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100792 * @dmi_id: A DMI ID, e.g. `BiosVersion`
Richard Hughesd7704d42017-08-08 20:29:09 +0100793 *
794 * Gets a hardware DMI value.
795 *
Richard Hughes4eada342017-10-03 21:20:32 +0100796 * Returns: The string, or %NULL
797 *
Richard Hughesd7704d42017-08-08 20:29:09 +0100798 * Since: 0.9.7
799 **/
800const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100801fu_plugin_get_dmi_value (FuPlugin *self, const gchar *dmi_id)
Richard Hughesd7704d42017-08-08 20:29:09 +0100802{
Richard Hughes12724852018-09-04 13:53:44 +0100803 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd7704d42017-08-08 20:29:09 +0100804 if (priv->hwids == NULL)
Richard Hughes7ef96b82017-08-23 18:28:24 +0100805 return NULL;
Richard Hughesd7704d42017-08-08 20:29:09 +0100806 return fu_hwids_get_value (priv->hwids, dmi_id);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100807}
808
Richard Hughes49e5e052017-09-03 12:15:41 +0100809/**
810 * fu_plugin_get_smbios_string:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100811 * @self: A #FuPlugin
Richard Hughes49e5e052017-09-03 12:15:41 +0100812 * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
813 * @offset: A SMBIOS offset
814 *
815 * Gets a hardware SMBIOS string.
816 *
817 * The @type and @offset can be referenced from the DMTF SMBIOS specification:
818 * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.1.1.pdf
819 *
Richard Hughes4eada342017-10-03 21:20:32 +0100820 * Returns: A string, or %NULL
821 *
Richard Hughes49e5e052017-09-03 12:15:41 +0100822 * Since: 0.9.8
823 **/
824const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100825fu_plugin_get_smbios_string (FuPlugin *self, guint8 structure_type, guint8 offset)
Richard Hughes49e5e052017-09-03 12:15:41 +0100826{
Richard Hughes12724852018-09-04 13:53:44 +0100827 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100828 if (priv->smbios == NULL)
829 return NULL;
830 return fu_smbios_get_string (priv->smbios, structure_type, offset, NULL);
831}
832
833/**
834 * fu_plugin_get_smbios_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100835 * @self: A #FuPlugin
Richard Hughes49e5e052017-09-03 12:15:41 +0100836 * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
837 *
838 * Gets a hardware SMBIOS data.
839 *
Richard Hughesdfaca2d2019-08-01 08:08:03 +0100840 * Returns: (transfer full): A #GBytes, or %NULL
Richard Hughes4eada342017-10-03 21:20:32 +0100841 *
Richard Hughes49e5e052017-09-03 12:15:41 +0100842 * Since: 0.9.8
843 **/
844GBytes *
Richard Hughes12724852018-09-04 13:53:44 +0100845fu_plugin_get_smbios_data (FuPlugin *self, guint8 structure_type)
Richard Hughes49e5e052017-09-03 12:15:41 +0100846{
Richard Hughes12724852018-09-04 13:53:44 +0100847 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100848 if (priv->smbios == NULL)
849 return NULL;
850 return fu_smbios_get_data (priv->smbios, structure_type, NULL);
851}
852
Mario Limonciello1a680f32019-11-25 19:44:53 -0600853/**
854 * fu_plugin_set_hwids:
855 * @self: A #FuPlugin
856 * @hwids: A #FuHwids
857 *
858 * Sets the hwids for a plugin
859 *
860 * Since: 0.9.7
861 **/
Richard Hughesb8f8db22017-04-25 15:56:00 +0100862void
Richard Hughes12724852018-09-04 13:53:44 +0100863fu_plugin_set_hwids (FuPlugin *self, FuHwids *hwids)
Richard Hughesb8f8db22017-04-25 15:56:00 +0100864{
Richard Hughes12724852018-09-04 13:53:44 +0100865 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd7704d42017-08-08 20:29:09 +0100866 g_set_object (&priv->hwids, hwids);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100867}
868
Mario Limonciello1a680f32019-11-25 19:44:53 -0600869/**
870 * fu_plugin_set_udev_subsystems:
871 * @self: A #FuPlugin
Richard Hughesa0d81c72019-11-27 11:41:54 +0000872 * @udev_subsystems: (element-type utf8): A #GPtrArray
Mario Limonciello1a680f32019-11-25 19:44:53 -0600873 *
874 * Sets the udev subsystems used by a plugin
875 *
876 * Since: 1.1.2
877 **/
Richard Hughes49e5e052017-09-03 12:15:41 +0100878void
Richard Hughes12724852018-09-04 13:53:44 +0100879fu_plugin_set_udev_subsystems (FuPlugin *self, GPtrArray *udev_subsystems)
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100880{
Richard Hughes12724852018-09-04 13:53:44 +0100881 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100882 if (priv->udev_subsystems != NULL)
883 g_ptr_array_unref (priv->udev_subsystems);
884 priv->udev_subsystems = g_ptr_array_ref (udev_subsystems);
885}
886
Mario Limonciello1a680f32019-11-25 19:44:53 -0600887/**
888 * fu_plugin_set_quirks:
889 * @self: A #FuPlugin
890 * @quirks: A #FuQuirks
891 *
892 * Sets the quirks for a plugin
893 *
894 * Since: 1.0.1
895 **/
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100896void
Richard Hughes12724852018-09-04 13:53:44 +0100897fu_plugin_set_quirks (FuPlugin *self, FuQuirks *quirks)
Richard Hughes9c028f02017-10-28 21:14:28 +0100898{
Richard Hughes12724852018-09-04 13:53:44 +0100899 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9c028f02017-10-28 21:14:28 +0100900 g_set_object (&priv->quirks, quirks);
901}
902
903/**
904 * fu_plugin_get_quirks:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100905 * @self: A #FuPlugin
Richard Hughes9c028f02017-10-28 21:14:28 +0100906 *
907 * Returns the hardware database object. This can be used to discover device
908 * quirks or other device-specific settings.
909 *
910 * Returns: (transfer none): a #FuQuirks, or %NULL if not set
911 *
912 * Since: 1.0.1
913 **/
914FuQuirks *
Richard Hughes12724852018-09-04 13:53:44 +0100915fu_plugin_get_quirks (FuPlugin *self)
Richard Hughes9c028f02017-10-28 21:14:28 +0100916{
Richard Hughes12724852018-09-04 13:53:44 +0100917 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9c028f02017-10-28 21:14:28 +0100918 return priv->quirks;
919}
920
Mario Limonciello1a680f32019-11-25 19:44:53 -0600921/**
922 * fu_plugin_set_runtime_versions:
923 * @self: A #FuPlugin
924 * @runtime_versions: A #GHashTables
925 *
926 * Sets the runtime versions for a plugin
927 *
928 * Since: 1.0.7
929 **/
Richard Hughes0eb123b2018-04-19 12:00:04 +0100930void
Richard Hughes12724852018-09-04 13:53:44 +0100931fu_plugin_set_runtime_versions (FuPlugin *self, GHashTable *runtime_versions)
Richard Hughes0eb123b2018-04-19 12:00:04 +0100932{
Richard Hughes12724852018-09-04 13:53:44 +0100933 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0eb123b2018-04-19 12:00:04 +0100934 priv->runtime_versions = g_hash_table_ref (runtime_versions);
935}
936
937/**
938 * fu_plugin_add_runtime_version:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100939 * @self: A #FuPlugin
Richard Hughes0eb123b2018-04-19 12:00:04 +0100940 * @component_id: An AppStream component id, e.g. "org.gnome.Software"
941 * @version: A version string, e.g. "1.2.3"
942 *
Richard Hughesdce91202019-04-08 12:47:45 +0100943 * Sets a runtime version of a specific dependency.
Richard Hughes0eb123b2018-04-19 12:00:04 +0100944 *
945 * Since: 1.0.7
946 **/
947void
Richard Hughes12724852018-09-04 13:53:44 +0100948fu_plugin_add_runtime_version (FuPlugin *self,
Richard Hughes0eb123b2018-04-19 12:00:04 +0100949 const gchar *component_id,
950 const gchar *version)
951{
Richard Hughes12724852018-09-04 13:53:44 +0100952 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesb01b4862018-04-20 16:39:48 +0100953 if (priv->runtime_versions == NULL)
954 return;
Richard Hughes0eb123b2018-04-19 12:00:04 +0100955 g_hash_table_insert (priv->runtime_versions,
956 g_strdup (component_id),
957 g_strdup (version));
958}
959
Mario Limonciello1a680f32019-11-25 19:44:53 -0600960/**
961 * fu_plugin_set_compile_versions:
962 * @self: A #FuPlugin
963 * @compile_versions: A #GHashTables
964 *
965 * Sets the compile time versions for a plugin
966 *
967 * Since: 1.0.7
968 **/
Richard Hughes34e0dab2018-04-20 16:43:00 +0100969void
Richard Hughes12724852018-09-04 13:53:44 +0100970fu_plugin_set_compile_versions (FuPlugin *self, GHashTable *compile_versions)
Richard Hughes34e0dab2018-04-20 16:43:00 +0100971{
Richard Hughes12724852018-09-04 13:53:44 +0100972 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes34e0dab2018-04-20 16:43:00 +0100973 priv->compile_versions = g_hash_table_ref (compile_versions);
974}
975
976/**
977 * fu_plugin_add_compile_version:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100978 * @self: A #FuPlugin
Richard Hughes34e0dab2018-04-20 16:43:00 +0100979 * @component_id: An AppStream component id, e.g. "org.gnome.Software"
980 * @version: A version string, e.g. "1.2.3"
981 *
Richard Hughesdce91202019-04-08 12:47:45 +0100982 * Sets a compile-time version of a specific dependency.
Richard Hughes34e0dab2018-04-20 16:43:00 +0100983 *
984 * Since: 1.0.7
985 **/
986void
Richard Hughes12724852018-09-04 13:53:44 +0100987fu_plugin_add_compile_version (FuPlugin *self,
Richard Hughes34e0dab2018-04-20 16:43:00 +0100988 const gchar *component_id,
989 const gchar *version)
990{
Richard Hughes12724852018-09-04 13:53:44 +0100991 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes34e0dab2018-04-20 16:43:00 +0100992 if (priv->compile_versions == NULL)
993 return;
994 g_hash_table_insert (priv->compile_versions,
995 g_strdup (component_id),
996 g_strdup (version));
997}
998
Richard Hughes9c028f02017-10-28 21:14:28 +0100999/**
1000 * fu_plugin_lookup_quirk_by_id:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001001 * @self: A #FuPlugin
Richard Hughes87fb9ff2018-06-28 12:55:59 +01001002 * @group: A string, e.g. "DfuFlags"
1003 * @key: An ID to match the entry, e.g. "Summary"
Richard Hughes9c028f02017-10-28 21:14:28 +01001004 *
1005 * Looks up an entry in the hardware database using a string value.
1006 *
1007 * Returns: (transfer none): values from the database, or %NULL if not found
1008 *
1009 * Since: 1.0.1
1010 **/
1011const gchar *
Richard Hughes12724852018-09-04 13:53:44 +01001012fu_plugin_lookup_quirk_by_id (FuPlugin *self, const gchar *group, const gchar *key)
Richard Hughes9c028f02017-10-28 21:14:28 +01001013{
Richard Hughes12724852018-09-04 13:53:44 +01001014 FuPluginPrivate *priv = GET_PRIVATE (self);
1015 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes9c028f02017-10-28 21:14:28 +01001016
Richard Hughes9c028f02017-10-28 21:14:28 +01001017 /* exact ID */
Richard Hughes87fb9ff2018-06-28 12:55:59 +01001018 return fu_quirks_lookup_by_id (priv->quirks, group, key);
Richard Hughes9c028f02017-10-28 21:14:28 +01001019}
1020
1021/**
Richard Hughes8fe7cdd2018-08-23 10:02:44 +01001022 * fu_plugin_lookup_quirk_by_id_as_uint64:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001023 * @self: A #FuPlugin
Richard Hughes8fe7cdd2018-08-23 10:02:44 +01001024 * @group: A string, e.g. "DfuFlags"
1025 * @key: An ID to match the entry, e.g. "Size"
1026 *
1027 * Looks up an entry in the hardware database using a string key, returning
1028 * an integer value. Values are assumed base 10, unless prefixed with "0x"
1029 * where they are parsed as base 16.
1030 *
Mario Limonciello1a680f32019-11-25 19:44:53 -06001031 * Returns: guint64 id or 0 if not found
Richard Hughes8fe7cdd2018-08-23 10:02:44 +01001032 *
1033 * Since: 1.1.2
1034 **/
1035guint64
Richard Hughes12724852018-09-04 13:53:44 +01001036fu_plugin_lookup_quirk_by_id_as_uint64 (FuPlugin *self, const gchar *group, const gchar *key)
Richard Hughes8fe7cdd2018-08-23 10:02:44 +01001037{
Richard Hughes12724852018-09-04 13:53:44 +01001038 return fu_common_strtoull (fu_plugin_lookup_quirk_by_id (self, group, key));
Richard Hughes8fe7cdd2018-08-23 10:02:44 +01001039}
1040
Mario Limonciello1a680f32019-11-25 19:44:53 -06001041/**
1042 * fu_plugin_set_smbios:
1043 * @self: A #FuPlugin
1044 * @smbios: A #FuSmbios
1045 *
1046 * Sets the smbios for a plugin
1047 *
1048 * Since: 1.0.0
1049 **/
Richard Hughes1354ea92017-09-19 15:58:31 +01001050void
Richard Hughes12724852018-09-04 13:53:44 +01001051fu_plugin_set_smbios (FuPlugin *self, FuSmbios *smbios)
Richard Hughes49e5e052017-09-03 12:15:41 +01001052{
Richard Hughes12724852018-09-04 13:53:44 +01001053 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +01001054 g_set_object (&priv->smbios, smbios);
1055}
1056
Richard Hughesb8f8db22017-04-25 15:56:00 +01001057/**
Richard Hughesb0829032017-01-10 09:27:08 +00001058 * fu_plugin_set_coldplug_delay:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001059 * @self: A #FuPlugin
Richard Hughesb0829032017-01-10 09:27:08 +00001060 * @duration: A delay in milliseconds
1061 *
Richard Hughes21eaeef2020-01-14 12:10:01 +00001062 * Set the minimum time that should be waited in-between the call to
Richard Hughesb0829032017-01-10 09:27:08 +00001063 * fu_plugin_coldplug_prepare() and fu_plugin_coldplug(). This is usually going
Richard Hughes203ed842020-11-02 14:25:13 +00001064 * to be the minimum hardware initialization time from a datasheet.
Richard Hughesb0829032017-01-10 09:27:08 +00001065 *
1066 * It is better to use this function rather than using a sleep() in the plugin
1067 * itself as then only one delay is done in the daemon rather than waiting for
1068 * each coldplug prepare in a serial way.
1069 *
1070 * Additionally, very long delays should be avoided as the daemon will be
1071 * blocked from processing requests whilst the coldplug delay is being
1072 * performed.
1073 *
1074 * Since: 0.8.0
1075 **/
1076void
Richard Hughes12724852018-09-04 13:53:44 +01001077fu_plugin_set_coldplug_delay (FuPlugin *self, guint duration)
Richard Hughesb0829032017-01-10 09:27:08 +00001078{
Richard Hughes12724852018-09-04 13:53:44 +01001079 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesb0829032017-01-10 09:27:08 +00001080 g_return_if_fail (duration > 0);
1081
1082 /* check sanity */
1083 if (duration > FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM) {
1084 g_warning ("duration of %ums is crazy, truncating to %ums",
1085 duration,
1086 FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM);
1087 duration = FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM;
1088 }
1089
1090 /* emit */
Richard Hughes12724852018-09-04 13:53:44 +01001091 g_signal_emit (self, signals[SIGNAL_SET_COLDPLUG_DELAY], 0, duration);
Richard Hughesb0829032017-01-10 09:27:08 +00001092}
1093
Richard Hughes4b303802019-10-04 13:22:51 +01001094static gboolean
1095fu_plugin_device_attach (FuPlugin *self, FuDevice *device, GError **error)
1096{
1097 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughes4b303802019-10-04 13:22:51 +01001098 locker = fu_device_locker_new (device, error);
1099 if (locker == NULL)
1100 return FALSE;
1101 return fu_device_attach (device, error);
1102}
1103
1104static gboolean
1105fu_plugin_device_detach (FuPlugin *self, FuDevice *device, GError **error)
1106{
1107 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughes4b303802019-10-04 13:22:51 +01001108 locker = fu_device_locker_new (device, error);
1109 if (locker == NULL)
1110 return FALSE;
1111 return fu_device_detach (device, error);
1112}
1113
1114static gboolean
Richard Hughes4b303802019-10-04 13:22:51 +01001115fu_plugin_device_activate (FuPlugin *self, FuDevice *device, GError **error)
1116{
1117 g_autoptr(FuDeviceLocker) locker = NULL;
1118 locker = fu_device_locker_new (device, error);
1119 if (locker == NULL)
1120 return FALSE;
1121 return fu_device_activate (device, error);
1122}
1123
1124static gboolean
1125fu_plugin_device_write_firmware (FuPlugin *self, FuDevice *device,
1126 GBytes *fw, FwupdInstallFlags flags,
1127 GError **error)
1128{
1129 g_autoptr(FuDeviceLocker) locker = NULL;
1130 locker = fu_device_locker_new (device, error);
1131 if (locker == NULL)
1132 return FALSE;
Richard Hughes1a612582020-09-29 19:39:38 +01001133
1134 /* back the old firmware up to /var/lib/fwupd */
1135 if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL)) {
1136 g_autoptr(GBytes) fw_old = NULL;
1137 g_autofree gchar *path = NULL;
1138 g_autofree gchar *fn = NULL;
1139 g_autofree gchar *localstatedir = NULL;
1140
1141 fw_old = fu_device_dump_firmware (device, error);
1142 if (fw_old == NULL) {
1143 g_prefix_error (error, "failed to backup old firmware: ");
1144 return FALSE;
1145 }
1146 localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG);
1147 fn = g_strdup_printf ("%s.bin", fu_device_get_version (device));
1148 path = g_build_filename (localstatedir,
1149 "backup",
1150 fu_device_get_id (device),
1151 fu_device_get_serial (device) != NULL ?
1152 fu_device_get_serial (device) :
1153 "default",
1154 fn, NULL);
1155 if (!fu_common_set_contents_bytes (path, fw_old, error))
1156 return FALSE;
1157 }
1158
Richard Hughes4b303802019-10-04 13:22:51 +01001159 return fu_device_write_firmware (device, fw, flags, error);
1160}
1161
Richard Hughes7f677212019-10-05 16:19:40 +01001162static gboolean
1163fu_plugin_device_read_firmware (FuPlugin *self, FuDevice *device, GError **error)
1164{
1165 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughesf0eb0912019-10-10 11:37:22 +01001166 g_autoptr(FuFirmware) firmware = NULL;
Richard Hughes7f677212019-10-05 16:19:40 +01001167 g_autoptr(GBytes) fw = NULL;
1168 GChecksumType checksum_types[] = {
1169 G_CHECKSUM_SHA1,
1170 G_CHECKSUM_SHA256,
1171 0 };
1172 locker = fu_device_locker_new (device, error);
1173 if (locker == NULL)
1174 return FALSE;
1175 if (!fu_device_detach (device, error))
1176 return FALSE;
Richard Hughesf0eb0912019-10-10 11:37:22 +01001177 firmware = fu_device_read_firmware (device, error);
1178 if (firmware == NULL) {
1179 g_autoptr(GError) error_local = NULL;
1180 if (!fu_device_attach (device, &error_local))
1181 g_debug ("ignoring attach failure: %s", error_local->message);
1182 g_prefix_error (error, "failed to read firmware: ");
1183 return FALSE;
1184 }
1185 fw = fu_firmware_write (firmware, error);
Richard Hughes7f677212019-10-05 16:19:40 +01001186 if (fw == NULL) {
1187 g_autoptr(GError) error_local = NULL;
1188 if (!fu_device_attach (device, &error_local))
Richard Hughesf0eb0912019-10-10 11:37:22 +01001189 g_debug ("ignoring attach failure: %s", error_local->message);
1190 g_prefix_error (error, "failed to write firmware: ");
Richard Hughes7f677212019-10-05 16:19:40 +01001191 return FALSE;
1192 }
1193 for (guint i = 0; checksum_types[i] != 0; i++) {
1194 g_autofree gchar *hash = NULL;
1195 hash = g_compute_checksum_for_bytes (checksum_types[i], fw);
1196 fu_device_add_checksum (device, hash);
1197 }
1198 return fu_device_attach (device, error);
1199}
1200
Mario Limonciello1a680f32019-11-25 19:44:53 -06001201/**
1202 * fu_plugin_runner_startup:
1203 * @self: a #FuPlugin
1204 * @error: a #GError or NULL
1205 *
1206 * Runs the startup routine for the plugin
1207 *
1208 * Returns: #TRUE for success, #FALSE for failure
1209 *
1210 * Since: 0.8.0
1211 **/
Richard Hughesd0905142016-03-13 09:46:49 +00001212gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001213fu_plugin_runner_startup (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00001214{
Richard Hughes12724852018-09-04 13:53:44 +01001215 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001216 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001217 g_autoptr(GError) error_local = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +00001218
1219 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001220 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughesd0905142016-03-13 09:46:49 +00001221 return TRUE;
1222
Richard Hughes639da472018-01-06 22:35:04 +00001223 /* no object loaded */
1224 if (priv->module == NULL)
1225 return TRUE;
1226
Richard Hughesd0905142016-03-13 09:46:49 +00001227 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00001228 g_module_symbol (priv->module, "fu_plugin_startup", (gpointer *) &func);
1229 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +00001230 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001231 g_debug ("startup(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001232 if (!func (self, &error_local)) {
1233 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001234 g_critical ("unset plugin error in startup(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001235 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001236 g_set_error_literal (&error_local,
1237 FWUPD_ERROR,
1238 FWUPD_ERROR_INTERNAL,
1239 "unspecified error");
1240 }
1241 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1242 "failed to startup using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001243 fu_plugin_get_name (self));
Richard Hughescff38bc2016-12-12 12:03:37 +00001244 return FALSE;
1245 }
1246 return TRUE;
1247}
1248
1249static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001250fu_plugin_runner_device_generic (FuPlugin *self, FuDevice *device,
Richard Hughes4b303802019-10-04 13:22:51 +01001251 const gchar *symbol_name,
1252 FuPluginDeviceFunc device_func,
1253 GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001254{
Richard Hughes12724852018-09-04 13:53:44 +01001255 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001256 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001257 g_autoptr(GError) error_local = NULL;
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001258
1259 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001260 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001261 return TRUE;
1262
Richard Hughesd3d96cc2017-11-14 11:34:33 +00001263 /* no object loaded */
1264 if (priv->module == NULL)
1265 return TRUE;
1266
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001267 /* optional */
1268 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
Richard Hughes4b303802019-10-04 13:22:51 +01001269 if (func == NULL) {
1270 if (device_func != NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001271 g_debug ("running superclassed %s(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001272 symbol_name + 10, fu_plugin_get_name (self));
Richard Hughes4b303802019-10-04 13:22:51 +01001273 return device_func (self, device, error);
1274 }
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001275 return TRUE;
Richard Hughes4b303802019-10-04 13:22:51 +01001276 }
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001277 g_debug ("%s(%s)", symbol_name + 10, fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001278 if (!func (self, device, &error_local)) {
1279 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001280 g_critical ("unset plugin error in %s(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001281 fu_plugin_get_name (self), symbol_name + 10);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001282 g_set_error_literal (&error_local,
1283 FWUPD_ERROR,
1284 FWUPD_ERROR_INTERNAL,
1285 "unspecified error");
1286 }
1287 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1288 "failed to %s using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001289 symbol_name + 10, fu_plugin_get_name (self));
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001290 return FALSE;
1291 }
1292 return TRUE;
1293}
1294
Richard Hughesdbd8c762018-06-15 20:31:40 +01001295static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001296fu_plugin_runner_flagged_device_generic (FuPlugin *self, FwupdInstallFlags flags,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001297 FuDevice *device,
1298 const gchar *symbol_name, GError **error)
1299{
Richard Hughes12724852018-09-04 13:53:44 +01001300 FuPluginPrivate *priv = GET_PRIVATE (self);
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001301 FuPluginFlaggedDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001302 g_autoptr(GError) error_local = NULL;
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001303
1304 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001305 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001306 return TRUE;
1307
1308 /* no object loaded */
1309 if (priv->module == NULL)
1310 return TRUE;
1311
1312 /* optional */
1313 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1314 if (func == NULL)
1315 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001316 g_debug ("%s(%s)", symbol_name + 10, fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001317 if (!func (self, flags, device, &error_local)) {
1318 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001319 g_critical ("unset plugin error in %s(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001320 fu_plugin_get_name (self), symbol_name + 10);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001321 g_set_error_literal (&error_local,
1322 FWUPD_ERROR,
1323 FWUPD_ERROR_INTERNAL,
1324 "unspecified error");
1325 }
1326 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1327 "failed to %s using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001328 symbol_name + 10, fu_plugin_get_name (self));
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001329 return FALSE;
1330 }
1331 return TRUE;
1332
1333}
1334
1335static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001336fu_plugin_runner_device_array_generic (FuPlugin *self, GPtrArray *devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001337 const gchar *symbol_name, GError **error)
1338{
Richard Hughes12724852018-09-04 13:53:44 +01001339 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesdbd8c762018-06-15 20:31:40 +01001340 FuPluginDeviceArrayFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001341 g_autoptr(GError) error_local = NULL;
Richard Hughesdbd8c762018-06-15 20:31:40 +01001342
1343 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001344 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughesdbd8c762018-06-15 20:31:40 +01001345 return TRUE;
1346
1347 /* no object loaded */
1348 if (priv->module == NULL)
1349 return TRUE;
1350
1351 /* optional */
1352 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1353 if (func == NULL)
1354 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001355 g_debug ("%s(%s)", symbol_name + 10, fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001356 if (!func (self, devices, &error_local)) {
1357 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001358 g_critical ("unset plugin error in for %s(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001359 fu_plugin_get_name (self), symbol_name + 10);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001360 g_set_error_literal (&error_local,
1361 FWUPD_ERROR,
1362 FWUPD_ERROR_INTERNAL,
1363 "unspecified error");
1364 }
1365 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1366 "failed to %s using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001367 symbol_name + 10, fu_plugin_get_name (self));
Richard Hughesdbd8c762018-06-15 20:31:40 +01001368 return FALSE;
1369 }
1370 return TRUE;
1371}
1372
Mario Limonciello1a680f32019-11-25 19:44:53 -06001373/**
1374 * fu_plugin_runner_coldplug:
1375 * @self: a #FuPlugin
1376 * @error: a #GError or NULL
1377 *
1378 * Runs the coldplug routine for the plugin
1379 *
1380 * Returns: #TRUE for success, #FALSE for failure
1381 *
1382 * Since: 0.8.0
1383 **/
Richard Hughesd0905142016-03-13 09:46:49 +00001384gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001385fu_plugin_runner_coldplug (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00001386{
Richard Hughes12724852018-09-04 13:53:44 +01001387 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001388 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001389 g_autoptr(GError) error_local = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +00001390
1391 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001392 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughesd0905142016-03-13 09:46:49 +00001393 return TRUE;
1394
Richard Hughes639da472018-01-06 22:35:04 +00001395 /* no object loaded */
1396 if (priv->module == NULL)
1397 return TRUE;
1398
Richard Hughesd0905142016-03-13 09:46:49 +00001399 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00001400 g_module_symbol (priv->module, "fu_plugin_coldplug", (gpointer *) &func);
1401 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +00001402 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001403 g_debug ("coldplug(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001404 if (!func (self, &error_local)) {
1405 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001406 g_critical ("unset plugin error in coldplug(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001407 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001408 g_set_error_literal (&error_local,
1409 FWUPD_ERROR,
1410 FWUPD_ERROR_INTERNAL,
1411 "unspecified error");
1412 }
1413 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001414 "failed to coldplug using %s: ", fu_plugin_get_name (self));
Richard Hughescff38bc2016-12-12 12:03:37 +00001415 return FALSE;
1416 }
1417 return TRUE;
1418}
1419
Mario Limonciello1a680f32019-11-25 19:44:53 -06001420/**
1421 * fu_plugin_runner_recoldplug:
1422 * @self: a #FuPlugin
1423 * @error: a #GError or NULL
1424 *
1425 * Runs the recoldplug routine for the plugin
1426 *
1427 * Returns: #TRUE for success, #FALSE for failure
1428 *
1429 * Since: 1.0.4
1430 **/
Richard Hughes7b8b2022016-12-12 16:15:03 +00001431gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001432fu_plugin_runner_recoldplug (FuPlugin *self, GError **error)
Richard Hughes2de8f132018-01-17 09:12:02 +00001433{
Richard Hughes12724852018-09-04 13:53:44 +01001434 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes2de8f132018-01-17 09:12:02 +00001435 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001436 g_autoptr(GError) error_local = NULL;
Richard Hughes2de8f132018-01-17 09:12:02 +00001437
1438 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001439 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes2de8f132018-01-17 09:12:02 +00001440 return TRUE;
1441
1442 /* no object loaded */
1443 if (priv->module == NULL)
1444 return TRUE;
1445
1446 /* optional */
1447 g_module_symbol (priv->module, "fu_plugin_recoldplug", (gpointer *) &func);
1448 if (func == NULL)
1449 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001450 g_debug ("recoldplug(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001451 if (!func (self, &error_local)) {
1452 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001453 g_critical ("unset plugin error in recoldplug(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001454 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001455 g_set_error_literal (&error_local,
1456 FWUPD_ERROR,
1457 FWUPD_ERROR_INTERNAL,
1458 "unspecified error");
1459 }
1460 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1461 "failed to recoldplug using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001462 fu_plugin_get_name (self));
Richard Hughes2de8f132018-01-17 09:12:02 +00001463 return FALSE;
1464 }
1465 return TRUE;
1466}
1467
Mario Limonciello1a680f32019-11-25 19:44:53 -06001468/**
1469 * fu_plugin_runner_coldplug_prepare:
1470 * @self: a #FuPlugin
1471 * @error: a #GError or NULL
1472 *
1473 * Runs the coldplug_prepare routine for the plugin
1474 *
1475 * Returns: #TRUE for success, #FALSE for failure
1476 *
1477 * Since: 0.8.0
1478 **/
Richard Hughes2de8f132018-01-17 09:12:02 +00001479gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001480fu_plugin_runner_coldplug_prepare (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001481{
Richard Hughes12724852018-09-04 13:53:44 +01001482 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001483 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001484 g_autoptr(GError) error_local = NULL;
Richard Hughes46487c92017-01-07 21:26:34 +00001485
1486 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001487 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes46487c92017-01-07 21:26:34 +00001488 return TRUE;
1489
Richard Hughes639da472018-01-06 22:35:04 +00001490 /* no object loaded */
1491 if (priv->module == NULL)
1492 return TRUE;
1493
Richard Hughes46487c92017-01-07 21:26:34 +00001494 /* optional */
1495 g_module_symbol (priv->module, "fu_plugin_coldplug_prepare", (gpointer *) &func);
1496 if (func == NULL)
1497 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001498 g_debug ("coldplug_prepare(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001499 if (!func (self, &error_local)) {
1500 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001501 g_critical ("unset plugin error in coldplug_prepare(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001502 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001503 g_set_error_literal (&error_local,
1504 FWUPD_ERROR,
1505 FWUPD_ERROR_INTERNAL,
1506 "unspecified error");
1507 }
1508 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1509 "failed to coldplug_prepare using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001510 fu_plugin_get_name (self));
Richard Hughes46487c92017-01-07 21:26:34 +00001511 return FALSE;
1512 }
1513 return TRUE;
1514}
1515
Mario Limonciello1a680f32019-11-25 19:44:53 -06001516/**
1517 * fu_plugin_runner_coldplug_cleanup:
1518 * @self: a #FuPlugin
1519 * @error: a #GError or NULL
1520 *
1521 * Runs the coldplug_cleanup routine for the plugin
1522 *
1523 * Returns: #TRUE for success, #FALSE for failure
1524 *
1525 * Since: 0.8.0
1526 **/
Richard Hughes46487c92017-01-07 21:26:34 +00001527gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001528fu_plugin_runner_coldplug_cleanup (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001529{
Richard Hughes12724852018-09-04 13:53:44 +01001530 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001531 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001532 g_autoptr(GError) error_local = NULL;
Richard Hughes46487c92017-01-07 21:26:34 +00001533
1534 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001535 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes46487c92017-01-07 21:26:34 +00001536 return TRUE;
1537
Richard Hughes639da472018-01-06 22:35:04 +00001538 /* no object loaded */
1539 if (priv->module == NULL)
1540 return TRUE;
1541
Richard Hughes46487c92017-01-07 21:26:34 +00001542 /* optional */
1543 g_module_symbol (priv->module, "fu_plugin_coldplug_cleanup", (gpointer *) &func);
1544 if (func == NULL)
1545 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001546 g_debug ("coldplug_cleanup(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001547 if (!func (self, &error_local)) {
1548 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001549 g_critical ("unset plugin error in coldplug_cleanup(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001550 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001551 g_set_error_literal (&error_local,
1552 FWUPD_ERROR,
1553 FWUPD_ERROR_INTERNAL,
1554 "unspecified error");
1555 }
1556 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1557 "failed to coldplug_cleanup using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001558 fu_plugin_get_name (self));
Richard Hughes46487c92017-01-07 21:26:34 +00001559 return FALSE;
1560 }
1561 return TRUE;
1562}
1563
Mario Limonciello1a680f32019-11-25 19:44:53 -06001564/**
1565 * fu_plugin_runner_composite_prepare:
1566 * @self: a #FuPlugin
Richard Hughesa0d81c72019-11-27 11:41:54 +00001567 * @devices: (element-type FuDevice): a #GPtrArray of devices
Mario Limonciello1a680f32019-11-25 19:44:53 -06001568 * @error: a #GError or NULL
1569 *
1570 * Runs the composite_prepare routine for the plugin
1571 *
1572 * Returns: #TRUE for success, #FALSE for failure
1573 *
1574 * Since: 1.0.9
1575 **/
Richard Hughes46487c92017-01-07 21:26:34 +00001576gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001577fu_plugin_runner_composite_prepare (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001578{
Richard Hughes12724852018-09-04 13:53:44 +01001579 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001580 "fu_plugin_composite_prepare",
1581 error);
1582}
1583
Mario Limonciello1a680f32019-11-25 19:44:53 -06001584/**
1585 * fu_plugin_runner_composite_cleanup:
1586 * @self: a #FuPlugin
Richard Hughesa0d81c72019-11-27 11:41:54 +00001587 * @devices: (element-type FuDevice): a #GPtrArray of devices
Mario Limonciello1a680f32019-11-25 19:44:53 -06001588 * @error: a #GError or NULL
1589 *
1590 * Runs the composite_cleanup routine for the plugin
1591 *
1592 * Returns: #TRUE for success, #FALSE for failure
1593 *
1594 * Since: 1.0.9
1595 **/
Richard Hughesdbd8c762018-06-15 20:31:40 +01001596gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001597fu_plugin_runner_composite_cleanup (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001598{
Richard Hughes12724852018-09-04 13:53:44 +01001599 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001600 "fu_plugin_composite_cleanup",
1601 error);
1602}
1603
Mario Limonciello1a680f32019-11-25 19:44:53 -06001604/**
1605 * fu_plugin_runner_update_prepare:
1606 * @self: a #FuPlugin
Richard Hughes2bbb7d22020-11-30 09:18:45 +00001607 * @flags: #FwupdInstallFlags
1608 * @device: a #FuDevice
Mario Limonciello1a680f32019-11-25 19:44:53 -06001609 * @error: a #GError or NULL
1610 *
1611 * Runs the update_prepare routine for the plugin
1612 *
1613 * Returns: #TRUE for success, #FALSE for failure
1614 *
1615 * Since: 1.1.2
1616 **/
Richard Hughesdbd8c762018-06-15 20:31:40 +01001617gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001618fu_plugin_runner_update_prepare (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001619 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001620{
Richard Hughes12724852018-09-04 13:53:44 +01001621 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001622 "fu_plugin_update_prepare",
1623 error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001624}
1625
Mario Limonciello1a680f32019-11-25 19:44:53 -06001626/**
1627 * fu_plugin_runner_update_cleanup:
1628 * @self: a #FuPlugin
Richard Hughes2bbb7d22020-11-30 09:18:45 +00001629 * @flags: #FwupdInstallFlags
1630 * @device: a #FuDevice
Mario Limonciello1a680f32019-11-25 19:44:53 -06001631 * @error: a #GError or NULL
1632 *
1633 * Runs the update_cleanup routine for the plugin
1634 *
1635 * Returns: #TRUE for success, #FALSE for failure
1636 *
1637 * Since: 1.1.2
1638 **/
Richard Hughes7b8b2022016-12-12 16:15:03 +00001639gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001640fu_plugin_runner_update_cleanup (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001641 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001642{
Richard Hughes12724852018-09-04 13:53:44 +01001643 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001644 "fu_plugin_update_cleanup",
1645 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001646}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001647
Mario Limonciello1a680f32019-11-25 19:44:53 -06001648/**
1649 * fu_plugin_runner_update_attach:
1650 * @self: a #FuPlugin
1651 * @device: a #FuDevice
1652 * @error: a #GError or NULL
1653 *
1654 * Runs the update_attach routine for the plugin
1655 *
1656 * Returns: #TRUE for success, #FALSE for failure
1657 *
1658 * Since: 1.1.2
1659 **/
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001660gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001661fu_plugin_runner_update_attach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001662{
Richard Hughes12724852018-09-04 13:53:44 +01001663 return fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001664 "fu_plugin_update_attach",
1665 fu_plugin_device_attach,
1666 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001667}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001668
Mario Limonciello1a680f32019-11-25 19:44:53 -06001669/**
1670 * fu_plugin_runner_update_detach:
1671 * @self: a #FuPlugin
1672 * @device: A #FuDevice
1673 * @error: a #GError or NULL
1674 *
1675 * Runs the update_detach routine for the plugin
1676 *
1677 * Returns: #TRUE for success, #FALSE for failure
1678 *
1679 * Since: 1.1.2
1680 **/
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001681gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001682fu_plugin_runner_update_detach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001683{
Richard Hughes12724852018-09-04 13:53:44 +01001684 return fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001685 "fu_plugin_update_detach",
1686 fu_plugin_device_detach,
1687 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001688}
1689
Mario Limonciello1a680f32019-11-25 19:44:53 -06001690/**
1691 * fu_plugin_runner_update_reload:
1692 * @self: a #FuPlugin
Richard Hughes2bbb7d22020-11-30 09:18:45 +00001693 * @device: A #FuDevice
Mario Limonciello1a680f32019-11-25 19:44:53 -06001694 * @error: a #GError or NULL
1695 *
1696 * Runs reload routine for a device
1697 *
1698 * Returns: #TRUE for success, #FALSE for failure
1699 *
1700 * Since: 1.1.2
1701 **/
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001702gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001703fu_plugin_runner_update_reload (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001704{
Richard Hughes42f33df2019-10-05 20:52:33 +01001705 g_autoptr(FuDeviceLocker) locker = NULL;
1706
1707 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001708 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes42f33df2019-10-05 20:52:33 +01001709 return TRUE;
1710
1711 /* no object loaded */
1712 locker = fu_device_locker_new (device, error);
1713 if (locker == NULL)
1714 return FALSE;
1715 return fu_device_reload (device, error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001716}
1717
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001718/**
Richard Hughes196c6c62020-05-11 19:42:47 +01001719 * fu_plugin_runner_add_security_attrs:
1720 * @self: a #FuPlugin
Richard Hughes3ecd22c2020-05-19 20:13:47 +01001721 * @attrs: a #FuSecurityAttrs
Richard Hughes196c6c62020-05-11 19:42:47 +01001722 *
Richard Hughes3ecd22c2020-05-19 20:13:47 +01001723 * Runs the `add_security_attrs()` routine for the plugin
Richard Hughes196c6c62020-05-11 19:42:47 +01001724 *
1725 * Since: 1.5.0
1726 **/
Richard Hughesf58ac732020-05-12 15:23:44 +01001727void
1728fu_plugin_runner_add_security_attrs (FuPlugin *self, FuSecurityAttrs *attrs)
Richard Hughes196c6c62020-05-11 19:42:47 +01001729{
Richard Hughesf58ac732020-05-12 15:23:44 +01001730 FuPluginPrivate *priv = GET_PRIVATE (self);
1731 FuPluginSecurityAttrsFunc func = NULL;
1732 const gchar *symbol_name = "fu_plugin_add_security_attrs";
1733
1734 /* no object loaded */
1735 if (priv->module == NULL)
1736 return;
1737
1738 /* optional, but gets called even for disabled plugins */
1739 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1740 if (func == NULL)
1741 return;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001742 g_debug ("%s(%s)", symbol_name + 10, fu_plugin_get_name (self));
Richard Hughesf58ac732020-05-12 15:23:44 +01001743 func (self, attrs);
Richard Hughes196c6c62020-05-11 19:42:47 +01001744}
1745
1746/**
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001747 * fu_plugin_add_udev_subsystem:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001748 * @self: a #FuPlugin
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001749 * @subsystem: a subsystem name, e.g. `pciport`
1750 *
1751 * Registers the udev subsystem to be watched by the daemon.
1752 *
1753 * Plugins can use this method only in fu_plugin_init()
Mario Limonciello1a680f32019-11-25 19:44:53 -06001754 *
1755 * Since: 1.1.2
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001756 **/
1757void
Richard Hughes12724852018-09-04 13:53:44 +01001758fu_plugin_add_udev_subsystem (FuPlugin *self, const gchar *subsystem)
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001759{
Richard Hughes12724852018-09-04 13:53:44 +01001760 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesea327fc2020-06-22 15:23:29 +01001761 if (priv->udev_subsystems == NULL)
1762 priv->udev_subsystems = g_ptr_array_new_with_free_func (g_free);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001763 for (guint i = 0; i < priv->udev_subsystems->len; i++) {
1764 const gchar *subsystem_tmp = g_ptr_array_index (priv->udev_subsystems, i);
1765 if (g_strcmp0 (subsystem_tmp, subsystem) == 0)
1766 return;
1767 }
1768 g_debug ("added udev subsystem watch of %s", subsystem);
1769 g_ptr_array_add (priv->udev_subsystems, g_strdup (subsystem));
1770}
1771
Richard Hughes989acf12019-10-05 20:16:47 +01001772/**
1773 * fu_plugin_set_device_gtype:
1774 * @self: a #FuPlugin
1775 * @device_gtype: a #GType `FU_TYPE_DEVICE`
1776 *
1777 * Sets the device #GType which is used when creating devices.
1778 *
Richard Hughes525f71f2021-02-09 14:52:47 +00001779 * If this method is used then fu_plugin_backend_device_added() is not called, and
Richard Hughes989acf12019-10-05 20:16:47 +01001780 * instead the object is created in the daemon for the plugin.
1781 *
1782 * Plugins can use this method only in fu_plugin_init()
1783 *
1784 * Since: 1.3.3
1785 **/
1786void
1787fu_plugin_set_device_gtype (FuPlugin *self, GType device_gtype)
1788{
1789 FuPluginPrivate *priv = GET_PRIVATE (self);
1790 priv->device_gtype = device_gtype;
1791}
1792
Richard Hughes9f71fe32021-01-03 20:35:36 +00001793static gchar *
1794fu_common_string_uncamelcase (const gchar *str)
1795{
1796 GString *tmp = g_string_new (NULL);
1797 for (guint i = 0; str[i] != '\0'; i++) {
1798 if (g_ascii_islower (str[i]) ||
1799 g_ascii_isdigit (str[i])) {
1800 g_string_append_c (tmp, str[i]);
1801 continue;
1802 }
1803 if (i > 0)
1804 g_string_append_c (tmp, '-');
1805 g_string_append_c (tmp, g_ascii_tolower (str[i]));
1806 }
1807 return g_string_free (tmp, FALSE);
1808}
1809
Mario Limonciello1a680f32019-11-25 19:44:53 -06001810/**
1811 * fu_plugin_add_firmware_gtype:
1812 * @self: a #FuPlugin
Richard Hughes9f71fe32021-01-03 20:35:36 +00001813 * @id: (nullable): An optional string describing the type, e.g. "ihex"
1814 * @gtype: a #GType e.g. `FU_TYPE_FOO_FIRMWARE`
Mario Limonciello1a680f32019-11-25 19:44:53 -06001815 *
Richard Hughes9f71fe32021-01-03 20:35:36 +00001816 * Adds a firmware #GType which is used when creating devices. If @id is not
1817 * specified then it is guessed using the #GType name.
1818 *
Mario Limonciello1a680f32019-11-25 19:44:53 -06001819 * Plugins can use this method only in fu_plugin_init()
1820 *
1821 * Since: 1.3.3
1822 **/
Richard Hughes95c98a92019-10-22 16:03:15 +01001823void
1824fu_plugin_add_firmware_gtype (FuPlugin *self, const gchar *id, GType gtype)
1825{
Richard Hughes9f71fe32021-01-03 20:35:36 +00001826 g_autofree gchar *id_safe = NULL;
1827 if (id != NULL) {
1828 id_safe = g_strdup (id);
1829 } else {
Richard Hughesebb10a52021-01-05 13:34:39 +00001830 g_autoptr(GString) str = g_string_new (g_type_name (gtype));
Richard Hughes9f71fe32021-01-03 20:35:36 +00001831 if (g_str_has_prefix (str->str, "Fu"))
1832 g_string_erase (str, 0, 2);
1833 fu_common_string_replace (str, "Firmware", "");
1834 id_safe = fu_common_string_uncamelcase (str->str);
1835 }
1836 g_signal_emit (self, signals[SIGNAL_ADD_FIRMWARE_GTYPE], 0, id_safe, gtype);
Richard Hughes95c98a92019-10-22 16:03:15 +01001837}
1838
Richard Hughes989acf12019-10-05 20:16:47 +01001839static gboolean
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001840fu_plugin_check_supported_device (FuPlugin *self, FuDevice *device)
1841{
1842 GPtrArray *instance_ids = fu_device_get_instance_ids (device);
1843 for (guint i = 0; i < instance_ids->len; i++) {
1844 const gchar *instance_id = g_ptr_array_index (instance_ids, i);
1845 g_autofree gchar *guid = fwupd_guid_hash_string (instance_id);
1846 if (fu_plugin_check_supported (self, guid))
1847 return TRUE;
1848 }
1849 return FALSE;
1850}
1851
1852static gboolean
Richard Hughes525f71f2021-02-09 14:52:47 +00001853fu_plugin_backend_device_added (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes989acf12019-10-05 20:16:47 +01001854{
1855 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001856 GType device_gtype = fu_device_get_specialized_gtype (FU_DEVICE (device));
Richard Hughes989acf12019-10-05 20:16:47 +01001857 g_autoptr(FuDevice) dev = NULL;
1858 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001859
1860 /* fall back to plugin default */
1861 if (device_gtype == G_TYPE_INVALID)
1862 device_gtype = priv->device_gtype;
1863
1864 /* create new device and incorporate existing properties */
1865 dev = g_object_new (device_gtype, NULL);
1866 fu_device_incorporate (dev, FU_DEVICE (device));
Richard Hughes0f66a022020-02-19 18:54:38 +00001867 if (!fu_plugin_runner_device_created (self, dev, error))
1868 return FALSE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001869
1870 /* there are a lot of different devices that match, but not all respond
1871 * well to opening -- so limit some ones with issued updates */
Richard Hughescf100292021-01-04 10:36:37 +00001872 if (fu_device_has_internal_flag (dev, FU_DEVICE_INTERNAL_FLAG_ONLY_SUPPORTED)) {
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001873 if (!fu_device_probe (dev, error))
1874 return FALSE;
1875 fu_device_convert_instance_ids (dev);
1876 if (!fu_plugin_check_supported_device (self, dev)) {
1877 g_autofree gchar *guids = fu_device_get_guids_as_str (dev);
1878 g_debug ("%s has no updates, so ignoring device", guids);
1879 return TRUE;
1880 }
1881 }
1882
1883 /* open and add */
1884 locker = fu_device_locker_new (dev, error);
1885 if (locker == NULL)
1886 return FALSE;
1887 fu_plugin_device_add (self, dev);
Richard Hughes6a078702020-05-09 20:36:33 +01001888 fu_plugin_runner_device_added (self, dev);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001889 return TRUE;
1890}
1891
Mario Limonciello1a680f32019-11-25 19:44:53 -06001892/**
1893 * fu_plugin_runner_usb_device_added:
1894 * @self: a #FuPlugin
1895 * @device: a #FuUsbDevice
1896 * @error: a #GError or NULL
1897 *
Richard Hughes525f71f2021-02-09 14:52:47 +00001898 * Call the backend_device_added routine for the plugin
Mario Limonciello1a680f32019-11-25 19:44:53 -06001899 *
1900 * Returns: #TRUE for success, #FALSE for failure
1901 *
1902 * Since: 1.0.2
1903 **/
Richard Hughes104f6512017-11-24 11:44:57 +00001904gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001905fu_plugin_runner_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error)
Richard Hughes104f6512017-11-24 11:44:57 +00001906{
Richard Hughes525f71f2021-02-09 14:52:47 +00001907 return fu_plugin_runner_backend_device_added (self, FU_DEVICE (device), error);
Richard Hughes104f6512017-11-24 11:44:57 +00001908}
1909
Mario Limonciello1a680f32019-11-25 19:44:53 -06001910/**
1911 * fu_plugin_runner_udev_device_added:
1912 * @self: a #FuPlugin
1913 * @device: a #FuUdevDevice
1914 * @error: a #GError or NULL
1915 *
Richard Hughes525f71f2021-02-09 14:52:47 +00001916 * Call the backend_device_added routine for the plugin
Mario Limonciello1a680f32019-11-25 19:44:53 -06001917 *
1918 * Returns: #TRUE for success, #FALSE for failure
1919 *
1920 * Since: 1.0.2
1921 **/
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001922gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001923fu_plugin_runner_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error)
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001924{
Richard Hughes525f71f2021-02-09 14:52:47 +00001925 return fu_plugin_runner_backend_device_added (self, FU_DEVICE (device), error);
1926}
1927
1928/**
1929 * fu_plugin_runner_backend_device_added:
1930 * @self: a #FuPlugin
1931 * @device: a #FuDevice
1932 * @error: a #GError or NULL
1933 *
1934 * Call the backend_device_added routine for the plugin
1935 *
1936 * Returns: #TRUE for success, #FALSE for failure
1937 *
1938 * Since: 1.5.6
1939 **/
1940gboolean
1941fu_plugin_runner_backend_device_added (FuPlugin *self, FuDevice *device, GError **error)
1942{
Richard Hughes12724852018-09-04 13:53:44 +01001943 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes525f71f2021-02-09 14:52:47 +00001944 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001945 g_autoptr(GError) error_local = NULL;
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001946
Richard Hughes6a489a92020-12-22 10:32:06 +00001947 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
Richard Hughes525f71f2021-02-09 14:52:47 +00001948 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
Richard Hughes6a489a92020-12-22 10:32:06 +00001949 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1950
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001951 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001952 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001953 return TRUE;
1954
1955 /* no object loaded */
1956 if (priv->module == NULL)
1957 return TRUE;
1958
1959 /* optional */
Richard Hughes525f71f2021-02-09 14:52:47 +00001960 g_module_symbol (priv->module, "fu_plugin_backend_device_added", (gpointer *) &func);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001961 if (func == NULL) {
1962 if (priv->device_gtype != G_TYPE_INVALID ||
Richard Hughes525f71f2021-02-09 14:52:47 +00001963 fu_device_get_specialized_gtype (device) != G_TYPE_INVALID) {
1964 return fu_plugin_backend_device_added (self, device, error);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001965 }
Richard Hughesa21e0252020-12-01 12:21:33 +00001966 g_set_error_literal (error,
1967 FWUPD_ERROR,
1968 FWUPD_ERROR_INTERNAL,
1969 "No device GType set");
1970 return FALSE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001971 }
Richard Hughes525f71f2021-02-09 14:52:47 +00001972 g_debug ("backend_device_added(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001973 if (!func (self, device, &error_local)) {
1974 if (error_local == NULL) {
Richard Hughes525f71f2021-02-09 14:52:47 +00001975 g_critical ("unset plugin error in backend_device_added(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001976 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001977 g_set_error_literal (&error_local,
1978 FWUPD_ERROR,
1979 FWUPD_ERROR_INTERNAL,
1980 "unspecified error");
1981 }
1982 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1983 "failed to add device using on %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001984 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001985 return FALSE;
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001986 }
1987 return TRUE;
1988}
1989
Mario Limonciello1a680f32019-11-25 19:44:53 -06001990/**
1991 * fu_plugin_runner_udev_device_changed:
1992 * @self: a #FuPlugin
1993 * @device: a #FuUdevDevice
1994 * @error: a #GError or NULL
1995 *
Richard Hughes525f71f2021-02-09 14:52:47 +00001996 * Call the backend_device_changed routine for the plugin
Mario Limonciello1a680f32019-11-25 19:44:53 -06001997 *
1998 * Returns: #TRUE for success, #FALSE for failure
1999 *
2000 * Since: 1.0.2
2001 **/
Richard Hughes5e952ce2019-08-26 11:09:46 +01002002gboolean
2003fu_plugin_runner_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GError **error)
2004{
Richard Hughes525f71f2021-02-09 14:52:47 +00002005 return fu_plugin_runner_backend_device_changed (self, FU_DEVICE (device), error);
2006}
2007
2008/**
2009 * fu_plugin_runner_backend_device_changed:
2010 * @self: a #FuPlugin
2011 * @device: a #FuDevice
2012 * @error: a #GError or NULL
2013 *
2014 * Call the backend_device_changed routine for the plugin
2015 *
2016 * Returns: #TRUE for success, #FALSE for failure
2017 *
2018 * Since: 1.5.6
2019 **/
2020gboolean
2021fu_plugin_runner_backend_device_changed (FuPlugin *self, FuDevice *device, GError **error)
2022{
Richard Hughes5e952ce2019-08-26 11:09:46 +01002023 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes525f71f2021-02-09 14:52:47 +00002024 FuPluginDeviceFunc func = NULL;
Richard Hughes5e952ce2019-08-26 11:09:46 +01002025 g_autoptr(GError) error_local = NULL;
2026
Richard Hughes6a489a92020-12-22 10:32:06 +00002027 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
Richard Hughes525f71f2021-02-09 14:52:47 +00002028 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
Richard Hughes6a489a92020-12-22 10:32:06 +00002029 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2030
Richard Hughes5e952ce2019-08-26 11:09:46 +01002031 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002032 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes5e952ce2019-08-26 11:09:46 +01002033 return TRUE;
2034
2035 /* no object loaded */
2036 if (priv->module == NULL)
2037 return TRUE;
2038
2039 /* optional */
Richard Hughes525f71f2021-02-09 14:52:47 +00002040 g_module_symbol (priv->module, "fu_plugin_backend_device_changed", (gpointer *) &func);
Mario Limonciello6d235142020-09-10 21:35:17 -05002041 if (func == NULL)
Richard Hughes5e952ce2019-08-26 11:09:46 +01002042 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002043 g_debug ("udev_device_changed(%s)", fu_plugin_get_name (self));
Richard Hughes5e952ce2019-08-26 11:09:46 +01002044 if (!func (self, device, &error_local)) {
2045 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05002046 g_critical ("unset plugin error in udev_device_changed(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002047 fu_plugin_get_name (self));
Richard Hughes5e952ce2019-08-26 11:09:46 +01002048 g_set_error_literal (&error_local,
2049 FWUPD_ERROR,
2050 FWUPD_ERROR_INTERNAL,
2051 "unspecified error");
2052 }
2053 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2054 "failed to change device on %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002055 fu_plugin_get_name (self));
Richard Hughes5e952ce2019-08-26 11:09:46 +01002056 return FALSE;
2057 }
2058 return TRUE;
2059}
2060
Mario Limonciello1a680f32019-11-25 19:44:53 -06002061/**
Richard Hughes6a078702020-05-09 20:36:33 +01002062 * fu_plugin_runner_device_added:
2063 * @self: a #FuPlugin
2064 * @device: a #FuDevice
2065 *
2066 * Call the device_added routine for the plugin
2067 *
2068 * Since: 1.5.0
2069 **/
2070void
2071fu_plugin_runner_device_added (FuPlugin *self, FuDevice *device)
2072{
2073 FuPluginPrivate *priv = GET_PRIVATE (self);
2074 FuPluginDeviceRegisterFunc func = NULL;
2075
2076 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002077 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes6a078702020-05-09 20:36:33 +01002078 return;
2079 if (priv->module == NULL)
2080 return;
2081
2082 /* optional */
2083 g_module_symbol (priv->module, "fu_plugin_device_added", (gpointer *) &func);
2084 if (func == NULL)
2085 return;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002086 g_debug ("fu_plugin_device_added(%s)", fu_plugin_get_name (self));
Richard Hughes6a078702020-05-09 20:36:33 +01002087 func (self, device);
2088}
2089
2090/**
Mario Limonciello1a680f32019-11-25 19:44:53 -06002091 * fu_plugin_runner_device_removed:
2092 * @self: a #FuPlugin
2093 * @device: a #FuDevice
2094 *
2095 * Call the device_removed routine for the plugin
2096 *
2097 * Since: 1.1.2
2098 **/
Richard Hughese1fd34d2017-08-24 14:19:51 +01002099void
Richard Hughes12724852018-09-04 13:53:44 +01002100fu_plugin_runner_device_removed (FuPlugin *self, FuDevice *device)
Mario Limoncielloe260ead2018-09-01 09:19:24 -05002101{
2102 g_autoptr(GError) error_local= NULL;
2103
Richard Hughes12724852018-09-04 13:53:44 +01002104 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes525f71f2021-02-09 14:52:47 +00002105 "fu_plugin_backend_device_removed",
Richard Hughes4b303802019-10-04 13:22:51 +01002106 NULL,
Mario Limoncielloe260ead2018-09-01 09:19:24 -05002107 &error_local))
2108 g_warning ("%s", error_local->message);
2109}
2110
Mario Limonciello1a680f32019-11-25 19:44:53 -06002111/**
2112 * fu_plugin_runner_device_register:
2113 * @self: a #FuPlugin
2114 * @device: a #FuDevice
2115 *
2116 * Call the device_registered routine for the plugin
2117 *
2118 * Since: 0.9.7
2119 **/
Mario Limoncielloe260ead2018-09-01 09:19:24 -05002120void
Richard Hughes12724852018-09-04 13:53:44 +01002121fu_plugin_runner_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +01002122{
Richard Hughes12724852018-09-04 13:53:44 +01002123 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughese1fd34d2017-08-24 14:19:51 +01002124 FuPluginDeviceRegisterFunc func = NULL;
2125
2126 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002127 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughese1fd34d2017-08-24 14:19:51 +01002128 return;
Richard Hughes34834102017-11-21 21:55:00 +00002129 if (priv->module == NULL)
2130 return;
Richard Hughese1fd34d2017-08-24 14:19:51 +01002131
2132 /* optional */
2133 g_module_symbol (priv->module, "fu_plugin_device_registered", (gpointer *) &func);
2134 if (func != NULL) {
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002135 g_debug ("fu_plugin_device_registered(%s)", fu_plugin_get_name (self));
Richard Hughes12724852018-09-04 13:53:44 +01002136 func (self, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +01002137 }
2138}
2139
Mario Limonciello1a680f32019-11-25 19:44:53 -06002140/**
Richard Hughes0f66a022020-02-19 18:54:38 +00002141 * fu_plugin_runner_device_created:
2142 * @self: a #FuPlugin
2143 * @device: a #FuDevice
2144 * @error: a #GError or NULL
2145 *
2146 * Call the device_created routine for the plugin
2147 *
2148 * Returns: #TRUE for success, #FALSE for failure
2149 *
Mario Limonciello96117d12020-02-28 10:17:56 -06002150 * Since: 1.4.0
Richard Hughes0f66a022020-02-19 18:54:38 +00002151 **/
2152gboolean
2153fu_plugin_runner_device_created (FuPlugin *self, FuDevice *device, GError **error)
2154{
2155 FuPluginPrivate *priv = GET_PRIVATE (self);
2156 FuPluginDeviceFunc func = NULL;
2157
Richard Hughes6a489a92020-12-22 10:32:06 +00002158 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
2159 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
2160 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2161
Richard Hughes0f66a022020-02-19 18:54:38 +00002162 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002163 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes0f66a022020-02-19 18:54:38 +00002164 return TRUE;
2165 if (priv->module == NULL)
2166 return TRUE;
2167
2168 /* optional */
2169 g_module_symbol (priv->module, "fu_plugin_device_created", (gpointer *) &func);
2170 if (func == NULL)
2171 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002172 g_debug ("fu_plugin_device_created(%s)", fu_plugin_get_name (self));
Richard Hughes0f66a022020-02-19 18:54:38 +00002173 return func (self, device, error);
2174}
2175
2176/**
Mario Limonciello1a680f32019-11-25 19:44:53 -06002177 * fu_plugin_runner_verify:
2178 * @self: a #FuPlugin
2179 * @device: a #FuDevice
2180 * @flags: #FuPluginVerifyFlags
2181 * @error: A #GError or NULL
2182 *
2183 * Call into the plugin's verify routine
2184 *
2185 * Returns: #TRUE for success, #FALSE for failure
2186 *
2187 * Since: 0.8.0
2188 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002189gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002190fu_plugin_runner_verify (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +00002191 FuDevice *device,
2192 FuPluginVerifyFlags flags,
2193 GError **error)
2194{
Richard Hughes12724852018-09-04 13:53:44 +01002195 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00002196 FuPluginVerifyFunc func = NULL;
Richard Hughesababbb72017-06-15 20:18:36 +01002197 GPtrArray *checksums;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002198 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002199
Richard Hughes6a489a92020-12-22 10:32:06 +00002200 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
2201 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
2202 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2203
Richard Hughescff38bc2016-12-12 12:03:37 +00002204 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002205 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughescff38bc2016-12-12 12:03:37 +00002206 return TRUE;
2207
Richard Hughes639da472018-01-06 22:35:04 +00002208 /* no object loaded */
2209 if (priv->module == NULL)
2210 return TRUE;
2211
Richard Hughescff38bc2016-12-12 12:03:37 +00002212 /* optional */
2213 g_module_symbol (priv->module, "fu_plugin_verify", (gpointer *) &func);
Richard Hughes7f677212019-10-05 16:19:40 +01002214 if (func == NULL) {
Richard Hughes7f677212019-10-05 16:19:40 +01002215 return fu_plugin_device_read_firmware (self, device, error);
2216 }
Richard Hughes1812fc72018-12-14 11:37:54 +00002217
2218 /* clear any existing verification checksums */
2219 checksums = fu_device_get_checksums (device);
2220 g_ptr_array_set_size (checksums, 0);
2221
Richard Hughesc9223be2019-03-18 08:46:42 +00002222 /* run additional detach */
2223 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01002224 "fu_plugin_update_detach",
Richard Hughes4b303802019-10-04 13:22:51 +01002225 fu_plugin_device_detach,
Richard Hughesc9223be2019-03-18 08:46:42 +00002226 error))
2227 return FALSE;
2228
Richard Hughes1812fc72018-12-14 11:37:54 +00002229 /* run vfunc */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002230 g_debug ("verify(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002231 if (!func (self, device, flags, &error_local)) {
Richard Hughesc9223be2019-03-18 08:46:42 +00002232 g_autoptr(GError) error_attach = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002233 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05002234 g_critical ("unset plugin error in verify(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002235 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002236 g_set_error_literal (&error_local,
2237 FWUPD_ERROR,
2238 FWUPD_ERROR_INTERNAL,
2239 "unspecified error");
2240 }
2241 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2242 "failed to verify using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002243 fu_plugin_get_name (self));
Richard Hughesc9223be2019-03-18 08:46:42 +00002244 /* make the device "work" again, but don't prefix the error */
2245 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01002246 "fu_plugin_update_attach",
Richard Hughes4b303802019-10-04 13:22:51 +01002247 fu_plugin_device_attach,
Richard Hughesc9223be2019-03-18 08:46:42 +00002248 &error_attach)) {
2249 g_warning ("failed to attach whilst aborting verify(): %s",
2250 error_attach->message);
2251 }
Richard Hughesd0905142016-03-13 09:46:49 +00002252 return FALSE;
2253 }
Richard Hughesc9223be2019-03-18 08:46:42 +00002254
2255 /* run optional attach */
2256 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01002257 "fu_plugin_update_attach",
Richard Hughes4b303802019-10-04 13:22:51 +01002258 fu_plugin_device_attach,
Richard Hughesc9223be2019-03-18 08:46:42 +00002259 error))
2260 return FALSE;
2261
2262 /* success */
Richard Hughesd0905142016-03-13 09:46:49 +00002263 return TRUE;
2264}
2265
Mario Limonciello1a680f32019-11-25 19:44:53 -06002266/**
2267 * fu_plugin_runner_activate:
2268 * @self: a #FuPlugin
2269 * @device: a #FuDevice
2270 * @error: A #GError or NULL
2271 *
2272 * Call into the plugin's activate routine
2273 *
2274 * Returns: #TRUE for success, #FALSE for failure
2275 *
2276 * Since: 1.2.6
2277 **/
Richard Hughesd0905142016-03-13 09:46:49 +00002278gboolean
Mario Limonciello96a0dd52019-02-25 13:50:03 -06002279fu_plugin_runner_activate (FuPlugin *self, FuDevice *device, GError **error)
2280{
2281 guint64 flags;
2282
Richard Hughes6a489a92020-12-22 10:32:06 +00002283 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
2284 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
2285 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2286
Mario Limonciello96a0dd52019-02-25 13:50:03 -06002287 /* final check */
2288 flags = fu_device_get_flags (device);
2289 if ((flags & FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION) == 0) {
2290 g_set_error (error,
2291 FWUPD_ERROR,
2292 FWUPD_ERROR_NOT_SUPPORTED,
2293 "Device %s does not need activation",
2294 fu_device_get_id (device));
2295 return FALSE;
2296 }
2297
2298 /* run vfunc */
2299 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01002300 "fu_plugin_activate",
2301 fu_plugin_device_activate,
2302 error))
Mario Limonciello96a0dd52019-02-25 13:50:03 -06002303 return FALSE;
2304
2305 /* update with correct flags */
2306 fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION);
2307 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
2308 return TRUE;
2309}
2310
Mario Limonciello1a680f32019-11-25 19:44:53 -06002311/**
2312 * fu_plugin_runner_unlock:
2313 * @self: a #FuPlugin
2314 * @device: a #FuDevice
2315 * @error: A #GError or NULL
2316 *
2317 * Call into the plugin's unlock routine
2318 *
2319 * Returns: #TRUE for success, #FALSE for failure
2320 *
2321 * Since: 0.8.0
2322 **/
Mario Limonciello96a0dd52019-02-25 13:50:03 -06002323gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002324fu_plugin_runner_unlock (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00002325{
Richard Hughescff38bc2016-12-12 12:03:37 +00002326 guint64 flags;
Richard Hughescff38bc2016-12-12 12:03:37 +00002327
Richard Hughes6a489a92020-12-22 10:32:06 +00002328 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
2329 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
2330 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2331
Richard Hughescff38bc2016-12-12 12:03:37 +00002332 /* final check */
2333 flags = fu_device_get_flags (device);
2334 if ((flags & FWUPD_DEVICE_FLAG_LOCKED) == 0) {
2335 g_set_error (error,
2336 FWUPD_ERROR,
2337 FWUPD_ERROR_NOT_SUPPORTED,
2338 "Device %s is not locked",
2339 fu_device_get_id (device));
2340 return FALSE;
2341 }
2342
Richard Hughes9c4b5312017-11-14 11:34:53 +00002343 /* run vfunc */
Richard Hughes12724852018-09-04 13:53:44 +01002344 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01002345 "fu_plugin_unlock",
2346 NULL,
2347 error))
Richard Hughes9c4b5312017-11-14 11:34:53 +00002348 return FALSE;
Richard Hughescff38bc2016-12-12 12:03:37 +00002349
2350 /* update with correct flags */
Richard Hughesed0af242021-02-22 21:27:16 +00002351 fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_LOCKED);
Richard Hughescff38bc2016-12-12 12:03:37 +00002352 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
2353 return TRUE;
2354}
2355
Mario Limonciello1a680f32019-11-25 19:44:53 -06002356/**
2357 * fu_plugin_runner_update:
2358 * @self: a #FuPlugin
2359 * @device: a #FuDevice
2360 * @blob_fw: A #GBytes
2361 * @flags: A #FwupdInstallFlags
2362 * @error: A #GError or NULL
2363 *
2364 * Call into the plugin's update routine
2365 *
2366 * Returns: #TRUE for success, #FALSE for failure
2367 *
2368 * Since: 0.8.0
2369 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002370gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002371fu_plugin_runner_update (FuPlugin *self,
Richard Hughesa785a1c2017-08-25 16:00:58 +01002372 FuDevice *device,
Richard Hughesa785a1c2017-08-25 16:00:58 +01002373 GBytes *blob_fw,
2374 FwupdInstallFlags flags,
2375 GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00002376{
Richard Hughes12724852018-09-04 13:53:44 +01002377 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesa785a1c2017-08-25 16:00:58 +01002378 FuPluginUpdateFunc update_func;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002379 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002380
Richard Hughes6a489a92020-12-22 10:32:06 +00002381 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
2382 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
2383 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2384
Richard Hughescff38bc2016-12-12 12:03:37 +00002385 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002386 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) {
Richard Hughes41c15482018-02-01 22:07:21 +00002387 g_debug ("plugin not enabled, skipping");
Richard Hughesd0905142016-03-13 09:46:49 +00002388 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00002389 }
Richard Hughesd0905142016-03-13 09:46:49 +00002390
Richard Hughes639da472018-01-06 22:35:04 +00002391 /* no object loaded */
Richard Hughes41c15482018-02-01 22:07:21 +00002392 if (priv->module == NULL) {
2393 g_debug ("module not enabled, skipping");
Richard Hughes639da472018-01-06 22:35:04 +00002394 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00002395 }
Richard Hughes639da472018-01-06 22:35:04 +00002396
Richard Hughesd0905142016-03-13 09:46:49 +00002397 /* optional */
Richard Hughesa785a1c2017-08-25 16:00:58 +01002398 g_module_symbol (priv->module, "fu_plugin_update", (gpointer *) &update_func);
2399 if (update_func == NULL) {
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002400 g_debug ("superclassed write_firmware(%s)", fu_plugin_get_name (self));
Richard Hughes4b303802019-10-04 13:22:51 +01002401 return fu_plugin_device_write_firmware (self, device, blob_fw, flags, error);
Richard Hughesa785a1c2017-08-25 16:00:58 +01002402 }
Richard Hughesd0905142016-03-13 09:46:49 +00002403
Richard Hughescff38bc2016-12-12 12:03:37 +00002404 /* online */
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002405 if (!update_func (self, device, blob_fw, flags, &error_local)) {
2406 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05002407 g_critical ("unset plugin error in update(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002408 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002409 g_set_error_literal (&error_local,
Richard Hughes3c8ada32018-10-12 10:08:58 +01002410 FWUPD_ERROR,
2411 FWUPD_ERROR_INTERNAL,
2412 "unspecified error");
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002413 return FALSE;
Richard Hughes3c8ada32018-10-12 10:08:58 +01002414 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002415 fu_device_set_update_error (device, error_local->message);
2416 g_propagate_error (error, g_steal_pointer (&error_local));
Richard Hughescff38bc2016-12-12 12:03:37 +00002417 return FALSE;
2418 }
2419
Richard Hughesf556d372017-06-15 19:49:18 +01002420 /* no longer valid */
Richard Hughesf8039642019-01-16 12:22:22 +00002421 if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT) &&
2422 !fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) {
Richard Hughes08435162018-12-12 10:34:16 +00002423 GPtrArray *checksums = fu_device_get_checksums (device);
2424 g_ptr_array_set_size (checksums, 0);
2425 }
Richard Hughesf556d372017-06-15 19:49:18 +01002426
Richard Hughes019a1bc2019-11-26 10:19:33 +00002427 /* success */
Richard Hughesd0905142016-03-13 09:46:49 +00002428 return TRUE;
2429}
Richard Hughescff38bc2016-12-12 12:03:37 +00002430
Mario Limonciello1a680f32019-11-25 19:44:53 -06002431/**
2432 * fu_plugin_runner_clear_results:
2433 * @self: a #FuPlugin
2434 * @device: a #FuDevice
2435 * @error: A #GError or NULL
2436 *
2437 * Call into the plugin's clear results routine
2438 *
2439 * Returns: #TRUE for success, #FALSE for failure
2440 *
2441 * Since: 0.8.0
2442 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002443gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002444fu_plugin_runner_clear_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00002445{
Richard Hughes12724852018-09-04 13:53:44 +01002446 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00002447 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002448 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002449
Richard Hughes6a489a92020-12-22 10:32:06 +00002450 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
2451 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
2452 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2453
Richard Hughescff38bc2016-12-12 12:03:37 +00002454 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002455 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughescff38bc2016-12-12 12:03:37 +00002456 return TRUE;
2457
Richard Hughes639da472018-01-06 22:35:04 +00002458 /* no object loaded */
2459 if (priv->module == NULL)
2460 return TRUE;
2461
Richard Hughes65e44ca2018-01-30 17:26:30 +00002462 /* optional */
Richard Hughescd644902019-11-01 12:35:17 +00002463 g_module_symbol (priv->module, "fu_plugin_clear_results", (gpointer *) &func);
Richard Hughes65e44ca2018-01-30 17:26:30 +00002464 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00002465 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002466 g_debug ("clear_result(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002467 if (!func (self, device, &error_local)) {
2468 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05002469 g_critical ("unset plugin error in clear_result(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002470 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002471 g_set_error_literal (&error_local,
2472 FWUPD_ERROR,
2473 FWUPD_ERROR_INTERNAL,
2474 "unspecified error");
2475 }
2476 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2477 "failed to clear_result using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002478 fu_plugin_get_name (self));
Richard Hughescff38bc2016-12-12 12:03:37 +00002479 return FALSE;
2480 }
Richard Hughes65e44ca2018-01-30 17:26:30 +00002481 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00002482}
2483
Mario Limonciello1a680f32019-11-25 19:44:53 -06002484/**
2485 * fu_plugin_runner_get_results:
2486 * @self: a #FuPlugin
2487 * @device: a #FuDevice
2488 * @error: A #GError or NULL
2489 *
2490 * Call into the plugin's get results routine
2491 *
2492 * Returns: #TRUE for success, #FALSE for failure
2493 *
2494 * Since: 0.8.0
2495 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002496gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002497fu_plugin_runner_get_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00002498{
Richard Hughes12724852018-09-04 13:53:44 +01002499 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00002500 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002501 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002502
Richard Hughes6a489a92020-12-22 10:32:06 +00002503 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
2504 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
2505 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2506
Richard Hughescff38bc2016-12-12 12:03:37 +00002507 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002508 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughescff38bc2016-12-12 12:03:37 +00002509 return TRUE;
2510
Richard Hughes639da472018-01-06 22:35:04 +00002511 /* no object loaded */
2512 if (priv->module == NULL)
2513 return TRUE;
2514
Richard Hughes65e44ca2018-01-30 17:26:30 +00002515 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00002516 g_module_symbol (priv->module, "fu_plugin_get_results", (gpointer *) &func);
Richard Hughes65e44ca2018-01-30 17:26:30 +00002517 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00002518 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002519 g_debug ("get_results(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002520 if (!func (self, device, &error_local)) {
2521 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05002522 g_critical ("unset plugin error in get_results(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002523 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002524 g_set_error_literal (&error_local,
2525 FWUPD_ERROR,
2526 FWUPD_ERROR_INTERNAL,
2527 "unspecified error");
2528 }
2529 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2530 "failed to get_results using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002531 fu_plugin_get_name (self));
Richard Hughescff38bc2016-12-12 12:03:37 +00002532 return FALSE;
2533 }
Richard Hughescff38bc2016-12-12 12:03:37 +00002534 return TRUE;
2535}
2536
Richard Hughes08a37992017-09-12 12:57:43 +01002537/**
2538 * fu_plugin_get_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002539 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002540 *
2541 * Gets the plugin order, where higher numbers are run after lower
2542 * numbers.
2543 *
2544 * Returns: the integer value
Mario Limonciello1a680f32019-11-25 19:44:53 -06002545 *
2546 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002547 **/
2548guint
Richard Hughes12724852018-09-04 13:53:44 +01002549fu_plugin_get_order (FuPlugin *self)
Richard Hughes08a37992017-09-12 12:57:43 +01002550{
Richard Hughes12724852018-09-04 13:53:44 +01002551 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002552 return priv->order;
2553}
2554
2555/**
2556 * fu_plugin_set_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002557 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002558 * @order: a integer value
2559 *
2560 * Sets the plugin order, where higher numbers are run after lower
2561 * numbers.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002562 *
2563 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002564 **/
2565void
Richard Hughes12724852018-09-04 13:53:44 +01002566fu_plugin_set_order (FuPlugin *self, guint order)
Richard Hughes08a37992017-09-12 12:57:43 +01002567{
Richard Hughes12724852018-09-04 13:53:44 +01002568 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002569 priv->order = order;
2570}
2571
2572/**
Richard Hughes81c427c2018-08-06 15:20:17 +01002573 * fu_plugin_get_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002574 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01002575 *
2576 * Gets the plugin priority, where higher numbers are better.
2577 *
2578 * Returns: the integer value
Mario Limonciello1a680f32019-11-25 19:44:53 -06002579 *
2580 * Since: 1.1.1
Richard Hughes81c427c2018-08-06 15:20:17 +01002581 **/
2582guint
Richard Hughes12724852018-09-04 13:53:44 +01002583fu_plugin_get_priority (FuPlugin *self)
Richard Hughes81c427c2018-08-06 15:20:17 +01002584{
Richard Hughes12724852018-09-04 13:53:44 +01002585 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01002586 return priv->priority;
2587}
2588
2589/**
2590 * fu_plugin_set_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002591 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01002592 * @priority: a integer value
2593 *
2594 * Sets the plugin priority, where higher numbers are better.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002595 *
2596 * Since: 1.0.0
Richard Hughes81c427c2018-08-06 15:20:17 +01002597 **/
2598void
Richard Hughes12724852018-09-04 13:53:44 +01002599fu_plugin_set_priority (FuPlugin *self, guint priority)
Richard Hughes81c427c2018-08-06 15:20:17 +01002600{
Richard Hughes12724852018-09-04 13:53:44 +01002601 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01002602 priv->priority = priority;
2603}
2604
2605/**
Richard Hughes08a37992017-09-12 12:57:43 +01002606 * fu_plugin_add_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002607 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002608 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
Richard Hughes4eada342017-10-03 21:20:32 +01002609 * @name: a plugin name, e.g. `upower`
Richard Hughes08a37992017-09-12 12:57:43 +01002610 *
2611 * If the plugin name is found, the rule will be used to sort the plugin list,
2612 * for example the plugin specified by @name will be ordered after this plugin
2613 * when %FU_PLUGIN_RULE_RUN_AFTER is used.
2614 *
2615 * NOTE: The depsolver is iterative and may not solve overly-complicated rules;
2616 * If depsolving fails then fwupd will not start.
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_add_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
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 Hughes11c59412020-06-22 15:29:48 +01002624 if (priv->rules[rule] == NULL)
2625 priv->rules[rule] = g_ptr_array_new_with_free_func (g_free);
Richard Hughes08a37992017-09-12 12:57:43 +01002626 g_ptr_array_add (priv->rules[rule], g_strdup (name));
Richard Hughes75b965d2018-11-15 13:51:21 +00002627 g_signal_emit (self, signals[SIGNAL_RULES_CHANGED], 0);
Richard Hughes08a37992017-09-12 12:57:43 +01002628}
2629
2630/**
2631 * fu_plugin_get_rules:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002632 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002633 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
2634 *
2635 * Gets the plugin IDs that should be run after this plugin.
2636 *
Richard Hughes11c59412020-06-22 15:29:48 +01002637 * Returns: (element-type utf8) (transfer none) (nullable): the list of plugin names, e.g. ['appstream']
Mario Limonciello1a680f32019-11-25 19:44:53 -06002638 *
2639 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002640 **/
2641GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +01002642fu_plugin_get_rules (FuPlugin *self, FuPluginRule rule)
Richard Hughes08a37992017-09-12 12:57:43 +01002643{
Richard Hughes12724852018-09-04 13:53:44 +01002644 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughesdad35972019-12-06 11:00:25 +00002645 g_return_val_if_fail (rule < FU_PLUGIN_RULE_LAST, NULL);
Richard Hughes08a37992017-09-12 12:57:43 +01002646 return priv->rules[rule];
2647}
2648
Richard Hughes80b79bb2018-01-11 21:11:06 +00002649/**
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002650 * fu_plugin_has_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002651 * @self: a #FuPlugin
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002652 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
2653 * @name: a plugin name, e.g. `upower`
2654 *
Richard Hughes87fb9ff2018-06-28 12:55:59 +01002655 * Gets the plugin IDs that should be run after this plugin.
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002656 *
2657 * Returns: %TRUE if the name exists for the specific rule
Mario Limonciello1a680f32019-11-25 19:44:53 -06002658 *
2659 * Since: 1.0.0
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002660 **/
2661gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002662fu_plugin_has_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002663{
Richard Hughes12724852018-09-04 13:53:44 +01002664 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes11c59412020-06-22 15:29:48 +01002665 if (priv->rules[rule] == NULL)
2666 return FALSE;
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002667 for (guint i = 0; i < priv->rules[rule]->len; i++) {
2668 const gchar *tmp = g_ptr_array_index (priv->rules[rule], i);
2669 if (g_strcmp0 (tmp, name) == 0)
2670 return TRUE;
2671 }
2672 return FALSE;
2673}
2674
2675/**
Richard Hughes80b79bb2018-01-11 21:11:06 +00002676 * fu_plugin_add_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002677 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00002678 * @key: a string, e.g. `FwupdateVersion`
2679 * @value: a string, e.g. `10`
2680 *
2681 * Sets any additional metadata to be included in the firmware report to aid
2682 * debugging problems.
2683 *
2684 * Any data included here will be sent to the metadata server after user
2685 * confirmation.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002686 *
2687 * Since: 1.0.4
Richard Hughes80b79bb2018-01-11 21:11:06 +00002688 **/
2689void
Richard Hughes12724852018-09-04 13:53:44 +01002690fu_plugin_add_report_metadata (FuPlugin *self, const gchar *key, const gchar *value)
Richard Hughes80b79bb2018-01-11 21:11:06 +00002691{
Richard Hughes12724852018-09-04 13:53:44 +01002692 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes1d900f72020-06-22 15:17:39 +01002693 if (priv->report_metadata == NULL) {
2694 priv->report_metadata = g_hash_table_new_full (g_str_hash,
2695 g_str_equal,
2696 g_free,
2697 g_free);
2698 }
Richard Hughes80b79bb2018-01-11 21:11:06 +00002699 g_hash_table_insert (priv->report_metadata, g_strdup (key), g_strdup (value));
2700}
2701
2702/**
2703 * fu_plugin_get_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002704 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00002705 *
2706 * Returns the list of additional metadata to be added when filing a report.
2707 *
Richard Hughes1d900f72020-06-22 15:17:39 +01002708 * Returns: (transfer none) (nullable): the map of report metadata
Mario Limonciello1a680f32019-11-25 19:44:53 -06002709 *
2710 * Since: 1.0.4
Richard Hughes80b79bb2018-01-11 21:11:06 +00002711 **/
2712GHashTable *
Richard Hughes12724852018-09-04 13:53:44 +01002713fu_plugin_get_report_metadata (FuPlugin *self)
Richard Hughes80b79bb2018-01-11 21:11:06 +00002714{
Richard Hughes12724852018-09-04 13:53:44 +01002715 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002716 return priv->report_metadata;
2717}
2718
Mario Limonciello963dc422018-02-27 14:26:58 -06002719/**
2720 * fu_plugin_get_config_value:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002721 * @self: a #FuPlugin
Mario Limonciello963dc422018-02-27 14:26:58 -06002722 * @key: A settings key
2723 *
2724 * Return the value of a key if it's been configured
2725 *
2726 * Since: 1.0.6
2727 **/
2728gchar *
Richard Hughes12724852018-09-04 13:53:44 +01002729fu_plugin_get_config_value (FuPlugin *self, const gchar *key)
Mario Limonciello963dc422018-02-27 14:26:58 -06002730{
Richard Hughes4be17d12018-05-30 20:36:29 +01002731 g_autofree gchar *conf_dir = NULL;
Mario Limonciello963dc422018-02-27 14:26:58 -06002732 g_autofree gchar *conf_file = NULL;
2733 g_autofree gchar *conf_path = NULL;
2734 g_autoptr(GKeyFile) keyfile = NULL;
2735 const gchar *plugin_name;
2736
Richard Hughes4be17d12018-05-30 20:36:29 +01002737 conf_dir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR_PKG);
Richard Hughes12724852018-09-04 13:53:44 +01002738 plugin_name = fu_plugin_get_name (self);
Mario Limonciello963dc422018-02-27 14:26:58 -06002739 conf_file = g_strdup_printf ("%s.conf", plugin_name);
Richard Hughes4be17d12018-05-30 20:36:29 +01002740 conf_path = g_build_filename (conf_dir, conf_file, NULL);
Mario Limonciello963dc422018-02-27 14:26:58 -06002741 if (!g_file_test (conf_path, G_FILE_TEST_IS_REGULAR))
2742 return NULL;
2743 keyfile = g_key_file_new ();
2744 if (!g_key_file_load_from_file (keyfile, conf_path,
2745 G_KEY_FILE_NONE, NULL))
2746 return NULL;
2747 return g_key_file_get_string (keyfile, plugin_name, key, NULL);
2748}
2749
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002750/**
Richard Hughes334ba792020-02-19 20:44:56 +00002751 * fu_plugin_get_config_value_boolean:
2752 * @self: a #FuPlugin
2753 * @key: A settings key
2754 *
2755 * Return the boolean value of a key if it's been configured
2756 *
2757 * Returns: %TRUE if the value is `true` (case insensitive), %FALSE otherwise
2758 *
Mario Limonciello96117d12020-02-28 10:17:56 -06002759 * Since: 1.4.0
Richard Hughes334ba792020-02-19 20:44:56 +00002760 **/
2761gboolean
2762fu_plugin_get_config_value_boolean (FuPlugin *self, const gchar *key)
2763{
2764 g_autofree gchar *tmp = fu_plugin_get_config_value (self, key);
2765 if (tmp == NULL)
2766 return FALSE;
Richard Hughes5337a432020-02-21 12:04:32 +00002767 return g_ascii_strcasecmp (tmp, "true") == 0;
Richard Hughes334ba792020-02-19 20:44:56 +00002768}
2769
2770/**
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002771 * fu_plugin_name_compare:
2772 * @plugin1: first #FuPlugin to compare.
2773 * @plugin2: second #FuPlugin to compare.
2774 *
2775 * Compares two plugins by their names.
2776 *
2777 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002778 *
2779 * Since: 1.0.8
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002780 **/
2781gint
2782fu_plugin_name_compare (FuPlugin *plugin1, FuPlugin *plugin2)
2783{
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002784 return g_strcmp0 (fu_plugin_get_name (plugin1), fu_plugin_get_name (plugin2));
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002785}
2786
2787/**
2788 * fu_plugin_order_compare:
2789 * @plugin1: first #FuPlugin to compare.
2790 * @plugin2: second #FuPlugin to compare.
2791 *
2792 * Compares two plugins by their depsolved order.
2793 *
2794 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002795 *
2796 * Since: 1.0.8
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002797 **/
2798gint
2799fu_plugin_order_compare (FuPlugin *plugin1, FuPlugin *plugin2)
2800{
2801 FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1);
2802 FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2);
2803 if (priv1->order < priv2->order)
2804 return -1;
2805 if (priv1->order > priv2->order)
2806 return 1;
2807 return 0;
2808}
2809
Richard Hughescff38bc2016-12-12 12:03:37 +00002810static void
2811fu_plugin_class_init (FuPluginClass *klass)
2812{
2813 GObjectClass *object_class = G_OBJECT_CLASS (klass);
2814 object_class->finalize = fu_plugin_finalize;
2815 signals[SIGNAL_DEVICE_ADDED] =
2816 g_signal_new ("device-added",
2817 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2818 G_STRUCT_OFFSET (FuPluginClass, device_added),
2819 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2820 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
2821 signals[SIGNAL_DEVICE_REMOVED] =
2822 g_signal_new ("device-removed",
2823 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2824 G_STRUCT_OFFSET (FuPluginClass, device_removed),
2825 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2826 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughese1fd34d2017-08-24 14:19:51 +01002827 signals[SIGNAL_DEVICE_REGISTER] =
2828 g_signal_new ("device-register",
2829 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2830 G_STRUCT_OFFSET (FuPluginClass, device_register),
2831 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2832 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughes362d6d72017-01-07 21:42:14 +00002833 signals[SIGNAL_RECOLDPLUG] =
2834 g_signal_new ("recoldplug",
2835 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2836 G_STRUCT_OFFSET (FuPluginClass, recoldplug),
2837 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2838 G_TYPE_NONE, 0);
Richard Hughes399859e2020-05-11 19:44:03 +01002839 signals[SIGNAL_SECURITY_CHANGED] =
2840 g_signal_new ("security-changed",
2841 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2842 G_STRUCT_OFFSET (FuPluginClass, security_changed),
2843 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2844 G_TYPE_NONE, 0);
Richard Hughesb0829032017-01-10 09:27:08 +00002845 signals[SIGNAL_SET_COLDPLUG_DELAY] =
2846 g_signal_new ("set-coldplug-delay",
2847 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2848 G_STRUCT_OFFSET (FuPluginClass, set_coldplug_delay),
2849 NULL, NULL, g_cclosure_marshal_VOID__UINT,
2850 G_TYPE_NONE, 1, G_TYPE_UINT);
Richard Hughesaabdc372018-11-14 10:11:08 +00002851 signals[SIGNAL_CHECK_SUPPORTED] =
2852 g_signal_new ("check-supported",
2853 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2854 G_STRUCT_OFFSET (FuPluginClass, check_supported),
2855 NULL, NULL, g_cclosure_marshal_generic,
2856 G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
Richard Hughes75b965d2018-11-15 13:51:21 +00002857 signals[SIGNAL_RULES_CHANGED] =
2858 g_signal_new ("rules-changed",
2859 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2860 G_STRUCT_OFFSET (FuPluginClass, rules_changed),
2861 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2862 G_TYPE_NONE, 0);
Richard Hughes95c98a92019-10-22 16:03:15 +01002863 signals[SIGNAL_ADD_FIRMWARE_GTYPE] =
2864 g_signal_new ("add-firmware-gtype",
2865 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2866 G_STRUCT_OFFSET (FuPluginClass, add_firmware_gtype),
2867 NULL, NULL, g_cclosure_marshal_generic,
2868 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_GTYPE);
Richard Hughescff38bc2016-12-12 12:03:37 +00002869}
2870
2871static void
Richard Hughes12724852018-09-04 13:53:44 +01002872fu_plugin_init (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +00002873{
Richard Hughes12724852018-09-04 13:53:44 +01002874 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesfaf2afe2021-01-13 14:00:20 +00002875 g_rw_lock_init (&priv->cache_mutex);
Richard Hughescff38bc2016-12-12 12:03:37 +00002876}
2877
2878static void
2879fu_plugin_finalize (GObject *object)
2880{
Richard Hughes12724852018-09-04 13:53:44 +01002881 FuPlugin *self = FU_PLUGIN (object);
2882 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002883 FuPluginInitFunc func = NULL;
2884
Richard Hughesfaf2afe2021-01-13 14:00:20 +00002885 g_rw_lock_clear (&priv->cache_mutex);
Richard Hughesaae22e42020-06-22 21:32:59 +01002886
Richard Hughescff38bc2016-12-12 12:03:37 +00002887 /* optional */
2888 if (priv->module != NULL) {
2889 g_module_symbol (priv->module, "fu_plugin_destroy", (gpointer *) &func);
2890 if (func != NULL) {
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002891 g_debug ("destroy(%s)", fu_plugin_get_name (self));
Richard Hughes12724852018-09-04 13:53:44 +01002892 func (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002893 }
2894 }
2895
Richard Hughes11c59412020-06-22 15:29:48 +01002896 for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++) {
2897 if (priv->rules[i] != NULL)
2898 g_ptr_array_unref (priv->rules[i]);
2899 }
Richard Hughes68ab1e42021-01-13 14:01:17 +00002900 if (priv->devices != NULL)
2901 g_ptr_array_unref (priv->devices);
Richard Hughesb8f8db22017-04-25 15:56:00 +01002902 if (priv->hwids != NULL)
Richard Hughesd7704d42017-08-08 20:29:09 +01002903 g_object_unref (priv->hwids);
Richard Hughes9c028f02017-10-28 21:14:28 +01002904 if (priv->quirks != NULL)
2905 g_object_unref (priv->quirks);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01002906 if (priv->udev_subsystems != NULL)
2907 g_ptr_array_unref (priv->udev_subsystems);
Richard Hughes49e5e052017-09-03 12:15:41 +01002908 if (priv->smbios != NULL)
2909 g_object_unref (priv->smbios);
Richard Hughes275d3b42018-04-20 16:40:37 +01002910 if (priv->runtime_versions != NULL)
2911 g_hash_table_unref (priv->runtime_versions);
Richard Hughes34e0dab2018-04-20 16:43:00 +01002912 if (priv->compile_versions != NULL)
2913 g_hash_table_unref (priv->compile_versions);
Richard Hughes1d900f72020-06-22 15:17:39 +01002914 if (priv->report_metadata != NULL)
2915 g_hash_table_unref (priv->report_metadata);
Richard Hughesfaf2afe2021-01-13 14:00:20 +00002916 if (priv->cache != NULL)
2917 g_hash_table_unref (priv->cache);
Richard Hughes84999302019-05-02 10:18:32 +01002918 g_free (priv->build_hash);
Richard Hughescff38bc2016-12-12 12:03:37 +00002919 g_free (priv->data);
Mario Limonciello3f9a1c12018-06-06 14:06:40 -05002920 /* Must happen as the last step to avoid prematurely
2921 * freeing memory held by the plugin */
Richard Hughes862ec5c2020-05-22 14:38:02 +01002922#ifdef RUNNING_ON_VALGRIND
2923 if (priv->module != NULL && RUNNING_ON_VALGRIND == 0)
2924#else
Mario Limonciello3f9a1c12018-06-06 14:06:40 -05002925 if (priv->module != NULL)
Mario Limonciello3f9a1c12018-06-06 14:06:40 -05002926#endif
Richard Hughes862ec5c2020-05-22 14:38:02 +01002927 g_module_close (priv->module);
Richard Hughescff38bc2016-12-12 12:03:37 +00002928
2929 G_OBJECT_CLASS (fu_plugin_parent_class)->finalize (object);
2930}
2931
Mario Limonciello1a680f32019-11-25 19:44:53 -06002932/**
2933 * fu_plugin_new:
2934 *
2935 * Creates a new #FuPlugin
2936 *
2937 * Since: 0.8.0
2938 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002939FuPlugin *
2940fu_plugin_new (void)
2941{
Richard Hughes12724852018-09-04 13:53:44 +01002942 return FU_PLUGIN (g_object_new (FU_TYPE_PLUGIN, NULL));
Richard Hughescff38bc2016-12-12 12:03:37 +00002943}