blob: a4a48705203ba6acc69edeef8705fb97a64e13be [file] [log] [blame]
Richard Hughes02c90d82018-08-09 12:13:03 +01001/*
Richard Hughes2de8f132018-01-17 09:12:02 +00002 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
Richard Hughesd0905142016-03-13 09:46:49 +00003 *
Mario Limonciello51308e62018-05-28 20:05:46 -05004 * SPDX-License-Identifier: LGPL-2.1+
Richard Hughesd0905142016-03-13 09:46:49 +00005 */
6
Richard Hughesb08e7bc2018-09-11 10:51:13 +01007#define G_LOG_DOMAIN "FuPlugin"
8
Richard Hughesd0905142016-03-13 09:46:49 +00009#include "config.h"
10
Richard Hughescff38bc2016-12-12 12:03:37 +000011#include <fwupd.h>
12#include <gmodule.h>
Richard Hughescff38bc2016-12-12 12:03:37 +000013#include <errno.h>
14#include <string.h>
Richard Hughes68f12dd2018-08-09 14:43:31 +010015#include <unistd.h>
Mario Limonciello6d0aa3d2017-02-28 08:22:27 -060016#ifdef HAVE_VALGRIND
Richard Hughes576c0122017-02-24 09:47:00 +000017#include <valgrind.h>
Mario Limonciello6d0aa3d2017-02-28 08:22:27 -060018#endif /* HAVE_VALGRIND */
Richard Hughesd0905142016-03-13 09:46:49 +000019
Richard Hughes9dde04f2017-09-13 12:07:15 +010020#include "fu-device-private.h"
Richard Hughescff38bc2016-12-12 12:03:37 +000021#include "fu-plugin-private.h"
Richard Hughes37d09432018-09-09 10:39:45 +010022#include "fu-mutex.h"
Richard Hughesd0905142016-03-13 09:46:49 +000023
Richard Hughes4eada342017-10-03 21:20:32 +010024/**
25 * SECTION:fu-plugin
26 * @short_description: a daemon plugin
27 *
28 * An object that represents a plugin run by the daemon.
29 *
30 * See also: #FuDevice
31 */
32
Richard Hughesb0829032017-01-10 09:27:08 +000033#define FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM 3000u /* ms */
34
Richard Hughescff38bc2016-12-12 12:03:37 +000035static void fu_plugin_finalize (GObject *object);
36
37typedef struct {
38 GModule *module;
39 GUsbContext *usb_ctx;
Richard Hughes08a37992017-09-12 12:57:43 +010040 guint order;
Richard Hughes81c427c2018-08-06 15:20:17 +010041 guint priority;
Richard Hughes08a37992017-09-12 12:57:43 +010042 GPtrArray *rules[FU_PLUGIN_RULE_LAST];
Richard 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 Hughes371f6b22020-06-22 15:21:17 +010051 GHashTable *devices; /* (nullable): platform_id:GObject */
Richard Hughes161e9b52019-06-12 14:22:45 +010052 GRWLock devices_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 Hughes12724852018-09-04 13:53:44 +0100100typedef gboolean (*FuPluginUsbDeviceAddedFunc) (FuPlugin *self,
Richard Hughesff704412018-09-04 11:28:32 +0100101 FuUsbDevice *device,
Richard Hughes104f6512017-11-24 11:44:57 +0000102 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +0100103typedef gboolean (*FuPluginUdevDeviceAddedFunc) (FuPlugin *self,
Richard Hughesff704412018-09-04 11:28:32 +0100104 FuUdevDevice *device,
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100105 GError **error);
Richard Hughesf58ac732020-05-12 15:23:44 +0100106typedef void (*FuPluginSecurityAttrsFunc) (FuPlugin *self,
107 FuSecurityAttrs *attrs);
Richard Hughescff38bc2016-12-12 12:03:37 +0000108
Richard Hughes57d18222017-01-10 16:02:59 +0000109/**
Mario Limonciello52e75ba2019-11-22 13:21:19 -0600110 * fu_plugin_is_open:
111 * @self: A #FuPlugin
112 *
113 * Determines if the plugin is opened
114 *
115 * Returns: TRUE for opened, FALSE for not
116 *
117 * Since: 1.3.5
118 **/
119gboolean
120fu_plugin_is_open (FuPlugin *self)
121{
122 FuPluginPrivate *priv = GET_PRIVATE (self);
123 return priv->module != NULL;
124}
125
126/**
Richard Hughes57d18222017-01-10 16:02:59 +0000127 * fu_plugin_get_name:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100128 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000129 *
130 * Gets the plugin name.
131 *
132 * Returns: a plugin name, or %NULL for unknown.
133 *
134 * Since: 0.8.0
135 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000136const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100137fu_plugin_get_name (FuPlugin *self)
Richard Hughesd0905142016-03-13 09:46:49 +0000138{
Richard Hughes12724852018-09-04 13:53:44 +0100139 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100140 return fwupd_plugin_get_name (FWUPD_PLUGIN (self));
Richard Hughescff38bc2016-12-12 12:03:37 +0000141}
Richard Hughesd0905142016-03-13 09:46:49 +0000142
Mario Limonciello1a680f32019-11-25 19:44:53 -0600143/**
144 * fu_plugin_set_name:
145 * @self: A #FuPlugin
146 * @name: A string
147 *
148 * Sets the plugin name.
149 *
150 * Since: 0.8.0
151 **/
Richard Hughes34834102017-11-21 21:55:00 +0000152void
Richard Hughes12724852018-09-04 13:53:44 +0100153fu_plugin_set_name (FuPlugin *self, const gchar *name)
Richard Hughes34834102017-11-21 21:55:00 +0000154{
Richard Hughes12724852018-09-04 13:53:44 +0100155 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100156 fwupd_plugin_set_name (FWUPD_PLUGIN (self), name);
Richard Hughes34834102017-11-21 21:55:00 +0000157}
158
Richard Hughes57d18222017-01-10 16:02:59 +0000159/**
Richard Hughesf425d292019-01-18 17:57:39 +0000160 * fu_plugin_set_build_hash:
161 * @self: A #FuPlugin
162 * @build_hash: A checksum
163 *
164 * Sets the plugin build hash, typically a SHA256 checksum. All plugins must
165 * set the correct checksum to avoid the daemon being marked as tainted.
166 *
167 * Since: 1.2.4
168 **/
169void
170fu_plugin_set_build_hash (FuPlugin *self, const gchar *build_hash)
171{
172 FuPluginPrivate *priv = GET_PRIVATE (self);
173 g_return_if_fail (FU_IS_PLUGIN (self));
174 g_return_if_fail (build_hash != NULL);
175 g_free (priv->build_hash);
176 priv->build_hash = g_strdup (build_hash);
177}
178
Mario Limonciello1a680f32019-11-25 19:44:53 -0600179/**
180 * fu_plugin_get_build_hash:
181 * @self: A #FuPlugin
182 *
183 * Gets the build hash a plugin was generated with.
184 *
185 * Returns: (transfer none): a #gchar, or %NULL for unset.
186 *
187 * Since: 1.2.4
188 **/
Richard Hughesf425d292019-01-18 17:57:39 +0000189const gchar *
190fu_plugin_get_build_hash (FuPlugin *self)
191{
192 FuPluginPrivate *priv = GET_PRIVATE (self);
193 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
194 return priv->build_hash;
195}
196
197/**
Richard Hughes57d18222017-01-10 16:02:59 +0000198 * fu_plugin_cache_lookup:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100199 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000200 * @id: the key
201 *
202 * Finds an object in the per-plugin cache.
203 *
204 * Returns: (transfer none): a #GObject, or %NULL for unfound.
205 *
206 * Since: 0.8.0
207 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000208gpointer
Richard Hughes12724852018-09-04 13:53:44 +0100209fu_plugin_cache_lookup (FuPlugin *self, const gchar *id)
Richard Hughescff38bc2016-12-12 12:03:37 +0000210{
Richard Hughes12724852018-09-04 13:53:44 +0100211 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes161e9b52019-06-12 14:22:45 +0100212 g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100213 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughesccd78a92017-01-11 16:57:41 +0000214 g_return_val_if_fail (id != NULL, NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100215 g_return_val_if_fail (locker != NULL, NULL);
Richard Hughes371f6b22020-06-22 15:21:17 +0100216 if (priv->devices == NULL)
217 return NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000218 return g_hash_table_lookup (priv->devices, id);
219}
Richard Hughesd0905142016-03-13 09:46:49 +0000220
Richard Hughes57d18222017-01-10 16:02:59 +0000221/**
222 * fu_plugin_cache_add:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100223 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000224 * @id: the key
225 * @dev: a #GObject, typically a #FuDevice
226 *
227 * Adds an object to the per-plugin cache.
228 *
229 * Since: 0.8.0
230 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000231void
Richard Hughes12724852018-09-04 13:53:44 +0100232fu_plugin_cache_add (FuPlugin *self, const gchar *id, gpointer dev)
Richard Hughescff38bc2016-12-12 12:03:37 +0000233{
Richard Hughes12724852018-09-04 13:53:44 +0100234 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0fe49142019-11-22 16:56:38 +0000235 g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100236 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000237 g_return_if_fail (id != NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100238 g_return_if_fail (locker != NULL);
Richard Hughes371f6b22020-06-22 15:21:17 +0100239 if (priv->devices == NULL) {
240 priv->devices = g_hash_table_new_full (g_str_hash,
241 g_str_equal,
242 g_free,
243 (GDestroyNotify) g_object_unref);
244 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000245 g_hash_table_insert (priv->devices, g_strdup (id), g_object_ref (dev));
246}
247
Richard Hughes57d18222017-01-10 16:02:59 +0000248/**
249 * fu_plugin_cache_remove:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100250 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000251 * @id: the key
252 *
253 * Removes an object from the per-plugin cache.
254 *
255 * Since: 0.8.0
256 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000257void
Richard Hughes12724852018-09-04 13:53:44 +0100258fu_plugin_cache_remove (FuPlugin *self, const gchar *id)
Richard Hughescff38bc2016-12-12 12:03:37 +0000259{
Richard Hughes12724852018-09-04 13:53:44 +0100260 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0fe49142019-11-22 16:56:38 +0000261 g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100262 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000263 g_return_if_fail (id != NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100264 g_return_if_fail (locker != NULL);
Richard Hughes371f6b22020-06-22 15:21:17 +0100265 if (priv->devices == NULL)
266 return;
Richard Hughescff38bc2016-12-12 12:03:37 +0000267 g_hash_table_remove (priv->devices, id);
268}
269
Richard Hughes57d18222017-01-10 16:02:59 +0000270/**
271 * fu_plugin_get_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100272 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000273 *
Richard Hughes4eada342017-10-03 21:20:32 +0100274 * Gets the per-plugin allocated private data. This will return %NULL unless
275 * fu_plugin_alloc_data() has been called by the plugin.
Richard Hughes57d18222017-01-10 16:02:59 +0000276 *
Richard Hughes4eada342017-10-03 21:20:32 +0100277 * Returns: (transfer none): a pointer to a structure, or %NULL for unset.
Richard Hughes57d18222017-01-10 16:02:59 +0000278 *
279 * Since: 0.8.0
280 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000281FuPluginData *
Richard Hughes12724852018-09-04 13:53:44 +0100282fu_plugin_get_data (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +0000283{
Richard Hughes12724852018-09-04 13:53:44 +0100284 FuPluginPrivate *priv = GET_PRIVATE (self);
285 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000286 return priv->data;
287}
288
Richard Hughes57d18222017-01-10 16:02:59 +0000289/**
Richard Hughes00f66f62019-11-27 11:42:53 +0000290 * fu_plugin_alloc_data: (skip):
Richard Hughes2c0635a2018-09-04 14:52:46 +0100291 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000292 * @data_sz: the size to allocate
293 *
294 * Allocates the per-plugin allocated private data.
295 *
296 * Returns: (transfer full): a pointer to a structure, or %NULL for unset.
297 *
298 * Since: 0.8.0
299 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000300FuPluginData *
Richard Hughes12724852018-09-04 13:53:44 +0100301fu_plugin_alloc_data (FuPlugin *self, gsize data_sz)
Richard Hughescff38bc2016-12-12 12:03:37 +0000302{
Richard Hughes12724852018-09-04 13:53:44 +0100303 FuPluginPrivate *priv = GET_PRIVATE (self);
304 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes44dee882017-01-11 08:31:10 +0000305 if (priv->data != NULL) {
306 g_critical ("fu_plugin_alloc_data() already used by plugin");
307 return priv->data;
308 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000309 priv->data = g_malloc0 (data_sz);
310 return priv->data;
Richard Hughesd0905142016-03-13 09:46:49 +0000311}
312
Richard Hughes57d18222017-01-10 16:02:59 +0000313/**
314 * fu_plugin_get_usb_context:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100315 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000316 *
317 * Gets the shared USB context that all plugins can use.
318 *
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 FuPluginPrivate *priv = GET_PRIVATE (self);
327 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000328 return priv->usb_ctx;
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000329}
330
Mario Limonciello1a680f32019-11-25 19:44:53 -0600331/**
332 * fu_plugin_set_usb_context:
333 * @self: A #FuPlugin
334 * @usb_ctx: A #FGUsbContext
335 *
336 * Sets the shared USB context for a plugin
337 *
338 * Since: 0.8.0
339 **/
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000340void
Richard Hughes12724852018-09-04 13:53:44 +0100341fu_plugin_set_usb_context (FuPlugin *self, GUsbContext *usb_ctx)
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000342{
Richard Hughes12724852018-09-04 13:53:44 +0100343 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +0000344 g_set_object (&priv->usb_ctx, usb_ctx);
345}
346
Richard Hughes57d18222017-01-10 16:02:59 +0000347/**
348 * fu_plugin_get_enabled:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100349 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000350 *
Richard Hughes4eada342017-10-03 21:20:32 +0100351 * Returns if the plugin is enabled. Plugins may self-disable using
352 * fu_plugin_set_enabled() or can be disabled by the daemon.
Richard Hughes57d18222017-01-10 16:02:59 +0000353 *
354 * Returns: %TRUE if the plugin is currently enabled.
355 *
356 * Since: 0.8.0
357 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000358gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100359fu_plugin_get_enabled (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +0000360{
Richard Hughes12724852018-09-04 13:53:44 +0100361 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100362 return !fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED);
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000363}
364
Richard Hughes57d18222017-01-10 16:02:59 +0000365/**
366 * fu_plugin_set_enabled:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100367 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000368 * @enabled: the enabled value
369 *
370 * Enables or disables a plugin. Plugins can self-disable at any point.
371 *
372 * Since: 0.8.0
373 **/
Richard Hughesd0905142016-03-13 09:46:49 +0000374void
Richard Hughes12724852018-09-04 13:53:44 +0100375fu_plugin_set_enabled (FuPlugin *self, gboolean enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000376{
Richard Hughes12724852018-09-04 13:53:44 +0100377 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100378 if (enabled) {
379 fwupd_plugin_remove_flag (FWUPD_PLUGIN (self),
380 FWUPD_PLUGIN_FLAG_DISABLED);
381 } else {
382 fu_plugin_add_flag (self, FWUPD_PLUGIN_FLAG_DISABLED);
383 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000384}
385
Mario Limonciello1a680f32019-11-25 19:44:53 -0600386/**
387 * fu_plugin_guess_name_from_fn:
388 * @filename: filename to guess
389 *
390 * Tries to guess the name of the plugin from a filename
391 *
392 * Returns: (transfer full): the guessed name of the plugin
393 *
394 * Since: 1.0.8
395 **/
Richard Hughes1e456bc2018-05-10 20:16:16 +0100396gchar *
397fu_plugin_guess_name_from_fn (const gchar *filename)
398{
399 const gchar *prefix = "libfu_plugin_";
400 gchar *name;
401 gchar *str = g_strstr_len (filename, -1, prefix);
402 if (str == NULL)
403 return NULL;
404 name = g_strdup (str + strlen (prefix));
405 g_strdelimit (name, ".", '\0');
406 return name;
407}
408
Mario Limonciello1a680f32019-11-25 19:44:53 -0600409/**
410 * fu_plugin_open:
411 * @self: A #FuPlugin
412 * @filename: The shared object filename to open
413 * @error: A #GError or NULL
414 *
415 * Opens the plugin module
416 *
417 * Returns: TRUE for success, FALSE for fail
418 *
419 * Since: 0.8.0
420 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000421gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100422fu_plugin_open (FuPlugin *self, const gchar *filename, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +0000423{
Richard Hughes12724852018-09-04 13:53:44 +0100424 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +0000425 FuPluginInitFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000426
Richard Hughes6a489a92020-12-22 10:32:06 +0000427 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
428 g_return_val_if_fail (filename != NULL, FALSE);
429 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
430
Richard Hughescff38bc2016-12-12 12:03:37 +0000431 priv->module = g_module_open (filename, 0);
432 if (priv->module == NULL) {
433 g_set_error (error,
434 G_IO_ERROR,
435 G_IO_ERROR_FAILED,
Mario Limonciellof5605532019-11-04 07:49:50 -0600436 "failed to open plugin %s: %s",
437 filename, g_module_error ());
Mario Limoncielloc3a81732020-10-20 09:16:18 -0500438 fu_plugin_add_flag (self, FWUPD_PLUGIN_FLAG_FAILED_OPEN);
439 fu_plugin_add_flag (self, FWUPD_PLUGIN_FLAG_USER_WARNING);
Richard Hughescff38bc2016-12-12 12:03:37 +0000440 return FALSE;
441 }
442
443 /* set automatically */
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100444 if (fu_plugin_get_name (self) == NULL) {
445 g_autofree gchar *str = fu_plugin_guess_name_from_fn (filename);
446 fu_plugin_set_name (self, str);
447 }
Richard Hughesd0905142016-03-13 09:46:49 +0000448
449 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000450 g_module_symbol (priv->module, "fu_plugin_init", (gpointer *) &func);
451 if (func != NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -0500452 g_debug ("init(%s)", filename);
Richard Hughes12724852018-09-04 13:53:44 +0100453 func (self);
Richard Hughesd0905142016-03-13 09:46:49 +0000454 }
455
Richard Hughescff38bc2016-12-12 12:03:37 +0000456 return TRUE;
457}
458
Richard Hughes203ed842020-11-02 14:25:13 +0000459/* order of usefulness to the user */
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100460static const gchar *
461fu_plugin_build_device_update_error (FuPlugin *self)
462{
463 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_NO_HARDWARE))
464 return "Not updatable as required hardware was not found";
465 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_LEGACY_BIOS))
466 return "Not updatable in legacy BIOS mode";
467 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED))
468 return "Not updatable as UEFI capsule updates not enabled";
469 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_UNLOCK_REQUIRED))
470 return "Not updatable as requires unlock";
471 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_EFIVAR_NOT_MOUNTED))
472 return "Not updatable as efivarfs was not found";
473 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND))
474 return "Not updatable as UEFI ESP partition not detected";
475 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
476 return "Not updatable as plugin was disabled";
477 return NULL;
478}
479
Richard Hughes57d18222017-01-10 16:02:59 +0000480/**
481 * fu_plugin_device_add:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100482 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000483 * @device: A #FuDevice
484 *
485 * Asks the daemon to add a device to the exported list. If this device ID
486 * has already been added by a different plugin then this request will be
487 * ignored.
488 *
489 * Plugins should use fu_plugin_device_add_delay() if they are not capable of
490 * actually flashing an image to the hardware so that higher-priority plugins
491 * can add the device themselves.
492 *
493 * Since: 0.8.0
494 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000495void
Richard Hughes12724852018-09-04 13:53:44 +0100496fu_plugin_device_add (FuPlugin *self, FuDevice *device)
Richard Hughescff38bc2016-12-12 12:03:37 +0000497{
Richard Hughes5e447292018-04-27 14:25:54 +0100498 GPtrArray *children;
Richard Hughesc125ec02018-09-05 19:35:17 +0100499 g_autoptr(GError) error = NULL;
Richard Hughes5e447292018-04-27 14:25:54 +0100500
Richard Hughes12724852018-09-04 13:53:44 +0100501 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000502 g_return_if_fail (FU_IS_DEVICE (device));
503
Richard Hughesc125ec02018-09-05 19:35:17 +0100504 /* ensure the device ID is set from the physical and logical IDs */
505 if (!fu_device_ensure_id (device, &error)) {
506 g_warning ("ignoring add: %s", error->message);
507 return;
508 }
509
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100510 /* proxy to device where required */
511 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE)) {
512 g_debug ("plugin %s has _CLEAR_UPDATABLE, so removing from %s",
513 fu_plugin_get_name (self),
514 fu_device_get_id (device));
515 fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE);
516 }
517 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_USER_WARNING) &&
518 fu_device_get_update_error (device) == NULL) {
519 const gchar *tmp = fu_plugin_build_device_update_error (self);
520 g_debug ("setting %s update error to '%s' from %s",
521 fu_device_get_id (device), tmp, fu_plugin_get_name (self));
522 fu_device_set_update_error (device, tmp);
523 }
524
Richard Hughescff38bc2016-12-12 12:03:37 +0000525 g_debug ("emit added from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100526 fu_plugin_get_name (self),
Richard Hughescff38bc2016-12-12 12:03:37 +0000527 fu_device_get_id (device));
528 fu_device_set_created (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
Richard Hughes12724852018-09-04 13:53:44 +0100529 fu_device_set_plugin (device, fu_plugin_get_name (self));
530 g_signal_emit (self, signals[SIGNAL_DEVICE_ADDED], 0, device);
Richard Hughes5e447292018-04-27 14:25:54 +0100531
Richard Hughes128c0162018-08-10 11:00:29 +0100532 /* add children if they have not already been added */
Richard Hughes5e447292018-04-27 14:25:54 +0100533 children = fu_device_get_children (device);
534 for (guint i = 0; i < children->len; i++) {
535 FuDevice *child = g_ptr_array_index (children, i);
Richard Hughes128c0162018-08-10 11:00:29 +0100536 if (fu_device_get_created (child) == 0)
Richard Hughes12724852018-09-04 13:53:44 +0100537 fu_plugin_device_add (self, child);
Richard Hughes5e447292018-04-27 14:25:54 +0100538 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000539}
540
Richard Hughese1fd34d2017-08-24 14:19:51 +0100541/**
542 * fu_plugin_device_register:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100543 * @self: A #FuPlugin
Richard Hughese1fd34d2017-08-24 14:19:51 +0100544 * @device: A #FuDevice
545 *
546 * Registers the device with other plugins so they can set metadata.
547 *
548 * Plugins do not have to call this manually as this is done automatically
549 * when using fu_plugin_device_add(). They may wish to use this manually
Richard Hughes21eaeef2020-01-14 12:10:01 +0000550 * if for instance the coldplug should be ignored based on the metadata
Richard Hughese1fd34d2017-08-24 14:19:51 +0100551 * set from other plugins.
552 *
553 * Since: 0.9.7
554 **/
555void
Richard Hughes12724852018-09-04 13:53:44 +0100556fu_plugin_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +0100557{
Richard Hughesc125ec02018-09-05 19:35:17 +0100558 g_autoptr(GError) error = NULL;
559
Richard Hughes12724852018-09-04 13:53:44 +0100560 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughese1fd34d2017-08-24 14:19:51 +0100561 g_return_if_fail (FU_IS_DEVICE (device));
562
Richard Hughesc125ec02018-09-05 19:35:17 +0100563 /* ensure the device ID is set from the physical and logical IDs */
564 if (!fu_device_ensure_id (device, &error)) {
565 g_warning ("ignoring registration: %s", error->message);
566 return;
567 }
568
Richard Hughese1fd34d2017-08-24 14:19:51 +0100569 g_debug ("emit device-register from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100570 fu_plugin_get_name (self),
Richard Hughese1fd34d2017-08-24 14:19:51 +0100571 fu_device_get_id (device));
Richard Hughes12724852018-09-04 13:53:44 +0100572 g_signal_emit (self, signals[SIGNAL_DEVICE_REGISTER], 0, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +0100573}
574
Richard Hughes57d18222017-01-10 16:02:59 +0000575/**
Richard Hughes4eada342017-10-03 21:20:32 +0100576 * fu_plugin_device_remove:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100577 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000578 * @device: A #FuDevice
579 *
580 * Asks the daemon to remove a device from the exported list.
581 *
582 * Since: 0.8.0
583 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000584void
Richard Hughes12724852018-09-04 13:53:44 +0100585fu_plugin_device_remove (FuPlugin *self, FuDevice *device)
Richard Hughescff38bc2016-12-12 12:03:37 +0000586{
Richard Hughes12724852018-09-04 13:53:44 +0100587 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000588 g_return_if_fail (FU_IS_DEVICE (device));
589
Richard Hughescff38bc2016-12-12 12:03:37 +0000590 g_debug ("emit removed from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100591 fu_plugin_get_name (self),
Richard Hughescff38bc2016-12-12 12:03:37 +0000592 fu_device_get_id (device));
Richard Hughes12724852018-09-04 13:53:44 +0100593 g_signal_emit (self, signals[SIGNAL_DEVICE_REMOVED], 0, device);
Richard Hughescff38bc2016-12-12 12:03:37 +0000594}
595
Richard Hughes57d18222017-01-10 16:02:59 +0000596/**
Richard Hughes2de8f132018-01-17 09:12:02 +0000597 * fu_plugin_request_recoldplug:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100598 * @self: A #FuPlugin
Richard Hughes362d6d72017-01-07 21:42:14 +0000599 *
600 * Ask all the plugins to coldplug all devices, which will include the prepare()
601 * and cleanup() phases. Duplicate devices added will be ignored.
602 *
603 * Since: 0.8.0
604 **/
605void
Richard Hughes12724852018-09-04 13:53:44 +0100606fu_plugin_request_recoldplug (FuPlugin *self)
Richard Hughes362d6d72017-01-07 21:42:14 +0000607{
Richard Hughes12724852018-09-04 13:53:44 +0100608 g_return_if_fail (FU_IS_PLUGIN (self));
609 g_signal_emit (self, signals[SIGNAL_RECOLDPLUG], 0);
Richard Hughes362d6d72017-01-07 21:42:14 +0000610}
611
Richard Hughesb0829032017-01-10 09:27:08 +0000612/**
Richard Hughes399859e2020-05-11 19:44:03 +0100613 * fu_plugin_security_changed:
614 * @self: A #FuPlugin
615 *
616 * Informs the daemon that the HSI state may have changed.
617 *
618 * Since: 1.5.0
619 **/
620void
621fu_plugin_security_changed (FuPlugin *self)
622{
623 g_return_if_fail (FU_IS_PLUGIN (self));
624 g_signal_emit (self, signals[SIGNAL_SECURITY_CHANGED], 0);
625}
626
627/**
Richard Hughesb8f8db22017-04-25 15:56:00 +0100628 * fu_plugin_check_hwid:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100629 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100630 * @hwid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
Richard Hughesb8f8db22017-04-25 15:56:00 +0100631 *
Richard Hughesd7704d42017-08-08 20:29:09 +0100632 * Checks to see if a specific GUID exists. All hardware IDs on a
Richard Hughesb8f8db22017-04-25 15:56:00 +0100633 * specific system can be shown using the `fwupdmgr hwids` command.
634 *
Richard Hughes4eada342017-10-03 21:20:32 +0100635 * Returns: %TRUE if the HwId is found on the system.
636 *
Richard Hughesb8f8db22017-04-25 15:56:00 +0100637 * Since: 0.9.1
638 **/
639gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100640fu_plugin_check_hwid (FuPlugin *self, const gchar *hwid)
Richard Hughesb8f8db22017-04-25 15:56:00 +0100641{
Richard Hughes12724852018-09-04 13:53:44 +0100642 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100643 if (priv->hwids == NULL)
644 return FALSE;
Richard Hughesd7704d42017-08-08 20:29:09 +0100645 return fu_hwids_has_guid (priv->hwids, hwid);
646}
647
648/**
Patrick Rudolpha60b5472019-10-16 10:43:03 +0200649 * fu_plugin_get_hwid_replace_value:
650 * @self: A #FuPlugin
651 * @keys: A key, e.g. `HardwareID-3` or %FU_HWIDS_KEY_PRODUCT_SKU
652 * @error: A #GError or %NULL
653 *
654 * Gets the replacement value for a specific key. All hardware IDs on a
655 * specific system can be shown using the `fwupdmgr hwids` command.
656 *
657 * Returns: (transfer full): a string, or %NULL for error.
658 *
659 * Since: 1.3.3
660 **/
661gchar *
662fu_plugin_get_hwid_replace_value (FuPlugin *self, const gchar *keys, GError **error)
663{
664 FuPluginPrivate *priv = GET_PRIVATE (self);
665 if (priv->hwids == NULL)
666 return NULL;
667
668 return fu_hwids_get_replace_values (priv->hwids, keys, error);
669}
670
671/**
Richard Hughes69a5f352018-08-08 11:58:15 +0100672 * fu_plugin_get_hwids:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100673 * @self: A #FuPlugin
Richard Hughes69a5f352018-08-08 11:58:15 +0100674 *
675 * Returns all the HWIDs defined in the system. All hardware IDs on a
676 * specific system can be shown using the `fwupdmgr hwids` command.
677 *
Mario Limonciello1a680f32019-11-25 19:44:53 -0600678 * Returns: (transfer none) (element-type utf8): An array of GUIDs
Richard Hughes69a5f352018-08-08 11:58:15 +0100679 *
680 * Since: 1.1.1
681 **/
682GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +0100683fu_plugin_get_hwids (FuPlugin *self)
Richard Hughes69a5f352018-08-08 11:58:15 +0100684{
Richard Hughes12724852018-09-04 13:53:44 +0100685 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes69a5f352018-08-08 11:58:15 +0100686 if (priv->hwids == NULL)
687 return NULL;
688 return fu_hwids_get_guids (priv->hwids);
689}
690
691/**
Richard Hughes19841802019-09-10 16:48:00 +0100692 * fu_plugin_has_custom_flag:
693 * @self: A #FuPlugin
694 * @flag: A custom text flag, specific to the plugin, e.g. `uefi-force-enable`
695 *
696 * Returns if a per-plugin HwId custom flag exists, typically added from a DMI quirk.
697 *
698 * Returns: %TRUE if the quirk entry exists
699 *
700 * Since: 1.3.1
701 **/
702gboolean
703fu_plugin_has_custom_flag (FuPlugin *self, const gchar *flag)
704{
705 FuPluginPrivate *priv = GET_PRIVATE (self);
706 GPtrArray *hwids = fu_plugin_get_hwids (self);
707
708 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
709 g_return_val_if_fail (flag != NULL, FALSE);
710
711 /* never set up, e.g. in tests */
712 if (hwids == NULL)
713 return FALSE;
714
715 /* search each hwid */
716 for (guint i = 0; i < hwids->len; i++) {
717 const gchar *hwid = g_ptr_array_index (hwids, i);
718 const gchar *value;
719 g_autofree gchar *key = g_strdup_printf ("HwId=%s", hwid);
720
721 /* does prefixed quirk exist */
722 value = fu_quirks_lookup_by_id (priv->quirks, key, FU_QUIRKS_FLAGS);
723 if (value != NULL) {
724 g_auto(GStrv) quirks = g_strsplit (value, ",", -1);
725 if (g_strv_contains ((const gchar * const *) quirks, flag))
726 return TRUE;
727 }
728 }
729 return FALSE;
730}
731
732/**
Richard Hughes1354ea92017-09-19 15:58:31 +0100733 * fu_plugin_check_supported:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100734 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100735 * @guid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
Richard Hughes1354ea92017-09-19 15:58:31 +0100736 *
737 * Checks to see if a specific device GUID is supported, i.e. available in the
738 * AppStream metadata.
739 *
Richard Hughes4eada342017-10-03 21:20:32 +0100740 * Returns: %TRUE if the device is supported.
741 *
Richard Hughes1354ea92017-09-19 15:58:31 +0100742 * Since: 1.0.0
743 **/
Richard Hughesd8a8d5e2019-10-08 13:05:02 +0100744static gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100745fu_plugin_check_supported (FuPlugin *self, const gchar *guid)
Richard Hughes1354ea92017-09-19 15:58:31 +0100746{
Richard Hughesaabdc372018-11-14 10:11:08 +0000747 gboolean retval = FALSE;
748 g_signal_emit (self, signals[SIGNAL_CHECK_SUPPORTED], 0, guid, &retval);
749 return retval;
Richard Hughes1354ea92017-09-19 15:58:31 +0100750}
751
752/**
Richard Hughesd7704d42017-08-08 20:29:09 +0100753 * fu_plugin_get_dmi_value:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100754 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100755 * @dmi_id: A DMI ID, e.g. `BiosVersion`
Richard Hughesd7704d42017-08-08 20:29:09 +0100756 *
757 * Gets a hardware DMI value.
758 *
Richard Hughes4eada342017-10-03 21:20:32 +0100759 * Returns: The string, or %NULL
760 *
Richard Hughesd7704d42017-08-08 20:29:09 +0100761 * Since: 0.9.7
762 **/
763const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100764fu_plugin_get_dmi_value (FuPlugin *self, const gchar *dmi_id)
Richard Hughesd7704d42017-08-08 20:29:09 +0100765{
Richard Hughes12724852018-09-04 13:53:44 +0100766 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd7704d42017-08-08 20:29:09 +0100767 if (priv->hwids == NULL)
Richard Hughes7ef96b82017-08-23 18:28:24 +0100768 return NULL;
Richard Hughesd7704d42017-08-08 20:29:09 +0100769 return fu_hwids_get_value (priv->hwids, dmi_id);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100770}
771
Richard Hughes49e5e052017-09-03 12:15:41 +0100772/**
773 * fu_plugin_get_smbios_string:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100774 * @self: A #FuPlugin
Richard Hughes49e5e052017-09-03 12:15:41 +0100775 * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
776 * @offset: A SMBIOS offset
777 *
778 * Gets a hardware SMBIOS string.
779 *
780 * The @type and @offset can be referenced from the DMTF SMBIOS specification:
781 * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.1.1.pdf
782 *
Richard Hughes4eada342017-10-03 21:20:32 +0100783 * Returns: A string, or %NULL
784 *
Richard Hughes49e5e052017-09-03 12:15:41 +0100785 * Since: 0.9.8
786 **/
787const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100788fu_plugin_get_smbios_string (FuPlugin *self, guint8 structure_type, guint8 offset)
Richard Hughes49e5e052017-09-03 12:15:41 +0100789{
Richard Hughes12724852018-09-04 13:53:44 +0100790 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100791 if (priv->smbios == NULL)
792 return NULL;
793 return fu_smbios_get_string (priv->smbios, structure_type, offset, NULL);
794}
795
796/**
797 * fu_plugin_get_smbios_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100798 * @self: A #FuPlugin
Richard Hughes49e5e052017-09-03 12:15:41 +0100799 * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
800 *
801 * Gets a hardware SMBIOS data.
802 *
Richard Hughesdfaca2d2019-08-01 08:08:03 +0100803 * Returns: (transfer full): A #GBytes, or %NULL
Richard Hughes4eada342017-10-03 21:20:32 +0100804 *
Richard Hughes49e5e052017-09-03 12:15:41 +0100805 * Since: 0.9.8
806 **/
807GBytes *
Richard Hughes12724852018-09-04 13:53:44 +0100808fu_plugin_get_smbios_data (FuPlugin *self, guint8 structure_type)
Richard Hughes49e5e052017-09-03 12:15:41 +0100809{
Richard Hughes12724852018-09-04 13:53:44 +0100810 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100811 if (priv->smbios == NULL)
812 return NULL;
813 return fu_smbios_get_data (priv->smbios, structure_type, NULL);
814}
815
Mario Limonciello1a680f32019-11-25 19:44:53 -0600816/**
817 * fu_plugin_set_hwids:
818 * @self: A #FuPlugin
819 * @hwids: A #FuHwids
820 *
821 * Sets the hwids for a plugin
822 *
823 * Since: 0.9.7
824 **/
Richard Hughesb8f8db22017-04-25 15:56:00 +0100825void
Richard Hughes12724852018-09-04 13:53:44 +0100826fu_plugin_set_hwids (FuPlugin *self, FuHwids *hwids)
Richard Hughesb8f8db22017-04-25 15:56:00 +0100827{
Richard Hughes12724852018-09-04 13:53:44 +0100828 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd7704d42017-08-08 20:29:09 +0100829 g_set_object (&priv->hwids, hwids);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100830}
831
Mario Limonciello1a680f32019-11-25 19:44:53 -0600832/**
833 * fu_plugin_set_udev_subsystems:
834 * @self: A #FuPlugin
Richard Hughesa0d81c72019-11-27 11:41:54 +0000835 * @udev_subsystems: (element-type utf8): A #GPtrArray
Mario Limonciello1a680f32019-11-25 19:44:53 -0600836 *
837 * Sets the udev subsystems used by a plugin
838 *
839 * Since: 1.1.2
840 **/
Richard Hughes49e5e052017-09-03 12:15:41 +0100841void
Richard Hughes12724852018-09-04 13:53:44 +0100842fu_plugin_set_udev_subsystems (FuPlugin *self, GPtrArray *udev_subsystems)
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100843{
Richard Hughes12724852018-09-04 13:53:44 +0100844 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100845 if (priv->udev_subsystems != NULL)
846 g_ptr_array_unref (priv->udev_subsystems);
847 priv->udev_subsystems = g_ptr_array_ref (udev_subsystems);
848}
849
Mario Limonciello1a680f32019-11-25 19:44:53 -0600850/**
851 * fu_plugin_set_quirks:
852 * @self: A #FuPlugin
853 * @quirks: A #FuQuirks
854 *
855 * Sets the quirks for a plugin
856 *
857 * Since: 1.0.1
858 **/
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100859void
Richard Hughes12724852018-09-04 13:53:44 +0100860fu_plugin_set_quirks (FuPlugin *self, FuQuirks *quirks)
Richard Hughes9c028f02017-10-28 21:14:28 +0100861{
Richard Hughes12724852018-09-04 13:53:44 +0100862 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9c028f02017-10-28 21:14:28 +0100863 g_set_object (&priv->quirks, quirks);
864}
865
866/**
867 * fu_plugin_get_quirks:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100868 * @self: A #FuPlugin
Richard Hughes9c028f02017-10-28 21:14:28 +0100869 *
870 * Returns the hardware database object. This can be used to discover device
871 * quirks or other device-specific settings.
872 *
873 * Returns: (transfer none): a #FuQuirks, or %NULL if not set
874 *
875 * Since: 1.0.1
876 **/
877FuQuirks *
Richard Hughes12724852018-09-04 13:53:44 +0100878fu_plugin_get_quirks (FuPlugin *self)
Richard Hughes9c028f02017-10-28 21:14:28 +0100879{
Richard Hughes12724852018-09-04 13:53:44 +0100880 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9c028f02017-10-28 21:14:28 +0100881 return priv->quirks;
882}
883
Mario Limonciello1a680f32019-11-25 19:44:53 -0600884/**
885 * fu_plugin_set_runtime_versions:
886 * @self: A #FuPlugin
887 * @runtime_versions: A #GHashTables
888 *
889 * Sets the runtime versions for a plugin
890 *
891 * Since: 1.0.7
892 **/
Richard Hughes0eb123b2018-04-19 12:00:04 +0100893void
Richard Hughes12724852018-09-04 13:53:44 +0100894fu_plugin_set_runtime_versions (FuPlugin *self, GHashTable *runtime_versions)
Richard Hughes0eb123b2018-04-19 12:00:04 +0100895{
Richard Hughes12724852018-09-04 13:53:44 +0100896 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0eb123b2018-04-19 12:00:04 +0100897 priv->runtime_versions = g_hash_table_ref (runtime_versions);
898}
899
900/**
901 * fu_plugin_add_runtime_version:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100902 * @self: A #FuPlugin
Richard Hughes0eb123b2018-04-19 12:00:04 +0100903 * @component_id: An AppStream component id, e.g. "org.gnome.Software"
904 * @version: A version string, e.g. "1.2.3"
905 *
Richard Hughesdce91202019-04-08 12:47:45 +0100906 * Sets a runtime version of a specific dependency.
Richard Hughes0eb123b2018-04-19 12:00:04 +0100907 *
908 * Since: 1.0.7
909 **/
910void
Richard Hughes12724852018-09-04 13:53:44 +0100911fu_plugin_add_runtime_version (FuPlugin *self,
Richard Hughes0eb123b2018-04-19 12:00:04 +0100912 const gchar *component_id,
913 const gchar *version)
914{
Richard Hughes12724852018-09-04 13:53:44 +0100915 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesb01b4862018-04-20 16:39:48 +0100916 if (priv->runtime_versions == NULL)
917 return;
Richard Hughes0eb123b2018-04-19 12:00:04 +0100918 g_hash_table_insert (priv->runtime_versions,
919 g_strdup (component_id),
920 g_strdup (version));
921}
922
Mario Limonciello1a680f32019-11-25 19:44:53 -0600923/**
924 * fu_plugin_set_compile_versions:
925 * @self: A #FuPlugin
926 * @compile_versions: A #GHashTables
927 *
928 * Sets the compile time versions for a plugin
929 *
930 * Since: 1.0.7
931 **/
Richard Hughes34e0dab2018-04-20 16:43:00 +0100932void
Richard Hughes12724852018-09-04 13:53:44 +0100933fu_plugin_set_compile_versions (FuPlugin *self, GHashTable *compile_versions)
Richard Hughes34e0dab2018-04-20 16:43:00 +0100934{
Richard Hughes12724852018-09-04 13:53:44 +0100935 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes34e0dab2018-04-20 16:43:00 +0100936 priv->compile_versions = g_hash_table_ref (compile_versions);
937}
938
939/**
940 * fu_plugin_add_compile_version:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100941 * @self: A #FuPlugin
Richard Hughes34e0dab2018-04-20 16:43:00 +0100942 * @component_id: An AppStream component id, e.g. "org.gnome.Software"
943 * @version: A version string, e.g. "1.2.3"
944 *
Richard Hughesdce91202019-04-08 12:47:45 +0100945 * Sets a compile-time version of a specific dependency.
Richard Hughes34e0dab2018-04-20 16:43:00 +0100946 *
947 * Since: 1.0.7
948 **/
949void
Richard Hughes12724852018-09-04 13:53:44 +0100950fu_plugin_add_compile_version (FuPlugin *self,
Richard Hughes34e0dab2018-04-20 16:43:00 +0100951 const gchar *component_id,
952 const gchar *version)
953{
Richard Hughes12724852018-09-04 13:53:44 +0100954 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes34e0dab2018-04-20 16:43:00 +0100955 if (priv->compile_versions == NULL)
956 return;
957 g_hash_table_insert (priv->compile_versions,
958 g_strdup (component_id),
959 g_strdup (version));
960}
961
Richard Hughes9c028f02017-10-28 21:14:28 +0100962/**
963 * fu_plugin_lookup_quirk_by_id:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100964 * @self: A #FuPlugin
Richard Hughes87fb9ff2018-06-28 12:55:59 +0100965 * @group: A string, e.g. "DfuFlags"
966 * @key: An ID to match the entry, e.g. "Summary"
Richard Hughes9c028f02017-10-28 21:14:28 +0100967 *
968 * Looks up an entry in the hardware database using a string value.
969 *
970 * Returns: (transfer none): values from the database, or %NULL if not found
971 *
972 * Since: 1.0.1
973 **/
974const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100975fu_plugin_lookup_quirk_by_id (FuPlugin *self, const gchar *group, const gchar *key)
Richard Hughes9c028f02017-10-28 21:14:28 +0100976{
Richard Hughes12724852018-09-04 13:53:44 +0100977 FuPluginPrivate *priv = GET_PRIVATE (self);
978 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes9c028f02017-10-28 21:14:28 +0100979
Richard Hughes9c028f02017-10-28 21:14:28 +0100980 /* exact ID */
Richard Hughes87fb9ff2018-06-28 12:55:59 +0100981 return fu_quirks_lookup_by_id (priv->quirks, group, key);
Richard Hughes9c028f02017-10-28 21:14:28 +0100982}
983
984/**
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100985 * fu_plugin_lookup_quirk_by_id_as_uint64:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100986 * @self: A #FuPlugin
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100987 * @group: A string, e.g. "DfuFlags"
988 * @key: An ID to match the entry, e.g. "Size"
989 *
990 * Looks up an entry in the hardware database using a string key, returning
991 * an integer value. Values are assumed base 10, unless prefixed with "0x"
992 * where they are parsed as base 16.
993 *
Mario Limonciello1a680f32019-11-25 19:44:53 -0600994 * Returns: guint64 id or 0 if not found
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100995 *
996 * Since: 1.1.2
997 **/
998guint64
Richard Hughes12724852018-09-04 13:53:44 +0100999fu_plugin_lookup_quirk_by_id_as_uint64 (FuPlugin *self, const gchar *group, const gchar *key)
Richard Hughes8fe7cdd2018-08-23 10:02:44 +01001000{
Richard Hughes12724852018-09-04 13:53:44 +01001001 return fu_common_strtoull (fu_plugin_lookup_quirk_by_id (self, group, key));
Richard Hughes8fe7cdd2018-08-23 10:02:44 +01001002}
1003
Mario Limonciello1a680f32019-11-25 19:44:53 -06001004/**
1005 * fu_plugin_set_smbios:
1006 * @self: A #FuPlugin
1007 * @smbios: A #FuSmbios
1008 *
1009 * Sets the smbios for a plugin
1010 *
1011 * Since: 1.0.0
1012 **/
Richard Hughes1354ea92017-09-19 15:58:31 +01001013void
Richard Hughes12724852018-09-04 13:53:44 +01001014fu_plugin_set_smbios (FuPlugin *self, FuSmbios *smbios)
Richard Hughes49e5e052017-09-03 12:15:41 +01001015{
Richard Hughes12724852018-09-04 13:53:44 +01001016 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +01001017 g_set_object (&priv->smbios, smbios);
1018}
1019
Richard Hughesb8f8db22017-04-25 15:56:00 +01001020/**
Richard Hughesb0829032017-01-10 09:27:08 +00001021 * fu_plugin_set_coldplug_delay:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001022 * @self: A #FuPlugin
Richard Hughesb0829032017-01-10 09:27:08 +00001023 * @duration: A delay in milliseconds
1024 *
Richard Hughes21eaeef2020-01-14 12:10:01 +00001025 * Set the minimum time that should be waited in-between the call to
Richard Hughesb0829032017-01-10 09:27:08 +00001026 * fu_plugin_coldplug_prepare() and fu_plugin_coldplug(). This is usually going
Richard Hughes203ed842020-11-02 14:25:13 +00001027 * to be the minimum hardware initialization time from a datasheet.
Richard Hughesb0829032017-01-10 09:27:08 +00001028 *
1029 * It is better to use this function rather than using a sleep() in the plugin
1030 * itself as then only one delay is done in the daemon rather than waiting for
1031 * each coldplug prepare in a serial way.
1032 *
1033 * Additionally, very long delays should be avoided as the daemon will be
1034 * blocked from processing requests whilst the coldplug delay is being
1035 * performed.
1036 *
1037 * Since: 0.8.0
1038 **/
1039void
Richard Hughes12724852018-09-04 13:53:44 +01001040fu_plugin_set_coldplug_delay (FuPlugin *self, guint duration)
Richard Hughesb0829032017-01-10 09:27:08 +00001041{
Richard Hughes12724852018-09-04 13:53:44 +01001042 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesb0829032017-01-10 09:27:08 +00001043 g_return_if_fail (duration > 0);
1044
1045 /* check sanity */
1046 if (duration > FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM) {
1047 g_warning ("duration of %ums is crazy, truncating to %ums",
1048 duration,
1049 FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM);
1050 duration = FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM;
1051 }
1052
1053 /* emit */
Richard Hughes12724852018-09-04 13:53:44 +01001054 g_signal_emit (self, signals[SIGNAL_SET_COLDPLUG_DELAY], 0, duration);
Richard Hughesb0829032017-01-10 09:27:08 +00001055}
1056
Richard Hughes4b303802019-10-04 13:22:51 +01001057static gboolean
1058fu_plugin_device_attach (FuPlugin *self, FuDevice *device, GError **error)
1059{
1060 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughes4b303802019-10-04 13:22:51 +01001061 locker = fu_device_locker_new (device, error);
1062 if (locker == NULL)
1063 return FALSE;
1064 return fu_device_attach (device, error);
1065}
1066
1067static gboolean
1068fu_plugin_device_detach (FuPlugin *self, FuDevice *device, GError **error)
1069{
1070 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughes4b303802019-10-04 13:22:51 +01001071 locker = fu_device_locker_new (device, error);
1072 if (locker == NULL)
1073 return FALSE;
1074 return fu_device_detach (device, error);
1075}
1076
1077static gboolean
Richard Hughes4b303802019-10-04 13:22:51 +01001078fu_plugin_device_activate (FuPlugin *self, FuDevice *device, GError **error)
1079{
1080 g_autoptr(FuDeviceLocker) locker = NULL;
1081 locker = fu_device_locker_new (device, error);
1082 if (locker == NULL)
1083 return FALSE;
1084 return fu_device_activate (device, error);
1085}
1086
1087static gboolean
1088fu_plugin_device_write_firmware (FuPlugin *self, FuDevice *device,
1089 GBytes *fw, FwupdInstallFlags flags,
1090 GError **error)
1091{
1092 g_autoptr(FuDeviceLocker) locker = NULL;
1093 locker = fu_device_locker_new (device, error);
1094 if (locker == NULL)
1095 return FALSE;
Richard Hughes1a612582020-09-29 19:39:38 +01001096
1097 /* back the old firmware up to /var/lib/fwupd */
1098 if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL)) {
1099 g_autoptr(GBytes) fw_old = NULL;
1100 g_autofree gchar *path = NULL;
1101 g_autofree gchar *fn = NULL;
1102 g_autofree gchar *localstatedir = NULL;
1103
1104 fw_old = fu_device_dump_firmware (device, error);
1105 if (fw_old == NULL) {
1106 g_prefix_error (error, "failed to backup old firmware: ");
1107 return FALSE;
1108 }
1109 localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG);
1110 fn = g_strdup_printf ("%s.bin", fu_device_get_version (device));
1111 path = g_build_filename (localstatedir,
1112 "backup",
1113 fu_device_get_id (device),
1114 fu_device_get_serial (device) != NULL ?
1115 fu_device_get_serial (device) :
1116 "default",
1117 fn, NULL);
1118 if (!fu_common_set_contents_bytes (path, fw_old, error))
1119 return FALSE;
1120 }
1121
Richard Hughes4b303802019-10-04 13:22:51 +01001122 return fu_device_write_firmware (device, fw, flags, error);
1123}
1124
Richard Hughes7f677212019-10-05 16:19:40 +01001125static gboolean
1126fu_plugin_device_read_firmware (FuPlugin *self, FuDevice *device, GError **error)
1127{
1128 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughesf0eb0912019-10-10 11:37:22 +01001129 g_autoptr(FuFirmware) firmware = NULL;
Richard Hughes7f677212019-10-05 16:19:40 +01001130 g_autoptr(GBytes) fw = NULL;
1131 GChecksumType checksum_types[] = {
1132 G_CHECKSUM_SHA1,
1133 G_CHECKSUM_SHA256,
1134 0 };
1135 locker = fu_device_locker_new (device, error);
1136 if (locker == NULL)
1137 return FALSE;
1138 if (!fu_device_detach (device, error))
1139 return FALSE;
Richard Hughesf0eb0912019-10-10 11:37:22 +01001140 firmware = fu_device_read_firmware (device, error);
1141 if (firmware == NULL) {
1142 g_autoptr(GError) error_local = NULL;
1143 if (!fu_device_attach (device, &error_local))
1144 g_debug ("ignoring attach failure: %s", error_local->message);
1145 g_prefix_error (error, "failed to read firmware: ");
1146 return FALSE;
1147 }
1148 fw = fu_firmware_write (firmware, error);
Richard Hughes7f677212019-10-05 16:19:40 +01001149 if (fw == NULL) {
1150 g_autoptr(GError) error_local = NULL;
1151 if (!fu_device_attach (device, &error_local))
Richard Hughesf0eb0912019-10-10 11:37:22 +01001152 g_debug ("ignoring attach failure: %s", error_local->message);
1153 g_prefix_error (error, "failed to write firmware: ");
Richard Hughes7f677212019-10-05 16:19:40 +01001154 return FALSE;
1155 }
1156 for (guint i = 0; checksum_types[i] != 0; i++) {
1157 g_autofree gchar *hash = NULL;
1158 hash = g_compute_checksum_for_bytes (checksum_types[i], fw);
1159 fu_device_add_checksum (device, hash);
1160 }
1161 return fu_device_attach (device, error);
1162}
1163
Mario Limonciello1a680f32019-11-25 19:44:53 -06001164/**
1165 * fu_plugin_runner_startup:
1166 * @self: a #FuPlugin
1167 * @error: a #GError or NULL
1168 *
1169 * Runs the startup routine for the plugin
1170 *
1171 * Returns: #TRUE for success, #FALSE for failure
1172 *
1173 * Since: 0.8.0
1174 **/
Richard Hughesd0905142016-03-13 09:46:49 +00001175gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001176fu_plugin_runner_startup (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00001177{
Richard Hughes12724852018-09-04 13:53:44 +01001178 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001179 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001180 g_autoptr(GError) error_local = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +00001181
1182 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001183 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughesd0905142016-03-13 09:46:49 +00001184 return TRUE;
1185
Richard Hughes639da472018-01-06 22:35:04 +00001186 /* no object loaded */
1187 if (priv->module == NULL)
1188 return TRUE;
1189
Richard Hughesd0905142016-03-13 09:46:49 +00001190 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00001191 g_module_symbol (priv->module, "fu_plugin_startup", (gpointer *) &func);
1192 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +00001193 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001194 g_debug ("startup(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001195 if (!func (self, &error_local)) {
1196 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001197 g_critical ("unset plugin error in startup(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001198 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001199 g_set_error_literal (&error_local,
1200 FWUPD_ERROR,
1201 FWUPD_ERROR_INTERNAL,
1202 "unspecified error");
1203 }
1204 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1205 "failed to startup using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001206 fu_plugin_get_name (self));
Richard Hughescff38bc2016-12-12 12:03:37 +00001207 return FALSE;
1208 }
1209 return TRUE;
1210}
1211
1212static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001213fu_plugin_runner_device_generic (FuPlugin *self, FuDevice *device,
Richard Hughes4b303802019-10-04 13:22:51 +01001214 const gchar *symbol_name,
1215 FuPluginDeviceFunc device_func,
1216 GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001217{
Richard Hughes12724852018-09-04 13:53:44 +01001218 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001219 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001220 g_autoptr(GError) error_local = NULL;
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001221
1222 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001223 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001224 return TRUE;
1225
Richard Hughesd3d96cc2017-11-14 11:34:33 +00001226 /* no object loaded */
1227 if (priv->module == NULL)
1228 return TRUE;
1229
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001230 /* optional */
1231 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
Richard Hughes4b303802019-10-04 13:22:51 +01001232 if (func == NULL) {
1233 if (device_func != NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001234 g_debug ("running superclassed %s(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001235 symbol_name + 10, fu_plugin_get_name (self));
Richard Hughes4b303802019-10-04 13:22:51 +01001236 return device_func (self, device, error);
1237 }
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001238 return TRUE;
Richard Hughes4b303802019-10-04 13:22:51 +01001239 }
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001240 g_debug ("%s(%s)", symbol_name + 10, fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001241 if (!func (self, device, &error_local)) {
1242 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001243 g_critical ("unset plugin error in %s(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001244 fu_plugin_get_name (self), symbol_name + 10);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001245 g_set_error_literal (&error_local,
1246 FWUPD_ERROR,
1247 FWUPD_ERROR_INTERNAL,
1248 "unspecified error");
1249 }
1250 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1251 "failed to %s using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001252 symbol_name + 10, fu_plugin_get_name (self));
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001253 return FALSE;
1254 }
1255 return TRUE;
1256}
1257
Richard Hughesdbd8c762018-06-15 20:31:40 +01001258static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001259fu_plugin_runner_flagged_device_generic (FuPlugin *self, FwupdInstallFlags flags,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001260 FuDevice *device,
1261 const gchar *symbol_name, GError **error)
1262{
Richard Hughes12724852018-09-04 13:53:44 +01001263 FuPluginPrivate *priv = GET_PRIVATE (self);
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001264 FuPluginFlaggedDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001265 g_autoptr(GError) error_local = NULL;
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001266
1267 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001268 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001269 return TRUE;
1270
1271 /* no object loaded */
1272 if (priv->module == NULL)
1273 return TRUE;
1274
1275 /* optional */
1276 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1277 if (func == NULL)
1278 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001279 g_debug ("%s(%s)", symbol_name + 10, fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001280 if (!func (self, flags, device, &error_local)) {
1281 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001282 g_critical ("unset plugin error in %s(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001283 fu_plugin_get_name (self), symbol_name + 10);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001284 g_set_error_literal (&error_local,
1285 FWUPD_ERROR,
1286 FWUPD_ERROR_INTERNAL,
1287 "unspecified error");
1288 }
1289 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1290 "failed to %s using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001291 symbol_name + 10, fu_plugin_get_name (self));
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001292 return FALSE;
1293 }
1294 return TRUE;
1295
1296}
1297
1298static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001299fu_plugin_runner_device_array_generic (FuPlugin *self, GPtrArray *devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001300 const gchar *symbol_name, GError **error)
1301{
Richard Hughes12724852018-09-04 13:53:44 +01001302 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesdbd8c762018-06-15 20:31:40 +01001303 FuPluginDeviceArrayFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001304 g_autoptr(GError) error_local = NULL;
Richard Hughesdbd8c762018-06-15 20:31:40 +01001305
1306 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001307 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughesdbd8c762018-06-15 20:31:40 +01001308 return TRUE;
1309
1310 /* no object loaded */
1311 if (priv->module == NULL)
1312 return TRUE;
1313
1314 /* optional */
1315 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1316 if (func == NULL)
1317 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001318 g_debug ("%s(%s)", symbol_name + 10, fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001319 if (!func (self, devices, &error_local)) {
1320 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001321 g_critical ("unset plugin error in for %s(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001322 fu_plugin_get_name (self), symbol_name + 10);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001323 g_set_error_literal (&error_local,
1324 FWUPD_ERROR,
1325 FWUPD_ERROR_INTERNAL,
1326 "unspecified error");
1327 }
1328 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1329 "failed to %s using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001330 symbol_name + 10, fu_plugin_get_name (self));
Richard Hughesdbd8c762018-06-15 20:31:40 +01001331 return FALSE;
1332 }
1333 return TRUE;
1334}
1335
Mario Limonciello1a680f32019-11-25 19:44:53 -06001336/**
1337 * fu_plugin_runner_coldplug:
1338 * @self: a #FuPlugin
1339 * @error: a #GError or NULL
1340 *
1341 * Runs the coldplug routine for the plugin
1342 *
1343 * Returns: #TRUE for success, #FALSE for failure
1344 *
1345 * Since: 0.8.0
1346 **/
Richard Hughesd0905142016-03-13 09:46:49 +00001347gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001348fu_plugin_runner_coldplug (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00001349{
Richard Hughes12724852018-09-04 13:53:44 +01001350 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001351 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001352 g_autoptr(GError) error_local = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +00001353
1354 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001355 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughesd0905142016-03-13 09:46:49 +00001356 return TRUE;
1357
Richard Hughes639da472018-01-06 22:35:04 +00001358 /* no object loaded */
1359 if (priv->module == NULL)
1360 return TRUE;
1361
Richard Hughesd0905142016-03-13 09:46:49 +00001362 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00001363 g_module_symbol (priv->module, "fu_plugin_coldplug", (gpointer *) &func);
1364 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +00001365 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001366 g_debug ("coldplug(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001367 if (!func (self, &error_local)) {
1368 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001369 g_critical ("unset plugin error in coldplug(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001370 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001371 g_set_error_literal (&error_local,
1372 FWUPD_ERROR,
1373 FWUPD_ERROR_INTERNAL,
1374 "unspecified error");
1375 }
1376 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001377 "failed to coldplug using %s: ", fu_plugin_get_name (self));
Richard Hughescff38bc2016-12-12 12:03:37 +00001378 return FALSE;
1379 }
1380 return TRUE;
1381}
1382
Mario Limonciello1a680f32019-11-25 19:44:53 -06001383/**
1384 * fu_plugin_runner_recoldplug:
1385 * @self: a #FuPlugin
1386 * @error: a #GError or NULL
1387 *
1388 * Runs the recoldplug routine for the plugin
1389 *
1390 * Returns: #TRUE for success, #FALSE for failure
1391 *
1392 * Since: 1.0.4
1393 **/
Richard Hughes7b8b2022016-12-12 16:15:03 +00001394gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001395fu_plugin_runner_recoldplug (FuPlugin *self, GError **error)
Richard Hughes2de8f132018-01-17 09:12:02 +00001396{
Richard Hughes12724852018-09-04 13:53:44 +01001397 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes2de8f132018-01-17 09:12:02 +00001398 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001399 g_autoptr(GError) error_local = NULL;
Richard Hughes2de8f132018-01-17 09:12:02 +00001400
1401 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001402 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes2de8f132018-01-17 09:12:02 +00001403 return TRUE;
1404
1405 /* no object loaded */
1406 if (priv->module == NULL)
1407 return TRUE;
1408
1409 /* optional */
1410 g_module_symbol (priv->module, "fu_plugin_recoldplug", (gpointer *) &func);
1411 if (func == NULL)
1412 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001413 g_debug ("recoldplug(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001414 if (!func (self, &error_local)) {
1415 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001416 g_critical ("unset plugin error in recoldplug(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001417 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001418 g_set_error_literal (&error_local,
1419 FWUPD_ERROR,
1420 FWUPD_ERROR_INTERNAL,
1421 "unspecified error");
1422 }
1423 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1424 "failed to recoldplug using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001425 fu_plugin_get_name (self));
Richard Hughes2de8f132018-01-17 09:12:02 +00001426 return FALSE;
1427 }
1428 return TRUE;
1429}
1430
Mario Limonciello1a680f32019-11-25 19:44:53 -06001431/**
1432 * fu_plugin_runner_coldplug_prepare:
1433 * @self: a #FuPlugin
1434 * @error: a #GError or NULL
1435 *
1436 * Runs the coldplug_prepare routine for the plugin
1437 *
1438 * Returns: #TRUE for success, #FALSE for failure
1439 *
1440 * Since: 0.8.0
1441 **/
Richard Hughes2de8f132018-01-17 09:12:02 +00001442gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001443fu_plugin_runner_coldplug_prepare (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001444{
Richard Hughes12724852018-09-04 13:53:44 +01001445 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001446 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001447 g_autoptr(GError) error_local = NULL;
Richard Hughes46487c92017-01-07 21:26:34 +00001448
1449 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001450 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes46487c92017-01-07 21:26:34 +00001451 return TRUE;
1452
Richard Hughes639da472018-01-06 22:35:04 +00001453 /* no object loaded */
1454 if (priv->module == NULL)
1455 return TRUE;
1456
Richard Hughes46487c92017-01-07 21:26:34 +00001457 /* optional */
1458 g_module_symbol (priv->module, "fu_plugin_coldplug_prepare", (gpointer *) &func);
1459 if (func == NULL)
1460 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001461 g_debug ("coldplug_prepare(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001462 if (!func (self, &error_local)) {
1463 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001464 g_critical ("unset plugin error in coldplug_prepare(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001465 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001466 g_set_error_literal (&error_local,
1467 FWUPD_ERROR,
1468 FWUPD_ERROR_INTERNAL,
1469 "unspecified error");
1470 }
1471 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1472 "failed to coldplug_prepare using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001473 fu_plugin_get_name (self));
Richard Hughes46487c92017-01-07 21:26:34 +00001474 return FALSE;
1475 }
1476 return TRUE;
1477}
1478
Mario Limonciello1a680f32019-11-25 19:44:53 -06001479/**
1480 * fu_plugin_runner_coldplug_cleanup:
1481 * @self: a #FuPlugin
1482 * @error: a #GError or NULL
1483 *
1484 * Runs the coldplug_cleanup routine for the plugin
1485 *
1486 * Returns: #TRUE for success, #FALSE for failure
1487 *
1488 * Since: 0.8.0
1489 **/
Richard Hughes46487c92017-01-07 21:26:34 +00001490gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001491fu_plugin_runner_coldplug_cleanup (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001492{
Richard Hughes12724852018-09-04 13:53:44 +01001493 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001494 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001495 g_autoptr(GError) error_local = NULL;
Richard Hughes46487c92017-01-07 21:26:34 +00001496
1497 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001498 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes46487c92017-01-07 21:26:34 +00001499 return TRUE;
1500
Richard Hughes639da472018-01-06 22:35:04 +00001501 /* no object loaded */
1502 if (priv->module == NULL)
1503 return TRUE;
1504
Richard Hughes46487c92017-01-07 21:26:34 +00001505 /* optional */
1506 g_module_symbol (priv->module, "fu_plugin_coldplug_cleanup", (gpointer *) &func);
1507 if (func == NULL)
1508 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001509 g_debug ("coldplug_cleanup(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001510 if (!func (self, &error_local)) {
1511 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001512 g_critical ("unset plugin error in coldplug_cleanup(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001513 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001514 g_set_error_literal (&error_local,
1515 FWUPD_ERROR,
1516 FWUPD_ERROR_INTERNAL,
1517 "unspecified error");
1518 }
1519 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1520 "failed to coldplug_cleanup using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001521 fu_plugin_get_name (self));
Richard Hughes46487c92017-01-07 21:26:34 +00001522 return FALSE;
1523 }
1524 return TRUE;
1525}
1526
Mario Limonciello1a680f32019-11-25 19:44:53 -06001527/**
1528 * fu_plugin_runner_composite_prepare:
1529 * @self: a #FuPlugin
Richard Hughesa0d81c72019-11-27 11:41:54 +00001530 * @devices: (element-type FuDevice): a #GPtrArray of devices
Mario Limonciello1a680f32019-11-25 19:44:53 -06001531 * @error: a #GError or NULL
1532 *
1533 * Runs the composite_prepare routine for the plugin
1534 *
1535 * Returns: #TRUE for success, #FALSE for failure
1536 *
1537 * Since: 1.0.9
1538 **/
Richard Hughes46487c92017-01-07 21:26:34 +00001539gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001540fu_plugin_runner_composite_prepare (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001541{
Richard Hughes12724852018-09-04 13:53:44 +01001542 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001543 "fu_plugin_composite_prepare",
1544 error);
1545}
1546
Mario Limonciello1a680f32019-11-25 19:44:53 -06001547/**
1548 * fu_plugin_runner_composite_cleanup:
1549 * @self: a #FuPlugin
Richard Hughesa0d81c72019-11-27 11:41:54 +00001550 * @devices: (element-type FuDevice): a #GPtrArray of devices
Mario Limonciello1a680f32019-11-25 19:44:53 -06001551 * @error: a #GError or NULL
1552 *
1553 * Runs the composite_cleanup routine for the plugin
1554 *
1555 * Returns: #TRUE for success, #FALSE for failure
1556 *
1557 * Since: 1.0.9
1558 **/
Richard Hughesdbd8c762018-06-15 20:31:40 +01001559gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001560fu_plugin_runner_composite_cleanup (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001561{
Richard Hughes12724852018-09-04 13:53:44 +01001562 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001563 "fu_plugin_composite_cleanup",
1564 error);
1565}
1566
Mario Limonciello1a680f32019-11-25 19:44:53 -06001567/**
1568 * fu_plugin_runner_update_prepare:
1569 * @self: a #FuPlugin
Richard Hughes2bbb7d22020-11-30 09:18:45 +00001570 * @flags: #FwupdInstallFlags
1571 * @device: a #FuDevice
Mario Limonciello1a680f32019-11-25 19:44:53 -06001572 * @error: a #GError or NULL
1573 *
1574 * Runs the update_prepare routine for the plugin
1575 *
1576 * Returns: #TRUE for success, #FALSE for failure
1577 *
1578 * Since: 1.1.2
1579 **/
Richard Hughesdbd8c762018-06-15 20:31:40 +01001580gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001581fu_plugin_runner_update_prepare (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001582 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001583{
Richard Hughes12724852018-09-04 13:53:44 +01001584 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001585 "fu_plugin_update_prepare",
1586 error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001587}
1588
Mario Limonciello1a680f32019-11-25 19:44:53 -06001589/**
1590 * fu_plugin_runner_update_cleanup:
1591 * @self: a #FuPlugin
Richard Hughes2bbb7d22020-11-30 09:18:45 +00001592 * @flags: #FwupdInstallFlags
1593 * @device: a #FuDevice
Mario Limonciello1a680f32019-11-25 19:44:53 -06001594 * @error: a #GError or NULL
1595 *
1596 * Runs the update_cleanup routine for the plugin
1597 *
1598 * Returns: #TRUE for success, #FALSE for failure
1599 *
1600 * Since: 1.1.2
1601 **/
Richard Hughes7b8b2022016-12-12 16:15:03 +00001602gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001603fu_plugin_runner_update_cleanup (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001604 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001605{
Richard Hughes12724852018-09-04 13:53:44 +01001606 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001607 "fu_plugin_update_cleanup",
1608 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001609}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001610
Mario Limonciello1a680f32019-11-25 19:44:53 -06001611/**
1612 * fu_plugin_runner_update_attach:
1613 * @self: a #FuPlugin
1614 * @device: a #FuDevice
1615 * @error: a #GError or NULL
1616 *
1617 * Runs the update_attach routine for the plugin
1618 *
1619 * Returns: #TRUE for success, #FALSE for failure
1620 *
1621 * Since: 1.1.2
1622 **/
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001623gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001624fu_plugin_runner_update_attach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001625{
Richard Hughes12724852018-09-04 13:53:44 +01001626 return fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001627 "fu_plugin_update_attach",
1628 fu_plugin_device_attach,
1629 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001630}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001631
Mario Limonciello1a680f32019-11-25 19:44:53 -06001632/**
1633 * fu_plugin_runner_update_detach:
1634 * @self: a #FuPlugin
1635 * @device: A #FuDevice
1636 * @error: a #GError or NULL
1637 *
1638 * Runs the update_detach routine for the plugin
1639 *
1640 * Returns: #TRUE for success, #FALSE for failure
1641 *
1642 * Since: 1.1.2
1643 **/
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001644gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001645fu_plugin_runner_update_detach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001646{
Richard Hughes12724852018-09-04 13:53:44 +01001647 return fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001648 "fu_plugin_update_detach",
1649 fu_plugin_device_detach,
1650 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001651}
1652
Mario Limonciello1a680f32019-11-25 19:44:53 -06001653/**
1654 * fu_plugin_runner_update_reload:
1655 * @self: a #FuPlugin
Richard Hughes2bbb7d22020-11-30 09:18:45 +00001656 * @device: A #FuDevice
Mario Limonciello1a680f32019-11-25 19:44:53 -06001657 * @error: a #GError or NULL
1658 *
1659 * Runs reload routine for a device
1660 *
1661 * Returns: #TRUE for success, #FALSE for failure
1662 *
1663 * Since: 1.1.2
1664 **/
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001665gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001666fu_plugin_runner_update_reload (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001667{
Richard Hughes42f33df2019-10-05 20:52:33 +01001668 g_autoptr(FuDeviceLocker) locker = NULL;
1669
1670 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001671 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes42f33df2019-10-05 20:52:33 +01001672 return TRUE;
1673
1674 /* no object loaded */
1675 locker = fu_device_locker_new (device, error);
1676 if (locker == NULL)
1677 return FALSE;
1678 return fu_device_reload (device, error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001679}
1680
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001681/**
Richard Hughes196c6c62020-05-11 19:42:47 +01001682 * fu_plugin_runner_add_security_attrs:
1683 * @self: a #FuPlugin
Richard Hughes3ecd22c2020-05-19 20:13:47 +01001684 * @attrs: a #FuSecurityAttrs
Richard Hughes196c6c62020-05-11 19:42:47 +01001685 *
Richard Hughes3ecd22c2020-05-19 20:13:47 +01001686 * Runs the `add_security_attrs()` routine for the plugin
Richard Hughes196c6c62020-05-11 19:42:47 +01001687 *
1688 * Since: 1.5.0
1689 **/
Richard Hughesf58ac732020-05-12 15:23:44 +01001690void
1691fu_plugin_runner_add_security_attrs (FuPlugin *self, FuSecurityAttrs *attrs)
Richard Hughes196c6c62020-05-11 19:42:47 +01001692{
Richard Hughesf58ac732020-05-12 15:23:44 +01001693 FuPluginPrivate *priv = GET_PRIVATE (self);
1694 FuPluginSecurityAttrsFunc func = NULL;
1695 const gchar *symbol_name = "fu_plugin_add_security_attrs";
1696
1697 /* no object loaded */
1698 if (priv->module == NULL)
1699 return;
1700
1701 /* optional, but gets called even for disabled plugins */
1702 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1703 if (func == NULL)
1704 return;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001705 g_debug ("%s(%s)", symbol_name + 10, fu_plugin_get_name (self));
Richard Hughesf58ac732020-05-12 15:23:44 +01001706 func (self, attrs);
Richard Hughes196c6c62020-05-11 19:42:47 +01001707}
1708
1709/**
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001710 * fu_plugin_add_udev_subsystem:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001711 * @self: a #FuPlugin
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001712 * @subsystem: a subsystem name, e.g. `pciport`
1713 *
1714 * Registers the udev subsystem to be watched by the daemon.
1715 *
1716 * Plugins can use this method only in fu_plugin_init()
Mario Limonciello1a680f32019-11-25 19:44:53 -06001717 *
1718 * Since: 1.1.2
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001719 **/
1720void
Richard Hughes12724852018-09-04 13:53:44 +01001721fu_plugin_add_udev_subsystem (FuPlugin *self, const gchar *subsystem)
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001722{
Richard Hughes12724852018-09-04 13:53:44 +01001723 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesea327fc2020-06-22 15:23:29 +01001724 if (priv->udev_subsystems == NULL)
1725 priv->udev_subsystems = g_ptr_array_new_with_free_func (g_free);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001726 for (guint i = 0; i < priv->udev_subsystems->len; i++) {
1727 const gchar *subsystem_tmp = g_ptr_array_index (priv->udev_subsystems, i);
1728 if (g_strcmp0 (subsystem_tmp, subsystem) == 0)
1729 return;
1730 }
1731 g_debug ("added udev subsystem watch of %s", subsystem);
1732 g_ptr_array_add (priv->udev_subsystems, g_strdup (subsystem));
1733}
1734
Richard Hughes989acf12019-10-05 20:16:47 +01001735/**
1736 * fu_plugin_set_device_gtype:
1737 * @self: a #FuPlugin
1738 * @device_gtype: a #GType `FU_TYPE_DEVICE`
1739 *
1740 * Sets the device #GType which is used when creating devices.
1741 *
1742 * If this method is used then fu_plugin_usb_device_added() is not called, and
1743 * instead the object is created in the daemon for the plugin.
1744 *
1745 * Plugins can use this method only in fu_plugin_init()
1746 *
1747 * Since: 1.3.3
1748 **/
1749void
1750fu_plugin_set_device_gtype (FuPlugin *self, GType device_gtype)
1751{
1752 FuPluginPrivate *priv = GET_PRIVATE (self);
1753 priv->device_gtype = device_gtype;
1754}
1755
Richard Hughes9f71fe32021-01-03 20:35:36 +00001756static gchar *
1757fu_common_string_uncamelcase (const gchar *str)
1758{
1759 GString *tmp = g_string_new (NULL);
1760 for (guint i = 0; str[i] != '\0'; i++) {
1761 if (g_ascii_islower (str[i]) ||
1762 g_ascii_isdigit (str[i])) {
1763 g_string_append_c (tmp, str[i]);
1764 continue;
1765 }
1766 if (i > 0)
1767 g_string_append_c (tmp, '-');
1768 g_string_append_c (tmp, g_ascii_tolower (str[i]));
1769 }
1770 return g_string_free (tmp, FALSE);
1771}
1772
Mario Limonciello1a680f32019-11-25 19:44:53 -06001773/**
1774 * fu_plugin_add_firmware_gtype:
1775 * @self: a #FuPlugin
Richard Hughes9f71fe32021-01-03 20:35:36 +00001776 * @id: (nullable): An optional string describing the type, e.g. "ihex"
1777 * @gtype: a #GType e.g. `FU_TYPE_FOO_FIRMWARE`
Mario Limonciello1a680f32019-11-25 19:44:53 -06001778 *
Richard Hughes9f71fe32021-01-03 20:35:36 +00001779 * Adds a firmware #GType which is used when creating devices. If @id is not
1780 * specified then it is guessed using the #GType name.
1781 *
Mario Limonciello1a680f32019-11-25 19:44:53 -06001782 * Plugins can use this method only in fu_plugin_init()
1783 *
1784 * Since: 1.3.3
1785 **/
Richard Hughes95c98a92019-10-22 16:03:15 +01001786void
1787fu_plugin_add_firmware_gtype (FuPlugin *self, const gchar *id, GType gtype)
1788{
Richard Hughes9f71fe32021-01-03 20:35:36 +00001789 g_autofree gchar *id_safe = NULL;
1790 if (id != NULL) {
1791 id_safe = g_strdup (id);
1792 } else {
1793 GString *str = g_string_new (g_type_name (gtype));
1794 if (g_str_has_prefix (str->str, "Fu"))
1795 g_string_erase (str, 0, 2);
1796 fu_common_string_replace (str, "Firmware", "");
1797 id_safe = fu_common_string_uncamelcase (str->str);
1798 }
1799 g_signal_emit (self, signals[SIGNAL_ADD_FIRMWARE_GTYPE], 0, id_safe, gtype);
Richard Hughes95c98a92019-10-22 16:03:15 +01001800}
1801
Richard Hughes989acf12019-10-05 20:16:47 +01001802static gboolean
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001803fu_plugin_check_supported_device (FuPlugin *self, FuDevice *device)
1804{
1805 GPtrArray *instance_ids = fu_device_get_instance_ids (device);
1806 for (guint i = 0; i < instance_ids->len; i++) {
1807 const gchar *instance_id = g_ptr_array_index (instance_ids, i);
1808 g_autofree gchar *guid = fwupd_guid_hash_string (instance_id);
1809 if (fu_plugin_check_supported (self, guid))
1810 return TRUE;
1811 }
1812 return FALSE;
1813}
1814
1815static gboolean
Richard Hughes989acf12019-10-05 20:16:47 +01001816fu_plugin_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error)
1817{
1818 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001819 GType device_gtype = fu_device_get_specialized_gtype (FU_DEVICE (device));
Richard Hughes989acf12019-10-05 20:16:47 +01001820 g_autoptr(FuDevice) dev = NULL;
1821 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001822
1823 /* fall back to plugin default */
1824 if (device_gtype == G_TYPE_INVALID)
1825 device_gtype = priv->device_gtype;
1826
1827 /* create new device and incorporate existing properties */
1828 dev = g_object_new (device_gtype, NULL);
1829 fu_device_incorporate (dev, FU_DEVICE (device));
Richard Hughes0f66a022020-02-19 18:54:38 +00001830 if (!fu_plugin_runner_device_created (self, dev, error))
1831 return FALSE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001832
1833 /* there are a lot of different devices that match, but not all respond
1834 * well to opening -- so limit some ones with issued updates */
1835 if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_ONLY_SUPPORTED)) {
1836 if (!fu_device_probe (dev, error))
1837 return FALSE;
1838 fu_device_convert_instance_ids (dev);
1839 if (!fu_plugin_check_supported_device (self, dev)) {
1840 g_autofree gchar *guids = fu_device_get_guids_as_str (dev);
1841 g_debug ("%s has no updates, so ignoring device", guids);
1842 return TRUE;
1843 }
1844 }
1845
1846 /* open and add */
1847 locker = fu_device_locker_new (dev, error);
1848 if (locker == NULL)
1849 return FALSE;
1850 fu_plugin_device_add (self, dev);
Richard Hughes6a078702020-05-09 20:36:33 +01001851 fu_plugin_runner_device_added (self, dev);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001852 return TRUE;
1853}
1854
1855static gboolean
1856fu_plugin_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error)
1857{
1858 FuPluginPrivate *priv = GET_PRIVATE (self);
1859 GType device_gtype = fu_device_get_specialized_gtype (FU_DEVICE (device));
1860 g_autoptr(FuDevice) dev = NULL;
1861 g_autoptr(FuDeviceLocker) locker = NULL;
1862
1863 /* fall back to plugin default */
1864 if (device_gtype == G_TYPE_INVALID)
1865 device_gtype = priv->device_gtype;
1866
1867 /* create new device and incorporate existing properties */
1868 dev = g_object_new (device_gtype, NULL);
Richard Hughes989acf12019-10-05 20:16:47 +01001869 fu_device_incorporate (FU_DEVICE (dev), FU_DEVICE (device));
Richard Hughes0f66a022020-02-19 18:54:38 +00001870 if (!fu_plugin_runner_device_created (self, dev, error))
1871 return FALSE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001872
1873 /* there are a lot of different devices that match, but not all respond
1874 * well to opening -- so limit some ones with issued updates */
1875 if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_ONLY_SUPPORTED)) {
1876 if (!fu_device_probe (dev, error))
1877 return FALSE;
1878 fu_device_convert_instance_ids (dev);
1879 if (!fu_plugin_check_supported_device (self, dev)) {
1880 g_autofree gchar *guids = fu_device_get_guids_as_str (dev);
1881 g_debug ("%s has no updates, so ignoring device", guids);
1882 return TRUE;
1883 }
1884 }
1885
1886 /* open and add */
Richard Hughes989acf12019-10-05 20:16:47 +01001887 locker = fu_device_locker_new (dev, error);
1888 if (locker == NULL)
1889 return FALSE;
1890 fu_plugin_device_add (self, FU_DEVICE (dev));
Richard Hughes6a078702020-05-09 20:36:33 +01001891 fu_plugin_runner_device_added (self, dev);
Richard Hughes989acf12019-10-05 20:16:47 +01001892 return TRUE;
1893}
1894
Mario Limonciello1a680f32019-11-25 19:44:53 -06001895/**
1896 * fu_plugin_runner_usb_device_added:
1897 * @self: a #FuPlugin
1898 * @device: a #FuUsbDevice
1899 * @error: a #GError or NULL
1900 *
1901 * Call the usb_device_added routine for the plugin
1902 *
1903 * Returns: #TRUE for success, #FALSE for failure
1904 *
1905 * Since: 1.0.2
1906 **/
Richard Hughes104f6512017-11-24 11:44:57 +00001907gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001908fu_plugin_runner_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error)
Richard Hughes104f6512017-11-24 11:44:57 +00001909{
Richard Hughes12724852018-09-04 13:53:44 +01001910 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes104f6512017-11-24 11:44:57 +00001911 FuPluginUsbDeviceAddedFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001912 g_autoptr(GError) error_local = NULL;
Richard Hughes104f6512017-11-24 11:44:57 +00001913
Richard Hughes6a489a92020-12-22 10:32:06 +00001914 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
1915 g_return_val_if_fail (FU_IS_USB_DEVICE (device), FALSE);
1916 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1917
Richard Hughes104f6512017-11-24 11:44:57 +00001918 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001919 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes104f6512017-11-24 11:44:57 +00001920 return TRUE;
Richard Hughes639da472018-01-06 22:35:04 +00001921
1922 /* no object loaded */
Richard Hughes104f6512017-11-24 11:44:57 +00001923 if (priv->module == NULL)
1924 return TRUE;
1925
1926 /* optional */
1927 g_module_symbol (priv->module, "fu_plugin_usb_device_added", (gpointer *) &func);
Richard Hughes989acf12019-10-05 20:16:47 +01001928 if (func == NULL) {
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001929 if (priv->device_gtype != G_TYPE_INVALID ||
1930 fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) {
Mario Limonciello0e500322019-10-17 18:41:04 -05001931 if (!fu_plugin_usb_device_added (self, device, error))
Mario Limoncielloa9be5362019-10-12 13:17:45 -05001932 return FALSE;
Richard Hughes989acf12019-10-05 20:16:47 +01001933 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001934 return TRUE;
Richard Hughes989acf12019-10-05 20:16:47 +01001935 }
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001936 g_debug ("usb_device_added(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001937 if (!func (self, device, &error_local)) {
1938 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001939 g_critical ("unset plugin error in usb_device_added(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001940 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001941 g_set_error_literal (&error_local,
1942 FWUPD_ERROR,
1943 FWUPD_ERROR_INTERNAL,
1944 "unspecified error");
1945 }
1946 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1947 "failed to add device using on %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001948 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001949 return FALSE;
Richard Hughes104f6512017-11-24 11:44:57 +00001950 }
1951 return TRUE;
1952}
1953
Mario Limonciello1a680f32019-11-25 19:44:53 -06001954/**
1955 * fu_plugin_runner_udev_device_added:
1956 * @self: a #FuPlugin
1957 * @device: a #FuUdevDevice
1958 * @error: a #GError or NULL
1959 *
1960 * Call the udev_device_added routine for the plugin
1961 *
1962 * Returns: #TRUE for success, #FALSE for failure
1963 *
1964 * Since: 1.0.2
1965 **/
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001966gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001967fu_plugin_runner_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error)
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001968{
Richard Hughes12724852018-09-04 13:53:44 +01001969 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001970 FuPluginUdevDeviceAddedFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001971 g_autoptr(GError) error_local = NULL;
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001972
Richard Hughes6a489a92020-12-22 10:32:06 +00001973 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
1974 g_return_val_if_fail (FU_IS_UDEV_DEVICE (device), FALSE);
1975 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1976
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001977 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001978 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001979 return TRUE;
1980
1981 /* no object loaded */
1982 if (priv->module == NULL)
1983 return TRUE;
1984
1985 /* optional */
1986 g_module_symbol (priv->module, "fu_plugin_udev_device_added", (gpointer *) &func);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001987 if (func == NULL) {
1988 if (priv->device_gtype != G_TYPE_INVALID ||
1989 fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) {
Richard Hughes6fca4692020-12-01 18:22:46 +00001990 return fu_plugin_udev_device_added (self, device, error);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001991 }
Richard Hughesa21e0252020-12-01 12:21:33 +00001992 g_set_error_literal (error,
1993 FWUPD_ERROR,
1994 FWUPD_ERROR_INTERNAL,
1995 "No device GType set");
1996 return FALSE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001997 }
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001998 g_debug ("udev_device_added(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001999 if (!func (self, device, &error_local)) {
2000 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05002001 g_critical ("unset plugin error in udev_device_added(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002002 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002003 g_set_error_literal (&error_local,
2004 FWUPD_ERROR,
2005 FWUPD_ERROR_INTERNAL,
2006 "unspecified error");
2007 }
2008 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2009 "failed to add device using on %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002010 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002011 return FALSE;
Richard Hughes9d6e0e72018-08-24 20:20:17 +01002012 }
2013 return TRUE;
2014}
2015
Mario Limonciello1a680f32019-11-25 19:44:53 -06002016/**
2017 * fu_plugin_runner_udev_device_changed:
2018 * @self: a #FuPlugin
2019 * @device: a #FuUdevDevice
2020 * @error: a #GError or NULL
2021 *
2022 * Call the udev_device_changed routine for the plugin
2023 *
2024 * Returns: #TRUE for success, #FALSE for failure
2025 *
2026 * Since: 1.0.2
2027 **/
Richard Hughes5e952ce2019-08-26 11:09:46 +01002028gboolean
2029fu_plugin_runner_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GError **error)
2030{
2031 FuPluginPrivate *priv = GET_PRIVATE (self);
2032 FuPluginUdevDeviceAddedFunc func = NULL;
2033 g_autoptr(GError) error_local = NULL;
2034
Richard Hughes6a489a92020-12-22 10:32:06 +00002035 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
2036 g_return_val_if_fail (FU_IS_UDEV_DEVICE (device), FALSE);
2037 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2038
Richard Hughes5e952ce2019-08-26 11:09:46 +01002039 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002040 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes5e952ce2019-08-26 11:09:46 +01002041 return TRUE;
2042
2043 /* no object loaded */
2044 if (priv->module == NULL)
2045 return TRUE;
2046
2047 /* optional */
2048 g_module_symbol (priv->module, "fu_plugin_udev_device_changed", (gpointer *) &func);
Mario Limonciello6d235142020-09-10 21:35:17 -05002049 if (func == NULL)
Richard Hughes5e952ce2019-08-26 11:09:46 +01002050 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002051 g_debug ("udev_device_changed(%s)", fu_plugin_get_name (self));
Richard Hughes5e952ce2019-08-26 11:09:46 +01002052 if (!func (self, device, &error_local)) {
2053 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05002054 g_critical ("unset plugin error in udev_device_changed(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002055 fu_plugin_get_name (self));
Richard Hughes5e952ce2019-08-26 11:09:46 +01002056 g_set_error_literal (&error_local,
2057 FWUPD_ERROR,
2058 FWUPD_ERROR_INTERNAL,
2059 "unspecified error");
2060 }
2061 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2062 "failed to change device on %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002063 fu_plugin_get_name (self));
Richard Hughes5e952ce2019-08-26 11:09:46 +01002064 return FALSE;
2065 }
2066 return TRUE;
2067}
2068
Mario Limonciello1a680f32019-11-25 19:44:53 -06002069/**
Richard Hughes6a078702020-05-09 20:36:33 +01002070 * fu_plugin_runner_device_added:
2071 * @self: a #FuPlugin
2072 * @device: a #FuDevice
2073 *
2074 * Call the device_added routine for the plugin
2075 *
2076 * Since: 1.5.0
2077 **/
2078void
2079fu_plugin_runner_device_added (FuPlugin *self, FuDevice *device)
2080{
2081 FuPluginPrivate *priv = GET_PRIVATE (self);
2082 FuPluginDeviceRegisterFunc func = NULL;
2083
2084 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002085 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes6a078702020-05-09 20:36:33 +01002086 return;
2087 if (priv->module == NULL)
2088 return;
2089
2090 /* optional */
2091 g_module_symbol (priv->module, "fu_plugin_device_added", (gpointer *) &func);
2092 if (func == NULL)
2093 return;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002094 g_debug ("fu_plugin_device_added(%s)", fu_plugin_get_name (self));
Richard Hughes6a078702020-05-09 20:36:33 +01002095 func (self, device);
2096}
2097
2098/**
Mario Limonciello1a680f32019-11-25 19:44:53 -06002099 * fu_plugin_runner_device_removed:
2100 * @self: a #FuPlugin
2101 * @device: a #FuDevice
2102 *
2103 * Call the device_removed routine for the plugin
2104 *
2105 * Since: 1.1.2
2106 **/
Richard Hughese1fd34d2017-08-24 14:19:51 +01002107void
Richard Hughes12724852018-09-04 13:53:44 +01002108fu_plugin_runner_device_removed (FuPlugin *self, FuDevice *device)
Mario Limoncielloe260ead2018-09-01 09:19:24 -05002109{
2110 g_autoptr(GError) error_local= NULL;
2111
Richard Hughes12724852018-09-04 13:53:44 +01002112 if (!fu_plugin_runner_device_generic (self, device,
Mario Limoncielloe260ead2018-09-01 09:19:24 -05002113 "fu_plugin_device_removed",
Richard Hughes4b303802019-10-04 13:22:51 +01002114 NULL,
Mario Limoncielloe260ead2018-09-01 09:19:24 -05002115 &error_local))
2116 g_warning ("%s", error_local->message);
2117}
2118
Mario Limonciello1a680f32019-11-25 19:44:53 -06002119/**
2120 * fu_plugin_runner_device_register:
2121 * @self: a #FuPlugin
2122 * @device: a #FuDevice
2123 *
2124 * Call the device_registered routine for the plugin
2125 *
2126 * Since: 0.9.7
2127 **/
Mario Limoncielloe260ead2018-09-01 09:19:24 -05002128void
Richard Hughes12724852018-09-04 13:53:44 +01002129fu_plugin_runner_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +01002130{
Richard Hughes12724852018-09-04 13:53:44 +01002131 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughese1fd34d2017-08-24 14:19:51 +01002132 FuPluginDeviceRegisterFunc func = NULL;
2133
2134 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002135 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughese1fd34d2017-08-24 14:19:51 +01002136 return;
Richard Hughes34834102017-11-21 21:55:00 +00002137 if (priv->module == NULL)
2138 return;
Richard Hughese1fd34d2017-08-24 14:19:51 +01002139
Mario Limonciello4910b242018-06-22 15:04:21 -05002140 /* don't notify plugins on their own devices */
Richard Hughes12724852018-09-04 13:53:44 +01002141 if (g_strcmp0 (fu_device_get_plugin (device), fu_plugin_get_name (self)) == 0)
Mario Limonciello4910b242018-06-22 15:04:21 -05002142 return;
2143
Richard Hughese1fd34d2017-08-24 14:19:51 +01002144 /* optional */
2145 g_module_symbol (priv->module, "fu_plugin_device_registered", (gpointer *) &func);
2146 if (func != NULL) {
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002147 g_debug ("fu_plugin_device_registered(%s)", fu_plugin_get_name (self));
Richard Hughes12724852018-09-04 13:53:44 +01002148 func (self, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +01002149 }
2150}
2151
Mario Limonciello1a680f32019-11-25 19:44:53 -06002152/**
Richard Hughes0f66a022020-02-19 18:54:38 +00002153 * fu_plugin_runner_device_created:
2154 * @self: a #FuPlugin
2155 * @device: a #FuDevice
2156 * @error: a #GError or NULL
2157 *
2158 * Call the device_created routine for the plugin
2159 *
2160 * Returns: #TRUE for success, #FALSE for failure
2161 *
Mario Limonciello96117d12020-02-28 10:17:56 -06002162 * Since: 1.4.0
Richard Hughes0f66a022020-02-19 18:54:38 +00002163 **/
2164gboolean
2165fu_plugin_runner_device_created (FuPlugin *self, FuDevice *device, GError **error)
2166{
2167 FuPluginPrivate *priv = GET_PRIVATE (self);
2168 FuPluginDeviceFunc func = NULL;
2169
Richard Hughes6a489a92020-12-22 10:32:06 +00002170 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
2171 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
2172 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2173
Richard Hughes0f66a022020-02-19 18:54:38 +00002174 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002175 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes0f66a022020-02-19 18:54:38 +00002176 return TRUE;
2177 if (priv->module == NULL)
2178 return TRUE;
2179
2180 /* optional */
2181 g_module_symbol (priv->module, "fu_plugin_device_created", (gpointer *) &func);
2182 if (func == NULL)
2183 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002184 g_debug ("fu_plugin_device_created(%s)", fu_plugin_get_name (self));
Richard Hughes0f66a022020-02-19 18:54:38 +00002185 return func (self, device, error);
2186}
2187
2188/**
Mario Limonciello1a680f32019-11-25 19:44:53 -06002189 * fu_plugin_runner_verify:
2190 * @self: a #FuPlugin
2191 * @device: a #FuDevice
2192 * @flags: #FuPluginVerifyFlags
2193 * @error: A #GError or NULL
2194 *
2195 * Call into the plugin's verify routine
2196 *
2197 * Returns: #TRUE for success, #FALSE for failure
2198 *
2199 * Since: 0.8.0
2200 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002201gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002202fu_plugin_runner_verify (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +00002203 FuDevice *device,
2204 FuPluginVerifyFlags flags,
2205 GError **error)
2206{
Richard Hughes12724852018-09-04 13:53:44 +01002207 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00002208 FuPluginVerifyFunc func = NULL;
Richard Hughesababbb72017-06-15 20:18:36 +01002209 GPtrArray *checksums;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002210 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002211
Richard Hughes6a489a92020-12-22 10:32:06 +00002212 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
2213 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
2214 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2215
Richard Hughescff38bc2016-12-12 12:03:37 +00002216 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002217 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughescff38bc2016-12-12 12:03:37 +00002218 return TRUE;
2219
Richard Hughes639da472018-01-06 22:35:04 +00002220 /* no object loaded */
2221 if (priv->module == NULL)
2222 return TRUE;
2223
Richard Hughescff38bc2016-12-12 12:03:37 +00002224 /* optional */
2225 g_module_symbol (priv->module, "fu_plugin_verify", (gpointer *) &func);
Richard Hughes7f677212019-10-05 16:19:40 +01002226 if (func == NULL) {
Richard Hughes7f677212019-10-05 16:19:40 +01002227 return fu_plugin_device_read_firmware (self, device, error);
2228 }
Richard Hughes1812fc72018-12-14 11:37:54 +00002229
2230 /* clear any existing verification checksums */
2231 checksums = fu_device_get_checksums (device);
2232 g_ptr_array_set_size (checksums, 0);
2233
Richard Hughesc9223be2019-03-18 08:46:42 +00002234 /* run additional detach */
2235 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01002236 "fu_plugin_update_detach",
Richard Hughes4b303802019-10-04 13:22:51 +01002237 fu_plugin_device_detach,
Richard Hughesc9223be2019-03-18 08:46:42 +00002238 error))
2239 return FALSE;
2240
Richard Hughes1812fc72018-12-14 11:37:54 +00002241 /* run vfunc */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002242 g_debug ("verify(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002243 if (!func (self, device, flags, &error_local)) {
Richard Hughesc9223be2019-03-18 08:46:42 +00002244 g_autoptr(GError) error_attach = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002245 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05002246 g_critical ("unset plugin error in verify(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002247 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002248 g_set_error_literal (&error_local,
2249 FWUPD_ERROR,
2250 FWUPD_ERROR_INTERNAL,
2251 "unspecified error");
2252 }
2253 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2254 "failed to verify using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002255 fu_plugin_get_name (self));
Richard Hughesc9223be2019-03-18 08:46:42 +00002256 /* make the device "work" again, but don't prefix the error */
2257 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01002258 "fu_plugin_update_attach",
Richard Hughes4b303802019-10-04 13:22:51 +01002259 fu_plugin_device_attach,
Richard Hughesc9223be2019-03-18 08:46:42 +00002260 &error_attach)) {
2261 g_warning ("failed to attach whilst aborting verify(): %s",
2262 error_attach->message);
2263 }
Richard Hughesd0905142016-03-13 09:46:49 +00002264 return FALSE;
2265 }
Richard Hughesc9223be2019-03-18 08:46:42 +00002266
2267 /* run optional attach */
2268 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01002269 "fu_plugin_update_attach",
Richard Hughes4b303802019-10-04 13:22:51 +01002270 fu_plugin_device_attach,
Richard Hughesc9223be2019-03-18 08:46:42 +00002271 error))
2272 return FALSE;
2273
2274 /* success */
Richard Hughesd0905142016-03-13 09:46:49 +00002275 return TRUE;
2276}
2277
Mario Limonciello1a680f32019-11-25 19:44:53 -06002278/**
2279 * fu_plugin_runner_activate:
2280 * @self: a #FuPlugin
2281 * @device: a #FuDevice
2282 * @error: A #GError or NULL
2283 *
2284 * Call into the plugin's activate routine
2285 *
2286 * Returns: #TRUE for success, #FALSE for failure
2287 *
2288 * Since: 1.2.6
2289 **/
Richard Hughesd0905142016-03-13 09:46:49 +00002290gboolean
Mario Limonciello96a0dd52019-02-25 13:50:03 -06002291fu_plugin_runner_activate (FuPlugin *self, FuDevice *device, GError **error)
2292{
2293 guint64 flags;
2294
Richard Hughes6a489a92020-12-22 10:32:06 +00002295 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
2296 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
2297 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2298
Mario Limonciello96a0dd52019-02-25 13:50:03 -06002299 /* final check */
2300 flags = fu_device_get_flags (device);
2301 if ((flags & FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION) == 0) {
2302 g_set_error (error,
2303 FWUPD_ERROR,
2304 FWUPD_ERROR_NOT_SUPPORTED,
2305 "Device %s does not need activation",
2306 fu_device_get_id (device));
2307 return FALSE;
2308 }
2309
2310 /* run vfunc */
2311 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01002312 "fu_plugin_activate",
2313 fu_plugin_device_activate,
2314 error))
Mario Limonciello96a0dd52019-02-25 13:50:03 -06002315 return FALSE;
2316
2317 /* update with correct flags */
2318 fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION);
2319 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
2320 return TRUE;
2321}
2322
Mario Limonciello1a680f32019-11-25 19:44:53 -06002323/**
2324 * fu_plugin_runner_unlock:
2325 * @self: a #FuPlugin
2326 * @device: a #FuDevice
2327 * @error: A #GError or NULL
2328 *
2329 * Call into the plugin's unlock routine
2330 *
2331 * Returns: #TRUE for success, #FALSE for failure
2332 *
2333 * Since: 0.8.0
2334 **/
Mario Limonciello96a0dd52019-02-25 13:50:03 -06002335gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002336fu_plugin_runner_unlock (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00002337{
Richard Hughescff38bc2016-12-12 12:03:37 +00002338 guint64 flags;
Richard Hughescff38bc2016-12-12 12:03:37 +00002339
Richard Hughes6a489a92020-12-22 10:32:06 +00002340 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
2341 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
2342 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2343
Richard Hughescff38bc2016-12-12 12:03:37 +00002344 /* final check */
2345 flags = fu_device_get_flags (device);
2346 if ((flags & FWUPD_DEVICE_FLAG_LOCKED) == 0) {
2347 g_set_error (error,
2348 FWUPD_ERROR,
2349 FWUPD_ERROR_NOT_SUPPORTED,
2350 "Device %s is not locked",
2351 fu_device_get_id (device));
2352 return FALSE;
2353 }
2354
Richard Hughes9c4b5312017-11-14 11:34:53 +00002355 /* run vfunc */
Richard Hughes12724852018-09-04 13:53:44 +01002356 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01002357 "fu_plugin_unlock",
2358 NULL,
2359 error))
Richard Hughes9c4b5312017-11-14 11:34:53 +00002360 return FALSE;
Richard Hughescff38bc2016-12-12 12:03:37 +00002361
2362 /* update with correct flags */
2363 flags = fu_device_get_flags (device);
2364 fu_device_set_flags (device, flags &= ~FWUPD_DEVICE_FLAG_LOCKED);
2365 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
2366 return TRUE;
2367}
2368
Mario Limonciello1a680f32019-11-25 19:44:53 -06002369/**
2370 * fu_plugin_runner_update:
2371 * @self: a #FuPlugin
2372 * @device: a #FuDevice
2373 * @blob_fw: A #GBytes
2374 * @flags: A #FwupdInstallFlags
2375 * @error: A #GError or NULL
2376 *
2377 * Call into the plugin's update routine
2378 *
2379 * Returns: #TRUE for success, #FALSE for failure
2380 *
2381 * Since: 0.8.0
2382 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002383gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002384fu_plugin_runner_update (FuPlugin *self,
Richard Hughesa785a1c2017-08-25 16:00:58 +01002385 FuDevice *device,
Richard Hughesa785a1c2017-08-25 16:00:58 +01002386 GBytes *blob_fw,
2387 FwupdInstallFlags flags,
2388 GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00002389{
Richard Hughes12724852018-09-04 13:53:44 +01002390 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesa785a1c2017-08-25 16:00:58 +01002391 FuPluginUpdateFunc update_func;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002392 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002393
Richard Hughes6a489a92020-12-22 10:32:06 +00002394 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
2395 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
2396 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2397
Richard Hughescff38bc2016-12-12 12:03:37 +00002398 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002399 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) {
Richard Hughes41c15482018-02-01 22:07:21 +00002400 g_debug ("plugin not enabled, skipping");
Richard Hughesd0905142016-03-13 09:46:49 +00002401 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00002402 }
Richard Hughesd0905142016-03-13 09:46:49 +00002403
Richard Hughes639da472018-01-06 22:35:04 +00002404 /* no object loaded */
Richard Hughes41c15482018-02-01 22:07:21 +00002405 if (priv->module == NULL) {
2406 g_debug ("module not enabled, skipping");
Richard Hughes639da472018-01-06 22:35:04 +00002407 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00002408 }
Richard Hughes639da472018-01-06 22:35:04 +00002409
Richard Hughesd0905142016-03-13 09:46:49 +00002410 /* optional */
Richard Hughesa785a1c2017-08-25 16:00:58 +01002411 g_module_symbol (priv->module, "fu_plugin_update", (gpointer *) &update_func);
2412 if (update_func == NULL) {
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002413 g_debug ("superclassed write_firmware(%s)", fu_plugin_get_name (self));
Richard Hughes4b303802019-10-04 13:22:51 +01002414 return fu_plugin_device_write_firmware (self, device, blob_fw, flags, error);
Richard Hughesa785a1c2017-08-25 16:00:58 +01002415 }
Richard Hughesd0905142016-03-13 09:46:49 +00002416
Richard Hughescff38bc2016-12-12 12:03:37 +00002417 /* online */
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002418 if (!update_func (self, device, blob_fw, flags, &error_local)) {
2419 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05002420 g_critical ("unset plugin error in update(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002421 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002422 g_set_error_literal (&error_local,
Richard Hughes3c8ada32018-10-12 10:08:58 +01002423 FWUPD_ERROR,
2424 FWUPD_ERROR_INTERNAL,
2425 "unspecified error");
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002426 return FALSE;
Richard Hughes3c8ada32018-10-12 10:08:58 +01002427 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002428 fu_device_set_update_error (device, error_local->message);
2429 g_propagate_error (error, g_steal_pointer (&error_local));
Richard Hughescff38bc2016-12-12 12:03:37 +00002430 return FALSE;
2431 }
2432
Richard Hughesf556d372017-06-15 19:49:18 +01002433 /* no longer valid */
Richard Hughesf8039642019-01-16 12:22:22 +00002434 if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT) &&
2435 !fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) {
Richard Hughes08435162018-12-12 10:34:16 +00002436 GPtrArray *checksums = fu_device_get_checksums (device);
2437 g_ptr_array_set_size (checksums, 0);
2438 }
Richard Hughesf556d372017-06-15 19:49:18 +01002439
Richard Hughes019a1bc2019-11-26 10:19:33 +00002440 /* success */
Richard Hughesd0905142016-03-13 09:46:49 +00002441 return TRUE;
2442}
Richard Hughescff38bc2016-12-12 12:03:37 +00002443
Mario Limonciello1a680f32019-11-25 19:44:53 -06002444/**
2445 * fu_plugin_runner_clear_results:
2446 * @self: a #FuPlugin
2447 * @device: a #FuDevice
2448 * @error: A #GError or NULL
2449 *
2450 * Call into the plugin's clear results routine
2451 *
2452 * Returns: #TRUE for success, #FALSE for failure
2453 *
2454 * Since: 0.8.0
2455 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002456gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002457fu_plugin_runner_clear_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00002458{
Richard Hughes12724852018-09-04 13:53:44 +01002459 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00002460 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002461 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002462
Richard Hughes6a489a92020-12-22 10:32:06 +00002463 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
2464 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
2465 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2466
Richard Hughescff38bc2016-12-12 12:03:37 +00002467 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002468 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughescff38bc2016-12-12 12:03:37 +00002469 return TRUE;
2470
Richard Hughes639da472018-01-06 22:35:04 +00002471 /* no object loaded */
2472 if (priv->module == NULL)
2473 return TRUE;
2474
Richard Hughes65e44ca2018-01-30 17:26:30 +00002475 /* optional */
Richard Hughescd644902019-11-01 12:35:17 +00002476 g_module_symbol (priv->module, "fu_plugin_clear_results", (gpointer *) &func);
Richard Hughes65e44ca2018-01-30 17:26:30 +00002477 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00002478 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002479 g_debug ("clear_result(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002480 if (!func (self, device, &error_local)) {
2481 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05002482 g_critical ("unset plugin error in clear_result(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002483 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002484 g_set_error_literal (&error_local,
2485 FWUPD_ERROR,
2486 FWUPD_ERROR_INTERNAL,
2487 "unspecified error");
2488 }
2489 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2490 "failed to clear_result using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002491 fu_plugin_get_name (self));
Richard Hughescff38bc2016-12-12 12:03:37 +00002492 return FALSE;
2493 }
Richard Hughes65e44ca2018-01-30 17:26:30 +00002494 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00002495}
2496
Mario Limonciello1a680f32019-11-25 19:44:53 -06002497/**
2498 * fu_plugin_runner_get_results:
2499 * @self: a #FuPlugin
2500 * @device: a #FuDevice
2501 * @error: A #GError or NULL
2502 *
2503 * Call into the plugin's get results routine
2504 *
2505 * Returns: #TRUE for success, #FALSE for failure
2506 *
2507 * Since: 0.8.0
2508 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002509gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002510fu_plugin_runner_get_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00002511{
Richard Hughes12724852018-09-04 13:53:44 +01002512 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00002513 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002514 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002515
Richard Hughes6a489a92020-12-22 10:32:06 +00002516 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
2517 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
2518 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2519
Richard Hughescff38bc2016-12-12 12:03:37 +00002520 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002521 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughescff38bc2016-12-12 12:03:37 +00002522 return TRUE;
2523
Richard Hughes639da472018-01-06 22:35:04 +00002524 /* no object loaded */
2525 if (priv->module == NULL)
2526 return TRUE;
2527
Richard Hughes65e44ca2018-01-30 17:26:30 +00002528 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00002529 g_module_symbol (priv->module, "fu_plugin_get_results", (gpointer *) &func);
Richard Hughes65e44ca2018-01-30 17:26:30 +00002530 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00002531 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002532 g_debug ("get_results(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002533 if (!func (self, device, &error_local)) {
2534 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05002535 g_critical ("unset plugin error in get_results(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002536 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002537 g_set_error_literal (&error_local,
2538 FWUPD_ERROR,
2539 FWUPD_ERROR_INTERNAL,
2540 "unspecified error");
2541 }
2542 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2543 "failed to get_results using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002544 fu_plugin_get_name (self));
Richard Hughescff38bc2016-12-12 12:03:37 +00002545 return FALSE;
2546 }
Richard Hughescff38bc2016-12-12 12:03:37 +00002547 return TRUE;
2548}
2549
Richard Hughes08a37992017-09-12 12:57:43 +01002550/**
2551 * fu_plugin_get_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002552 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002553 *
2554 * Gets the plugin order, where higher numbers are run after lower
2555 * numbers.
2556 *
2557 * Returns: the integer value
Mario Limonciello1a680f32019-11-25 19:44:53 -06002558 *
2559 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002560 **/
2561guint
Richard Hughes12724852018-09-04 13:53:44 +01002562fu_plugin_get_order (FuPlugin *self)
Richard Hughes08a37992017-09-12 12:57:43 +01002563{
Richard Hughes12724852018-09-04 13:53:44 +01002564 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002565 return priv->order;
2566}
2567
2568/**
2569 * fu_plugin_set_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002570 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002571 * @order: a integer value
2572 *
2573 * Sets the plugin order, where higher numbers are run after lower
2574 * numbers.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002575 *
2576 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002577 **/
2578void
Richard Hughes12724852018-09-04 13:53:44 +01002579fu_plugin_set_order (FuPlugin *self, guint order)
Richard Hughes08a37992017-09-12 12:57:43 +01002580{
Richard Hughes12724852018-09-04 13:53:44 +01002581 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002582 priv->order = order;
2583}
2584
2585/**
Richard Hughes81c427c2018-08-06 15:20:17 +01002586 * fu_plugin_get_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002587 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01002588 *
2589 * Gets the plugin priority, where higher numbers are better.
2590 *
2591 * Returns: the integer value
Mario Limonciello1a680f32019-11-25 19:44:53 -06002592 *
2593 * Since: 1.1.1
Richard Hughes81c427c2018-08-06 15:20:17 +01002594 **/
2595guint
Richard Hughes12724852018-09-04 13:53:44 +01002596fu_plugin_get_priority (FuPlugin *self)
Richard Hughes81c427c2018-08-06 15:20:17 +01002597{
Richard Hughes12724852018-09-04 13:53:44 +01002598 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01002599 return priv->priority;
2600}
2601
2602/**
2603 * fu_plugin_set_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002604 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01002605 * @priority: a integer value
2606 *
2607 * Sets the plugin priority, where higher numbers are better.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002608 *
2609 * Since: 1.0.0
Richard Hughes81c427c2018-08-06 15:20:17 +01002610 **/
2611void
Richard Hughes12724852018-09-04 13:53:44 +01002612fu_plugin_set_priority (FuPlugin *self, guint priority)
Richard Hughes81c427c2018-08-06 15:20:17 +01002613{
Richard Hughes12724852018-09-04 13:53:44 +01002614 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01002615 priv->priority = priority;
2616}
2617
2618/**
Richard Hughes08a37992017-09-12 12:57:43 +01002619 * fu_plugin_add_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002620 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002621 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
Richard Hughes4eada342017-10-03 21:20:32 +01002622 * @name: a plugin name, e.g. `upower`
Richard Hughes08a37992017-09-12 12:57:43 +01002623 *
2624 * If the plugin name is found, the rule will be used to sort the plugin list,
2625 * for example the plugin specified by @name will be ordered after this plugin
2626 * when %FU_PLUGIN_RULE_RUN_AFTER is used.
2627 *
2628 * NOTE: The depsolver is iterative and may not solve overly-complicated rules;
2629 * If depsolving fails then fwupd will not start.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002630 *
2631 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002632 **/
2633void
Richard Hughes12724852018-09-04 13:53:44 +01002634fu_plugin_add_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes08a37992017-09-12 12:57:43 +01002635{
Richard Hughes12724852018-09-04 13:53:44 +01002636 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes11c59412020-06-22 15:29:48 +01002637 if (priv->rules[rule] == NULL)
2638 priv->rules[rule] = g_ptr_array_new_with_free_func (g_free);
Richard Hughes08a37992017-09-12 12:57:43 +01002639 g_ptr_array_add (priv->rules[rule], g_strdup (name));
Richard Hughes75b965d2018-11-15 13:51:21 +00002640 g_signal_emit (self, signals[SIGNAL_RULES_CHANGED], 0);
Richard Hughes08a37992017-09-12 12:57:43 +01002641}
2642
2643/**
2644 * fu_plugin_get_rules:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002645 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002646 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
2647 *
2648 * Gets the plugin IDs that should be run after this plugin.
2649 *
Richard Hughes11c59412020-06-22 15:29:48 +01002650 * Returns: (element-type utf8) (transfer none) (nullable): the list of plugin names, e.g. ['appstream']
Mario Limonciello1a680f32019-11-25 19:44:53 -06002651 *
2652 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002653 **/
2654GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +01002655fu_plugin_get_rules (FuPlugin *self, FuPluginRule rule)
Richard Hughes08a37992017-09-12 12:57:43 +01002656{
Richard Hughes12724852018-09-04 13:53:44 +01002657 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughesdad35972019-12-06 11:00:25 +00002658 g_return_val_if_fail (rule < FU_PLUGIN_RULE_LAST, NULL);
Richard Hughes08a37992017-09-12 12:57:43 +01002659 return priv->rules[rule];
2660}
2661
Richard Hughes80b79bb2018-01-11 21:11:06 +00002662/**
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002663 * fu_plugin_has_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002664 * @self: a #FuPlugin
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002665 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
2666 * @name: a plugin name, e.g. `upower`
2667 *
Richard Hughes87fb9ff2018-06-28 12:55:59 +01002668 * Gets the plugin IDs that should be run after this plugin.
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002669 *
2670 * Returns: %TRUE if the name exists for the specific rule
Mario Limonciello1a680f32019-11-25 19:44:53 -06002671 *
2672 * Since: 1.0.0
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002673 **/
2674gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002675fu_plugin_has_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002676{
Richard Hughes12724852018-09-04 13:53:44 +01002677 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes11c59412020-06-22 15:29:48 +01002678 if (priv->rules[rule] == NULL)
2679 return FALSE;
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002680 for (guint i = 0; i < priv->rules[rule]->len; i++) {
2681 const gchar *tmp = g_ptr_array_index (priv->rules[rule], i);
2682 if (g_strcmp0 (tmp, name) == 0)
2683 return TRUE;
2684 }
2685 return FALSE;
2686}
2687
2688/**
Richard Hughes80b79bb2018-01-11 21:11:06 +00002689 * fu_plugin_add_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002690 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00002691 * @key: a string, e.g. `FwupdateVersion`
2692 * @value: a string, e.g. `10`
2693 *
2694 * Sets any additional metadata to be included in the firmware report to aid
2695 * debugging problems.
2696 *
2697 * Any data included here will be sent to the metadata server after user
2698 * confirmation.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002699 *
2700 * Since: 1.0.4
Richard Hughes80b79bb2018-01-11 21:11:06 +00002701 **/
2702void
Richard Hughes12724852018-09-04 13:53:44 +01002703fu_plugin_add_report_metadata (FuPlugin *self, const gchar *key, const gchar *value)
Richard Hughes80b79bb2018-01-11 21:11:06 +00002704{
Richard Hughes12724852018-09-04 13:53:44 +01002705 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes1d900f72020-06-22 15:17:39 +01002706 if (priv->report_metadata == NULL) {
2707 priv->report_metadata = g_hash_table_new_full (g_str_hash,
2708 g_str_equal,
2709 g_free,
2710 g_free);
2711 }
Richard Hughes80b79bb2018-01-11 21:11:06 +00002712 g_hash_table_insert (priv->report_metadata, g_strdup (key), g_strdup (value));
2713}
2714
2715/**
2716 * fu_plugin_get_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002717 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00002718 *
2719 * Returns the list of additional metadata to be added when filing a report.
2720 *
Richard Hughes1d900f72020-06-22 15:17:39 +01002721 * Returns: (transfer none) (nullable): the map of report metadata
Mario Limonciello1a680f32019-11-25 19:44:53 -06002722 *
2723 * Since: 1.0.4
Richard Hughes80b79bb2018-01-11 21:11:06 +00002724 **/
2725GHashTable *
Richard Hughes12724852018-09-04 13:53:44 +01002726fu_plugin_get_report_metadata (FuPlugin *self)
Richard Hughes80b79bb2018-01-11 21:11:06 +00002727{
Richard Hughes12724852018-09-04 13:53:44 +01002728 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002729 return priv->report_metadata;
2730}
2731
Mario Limonciello963dc422018-02-27 14:26:58 -06002732/**
2733 * fu_plugin_get_config_value:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002734 * @self: a #FuPlugin
Mario Limonciello963dc422018-02-27 14:26:58 -06002735 * @key: A settings key
2736 *
2737 * Return the value of a key if it's been configured
2738 *
2739 * Since: 1.0.6
2740 **/
2741gchar *
Richard Hughes12724852018-09-04 13:53:44 +01002742fu_plugin_get_config_value (FuPlugin *self, const gchar *key)
Mario Limonciello963dc422018-02-27 14:26:58 -06002743{
Richard Hughes4be17d12018-05-30 20:36:29 +01002744 g_autofree gchar *conf_dir = NULL;
Mario Limonciello963dc422018-02-27 14:26:58 -06002745 g_autofree gchar *conf_file = NULL;
2746 g_autofree gchar *conf_path = NULL;
2747 g_autoptr(GKeyFile) keyfile = NULL;
2748 const gchar *plugin_name;
2749
Richard Hughes4be17d12018-05-30 20:36:29 +01002750 conf_dir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR_PKG);
Richard Hughes12724852018-09-04 13:53:44 +01002751 plugin_name = fu_plugin_get_name (self);
Mario Limonciello963dc422018-02-27 14:26:58 -06002752 conf_file = g_strdup_printf ("%s.conf", plugin_name);
Richard Hughes4be17d12018-05-30 20:36:29 +01002753 conf_path = g_build_filename (conf_dir, conf_file, NULL);
Mario Limonciello963dc422018-02-27 14:26:58 -06002754 if (!g_file_test (conf_path, G_FILE_TEST_IS_REGULAR))
2755 return NULL;
2756 keyfile = g_key_file_new ();
2757 if (!g_key_file_load_from_file (keyfile, conf_path,
2758 G_KEY_FILE_NONE, NULL))
2759 return NULL;
2760 return g_key_file_get_string (keyfile, plugin_name, key, NULL);
2761}
2762
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002763/**
Richard Hughes334ba792020-02-19 20:44:56 +00002764 * fu_plugin_get_config_value_boolean:
2765 * @self: a #FuPlugin
2766 * @key: A settings key
2767 *
2768 * Return the boolean value of a key if it's been configured
2769 *
2770 * Returns: %TRUE if the value is `true` (case insensitive), %FALSE otherwise
2771 *
Mario Limonciello96117d12020-02-28 10:17:56 -06002772 * Since: 1.4.0
Richard Hughes334ba792020-02-19 20:44:56 +00002773 **/
2774gboolean
2775fu_plugin_get_config_value_boolean (FuPlugin *self, const gchar *key)
2776{
2777 g_autofree gchar *tmp = fu_plugin_get_config_value (self, key);
2778 if (tmp == NULL)
2779 return FALSE;
Richard Hughes5337a432020-02-21 12:04:32 +00002780 return g_ascii_strcasecmp (tmp, "true") == 0;
Richard Hughes334ba792020-02-19 20:44:56 +00002781}
2782
2783/**
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002784 * fu_plugin_name_compare:
2785 * @plugin1: first #FuPlugin to compare.
2786 * @plugin2: second #FuPlugin to compare.
2787 *
2788 * Compares two plugins by their names.
2789 *
2790 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002791 *
2792 * Since: 1.0.8
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002793 **/
2794gint
2795fu_plugin_name_compare (FuPlugin *plugin1, FuPlugin *plugin2)
2796{
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002797 return g_strcmp0 (fu_plugin_get_name (plugin1), fu_plugin_get_name (plugin2));
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002798}
2799
2800/**
2801 * fu_plugin_order_compare:
2802 * @plugin1: first #FuPlugin to compare.
2803 * @plugin2: second #FuPlugin to compare.
2804 *
2805 * Compares two plugins by their depsolved order.
2806 *
2807 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002808 *
2809 * Since: 1.0.8
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002810 **/
2811gint
2812fu_plugin_order_compare (FuPlugin *plugin1, FuPlugin *plugin2)
2813{
2814 FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1);
2815 FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2);
2816 if (priv1->order < priv2->order)
2817 return -1;
2818 if (priv1->order > priv2->order)
2819 return 1;
2820 return 0;
2821}
2822
Richard Hughescff38bc2016-12-12 12:03:37 +00002823static void
2824fu_plugin_class_init (FuPluginClass *klass)
2825{
2826 GObjectClass *object_class = G_OBJECT_CLASS (klass);
2827 object_class->finalize = fu_plugin_finalize;
2828 signals[SIGNAL_DEVICE_ADDED] =
2829 g_signal_new ("device-added",
2830 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2831 G_STRUCT_OFFSET (FuPluginClass, device_added),
2832 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2833 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
2834 signals[SIGNAL_DEVICE_REMOVED] =
2835 g_signal_new ("device-removed",
2836 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2837 G_STRUCT_OFFSET (FuPluginClass, device_removed),
2838 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2839 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughese1fd34d2017-08-24 14:19:51 +01002840 signals[SIGNAL_DEVICE_REGISTER] =
2841 g_signal_new ("device-register",
2842 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2843 G_STRUCT_OFFSET (FuPluginClass, device_register),
2844 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2845 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughes362d6d72017-01-07 21:42:14 +00002846 signals[SIGNAL_RECOLDPLUG] =
2847 g_signal_new ("recoldplug",
2848 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2849 G_STRUCT_OFFSET (FuPluginClass, recoldplug),
2850 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2851 G_TYPE_NONE, 0);
Richard Hughes399859e2020-05-11 19:44:03 +01002852 signals[SIGNAL_SECURITY_CHANGED] =
2853 g_signal_new ("security-changed",
2854 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2855 G_STRUCT_OFFSET (FuPluginClass, security_changed),
2856 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2857 G_TYPE_NONE, 0);
Richard Hughesb0829032017-01-10 09:27:08 +00002858 signals[SIGNAL_SET_COLDPLUG_DELAY] =
2859 g_signal_new ("set-coldplug-delay",
2860 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2861 G_STRUCT_OFFSET (FuPluginClass, set_coldplug_delay),
2862 NULL, NULL, g_cclosure_marshal_VOID__UINT,
2863 G_TYPE_NONE, 1, G_TYPE_UINT);
Richard Hughesaabdc372018-11-14 10:11:08 +00002864 signals[SIGNAL_CHECK_SUPPORTED] =
2865 g_signal_new ("check-supported",
2866 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2867 G_STRUCT_OFFSET (FuPluginClass, check_supported),
2868 NULL, NULL, g_cclosure_marshal_generic,
2869 G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
Richard Hughes75b965d2018-11-15 13:51:21 +00002870 signals[SIGNAL_RULES_CHANGED] =
2871 g_signal_new ("rules-changed",
2872 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2873 G_STRUCT_OFFSET (FuPluginClass, rules_changed),
2874 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2875 G_TYPE_NONE, 0);
Richard Hughes95c98a92019-10-22 16:03:15 +01002876 signals[SIGNAL_ADD_FIRMWARE_GTYPE] =
2877 g_signal_new ("add-firmware-gtype",
2878 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2879 G_STRUCT_OFFSET (FuPluginClass, add_firmware_gtype),
2880 NULL, NULL, g_cclosure_marshal_generic,
2881 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_GTYPE);
Richard Hughescff38bc2016-12-12 12:03:37 +00002882}
2883
2884static void
Richard Hughes12724852018-09-04 13:53:44 +01002885fu_plugin_init (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +00002886{
Richard Hughes12724852018-09-04 13:53:44 +01002887 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes161e9b52019-06-12 14:22:45 +01002888 g_rw_lock_init (&priv->devices_mutex);
Richard Hughescff38bc2016-12-12 12:03:37 +00002889}
2890
2891static void
2892fu_plugin_finalize (GObject *object)
2893{
Richard Hughes12724852018-09-04 13:53:44 +01002894 FuPlugin *self = FU_PLUGIN (object);
2895 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002896 FuPluginInitFunc func = NULL;
2897
Richard Hughesaae22e42020-06-22 21:32:59 +01002898 g_rw_lock_clear (&priv->devices_mutex);
2899
Richard Hughescff38bc2016-12-12 12:03:37 +00002900 /* optional */
2901 if (priv->module != NULL) {
2902 g_module_symbol (priv->module, "fu_plugin_destroy", (gpointer *) &func);
2903 if (func != NULL) {
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002904 g_debug ("destroy(%s)", fu_plugin_get_name (self));
Richard Hughes12724852018-09-04 13:53:44 +01002905 func (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002906 }
2907 }
2908
Richard Hughes11c59412020-06-22 15:29:48 +01002909 for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++) {
2910 if (priv->rules[i] != NULL)
2911 g_ptr_array_unref (priv->rules[i]);
2912 }
Richard Hughescff38bc2016-12-12 12:03:37 +00002913 if (priv->usb_ctx != NULL)
2914 g_object_unref (priv->usb_ctx);
Richard Hughesb8f8db22017-04-25 15:56:00 +01002915 if (priv->hwids != NULL)
Richard Hughesd7704d42017-08-08 20:29:09 +01002916 g_object_unref (priv->hwids);
Richard Hughes9c028f02017-10-28 21:14:28 +01002917 if (priv->quirks != NULL)
2918 g_object_unref (priv->quirks);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01002919 if (priv->udev_subsystems != NULL)
2920 g_ptr_array_unref (priv->udev_subsystems);
Richard Hughes49e5e052017-09-03 12:15:41 +01002921 if (priv->smbios != NULL)
2922 g_object_unref (priv->smbios);
Richard Hughes275d3b42018-04-20 16:40:37 +01002923 if (priv->runtime_versions != NULL)
2924 g_hash_table_unref (priv->runtime_versions);
Richard Hughes34e0dab2018-04-20 16:43:00 +01002925 if (priv->compile_versions != NULL)
2926 g_hash_table_unref (priv->compile_versions);
Richard Hughes1d900f72020-06-22 15:17:39 +01002927 if (priv->report_metadata != NULL)
2928 g_hash_table_unref (priv->report_metadata);
Richard Hughes371f6b22020-06-22 15:21:17 +01002929 if (priv->devices != NULL)
2930 g_hash_table_unref (priv->devices);
Richard Hughes84999302019-05-02 10:18:32 +01002931 g_free (priv->build_hash);
Richard Hughescff38bc2016-12-12 12:03:37 +00002932 g_free (priv->data);
Mario Limonciello3f9a1c12018-06-06 14:06:40 -05002933 /* Must happen as the last step to avoid prematurely
2934 * freeing memory held by the plugin */
Richard Hughes862ec5c2020-05-22 14:38:02 +01002935#ifdef RUNNING_ON_VALGRIND
2936 if (priv->module != NULL && RUNNING_ON_VALGRIND == 0)
2937#else
Mario Limonciello3f9a1c12018-06-06 14:06:40 -05002938 if (priv->module != NULL)
Mario Limonciello3f9a1c12018-06-06 14:06:40 -05002939#endif
Richard Hughes862ec5c2020-05-22 14:38:02 +01002940 g_module_close (priv->module);
Richard Hughescff38bc2016-12-12 12:03:37 +00002941
2942 G_OBJECT_CLASS (fu_plugin_parent_class)->finalize (object);
2943}
2944
Mario Limonciello1a680f32019-11-25 19:44:53 -06002945/**
2946 * fu_plugin_new:
2947 *
2948 * Creates a new #FuPlugin
2949 *
2950 * Since: 0.8.0
2951 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002952FuPlugin *
2953fu_plugin_new (void)
2954{
Richard Hughes12724852018-09-04 13:53:44 +01002955 return FU_PLUGIN (g_object_new (FU_TYPE_PLUGIN, NULL));
Richard Hughescff38bc2016-12-12 12:03:37 +00002956}