blob: 539f8ea082a1deddc2209f9df0acbf5b1fd27149 [file] [log] [blame]
Richard Hughes02c90d82018-08-09 12:13:03 +01001/*
Richard Hughes5c9b1fc2021-01-07 14:20:49 +00002 * Copyright (C) 2016 Richard Hughes <richard@hughsie.com>
Richard Hughesd0905142016-03-13 09:46:49 +00003 *
Mario Limonciello51308e62018-05-28 20:05:46 -05004 * SPDX-License-Identifier: LGPL-2.1+
Richard Hughesd0905142016-03-13 09:46:49 +00005 */
6
Richard Hughesb08e7bc2018-09-11 10:51:13 +01007#define G_LOG_DOMAIN "FuPlugin"
8
Richard Hughesd0905142016-03-13 09:46:49 +00009#include "config.h"
10
Richard Hughescff38bc2016-12-12 12:03:37 +000011#include <fwupd.h>
12#include <gmodule.h>
Richard Hughescff38bc2016-12-12 12:03:37 +000013#include <errno.h>
14#include <string.h>
Richard Hughes68f12dd2018-08-09 14:43:31 +010015#include <unistd.h>
Richard Hughesd0905142016-03-13 09:46:49 +000016
Richard Hughesb333e002021-04-01 10:40:02 +010017#include "fu-context-private.h"
Richard Hughes9dde04f2017-09-13 12:07:15 +010018#include "fu-device-private.h"
Richard Hughescff38bc2016-12-12 12:03:37 +000019#include "fu-plugin-private.h"
Richard Hughes37d09432018-09-09 10:39:45 +010020#include "fu-mutex.h"
Richard Hughesd0905142016-03-13 09:46:49 +000021
Richard Hughes4eada342017-10-03 21:20:32 +010022/**
23 * SECTION:fu-plugin
24 * @short_description: a daemon plugin
25 *
26 * An object that represents a plugin run by the daemon.
27 *
28 * See also: #FuDevice
29 */
30
Richard Hughescff38bc2016-12-12 12:03:37 +000031static void fu_plugin_finalize (GObject *object);
32
33typedef struct {
34 GModule *module;
Richard Hughes08a37992017-09-12 12:57:43 +010035 guint order;
Richard Hughes81c427c2018-08-06 15:20:17 +010036 guint priority;
Richard Hughes08a37992017-09-12 12:57:43 +010037 GPtrArray *rules[FU_PLUGIN_RULE_LAST];
Richard Hughes68ab1e42021-01-13 14:01:17 +000038 GPtrArray *devices; /* (nullable) (element-type FuDevice) */
Richard Hughesf425d292019-01-18 17:57:39 +000039 gchar *build_hash;
Richard Hughes0eb123b2018-04-19 12:00:04 +010040 GHashTable *runtime_versions;
Richard Hughes34e0dab2018-04-20 16:43:00 +010041 GHashTable *compile_versions;
Richard Hughesb333e002021-04-01 10:40:02 +010042 FuContext *ctx;
Richard Hughesfaa35e42021-04-15 09:38:03 +010043 GArray *device_gtypes; /* (nullable): of #GType */
Richard Hughesfaf2afe2021-01-13 14:00:20 +000044 GHashTable *cache; /* (nullable): platform_id:GObject */
45 GRWLock cache_mutex;
Richard Hughes1d900f72020-06-22 15:17:39 +010046 GHashTable *report_metadata; /* (nullable): key:value */
Richard Hughescff38bc2016-12-12 12:03:37 +000047 FuPluginData *data;
48} FuPluginPrivate;
49
50enum {
51 SIGNAL_DEVICE_ADDED,
52 SIGNAL_DEVICE_REMOVED,
Richard Hughese1fd34d2017-08-24 14:19:51 +010053 SIGNAL_DEVICE_REGISTER,
Richard Hughes75b965d2018-11-15 13:51:21 +000054 SIGNAL_RULES_CHANGED,
Richard Hughesaabdc372018-11-14 10:11:08 +000055 SIGNAL_CHECK_SUPPORTED,
Richard Hughescff38bc2016-12-12 12:03:37 +000056 SIGNAL_LAST
57};
58
59static guint signals[SIGNAL_LAST] = { 0 };
60
Richard Hughes7bcb8d42020-10-08 15:47:47 +010061G_DEFINE_TYPE_WITH_PRIVATE (FuPlugin, fu_plugin, FWUPD_TYPE_PLUGIN)
Richard Hughescff38bc2016-12-12 12:03:37 +000062#define GET_PRIVATE(o) (fu_plugin_get_instance_private (o))
63
64typedef const gchar *(*FuPluginGetNameFunc) (void);
Richard Hughes12724852018-09-04 13:53:44 +010065typedef void (*FuPluginInitFunc) (FuPlugin *self);
66typedef gboolean (*FuPluginStartupFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000067 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010068typedef void (*FuPluginDeviceRegisterFunc) (FuPlugin *self,
Richard Hughese1fd34d2017-08-24 14:19:51 +010069 FuDevice *device);
Richard Hughes12724852018-09-04 13:53:44 +010070typedef gboolean (*FuPluginDeviceFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000071 FuDevice *device,
72 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010073typedef gboolean (*FuPluginFlaggedDeviceFunc) (FuPlugin *self,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -050074 FwupdInstallFlags flags,
75 FuDevice *device,
76 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010077typedef gboolean (*FuPluginDeviceArrayFunc) (FuPlugin *self,
Richard Hughesdbd8c762018-06-15 20:31:40 +010078 GPtrArray *devices,
79 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010080typedef gboolean (*FuPluginVerifyFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000081 FuDevice *device,
82 FuPluginVerifyFlags flags,
83 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010084typedef gboolean (*FuPluginUpdateFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000085 FuDevice *device,
86 GBytes *blob_fw,
87 FwupdInstallFlags flags,
88 GError **error);
Richard Hughesf58ac732020-05-12 15:23:44 +010089typedef void (*FuPluginSecurityAttrsFunc) (FuPlugin *self,
90 FuSecurityAttrs *attrs);
Richard Hughescff38bc2016-12-12 12:03:37 +000091
Richard Hughes57d18222017-01-10 16:02:59 +000092/**
Mario Limonciello52e75ba2019-11-22 13:21:19 -060093 * fu_plugin_is_open:
94 * @self: A #FuPlugin
95 *
96 * Determines if the plugin is opened
97 *
98 * Returns: TRUE for opened, FALSE for not
99 *
100 * Since: 1.3.5
101 **/
102gboolean
103fu_plugin_is_open (FuPlugin *self)
104{
105 FuPluginPrivate *priv = GET_PRIVATE (self);
106 return priv->module != NULL;
107}
108
109/**
Richard Hughes57d18222017-01-10 16:02:59 +0000110 * fu_plugin_get_name:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100111 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000112 *
113 * Gets the plugin name.
114 *
115 * Returns: a plugin name, or %NULL for unknown.
116 *
117 * Since: 0.8.0
118 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000119const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100120fu_plugin_get_name (FuPlugin *self)
Richard Hughesd0905142016-03-13 09:46:49 +0000121{
Richard Hughes12724852018-09-04 13:53:44 +0100122 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100123 return fwupd_plugin_get_name (FWUPD_PLUGIN (self));
Richard Hughescff38bc2016-12-12 12:03:37 +0000124}
Richard Hughesd0905142016-03-13 09:46:49 +0000125
Mario Limonciello1a680f32019-11-25 19:44:53 -0600126/**
127 * fu_plugin_set_name:
128 * @self: A #FuPlugin
129 * @name: A string
130 *
131 * Sets the plugin name.
132 *
133 * Since: 0.8.0
134 **/
Richard Hughes34834102017-11-21 21:55:00 +0000135void
Richard Hughes12724852018-09-04 13:53:44 +0100136fu_plugin_set_name (FuPlugin *self, const gchar *name)
Richard Hughes34834102017-11-21 21:55:00 +0000137{
Richard Hughes12724852018-09-04 13:53:44 +0100138 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100139 fwupd_plugin_set_name (FWUPD_PLUGIN (self), name);
Richard Hughes34834102017-11-21 21:55:00 +0000140}
141
Richard Hughes57d18222017-01-10 16:02:59 +0000142/**
Richard Hughesf425d292019-01-18 17:57:39 +0000143 * fu_plugin_set_build_hash:
144 * @self: A #FuPlugin
145 * @build_hash: A checksum
146 *
147 * Sets the plugin build hash, typically a SHA256 checksum. All plugins must
148 * set the correct checksum to avoid the daemon being marked as tainted.
149 *
150 * Since: 1.2.4
151 **/
152void
153fu_plugin_set_build_hash (FuPlugin *self, const gchar *build_hash)
154{
155 FuPluginPrivate *priv = GET_PRIVATE (self);
156 g_return_if_fail (FU_IS_PLUGIN (self));
157 g_return_if_fail (build_hash != NULL);
Richard Hughes382524d2021-01-28 13:14:35 +0000158
159 /* not changed */
160 if (g_strcmp0 (priv->build_hash, build_hash) == 0)
161 return;
162
Richard Hughesf425d292019-01-18 17:57:39 +0000163 g_free (priv->build_hash);
164 priv->build_hash = g_strdup (build_hash);
165}
166
Mario Limonciello1a680f32019-11-25 19:44:53 -0600167/**
168 * fu_plugin_get_build_hash:
169 * @self: A #FuPlugin
170 *
171 * Gets the build hash a plugin was generated with.
172 *
173 * Returns: (transfer none): a #gchar, or %NULL for unset.
174 *
175 * Since: 1.2.4
176 **/
Richard Hughesf425d292019-01-18 17:57:39 +0000177const gchar *
178fu_plugin_get_build_hash (FuPlugin *self)
179{
180 FuPluginPrivate *priv = GET_PRIVATE (self);
181 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
182 return priv->build_hash;
183}
184
185/**
Richard Hughes57d18222017-01-10 16:02:59 +0000186 * fu_plugin_cache_lookup:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100187 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000188 * @id: the key
189 *
190 * Finds an object in the per-plugin cache.
191 *
192 * Returns: (transfer none): a #GObject, or %NULL for unfound.
193 *
194 * Since: 0.8.0
195 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000196gpointer
Richard Hughes12724852018-09-04 13:53:44 +0100197fu_plugin_cache_lookup (FuPlugin *self, const gchar *id)
Richard Hughescff38bc2016-12-12 12:03:37 +0000198{
Richard Hughes12724852018-09-04 13:53:44 +0100199 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesfaf2afe2021-01-13 14:00:20 +0000200 g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&priv->cache_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100201 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughesccd78a92017-01-11 16:57:41 +0000202 g_return_val_if_fail (id != NULL, NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100203 g_return_val_if_fail (locker != NULL, NULL);
Richard Hughesfaf2afe2021-01-13 14:00:20 +0000204 if (priv->cache == NULL)
Richard Hughes371f6b22020-06-22 15:21:17 +0100205 return NULL;
Richard Hughesfaf2afe2021-01-13 14:00:20 +0000206 return g_hash_table_lookup (priv->cache, id);
Richard Hughescff38bc2016-12-12 12:03:37 +0000207}
Richard Hughesd0905142016-03-13 09:46:49 +0000208
Richard Hughes57d18222017-01-10 16:02:59 +0000209/**
210 * fu_plugin_cache_add:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100211 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000212 * @id: the key
213 * @dev: a #GObject, typically a #FuDevice
214 *
215 * Adds an object to the per-plugin cache.
216 *
217 * Since: 0.8.0
218 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000219void
Richard Hughes12724852018-09-04 13:53:44 +0100220fu_plugin_cache_add (FuPlugin *self, const gchar *id, gpointer dev)
Richard Hughescff38bc2016-12-12 12:03:37 +0000221{
Richard Hughes12724852018-09-04 13:53:44 +0100222 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesfaf2afe2021-01-13 14:00:20 +0000223 g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&priv->cache_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100224 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000225 g_return_if_fail (id != NULL);
Richard Hughes46f86a52021-04-20 11:47:46 +0100226 g_return_if_fail (G_IS_OBJECT (dev));
Richard Hughes37d09432018-09-09 10:39:45 +0100227 g_return_if_fail (locker != NULL);
Richard Hughesfaf2afe2021-01-13 14:00:20 +0000228 if (priv->cache == NULL) {
229 priv->cache = g_hash_table_new_full (g_str_hash,
230 g_str_equal,
231 g_free,
232 (GDestroyNotify) g_object_unref);
Richard Hughes371f6b22020-06-22 15:21:17 +0100233 }
Richard Hughesfaf2afe2021-01-13 14:00:20 +0000234 g_hash_table_insert (priv->cache, g_strdup (id), g_object_ref (dev));
Richard Hughescff38bc2016-12-12 12:03:37 +0000235}
236
Richard Hughes57d18222017-01-10 16:02:59 +0000237/**
238 * fu_plugin_cache_remove:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100239 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000240 * @id: the key
241 *
242 * Removes an object from the per-plugin cache.
243 *
244 * Since: 0.8.0
245 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000246void
Richard Hughes12724852018-09-04 13:53:44 +0100247fu_plugin_cache_remove (FuPlugin *self, const gchar *id)
Richard Hughescff38bc2016-12-12 12:03:37 +0000248{
Richard Hughes12724852018-09-04 13:53:44 +0100249 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesfaf2afe2021-01-13 14:00:20 +0000250 g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&priv->cache_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100251 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000252 g_return_if_fail (id != NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100253 g_return_if_fail (locker != NULL);
Richard Hughesfaf2afe2021-01-13 14:00:20 +0000254 if (priv->cache == NULL)
Richard Hughes371f6b22020-06-22 15:21:17 +0100255 return;
Richard Hughesfaf2afe2021-01-13 14:00:20 +0000256 g_hash_table_remove (priv->cache, id);
Richard Hughescff38bc2016-12-12 12:03:37 +0000257}
258
Richard Hughes57d18222017-01-10 16:02:59 +0000259/**
260 * fu_plugin_get_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100261 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000262 *
Richard Hughes4eada342017-10-03 21:20:32 +0100263 * Gets the per-plugin allocated private data. This will return %NULL unless
264 * fu_plugin_alloc_data() has been called by the plugin.
Richard Hughes57d18222017-01-10 16:02:59 +0000265 *
Richard Hughes4eada342017-10-03 21:20:32 +0100266 * Returns: (transfer none): a pointer to a structure, or %NULL for unset.
Richard Hughes57d18222017-01-10 16:02:59 +0000267 *
268 * Since: 0.8.0
269 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000270FuPluginData *
Richard Hughes12724852018-09-04 13:53:44 +0100271fu_plugin_get_data (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +0000272{
Richard Hughes12724852018-09-04 13:53:44 +0100273 FuPluginPrivate *priv = GET_PRIVATE (self);
274 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000275 return priv->data;
276}
277
Richard Hughes57d18222017-01-10 16:02:59 +0000278/**
Richard Hughes00f66f62019-11-27 11:42:53 +0000279 * fu_plugin_alloc_data: (skip):
Richard Hughes2c0635a2018-09-04 14:52:46 +0100280 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000281 * @data_sz: the size to allocate
282 *
283 * Allocates the per-plugin allocated private data.
284 *
285 * Returns: (transfer full): a pointer to a structure, or %NULL for unset.
286 *
287 * Since: 0.8.0
288 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000289FuPluginData *
Richard Hughes12724852018-09-04 13:53:44 +0100290fu_plugin_alloc_data (FuPlugin *self, gsize data_sz)
Richard Hughescff38bc2016-12-12 12:03:37 +0000291{
Richard Hughes12724852018-09-04 13:53:44 +0100292 FuPluginPrivate *priv = GET_PRIVATE (self);
293 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes44dee882017-01-11 08:31:10 +0000294 if (priv->data != NULL) {
295 g_critical ("fu_plugin_alloc_data() already used by plugin");
296 return priv->data;
297 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000298 priv->data = g_malloc0 (data_sz);
299 return priv->data;
Richard Hughesd0905142016-03-13 09:46:49 +0000300}
301
Richard Hughes57d18222017-01-10 16:02:59 +0000302/**
Mario Limonciello1a680f32019-11-25 19:44:53 -0600303 * fu_plugin_guess_name_from_fn:
304 * @filename: filename to guess
305 *
306 * Tries to guess the name of the plugin from a filename
307 *
308 * Returns: (transfer full): the guessed name of the plugin
309 *
310 * Since: 1.0.8
311 **/
Richard Hughes1e456bc2018-05-10 20:16:16 +0100312gchar *
313fu_plugin_guess_name_from_fn (const gchar *filename)
314{
315 const gchar *prefix = "libfu_plugin_";
316 gchar *name;
317 gchar *str = g_strstr_len (filename, -1, prefix);
318 if (str == NULL)
319 return NULL;
320 name = g_strdup (str + strlen (prefix));
321 g_strdelimit (name, ".", '\0');
322 return name;
323}
324
Mario Limonciello1a680f32019-11-25 19:44:53 -0600325/**
326 * fu_plugin_open:
327 * @self: A #FuPlugin
328 * @filename: The shared object filename to open
329 * @error: A #GError or NULL
330 *
331 * Opens the plugin module
332 *
333 * Returns: TRUE for success, FALSE for fail
334 *
335 * Since: 0.8.0
336 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000337gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100338fu_plugin_open (FuPlugin *self, const gchar *filename, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +0000339{
Richard Hughes12724852018-09-04 13:53:44 +0100340 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +0000341 FuPluginInitFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000342
Richard Hughes6a489a92020-12-22 10:32:06 +0000343 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
344 g_return_val_if_fail (filename != NULL, FALSE);
345 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
346
Richard Hughescff38bc2016-12-12 12:03:37 +0000347 priv->module = g_module_open (filename, 0);
348 if (priv->module == NULL) {
349 g_set_error (error,
350 G_IO_ERROR,
351 G_IO_ERROR_FAILED,
Mario Limonciellof5605532019-11-04 07:49:50 -0600352 "failed to open plugin %s: %s",
353 filename, g_module_error ());
Mario Limoncielloc3a81732020-10-20 09:16:18 -0500354 fu_plugin_add_flag (self, FWUPD_PLUGIN_FLAG_FAILED_OPEN);
355 fu_plugin_add_flag (self, FWUPD_PLUGIN_FLAG_USER_WARNING);
Richard Hughescff38bc2016-12-12 12:03:37 +0000356 return FALSE;
357 }
358
359 /* set automatically */
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100360 if (fu_plugin_get_name (self) == NULL) {
361 g_autofree gchar *str = fu_plugin_guess_name_from_fn (filename);
362 fu_plugin_set_name (self, str);
363 }
Richard Hughesd0905142016-03-13 09:46:49 +0000364
365 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000366 g_module_symbol (priv->module, "fu_plugin_init", (gpointer *) &func);
367 if (func != NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -0500368 g_debug ("init(%s)", filename);
Richard Hughes12724852018-09-04 13:53:44 +0100369 func (self);
Richard Hughesd0905142016-03-13 09:46:49 +0000370 }
371
Richard Hughescff38bc2016-12-12 12:03:37 +0000372 return TRUE;
373}
374
Richard Hughes203ed842020-11-02 14:25:13 +0000375/* order of usefulness to the user */
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100376static const gchar *
377fu_plugin_build_device_update_error (FuPlugin *self)
378{
379 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_NO_HARDWARE))
380 return "Not updatable as required hardware was not found";
381 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_LEGACY_BIOS))
382 return "Not updatable in legacy BIOS mode";
383 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED))
Mario Limonciello797da4f2021-01-12 12:38:51 -0600384 return "Not updatable as UEFI capsule updates not enabled in firmware setup";
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100385 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_UNLOCK_REQUIRED))
386 return "Not updatable as requires unlock";
387 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_EFIVAR_NOT_MOUNTED))
388 return "Not updatable as efivarfs was not found";
389 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND))
390 return "Not updatable as UEFI ESP partition not detected";
391 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
392 return "Not updatable as plugin was disabled";
393 return NULL;
394}
395
Richard Hughes68ab1e42021-01-13 14:01:17 +0000396static void
397fu_plugin_ensure_devices (FuPlugin *self)
398{
399 FuPluginPrivate *priv = GET_PRIVATE (self);
400 if (priv->devices != NULL)
401 return;
402 priv->devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
403}
404
Richard Hughes57d18222017-01-10 16:02:59 +0000405/**
406 * fu_plugin_device_add:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100407 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000408 * @device: A #FuDevice
409 *
410 * Asks the daemon to add a device to the exported list. If this device ID
411 * has already been added by a different plugin then this request will be
412 * ignored.
413 *
414 * Plugins should use fu_plugin_device_add_delay() if they are not capable of
415 * actually flashing an image to the hardware so that higher-priority plugins
416 * can add the device themselves.
417 *
418 * Since: 0.8.0
419 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000420void
Richard Hughes12724852018-09-04 13:53:44 +0100421fu_plugin_device_add (FuPlugin *self, FuDevice *device)
Richard Hughescff38bc2016-12-12 12:03:37 +0000422{
Richard Hughes68ab1e42021-01-13 14:01:17 +0000423 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes5e447292018-04-27 14:25:54 +0100424 GPtrArray *children;
Richard Hughesc125ec02018-09-05 19:35:17 +0100425 g_autoptr(GError) error = NULL;
Richard Hughes5e447292018-04-27 14:25:54 +0100426
Richard Hughes12724852018-09-04 13:53:44 +0100427 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000428 g_return_if_fail (FU_IS_DEVICE (device));
429
Richard Hughesc125ec02018-09-05 19:35:17 +0100430 /* ensure the device ID is set from the physical and logical IDs */
431 if (!fu_device_ensure_id (device, &error)) {
432 g_warning ("ignoring add: %s", error->message);
433 return;
434 }
435
Richard Hughes68ab1e42021-01-13 14:01:17 +0000436 /* add to array */
437 fu_plugin_ensure_devices (self);
438 g_ptr_array_add (priv->devices, g_object_ref (device));
439
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100440 /* proxy to device where required */
441 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE)) {
442 g_debug ("plugin %s has _CLEAR_UPDATABLE, so removing from %s",
443 fu_plugin_get_name (self),
444 fu_device_get_id (device));
445 fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE);
446 }
447 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_USER_WARNING) &&
448 fu_device_get_update_error (device) == NULL) {
449 const gchar *tmp = fu_plugin_build_device_update_error (self);
450 g_debug ("setting %s update error to '%s' from %s",
451 fu_device_get_id (device), tmp, fu_plugin_get_name (self));
452 fu_device_set_update_error (device, tmp);
453 }
454
Richard Hughescff38bc2016-12-12 12:03:37 +0000455 g_debug ("emit added from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100456 fu_plugin_get_name (self),
Richard Hughescff38bc2016-12-12 12:03:37 +0000457 fu_device_get_id (device));
458 fu_device_set_created (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
Richard Hughes12724852018-09-04 13:53:44 +0100459 fu_device_set_plugin (device, fu_plugin_get_name (self));
460 g_signal_emit (self, signals[SIGNAL_DEVICE_ADDED], 0, device);
Richard Hughes5e447292018-04-27 14:25:54 +0100461
Richard Hughes128c0162018-08-10 11:00:29 +0100462 /* add children if they have not already been added */
Richard Hughes5e447292018-04-27 14:25:54 +0100463 children = fu_device_get_children (device);
464 for (guint i = 0; i < children->len; i++) {
465 FuDevice *child = g_ptr_array_index (children, i);
Richard Hughes128c0162018-08-10 11:00:29 +0100466 if (fu_device_get_created (child) == 0)
Richard Hughes12724852018-09-04 13:53:44 +0100467 fu_plugin_device_add (self, child);
Richard Hughes5e447292018-04-27 14:25:54 +0100468 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000469}
470
Richard Hughese1fd34d2017-08-24 14:19:51 +0100471/**
Richard Hughes68ab1e42021-01-13 14:01:17 +0000472 * fu_plugin_get_devices:
473 * @self: A #FuPlugin
474 *
475 * Returns all devices added by the plugin using fu_plugin_device_add() and
476 * not yet removed with fu_plugin_device_remove().
477 *
478 * Returns: (transfer none) (element-type FuDevice): devices
479 *
480 * Since: 1.5.6
481 **/
482GPtrArray *
483fu_plugin_get_devices (FuPlugin *self)
484{
485 FuPluginPrivate *priv = GET_PRIVATE (self);
486 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
487 fu_plugin_ensure_devices (self);
488 return priv->devices;
489}
490
491/**
Richard Hughese1fd34d2017-08-24 14:19:51 +0100492 * fu_plugin_device_register:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100493 * @self: A #FuPlugin
Richard Hughese1fd34d2017-08-24 14:19:51 +0100494 * @device: A #FuDevice
495 *
496 * Registers the device with other plugins so they can set metadata.
497 *
498 * Plugins do not have to call this manually as this is done automatically
499 * when using fu_plugin_device_add(). They may wish to use this manually
Richard Hughes21eaeef2020-01-14 12:10:01 +0000500 * if for instance the coldplug should be ignored based on the metadata
Richard Hughese1fd34d2017-08-24 14:19:51 +0100501 * set from other plugins.
502 *
503 * Since: 0.9.7
504 **/
505void
Richard Hughes12724852018-09-04 13:53:44 +0100506fu_plugin_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +0100507{
Richard Hughesc125ec02018-09-05 19:35:17 +0100508 g_autoptr(GError) error = NULL;
509
Richard Hughes12724852018-09-04 13:53:44 +0100510 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughese1fd34d2017-08-24 14:19:51 +0100511 g_return_if_fail (FU_IS_DEVICE (device));
512
Richard Hughesc125ec02018-09-05 19:35:17 +0100513 /* ensure the device ID is set from the physical and logical IDs */
514 if (!fu_device_ensure_id (device, &error)) {
515 g_warning ("ignoring registration: %s", error->message);
516 return;
517 }
518
Richard Hughese1fd34d2017-08-24 14:19:51 +0100519 g_debug ("emit device-register from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100520 fu_plugin_get_name (self),
Richard Hughese1fd34d2017-08-24 14:19:51 +0100521 fu_device_get_id (device));
Richard Hughes12724852018-09-04 13:53:44 +0100522 g_signal_emit (self, signals[SIGNAL_DEVICE_REGISTER], 0, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +0100523}
524
Richard Hughes57d18222017-01-10 16:02:59 +0000525/**
Richard Hughes4eada342017-10-03 21:20:32 +0100526 * fu_plugin_device_remove:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100527 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000528 * @device: A #FuDevice
529 *
530 * Asks the daemon to remove a device from the exported list.
531 *
532 * Since: 0.8.0
533 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000534void
Richard Hughes12724852018-09-04 13:53:44 +0100535fu_plugin_device_remove (FuPlugin *self, FuDevice *device)
Richard Hughescff38bc2016-12-12 12:03:37 +0000536{
Richard Hughes68ab1e42021-01-13 14:01:17 +0000537 FuPluginPrivate *priv = GET_PRIVATE (self);
538
Richard Hughes12724852018-09-04 13:53:44 +0100539 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000540 g_return_if_fail (FU_IS_DEVICE (device));
541
Richard Hughes68ab1e42021-01-13 14:01:17 +0000542 /* remove from array */
543 if (priv->devices != NULL)
544 g_ptr_array_remove (priv->devices, device);
545
Richard Hughescff38bc2016-12-12 12:03:37 +0000546 g_debug ("emit removed from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100547 fu_plugin_get_name (self),
Richard Hughescff38bc2016-12-12 12:03:37 +0000548 fu_device_get_id (device));
Richard Hughes12724852018-09-04 13:53:44 +0100549 g_signal_emit (self, signals[SIGNAL_DEVICE_REMOVED], 0, device);
Richard Hughescff38bc2016-12-12 12:03:37 +0000550}
551
Richard Hughes57d18222017-01-10 16:02:59 +0000552/**
Richard Hughes19841802019-09-10 16:48:00 +0100553 * fu_plugin_has_custom_flag:
554 * @self: A #FuPlugin
555 * @flag: A custom text flag, specific to the plugin, e.g. `uefi-force-enable`
556 *
557 * Returns if a per-plugin HwId custom flag exists, typically added from a DMI quirk.
558 *
559 * Returns: %TRUE if the quirk entry exists
560 *
561 * Since: 1.3.1
562 **/
563gboolean
564fu_plugin_has_custom_flag (FuPlugin *self, const gchar *flag)
565{
566 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesb333e002021-04-01 10:40:02 +0100567 GPtrArray *guids;
Richard Hughes19841802019-09-10 16:48:00 +0100568
569 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
570 g_return_val_if_fail (flag != NULL, FALSE);
571
572 /* never set up, e.g. in tests */
Richard Hughesb333e002021-04-01 10:40:02 +0100573 if (priv->ctx == NULL)
Richard Hughes19841802019-09-10 16:48:00 +0100574 return FALSE;
575
576 /* search each hwid */
Richard Hughesb333e002021-04-01 10:40:02 +0100577 guids = fu_context_get_hwid_guids (priv->ctx);
578 for (guint i = 0; i < guids->len; i++) {
579 const gchar *guid = g_ptr_array_index (guids, i);
Richard Hughes19841802019-09-10 16:48:00 +0100580 const gchar *value;
Richard Hughes19841802019-09-10 16:48:00 +0100581
582 /* does prefixed quirk exist */
Richard Hughesb333e002021-04-01 10:40:02 +0100583 value = fu_context_lookup_quirk_by_id (priv->ctx, guid, FU_QUIRKS_FLAGS);
Richard Hughes19841802019-09-10 16:48:00 +0100584 if (value != NULL) {
Richard Hughesb333e002021-04-01 10:40:02 +0100585 g_auto(GStrv) values = g_strsplit (value, ",", -1);
586 if (g_strv_contains ((const gchar * const *) values, flag))
Richard Hughes19841802019-09-10 16:48:00 +0100587 return TRUE;
588 }
589 }
590 return FALSE;
591}
592
593/**
Richard Hughes1354ea92017-09-19 15:58:31 +0100594 * fu_plugin_check_supported:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100595 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100596 * @guid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
Richard Hughes1354ea92017-09-19 15:58:31 +0100597 *
598 * Checks to see if a specific device GUID is supported, i.e. available in the
599 * AppStream metadata.
600 *
Richard Hughes4eada342017-10-03 21:20:32 +0100601 * Returns: %TRUE if the device is supported.
602 *
Richard Hughes1354ea92017-09-19 15:58:31 +0100603 * Since: 1.0.0
604 **/
Richard Hughesd8a8d5e2019-10-08 13:05:02 +0100605static gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100606fu_plugin_check_supported (FuPlugin *self, const gchar *guid)
Richard Hughes1354ea92017-09-19 15:58:31 +0100607{
Richard Hughesaabdc372018-11-14 10:11:08 +0000608 gboolean retval = FALSE;
609 g_signal_emit (self, signals[SIGNAL_CHECK_SUPPORTED], 0, guid, &retval);
610 return retval;
Richard Hughes1354ea92017-09-19 15:58:31 +0100611}
612
613/**
Richard Hughesb333e002021-04-01 10:40:02 +0100614 * fu_plugin_get_context:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100615 * @self: A #FuPlugin
Richard Hughesd7704d42017-08-08 20:29:09 +0100616 *
Richard Hughesb333e002021-04-01 10:40:02 +0100617 * Gets the context for a plugin.
Richard Hughesd7704d42017-08-08 20:29:09 +0100618 *
Richard Hughesb333e002021-04-01 10:40:02 +0100619 * Returns: (transfer none): a #FuContext or %NULL if not set
Richard Hughes4eada342017-10-03 21:20:32 +0100620 *
Richard Hughesb333e002021-04-01 10:40:02 +0100621 * Since: 1.6.0
Richard Hughesd7704d42017-08-08 20:29:09 +0100622 **/
Richard Hughesb333e002021-04-01 10:40:02 +0100623FuContext *
624fu_plugin_get_context (FuPlugin *self)
Richard Hughesd7704d42017-08-08 20:29:09 +0100625{
Richard Hughes12724852018-09-04 13:53:44 +0100626 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesb333e002021-04-01 10:40:02 +0100627 return priv->ctx;
Richard Hughes49e5e052017-09-03 12:15:41 +0100628}
629
Richard Hughes4b303802019-10-04 13:22:51 +0100630static gboolean
631fu_plugin_device_attach (FuPlugin *self, FuDevice *device, GError **error)
632{
633 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughes4b303802019-10-04 13:22:51 +0100634 locker = fu_device_locker_new (device, error);
635 if (locker == NULL)
636 return FALSE;
637 return fu_device_attach (device, error);
638}
639
640static gboolean
641fu_plugin_device_detach (FuPlugin *self, FuDevice *device, GError **error)
642{
643 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughes4b303802019-10-04 13:22:51 +0100644 locker = fu_device_locker_new (device, error);
645 if (locker == NULL)
646 return FALSE;
647 return fu_device_detach (device, error);
648}
649
650static gboolean
Richard Hughes4b303802019-10-04 13:22:51 +0100651fu_plugin_device_activate (FuPlugin *self, FuDevice *device, GError **error)
652{
653 g_autoptr(FuDeviceLocker) locker = NULL;
654 locker = fu_device_locker_new (device, error);
655 if (locker == NULL)
656 return FALSE;
657 return fu_device_activate (device, error);
658}
659
660static gboolean
661fu_plugin_device_write_firmware (FuPlugin *self, FuDevice *device,
662 GBytes *fw, FwupdInstallFlags flags,
663 GError **error)
664{
665 g_autoptr(FuDeviceLocker) locker = NULL;
666 locker = fu_device_locker_new (device, error);
667 if (locker == NULL)
668 return FALSE;
Richard Hughes1a612582020-09-29 19:39:38 +0100669
670 /* back the old firmware up to /var/lib/fwupd */
671 if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL)) {
672 g_autoptr(GBytes) fw_old = NULL;
673 g_autofree gchar *path = NULL;
674 g_autofree gchar *fn = NULL;
675 g_autofree gchar *localstatedir = NULL;
676
677 fw_old = fu_device_dump_firmware (device, error);
678 if (fw_old == NULL) {
679 g_prefix_error (error, "failed to backup old firmware: ");
680 return FALSE;
681 }
682 localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG);
683 fn = g_strdup_printf ("%s.bin", fu_device_get_version (device));
684 path = g_build_filename (localstatedir,
685 "backup",
686 fu_device_get_id (device),
687 fu_device_get_serial (device) != NULL ?
688 fu_device_get_serial (device) :
689 "default",
690 fn, NULL);
691 if (!fu_common_set_contents_bytes (path, fw_old, error))
692 return FALSE;
693 }
694
Richard Hughes4b303802019-10-04 13:22:51 +0100695 return fu_device_write_firmware (device, fw, flags, error);
696}
697
Richard Hughes7f677212019-10-05 16:19:40 +0100698static gboolean
699fu_plugin_device_read_firmware (FuPlugin *self, FuDevice *device, GError **error)
700{
701 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughesf0eb0912019-10-10 11:37:22 +0100702 g_autoptr(FuFirmware) firmware = NULL;
Richard Hughes7f677212019-10-05 16:19:40 +0100703 g_autoptr(GBytes) fw = NULL;
704 GChecksumType checksum_types[] = {
705 G_CHECKSUM_SHA1,
706 G_CHECKSUM_SHA256,
707 0 };
708 locker = fu_device_locker_new (device, error);
709 if (locker == NULL)
710 return FALSE;
711 if (!fu_device_detach (device, error))
712 return FALSE;
Richard Hughesf0eb0912019-10-10 11:37:22 +0100713 firmware = fu_device_read_firmware (device, error);
714 if (firmware == NULL) {
715 g_autoptr(GError) error_local = NULL;
716 if (!fu_device_attach (device, &error_local))
717 g_debug ("ignoring attach failure: %s", error_local->message);
718 g_prefix_error (error, "failed to read firmware: ");
719 return FALSE;
720 }
721 fw = fu_firmware_write (firmware, error);
Richard Hughes7f677212019-10-05 16:19:40 +0100722 if (fw == NULL) {
723 g_autoptr(GError) error_local = NULL;
724 if (!fu_device_attach (device, &error_local))
Richard Hughesf0eb0912019-10-10 11:37:22 +0100725 g_debug ("ignoring attach failure: %s", error_local->message);
726 g_prefix_error (error, "failed to write firmware: ");
Richard Hughes7f677212019-10-05 16:19:40 +0100727 return FALSE;
728 }
729 for (guint i = 0; checksum_types[i] != 0; i++) {
730 g_autofree gchar *hash = NULL;
731 hash = g_compute_checksum_for_bytes (checksum_types[i], fw);
732 fu_device_add_checksum (device, hash);
733 }
734 return fu_device_attach (device, error);
735}
736
Mario Limonciello1a680f32019-11-25 19:44:53 -0600737/**
738 * fu_plugin_runner_startup:
739 * @self: a #FuPlugin
740 * @error: a #GError or NULL
741 *
742 * Runs the startup routine for the plugin
743 *
744 * Returns: #TRUE for success, #FALSE for failure
745 *
746 * Since: 0.8.0
747 **/
Richard Hughesd0905142016-03-13 09:46:49 +0000748gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100749fu_plugin_runner_startup (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +0000750{
Richard Hughes12724852018-09-04 13:53:44 +0100751 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000752 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +0000753 g_autoptr(GError) error_local = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +0000754
755 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100756 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughesd0905142016-03-13 09:46:49 +0000757 return TRUE;
758
Richard Hughes639da472018-01-06 22:35:04 +0000759 /* no object loaded */
760 if (priv->module == NULL)
761 return TRUE;
762
Richard Hughesd0905142016-03-13 09:46:49 +0000763 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000764 g_module_symbol (priv->module, "fu_plugin_startup", (gpointer *) &func);
765 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +0000766 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100767 g_debug ("startup(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +0000768 if (!func (self, &error_local)) {
769 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -0500770 g_critical ("unset plugin error in startup(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100771 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +0000772 g_set_error_literal (&error_local,
773 FWUPD_ERROR,
774 FWUPD_ERROR_INTERNAL,
775 "unspecified error");
776 }
777 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
778 "failed to startup using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100779 fu_plugin_get_name (self));
Richard Hughescff38bc2016-12-12 12:03:37 +0000780 return FALSE;
781 }
782 return TRUE;
783}
784
785static gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100786fu_plugin_runner_device_generic (FuPlugin *self, FuDevice *device,
Richard Hughes4b303802019-10-04 13:22:51 +0100787 const gchar *symbol_name,
788 FuPluginDeviceFunc device_func,
789 GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +0000790{
Richard Hughes12724852018-09-04 13:53:44 +0100791 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0d7fdb32017-11-11 20:23:14 +0000792 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +0000793 g_autoptr(GError) error_local = NULL;
Richard Hughes0d7fdb32017-11-11 20:23:14 +0000794
795 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100796 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes0d7fdb32017-11-11 20:23:14 +0000797 return TRUE;
798
Richard Hughesd3d96cc2017-11-14 11:34:33 +0000799 /* no object loaded */
800 if (priv->module == NULL)
801 return TRUE;
802
Richard Hughes0d7fdb32017-11-11 20:23:14 +0000803 /* optional */
804 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
Richard Hughes4b303802019-10-04 13:22:51 +0100805 if (func == NULL) {
806 if (device_func != NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -0500807 g_debug ("running superclassed %s(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100808 symbol_name + 10, fu_plugin_get_name (self));
Richard Hughes4b303802019-10-04 13:22:51 +0100809 return device_func (self, device, error);
810 }
Richard Hughes0d7fdb32017-11-11 20:23:14 +0000811 return TRUE;
Richard Hughes4b303802019-10-04 13:22:51 +0100812 }
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100813 g_debug ("%s(%s)", symbol_name + 10, fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +0000814 if (!func (self, device, &error_local)) {
815 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -0500816 g_critical ("unset plugin error in %s(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100817 fu_plugin_get_name (self), symbol_name + 10);
Richard Hughescd2fb3e2018-11-29 19:58:09 +0000818 g_set_error_literal (&error_local,
819 FWUPD_ERROR,
820 FWUPD_ERROR_INTERNAL,
821 "unspecified error");
822 }
823 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
824 "failed to %s using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100825 symbol_name + 10, fu_plugin_get_name (self));
Richard Hughes0d7fdb32017-11-11 20:23:14 +0000826 return FALSE;
827 }
828 return TRUE;
829}
830
Richard Hughesdbd8c762018-06-15 20:31:40 +0100831static gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100832fu_plugin_runner_flagged_device_generic (FuPlugin *self, FwupdInstallFlags flags,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -0500833 FuDevice *device,
834 const gchar *symbol_name, GError **error)
835{
Richard Hughes12724852018-09-04 13:53:44 +0100836 FuPluginPrivate *priv = GET_PRIVATE (self);
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -0500837 FuPluginFlaggedDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +0000838 g_autoptr(GError) error_local = NULL;
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -0500839
840 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100841 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -0500842 return TRUE;
843
844 /* no object loaded */
845 if (priv->module == NULL)
846 return TRUE;
847
848 /* optional */
849 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
850 if (func == NULL)
851 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100852 g_debug ("%s(%s)", symbol_name + 10, fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +0000853 if (!func (self, flags, device, &error_local)) {
854 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -0500855 g_critical ("unset plugin error in %s(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100856 fu_plugin_get_name (self), symbol_name + 10);
Richard Hughescd2fb3e2018-11-29 19:58:09 +0000857 g_set_error_literal (&error_local,
858 FWUPD_ERROR,
859 FWUPD_ERROR_INTERNAL,
860 "unspecified error");
861 }
862 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
863 "failed to %s using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100864 symbol_name + 10, fu_plugin_get_name (self));
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -0500865 return FALSE;
866 }
867 return TRUE;
868
869}
870
871static gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100872fu_plugin_runner_device_array_generic (FuPlugin *self, GPtrArray *devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +0100873 const gchar *symbol_name, GError **error)
874{
Richard Hughes12724852018-09-04 13:53:44 +0100875 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesdbd8c762018-06-15 20:31:40 +0100876 FuPluginDeviceArrayFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +0000877 g_autoptr(GError) error_local = NULL;
Richard Hughesdbd8c762018-06-15 20:31:40 +0100878
879 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100880 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughesdbd8c762018-06-15 20:31:40 +0100881 return TRUE;
882
883 /* no object loaded */
884 if (priv->module == NULL)
885 return TRUE;
886
887 /* optional */
888 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
889 if (func == NULL)
890 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100891 g_debug ("%s(%s)", symbol_name + 10, fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +0000892 if (!func (self, devices, &error_local)) {
893 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -0500894 g_critical ("unset plugin error in for %s(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100895 fu_plugin_get_name (self), symbol_name + 10);
Richard Hughescd2fb3e2018-11-29 19:58:09 +0000896 g_set_error_literal (&error_local,
897 FWUPD_ERROR,
898 FWUPD_ERROR_INTERNAL,
899 "unspecified error");
900 }
901 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
902 "failed to %s using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100903 symbol_name + 10, fu_plugin_get_name (self));
Richard Hughesdbd8c762018-06-15 20:31:40 +0100904 return FALSE;
905 }
906 return TRUE;
907}
908
Mario Limonciello1a680f32019-11-25 19:44:53 -0600909/**
910 * fu_plugin_runner_coldplug:
911 * @self: a #FuPlugin
912 * @error: a #GError or NULL
913 *
914 * Runs the coldplug routine for the plugin
915 *
916 * Returns: #TRUE for success, #FALSE for failure
917 *
918 * Since: 0.8.0
919 **/
Richard Hughesd0905142016-03-13 09:46:49 +0000920gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100921fu_plugin_runner_coldplug (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +0000922{
Richard Hughes12724852018-09-04 13:53:44 +0100923 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000924 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +0000925 g_autoptr(GError) error_local = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +0000926
927 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100928 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughesd0905142016-03-13 09:46:49 +0000929 return TRUE;
930
Daniel Campello0b9b7ec2021-04-08 16:32:25 -0600931 /* no HwId */
932 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_REQUIRE_HWID))
933 return TRUE;
934
Richard Hughes639da472018-01-06 22:35:04 +0000935 /* no object loaded */
936 if (priv->module == NULL)
937 return TRUE;
938
Richard Hughesd0905142016-03-13 09:46:49 +0000939 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000940 g_module_symbol (priv->module, "fu_plugin_coldplug", (gpointer *) &func);
941 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +0000942 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100943 g_debug ("coldplug(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +0000944 if (!func (self, &error_local)) {
945 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -0500946 g_critical ("unset plugin error in coldplug(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100947 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +0000948 g_set_error_literal (&error_local,
949 FWUPD_ERROR,
950 FWUPD_ERROR_INTERNAL,
951 "unspecified error");
952 }
953 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100954 "failed to coldplug using %s: ", fu_plugin_get_name (self));
Richard Hughescff38bc2016-12-12 12:03:37 +0000955 return FALSE;
956 }
957 return TRUE;
958}
959
Mario Limonciello1a680f32019-11-25 19:44:53 -0600960/**
Mario Limonciello1a680f32019-11-25 19:44:53 -0600961 * fu_plugin_runner_coldplug_prepare:
962 * @self: a #FuPlugin
963 * @error: a #GError or NULL
964 *
965 * Runs the coldplug_prepare routine for the plugin
966 *
967 * Returns: #TRUE for success, #FALSE for failure
968 *
969 * Since: 0.8.0
970 **/
Richard Hughes2de8f132018-01-17 09:12:02 +0000971gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100972fu_plugin_runner_coldplug_prepare (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +0000973{
Richard Hughes12724852018-09-04 13:53:44 +0100974 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +0000975 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +0000976 g_autoptr(GError) error_local = NULL;
Richard Hughes46487c92017-01-07 21:26:34 +0000977
978 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100979 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes46487c92017-01-07 21:26:34 +0000980 return TRUE;
981
Richard Hughes639da472018-01-06 22:35:04 +0000982 /* no object loaded */
983 if (priv->module == NULL)
984 return TRUE;
985
Richard Hughes46487c92017-01-07 21:26:34 +0000986 /* optional */
987 g_module_symbol (priv->module, "fu_plugin_coldplug_prepare", (gpointer *) &func);
988 if (func == NULL)
989 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100990 g_debug ("coldplug_prepare(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +0000991 if (!func (self, &error_local)) {
992 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -0500993 g_critical ("unset plugin error in coldplug_prepare(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +0100994 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +0000995 g_set_error_literal (&error_local,
996 FWUPD_ERROR,
997 FWUPD_ERROR_INTERNAL,
998 "unspecified error");
999 }
1000 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1001 "failed to coldplug_prepare using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001002 fu_plugin_get_name (self));
Richard Hughes46487c92017-01-07 21:26:34 +00001003 return FALSE;
1004 }
1005 return TRUE;
1006}
1007
Mario Limonciello1a680f32019-11-25 19:44:53 -06001008/**
1009 * fu_plugin_runner_coldplug_cleanup:
1010 * @self: a #FuPlugin
1011 * @error: a #GError or NULL
1012 *
1013 * Runs the coldplug_cleanup routine for the plugin
1014 *
1015 * Returns: #TRUE for success, #FALSE for failure
1016 *
1017 * Since: 0.8.0
1018 **/
Richard Hughes46487c92017-01-07 21:26:34 +00001019gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001020fu_plugin_runner_coldplug_cleanup (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001021{
Richard Hughes12724852018-09-04 13:53:44 +01001022 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001023 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001024 g_autoptr(GError) error_local = NULL;
Richard Hughes46487c92017-01-07 21:26:34 +00001025
1026 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001027 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes46487c92017-01-07 21:26:34 +00001028 return TRUE;
1029
Richard Hughes639da472018-01-06 22:35:04 +00001030 /* no object loaded */
1031 if (priv->module == NULL)
1032 return TRUE;
1033
Richard Hughes46487c92017-01-07 21:26:34 +00001034 /* optional */
1035 g_module_symbol (priv->module, "fu_plugin_coldplug_cleanup", (gpointer *) &func);
1036 if (func == NULL)
1037 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001038 g_debug ("coldplug_cleanup(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001039 if (!func (self, &error_local)) {
1040 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001041 g_critical ("unset plugin error in coldplug_cleanup(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001042 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001043 g_set_error_literal (&error_local,
1044 FWUPD_ERROR,
1045 FWUPD_ERROR_INTERNAL,
1046 "unspecified error");
1047 }
1048 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1049 "failed to coldplug_cleanup using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001050 fu_plugin_get_name (self));
Richard Hughes46487c92017-01-07 21:26:34 +00001051 return FALSE;
1052 }
1053 return TRUE;
1054}
1055
Mario Limonciello1a680f32019-11-25 19:44:53 -06001056/**
1057 * fu_plugin_runner_composite_prepare:
1058 * @self: a #FuPlugin
Richard Hughesa0d81c72019-11-27 11:41:54 +00001059 * @devices: (element-type FuDevice): a #GPtrArray of devices
Mario Limonciello1a680f32019-11-25 19:44:53 -06001060 * @error: a #GError or NULL
1061 *
1062 * Runs the composite_prepare routine for the plugin
1063 *
1064 * Returns: #TRUE for success, #FALSE for failure
1065 *
1066 * Since: 1.0.9
1067 **/
Richard Hughes46487c92017-01-07 21:26:34 +00001068gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001069fu_plugin_runner_composite_prepare (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001070{
Richard Hughes12724852018-09-04 13:53:44 +01001071 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001072 "fu_plugin_composite_prepare",
1073 error);
1074}
1075
Mario Limonciello1a680f32019-11-25 19:44:53 -06001076/**
1077 * fu_plugin_runner_composite_cleanup:
1078 * @self: a #FuPlugin
Richard Hughesa0d81c72019-11-27 11:41:54 +00001079 * @devices: (element-type FuDevice): a #GPtrArray of devices
Mario Limonciello1a680f32019-11-25 19:44:53 -06001080 * @error: a #GError or NULL
1081 *
1082 * Runs the composite_cleanup routine for the plugin
1083 *
1084 * Returns: #TRUE for success, #FALSE for failure
1085 *
1086 * Since: 1.0.9
1087 **/
Richard Hughesdbd8c762018-06-15 20:31:40 +01001088gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001089fu_plugin_runner_composite_cleanup (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001090{
Richard Hughes12724852018-09-04 13:53:44 +01001091 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001092 "fu_plugin_composite_cleanup",
1093 error);
1094}
1095
Mario Limonciello1a680f32019-11-25 19:44:53 -06001096/**
1097 * fu_plugin_runner_update_prepare:
1098 * @self: a #FuPlugin
Richard Hughes2bbb7d22020-11-30 09:18:45 +00001099 * @flags: #FwupdInstallFlags
1100 * @device: a #FuDevice
Mario Limonciello1a680f32019-11-25 19:44:53 -06001101 * @error: a #GError or NULL
1102 *
1103 * Runs the update_prepare routine for the plugin
1104 *
1105 * Returns: #TRUE for success, #FALSE for failure
1106 *
1107 * Since: 1.1.2
1108 **/
Richard Hughesdbd8c762018-06-15 20:31:40 +01001109gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001110fu_plugin_runner_update_prepare (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001111 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001112{
Richard Hughes12724852018-09-04 13:53:44 +01001113 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001114 "fu_plugin_update_prepare",
1115 error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001116}
1117
Mario Limonciello1a680f32019-11-25 19:44:53 -06001118/**
1119 * fu_plugin_runner_update_cleanup:
1120 * @self: a #FuPlugin
Richard Hughes2bbb7d22020-11-30 09:18:45 +00001121 * @flags: #FwupdInstallFlags
1122 * @device: a #FuDevice
Mario Limonciello1a680f32019-11-25 19:44:53 -06001123 * @error: a #GError or NULL
1124 *
1125 * Runs the update_cleanup routine for the plugin
1126 *
1127 * Returns: #TRUE for success, #FALSE for failure
1128 *
1129 * Since: 1.1.2
1130 **/
Richard Hughes7b8b2022016-12-12 16:15:03 +00001131gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001132fu_plugin_runner_update_cleanup (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001133 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001134{
Richard Hughes12724852018-09-04 13:53:44 +01001135 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001136 "fu_plugin_update_cleanup",
1137 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001138}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001139
Mario Limonciello1a680f32019-11-25 19:44:53 -06001140/**
1141 * fu_plugin_runner_update_attach:
1142 * @self: a #FuPlugin
1143 * @device: a #FuDevice
1144 * @error: a #GError or NULL
1145 *
1146 * Runs the update_attach routine for the plugin
1147 *
1148 * Returns: #TRUE for success, #FALSE for failure
1149 *
1150 * Since: 1.1.2
1151 **/
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001152gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001153fu_plugin_runner_update_attach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001154{
Richard Hughes12724852018-09-04 13:53:44 +01001155 return fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001156 "fu_plugin_update_attach",
1157 fu_plugin_device_attach,
1158 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001159}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001160
Mario Limonciello1a680f32019-11-25 19:44:53 -06001161/**
1162 * fu_plugin_runner_update_detach:
1163 * @self: a #FuPlugin
1164 * @device: A #FuDevice
1165 * @error: a #GError or NULL
1166 *
1167 * Runs the update_detach routine for the plugin
1168 *
1169 * Returns: #TRUE for success, #FALSE for failure
1170 *
1171 * Since: 1.1.2
1172 **/
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001173gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001174fu_plugin_runner_update_detach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001175{
Richard Hughes12724852018-09-04 13:53:44 +01001176 return fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001177 "fu_plugin_update_detach",
1178 fu_plugin_device_detach,
1179 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001180}
1181
Mario Limonciello1a680f32019-11-25 19:44:53 -06001182/**
1183 * fu_plugin_runner_update_reload:
1184 * @self: a #FuPlugin
Richard Hughes2bbb7d22020-11-30 09:18:45 +00001185 * @device: A #FuDevice
Mario Limonciello1a680f32019-11-25 19:44:53 -06001186 * @error: a #GError or NULL
1187 *
1188 * Runs reload routine for a device
1189 *
1190 * Returns: #TRUE for success, #FALSE for failure
1191 *
1192 * Since: 1.1.2
1193 **/
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001194gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001195fu_plugin_runner_update_reload (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001196{
Richard Hughes42f33df2019-10-05 20:52:33 +01001197 g_autoptr(FuDeviceLocker) locker = NULL;
1198
1199 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001200 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes42f33df2019-10-05 20:52:33 +01001201 return TRUE;
1202
1203 /* no object loaded */
1204 locker = fu_device_locker_new (device, error);
1205 if (locker == NULL)
1206 return FALSE;
1207 return fu_device_reload (device, error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001208}
1209
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001210/**
Richard Hughes196c6c62020-05-11 19:42:47 +01001211 * fu_plugin_runner_add_security_attrs:
1212 * @self: a #FuPlugin
Richard Hughes3ecd22c2020-05-19 20:13:47 +01001213 * @attrs: a #FuSecurityAttrs
Richard Hughes196c6c62020-05-11 19:42:47 +01001214 *
Richard Hughes3ecd22c2020-05-19 20:13:47 +01001215 * Runs the `add_security_attrs()` routine for the plugin
Richard Hughes196c6c62020-05-11 19:42:47 +01001216 *
1217 * Since: 1.5.0
1218 **/
Richard Hughesf58ac732020-05-12 15:23:44 +01001219void
1220fu_plugin_runner_add_security_attrs (FuPlugin *self, FuSecurityAttrs *attrs)
Richard Hughes196c6c62020-05-11 19:42:47 +01001221{
Richard Hughesf58ac732020-05-12 15:23:44 +01001222 FuPluginPrivate *priv = GET_PRIVATE (self);
1223 FuPluginSecurityAttrsFunc func = NULL;
1224 const gchar *symbol_name = "fu_plugin_add_security_attrs";
1225
1226 /* no object loaded */
1227 if (priv->module == NULL)
1228 return;
1229
1230 /* optional, but gets called even for disabled plugins */
1231 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1232 if (func == NULL)
1233 return;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001234 g_debug ("%s(%s)", symbol_name + 10, fu_plugin_get_name (self));
Richard Hughesf58ac732020-05-12 15:23:44 +01001235 func (self, attrs);
Richard Hughes196c6c62020-05-11 19:42:47 +01001236}
1237
1238/**
Richard Hughesfaa35e42021-04-15 09:38:03 +01001239 * fu_plugin_add_device_gtype:
Richard Hughes989acf12019-10-05 20:16:47 +01001240 * @self: a #FuPlugin
1241 * @device_gtype: a #GType `FU_TYPE_DEVICE`
1242 *
Richard Hughesfaa35e42021-04-15 09:38:03 +01001243 * Adds the device #GType which is used when creating devices.
Richard Hughes989acf12019-10-05 20:16:47 +01001244 *
Richard Hughes525f71f2021-02-09 14:52:47 +00001245 * If this method is used then fu_plugin_backend_device_added() is not called, and
Richard Hughes989acf12019-10-05 20:16:47 +01001246 * instead the object is created in the daemon for the plugin.
1247 *
1248 * Plugins can use this method only in fu_plugin_init()
1249 *
Richard Hughesfaa35e42021-04-15 09:38:03 +01001250 * Since: 1.6.0
Richard Hughes989acf12019-10-05 20:16:47 +01001251 **/
1252void
Richard Hughesfaa35e42021-04-15 09:38:03 +01001253fu_plugin_add_device_gtype (FuPlugin *self, GType device_gtype)
Richard Hughes989acf12019-10-05 20:16:47 +01001254{
1255 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesfaa35e42021-04-15 09:38:03 +01001256
1257 /* create as required */
1258 if (priv->device_gtypes == NULL)
1259 priv->device_gtypes = g_array_new (FALSE, FALSE, sizeof(GType));
1260
1261 /* ensure (to allow quirks to use it) then add */
1262 g_type_ensure (device_gtype);
1263 g_array_append_val (priv->device_gtypes, device_gtype);
Richard Hughes989acf12019-10-05 20:16:47 +01001264}
1265
Richard Hughes9f71fe32021-01-03 20:35:36 +00001266static gchar *
1267fu_common_string_uncamelcase (const gchar *str)
1268{
1269 GString *tmp = g_string_new (NULL);
1270 for (guint i = 0; str[i] != '\0'; i++) {
1271 if (g_ascii_islower (str[i]) ||
1272 g_ascii_isdigit (str[i])) {
1273 g_string_append_c (tmp, str[i]);
1274 continue;
1275 }
1276 if (i > 0)
1277 g_string_append_c (tmp, '-');
1278 g_string_append_c (tmp, g_ascii_tolower (str[i]));
1279 }
1280 return g_string_free (tmp, FALSE);
1281}
1282
Mario Limonciello1a680f32019-11-25 19:44:53 -06001283/**
1284 * fu_plugin_add_firmware_gtype:
1285 * @self: a #FuPlugin
Richard Hughes9f71fe32021-01-03 20:35:36 +00001286 * @id: (nullable): An optional string describing the type, e.g. "ihex"
1287 * @gtype: a #GType e.g. `FU_TYPE_FOO_FIRMWARE`
Mario Limonciello1a680f32019-11-25 19:44:53 -06001288 *
Richard Hughes9f71fe32021-01-03 20:35:36 +00001289 * Adds a firmware #GType which is used when creating devices. If @id is not
1290 * specified then it is guessed using the #GType name.
1291 *
Mario Limonciello1a680f32019-11-25 19:44:53 -06001292 * Plugins can use this method only in fu_plugin_init()
1293 *
1294 * Since: 1.3.3
1295 **/
Richard Hughes95c98a92019-10-22 16:03:15 +01001296void
1297fu_plugin_add_firmware_gtype (FuPlugin *self, const gchar *id, GType gtype)
1298{
Richard Hughesb333e002021-04-01 10:40:02 +01001299 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9f71fe32021-01-03 20:35:36 +00001300 g_autofree gchar *id_safe = NULL;
1301 if (id != NULL) {
1302 id_safe = g_strdup (id);
1303 } else {
Richard Hughesebb10a52021-01-05 13:34:39 +00001304 g_autoptr(GString) str = g_string_new (g_type_name (gtype));
Richard Hughes9f71fe32021-01-03 20:35:36 +00001305 if (g_str_has_prefix (str->str, "Fu"))
1306 g_string_erase (str, 0, 2);
1307 fu_common_string_replace (str, "Firmware", "");
1308 id_safe = fu_common_string_uncamelcase (str->str);
1309 }
Richard Hughesb333e002021-04-01 10:40:02 +01001310 fu_context_add_firmware_gtype (priv->ctx, id_safe, gtype);
Richard Hughes95c98a92019-10-22 16:03:15 +01001311}
1312
Richard Hughes989acf12019-10-05 20:16:47 +01001313static gboolean
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001314fu_plugin_check_supported_device (FuPlugin *self, FuDevice *device)
1315{
1316 GPtrArray *instance_ids = fu_device_get_instance_ids (device);
1317 for (guint i = 0; i < instance_ids->len; i++) {
1318 const gchar *instance_id = g_ptr_array_index (instance_ids, i);
1319 g_autofree gchar *guid = fwupd_guid_hash_string (instance_id);
1320 if (fu_plugin_check_supported (self, guid))
1321 return TRUE;
1322 }
1323 return FALSE;
1324}
1325
1326static gboolean
Richard Hughes525f71f2021-02-09 14:52:47 +00001327fu_plugin_backend_device_added (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes989acf12019-10-05 20:16:47 +01001328{
1329 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001330 GType device_gtype = fu_device_get_specialized_gtype (FU_DEVICE (device));
Richard Hughes989acf12019-10-05 20:16:47 +01001331 g_autoptr(FuDevice) dev = NULL;
1332 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001333
1334 /* fall back to plugin default */
Richard Hughesfaa35e42021-04-15 09:38:03 +01001335 if (device_gtype == G_TYPE_INVALID) {
1336 if (priv->device_gtypes->len > 1) {
1337 g_set_error_literal (error,
1338 FWUPD_ERROR,
1339 FWUPD_ERROR_INTERNAL,
1340 "too many GTypes to choose a default");
1341 return FALSE;
1342 }
1343 device_gtype = g_array_index (priv->device_gtypes, GType, 0);
1344 }
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001345
1346 /* create new device and incorporate existing properties */
1347 dev = g_object_new (device_gtype, NULL);
1348 fu_device_incorporate (dev, FU_DEVICE (device));
Richard Hughes0f66a022020-02-19 18:54:38 +00001349 if (!fu_plugin_runner_device_created (self, dev, error))
1350 return FALSE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001351
1352 /* there are a lot of different devices that match, but not all respond
1353 * well to opening -- so limit some ones with issued updates */
Richard Hughescf100292021-01-04 10:36:37 +00001354 if (fu_device_has_internal_flag (dev, FU_DEVICE_INTERNAL_FLAG_ONLY_SUPPORTED)) {
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001355 if (!fu_device_probe (dev, error))
1356 return FALSE;
1357 fu_device_convert_instance_ids (dev);
1358 if (!fu_plugin_check_supported_device (self, dev)) {
1359 g_autofree gchar *guids = fu_device_get_guids_as_str (dev);
1360 g_debug ("%s has no updates, so ignoring device", guids);
1361 return TRUE;
1362 }
1363 }
1364
1365 /* open and add */
1366 locker = fu_device_locker_new (dev, error);
1367 if (locker == NULL)
1368 return FALSE;
1369 fu_plugin_device_add (self, dev);
Richard Hughes6a078702020-05-09 20:36:33 +01001370 fu_plugin_runner_device_added (self, dev);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001371 return TRUE;
1372}
1373
Mario Limonciello1a680f32019-11-25 19:44:53 -06001374/**
Richard Hughes525f71f2021-02-09 14:52:47 +00001375 * fu_plugin_runner_backend_device_added:
1376 * @self: a #FuPlugin
1377 * @device: a #FuDevice
1378 * @error: a #GError or NULL
1379 *
1380 * Call the backend_device_added routine for the plugin
1381 *
1382 * Returns: #TRUE for success, #FALSE for failure
1383 *
1384 * Since: 1.5.6
1385 **/
1386gboolean
1387fu_plugin_runner_backend_device_added (FuPlugin *self, FuDevice *device, GError **error)
1388{
Richard Hughes12724852018-09-04 13:53:44 +01001389 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes525f71f2021-02-09 14:52:47 +00001390 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001391 g_autoptr(GError) error_local = NULL;
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001392
Richard Hughes6a489a92020-12-22 10:32:06 +00001393 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
Richard Hughes525f71f2021-02-09 14:52:47 +00001394 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
Richard Hughes6a489a92020-12-22 10:32:06 +00001395 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1396
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001397 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001398 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001399 return TRUE;
1400
1401 /* no object loaded */
1402 if (priv->module == NULL)
1403 return TRUE;
1404
1405 /* optional */
Richard Hughes525f71f2021-02-09 14:52:47 +00001406 g_module_symbol (priv->module, "fu_plugin_backend_device_added", (gpointer *) &func);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001407 if (func == NULL) {
Richard Hughesfaa35e42021-04-15 09:38:03 +01001408 if (priv->device_gtypes != NULL ||
Richard Hughes525f71f2021-02-09 14:52:47 +00001409 fu_device_get_specialized_gtype (device) != G_TYPE_INVALID) {
1410 return fu_plugin_backend_device_added (self, device, error);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001411 }
Richard Hughesa21e0252020-12-01 12:21:33 +00001412 g_set_error_literal (error,
1413 FWUPD_ERROR,
1414 FWUPD_ERROR_INTERNAL,
1415 "No device GType set");
1416 return FALSE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001417 }
Richard Hughes525f71f2021-02-09 14:52:47 +00001418 g_debug ("backend_device_added(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001419 if (!func (self, device, &error_local)) {
1420 if (error_local == NULL) {
Richard Hughes525f71f2021-02-09 14:52:47 +00001421 g_critical ("unset plugin error in backend_device_added(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001422 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001423 g_set_error_literal (&error_local,
1424 FWUPD_ERROR,
1425 FWUPD_ERROR_INTERNAL,
1426 "unspecified error");
1427 }
1428 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1429 "failed to add device using on %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001430 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001431 return FALSE;
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001432 }
1433 return TRUE;
1434}
1435
Mario Limonciello1a680f32019-11-25 19:44:53 -06001436/**
Richard Hughes525f71f2021-02-09 14:52:47 +00001437 * fu_plugin_runner_backend_device_changed:
1438 * @self: a #FuPlugin
1439 * @device: a #FuDevice
1440 * @error: a #GError or NULL
1441 *
1442 * Call the backend_device_changed routine for the plugin
1443 *
1444 * Returns: #TRUE for success, #FALSE for failure
1445 *
1446 * Since: 1.5.6
1447 **/
1448gboolean
1449fu_plugin_runner_backend_device_changed (FuPlugin *self, FuDevice *device, GError **error)
1450{
Richard Hughes5e952ce2019-08-26 11:09:46 +01001451 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes525f71f2021-02-09 14:52:47 +00001452 FuPluginDeviceFunc func = NULL;
Richard Hughes5e952ce2019-08-26 11:09:46 +01001453 g_autoptr(GError) error_local = NULL;
1454
Richard Hughes6a489a92020-12-22 10:32:06 +00001455 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
Richard Hughes525f71f2021-02-09 14:52:47 +00001456 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
Richard Hughes6a489a92020-12-22 10:32:06 +00001457 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1458
Richard Hughes5e952ce2019-08-26 11:09:46 +01001459 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001460 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes5e952ce2019-08-26 11:09:46 +01001461 return TRUE;
1462
1463 /* no object loaded */
1464 if (priv->module == NULL)
1465 return TRUE;
1466
1467 /* optional */
Richard Hughes525f71f2021-02-09 14:52:47 +00001468 g_module_symbol (priv->module, "fu_plugin_backend_device_changed", (gpointer *) &func);
Mario Limonciello6d235142020-09-10 21:35:17 -05001469 if (func == NULL)
Richard Hughes5e952ce2019-08-26 11:09:46 +01001470 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001471 g_debug ("udev_device_changed(%s)", fu_plugin_get_name (self));
Richard Hughes5e952ce2019-08-26 11:09:46 +01001472 if (!func (self, device, &error_local)) {
1473 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001474 g_critical ("unset plugin error in udev_device_changed(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001475 fu_plugin_get_name (self));
Richard Hughes5e952ce2019-08-26 11:09:46 +01001476 g_set_error_literal (&error_local,
1477 FWUPD_ERROR,
1478 FWUPD_ERROR_INTERNAL,
1479 "unspecified error");
1480 }
1481 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1482 "failed to change device on %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001483 fu_plugin_get_name (self));
Richard Hughes5e952ce2019-08-26 11:09:46 +01001484 return FALSE;
1485 }
1486 return TRUE;
1487}
1488
Mario Limonciello1a680f32019-11-25 19:44:53 -06001489/**
Richard Hughes6a078702020-05-09 20:36:33 +01001490 * fu_plugin_runner_device_added:
1491 * @self: a #FuPlugin
1492 * @device: a #FuDevice
1493 *
1494 * Call the device_added routine for the plugin
1495 *
1496 * Since: 1.5.0
1497 **/
1498void
1499fu_plugin_runner_device_added (FuPlugin *self, FuDevice *device)
1500{
1501 FuPluginPrivate *priv = GET_PRIVATE (self);
1502 FuPluginDeviceRegisterFunc func = NULL;
1503
1504 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001505 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes6a078702020-05-09 20:36:33 +01001506 return;
1507 if (priv->module == NULL)
1508 return;
1509
1510 /* optional */
1511 g_module_symbol (priv->module, "fu_plugin_device_added", (gpointer *) &func);
1512 if (func == NULL)
1513 return;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001514 g_debug ("fu_plugin_device_added(%s)", fu_plugin_get_name (self));
Richard Hughes6a078702020-05-09 20:36:33 +01001515 func (self, device);
1516}
1517
1518/**
Mario Limonciello1a680f32019-11-25 19:44:53 -06001519 * fu_plugin_runner_device_removed:
1520 * @self: a #FuPlugin
1521 * @device: a #FuDevice
1522 *
1523 * Call the device_removed routine for the plugin
1524 *
1525 * Since: 1.1.2
1526 **/
Richard Hughese1fd34d2017-08-24 14:19:51 +01001527void
Richard Hughes12724852018-09-04 13:53:44 +01001528fu_plugin_runner_device_removed (FuPlugin *self, FuDevice *device)
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001529{
1530 g_autoptr(GError) error_local= NULL;
1531
Richard Hughes12724852018-09-04 13:53:44 +01001532 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes525f71f2021-02-09 14:52:47 +00001533 "fu_plugin_backend_device_removed",
Richard Hughes4b303802019-10-04 13:22:51 +01001534 NULL,
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001535 &error_local))
1536 g_warning ("%s", error_local->message);
1537}
1538
Mario Limonciello1a680f32019-11-25 19:44:53 -06001539/**
1540 * fu_plugin_runner_device_register:
1541 * @self: a #FuPlugin
1542 * @device: a #FuDevice
1543 *
1544 * Call the device_registered routine for the plugin
1545 *
1546 * Since: 0.9.7
1547 **/
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001548void
Richard Hughes12724852018-09-04 13:53:44 +01001549fu_plugin_runner_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +01001550{
Richard Hughes12724852018-09-04 13:53:44 +01001551 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughese1fd34d2017-08-24 14:19:51 +01001552 FuPluginDeviceRegisterFunc func = NULL;
1553
1554 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001555 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughese1fd34d2017-08-24 14:19:51 +01001556 return;
Richard Hughes34834102017-11-21 21:55:00 +00001557 if (priv->module == NULL)
1558 return;
Richard Hughese1fd34d2017-08-24 14:19:51 +01001559
1560 /* optional */
1561 g_module_symbol (priv->module, "fu_plugin_device_registered", (gpointer *) &func);
1562 if (func != NULL) {
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001563 g_debug ("fu_plugin_device_registered(%s)", fu_plugin_get_name (self));
Richard Hughes12724852018-09-04 13:53:44 +01001564 func (self, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +01001565 }
1566}
1567
Mario Limonciello1a680f32019-11-25 19:44:53 -06001568/**
Richard Hughes0f66a022020-02-19 18:54:38 +00001569 * fu_plugin_runner_device_created:
1570 * @self: a #FuPlugin
1571 * @device: a #FuDevice
1572 * @error: a #GError or NULL
1573 *
1574 * Call the device_created routine for the plugin
1575 *
1576 * Returns: #TRUE for success, #FALSE for failure
1577 *
Mario Limonciello96117d12020-02-28 10:17:56 -06001578 * Since: 1.4.0
Richard Hughes0f66a022020-02-19 18:54:38 +00001579 **/
1580gboolean
1581fu_plugin_runner_device_created (FuPlugin *self, FuDevice *device, GError **error)
1582{
1583 FuPluginPrivate *priv = GET_PRIVATE (self);
1584 FuPluginDeviceFunc func = NULL;
1585
Richard Hughes6a489a92020-12-22 10:32:06 +00001586 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
1587 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
1588 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1589
Richard Hughes0f66a022020-02-19 18:54:38 +00001590 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001591 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughes0f66a022020-02-19 18:54:38 +00001592 return TRUE;
1593 if (priv->module == NULL)
1594 return TRUE;
1595
1596 /* optional */
1597 g_module_symbol (priv->module, "fu_plugin_device_created", (gpointer *) &func);
1598 if (func == NULL)
1599 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001600 g_debug ("fu_plugin_device_created(%s)", fu_plugin_get_name (self));
Richard Hughes0f66a022020-02-19 18:54:38 +00001601 return func (self, device, error);
1602}
1603
1604/**
Mario Limonciello1a680f32019-11-25 19:44:53 -06001605 * fu_plugin_runner_verify:
1606 * @self: a #FuPlugin
1607 * @device: a #FuDevice
1608 * @flags: #FuPluginVerifyFlags
1609 * @error: A #GError or NULL
1610 *
1611 * Call into the plugin's verify routine
1612 *
1613 * Returns: #TRUE for success, #FALSE for failure
1614 *
1615 * Since: 0.8.0
1616 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00001617gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001618fu_plugin_runner_verify (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +00001619 FuDevice *device,
1620 FuPluginVerifyFlags flags,
1621 GError **error)
1622{
Richard Hughes12724852018-09-04 13:53:44 +01001623 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001624 FuPluginVerifyFunc func = NULL;
Richard Hughesababbb72017-06-15 20:18:36 +01001625 GPtrArray *checksums;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001626 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001627
Richard Hughes6a489a92020-12-22 10:32:06 +00001628 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
1629 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
1630 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1631
Richard Hughescff38bc2016-12-12 12:03:37 +00001632 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001633 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughescff38bc2016-12-12 12:03:37 +00001634 return TRUE;
1635
Richard Hughes639da472018-01-06 22:35:04 +00001636 /* no object loaded */
1637 if (priv->module == NULL)
1638 return TRUE;
1639
Richard Hughescff38bc2016-12-12 12:03:37 +00001640 /* optional */
1641 g_module_symbol (priv->module, "fu_plugin_verify", (gpointer *) &func);
Richard Hughes7f677212019-10-05 16:19:40 +01001642 if (func == NULL) {
Richard Hughes53de7e22021-02-23 14:28:28 +00001643 if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_CAN_VERIFY)) {
1644 g_set_error (error,
1645 FWUPD_ERROR,
1646 FWUPD_ERROR_NOT_SUPPORTED,
1647 "device %s does not support verification",
1648 fu_device_get_id (device));
1649 return FALSE;
1650 }
Richard Hughes7f677212019-10-05 16:19:40 +01001651 return fu_plugin_device_read_firmware (self, device, error);
1652 }
Richard Hughes1812fc72018-12-14 11:37:54 +00001653
1654 /* clear any existing verification checksums */
1655 checksums = fu_device_get_checksums (device);
1656 g_ptr_array_set_size (checksums, 0);
1657
Richard Hughesc9223be2019-03-18 08:46:42 +00001658 /* run additional detach */
1659 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01001660 "fu_plugin_update_detach",
Richard Hughes4b303802019-10-04 13:22:51 +01001661 fu_plugin_device_detach,
Richard Hughesc9223be2019-03-18 08:46:42 +00001662 error))
1663 return FALSE;
1664
Richard Hughes1812fc72018-12-14 11:37:54 +00001665 /* run vfunc */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001666 g_debug ("verify(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001667 if (!func (self, device, flags, &error_local)) {
Richard Hughesc9223be2019-03-18 08:46:42 +00001668 g_autoptr(GError) error_attach = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001669 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001670 g_critical ("unset plugin error in verify(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001671 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001672 g_set_error_literal (&error_local,
1673 FWUPD_ERROR,
1674 FWUPD_ERROR_INTERNAL,
1675 "unspecified error");
1676 }
1677 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1678 "failed to verify using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001679 fu_plugin_get_name (self));
Richard Hughesc9223be2019-03-18 08:46:42 +00001680 /* make the device "work" again, but don't prefix the error */
1681 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01001682 "fu_plugin_update_attach",
Richard Hughes4b303802019-10-04 13:22:51 +01001683 fu_plugin_device_attach,
Richard Hughesc9223be2019-03-18 08:46:42 +00001684 &error_attach)) {
1685 g_warning ("failed to attach whilst aborting verify(): %s",
1686 error_attach->message);
1687 }
Richard Hughesd0905142016-03-13 09:46:49 +00001688 return FALSE;
1689 }
Richard Hughesc9223be2019-03-18 08:46:42 +00001690
1691 /* run optional attach */
1692 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01001693 "fu_plugin_update_attach",
Richard Hughes4b303802019-10-04 13:22:51 +01001694 fu_plugin_device_attach,
Richard Hughesc9223be2019-03-18 08:46:42 +00001695 error))
1696 return FALSE;
1697
1698 /* success */
Richard Hughesd0905142016-03-13 09:46:49 +00001699 return TRUE;
1700}
1701
Mario Limonciello1a680f32019-11-25 19:44:53 -06001702/**
1703 * fu_plugin_runner_activate:
1704 * @self: a #FuPlugin
1705 * @device: a #FuDevice
1706 * @error: A #GError or NULL
1707 *
1708 * Call into the plugin's activate routine
1709 *
1710 * Returns: #TRUE for success, #FALSE for failure
1711 *
1712 * Since: 1.2.6
1713 **/
Richard Hughesd0905142016-03-13 09:46:49 +00001714gboolean
Mario Limonciello96a0dd52019-02-25 13:50:03 -06001715fu_plugin_runner_activate (FuPlugin *self, FuDevice *device, GError **error)
1716{
1717 guint64 flags;
1718
Richard Hughes6a489a92020-12-22 10:32:06 +00001719 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
1720 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
1721 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1722
Mario Limonciello96a0dd52019-02-25 13:50:03 -06001723 /* final check */
1724 flags = fu_device_get_flags (device);
1725 if ((flags & FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION) == 0) {
1726 g_set_error (error,
1727 FWUPD_ERROR,
1728 FWUPD_ERROR_NOT_SUPPORTED,
1729 "Device %s does not need activation",
1730 fu_device_get_id (device));
1731 return FALSE;
1732 }
1733
1734 /* run vfunc */
1735 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001736 "fu_plugin_activate",
1737 fu_plugin_device_activate,
1738 error))
Mario Limonciello96a0dd52019-02-25 13:50:03 -06001739 return FALSE;
1740
1741 /* update with correct flags */
1742 fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION);
1743 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
1744 return TRUE;
1745}
1746
Mario Limonciello1a680f32019-11-25 19:44:53 -06001747/**
1748 * fu_plugin_runner_unlock:
1749 * @self: a #FuPlugin
1750 * @device: a #FuDevice
1751 * @error: A #GError or NULL
1752 *
1753 * Call into the plugin's unlock routine
1754 *
1755 * Returns: #TRUE for success, #FALSE for failure
1756 *
1757 * Since: 0.8.0
1758 **/
Mario Limonciello96a0dd52019-02-25 13:50:03 -06001759gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001760fu_plugin_runner_unlock (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00001761{
Richard Hughescff38bc2016-12-12 12:03:37 +00001762 guint64 flags;
Richard Hughescff38bc2016-12-12 12:03:37 +00001763
Richard Hughes6a489a92020-12-22 10:32:06 +00001764 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
1765 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
1766 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1767
Richard Hughescff38bc2016-12-12 12:03:37 +00001768 /* final check */
1769 flags = fu_device_get_flags (device);
1770 if ((flags & FWUPD_DEVICE_FLAG_LOCKED) == 0) {
1771 g_set_error (error,
1772 FWUPD_ERROR,
1773 FWUPD_ERROR_NOT_SUPPORTED,
1774 "Device %s is not locked",
1775 fu_device_get_id (device));
1776 return FALSE;
1777 }
1778
Richard Hughes9c4b5312017-11-14 11:34:53 +00001779 /* run vfunc */
Richard Hughes12724852018-09-04 13:53:44 +01001780 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001781 "fu_plugin_unlock",
1782 NULL,
1783 error))
Richard Hughes9c4b5312017-11-14 11:34:53 +00001784 return FALSE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001785
1786 /* update with correct flags */
Richard Hughesed0af242021-02-22 21:27:16 +00001787 fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_LOCKED);
Richard Hughescff38bc2016-12-12 12:03:37 +00001788 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
1789 return TRUE;
1790}
1791
Mario Limonciello1a680f32019-11-25 19:44:53 -06001792/**
1793 * fu_plugin_runner_update:
1794 * @self: a #FuPlugin
1795 * @device: a #FuDevice
1796 * @blob_fw: A #GBytes
1797 * @flags: A #FwupdInstallFlags
1798 * @error: A #GError or NULL
1799 *
1800 * Call into the plugin's update routine
1801 *
1802 * Returns: #TRUE for success, #FALSE for failure
1803 *
1804 * Since: 0.8.0
1805 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00001806gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001807fu_plugin_runner_update (FuPlugin *self,
Richard Hughesa785a1c2017-08-25 16:00:58 +01001808 FuDevice *device,
Richard Hughesa785a1c2017-08-25 16:00:58 +01001809 GBytes *blob_fw,
1810 FwupdInstallFlags flags,
1811 GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00001812{
Richard Hughes12724852018-09-04 13:53:44 +01001813 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesa785a1c2017-08-25 16:00:58 +01001814 FuPluginUpdateFunc update_func;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001815 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001816
Richard Hughes6a489a92020-12-22 10:32:06 +00001817 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
1818 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
1819 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1820
Richard Hughescff38bc2016-12-12 12:03:37 +00001821 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001822 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED)) {
Richard Hughes41c15482018-02-01 22:07:21 +00001823 g_debug ("plugin not enabled, skipping");
Richard Hughesd0905142016-03-13 09:46:49 +00001824 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00001825 }
Richard Hughesd0905142016-03-13 09:46:49 +00001826
Richard Hughes639da472018-01-06 22:35:04 +00001827 /* no object loaded */
Richard Hughes41c15482018-02-01 22:07:21 +00001828 if (priv->module == NULL) {
1829 g_debug ("module not enabled, skipping");
Richard Hughes639da472018-01-06 22:35:04 +00001830 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00001831 }
Richard Hughes639da472018-01-06 22:35:04 +00001832
Richard Hughesd0905142016-03-13 09:46:49 +00001833 /* optional */
Richard Hughesa785a1c2017-08-25 16:00:58 +01001834 g_module_symbol (priv->module, "fu_plugin_update", (gpointer *) &update_func);
1835 if (update_func == NULL) {
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001836 g_debug ("superclassed write_firmware(%s)", fu_plugin_get_name (self));
Richard Hughes4b303802019-10-04 13:22:51 +01001837 return fu_plugin_device_write_firmware (self, device, blob_fw, flags, error);
Richard Hughesa785a1c2017-08-25 16:00:58 +01001838 }
Richard Hughesd0905142016-03-13 09:46:49 +00001839
Richard Hughescff38bc2016-12-12 12:03:37 +00001840 /* online */
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001841 if (!update_func (self, device, blob_fw, flags, &error_local)) {
1842 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001843 g_critical ("unset plugin error in update(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001844 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001845 g_set_error_literal (&error_local,
Richard Hughes3c8ada32018-10-12 10:08:58 +01001846 FWUPD_ERROR,
1847 FWUPD_ERROR_INTERNAL,
1848 "unspecified error");
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001849 return FALSE;
Richard Hughes3c8ada32018-10-12 10:08:58 +01001850 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001851 fu_device_set_update_error (device, error_local->message);
1852 g_propagate_error (error, g_steal_pointer (&error_local));
Richard Hughescff38bc2016-12-12 12:03:37 +00001853 return FALSE;
1854 }
1855
Richard Hughesf556d372017-06-15 19:49:18 +01001856 /* no longer valid */
Richard Hughesf8039642019-01-16 12:22:22 +00001857 if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT) &&
1858 !fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) {
Richard Hughes08435162018-12-12 10:34:16 +00001859 GPtrArray *checksums = fu_device_get_checksums (device);
1860 g_ptr_array_set_size (checksums, 0);
1861 }
Richard Hughesf556d372017-06-15 19:49:18 +01001862
Richard Hughes019a1bc2019-11-26 10:19:33 +00001863 /* success */
Richard Hughesd0905142016-03-13 09:46:49 +00001864 return TRUE;
1865}
Richard Hughescff38bc2016-12-12 12:03:37 +00001866
Mario Limonciello1a680f32019-11-25 19:44:53 -06001867/**
1868 * fu_plugin_runner_clear_results:
1869 * @self: a #FuPlugin
1870 * @device: a #FuDevice
1871 * @error: A #GError or NULL
1872 *
1873 * Call into the plugin's clear results routine
1874 *
1875 * Returns: #TRUE for success, #FALSE for failure
1876 *
1877 * Since: 0.8.0
1878 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00001879gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001880fu_plugin_runner_clear_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00001881{
Richard Hughes12724852018-09-04 13:53:44 +01001882 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001883 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001884 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001885
Richard Hughes6a489a92020-12-22 10:32:06 +00001886 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
1887 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
1888 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1889
Richard Hughescff38bc2016-12-12 12:03:37 +00001890 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001891 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughescff38bc2016-12-12 12:03:37 +00001892 return TRUE;
1893
Richard Hughes639da472018-01-06 22:35:04 +00001894 /* no object loaded */
1895 if (priv->module == NULL)
1896 return TRUE;
1897
Richard Hughes65e44ca2018-01-30 17:26:30 +00001898 /* optional */
Richard Hughescd644902019-11-01 12:35:17 +00001899 g_module_symbol (priv->module, "fu_plugin_clear_results", (gpointer *) &func);
Richard Hughes65e44ca2018-01-30 17:26:30 +00001900 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00001901 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001902 g_debug ("clear_result(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001903 if (!func (self, device, &error_local)) {
1904 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001905 g_critical ("unset plugin error in clear_result(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001906 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001907 g_set_error_literal (&error_local,
1908 FWUPD_ERROR,
1909 FWUPD_ERROR_INTERNAL,
1910 "unspecified error");
1911 }
1912 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1913 "failed to clear_result using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001914 fu_plugin_get_name (self));
Richard Hughescff38bc2016-12-12 12:03:37 +00001915 return FALSE;
1916 }
Richard Hughes65e44ca2018-01-30 17:26:30 +00001917 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001918}
1919
Mario Limonciello1a680f32019-11-25 19:44:53 -06001920/**
1921 * fu_plugin_runner_get_results:
1922 * @self: a #FuPlugin
1923 * @device: a #FuDevice
1924 * @error: A #GError or NULL
1925 *
1926 * Call into the plugin's get results routine
1927 *
1928 * Returns: #TRUE for success, #FALSE for failure
1929 *
1930 * Since: 0.8.0
1931 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00001932gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001933fu_plugin_runner_get_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00001934{
Richard Hughes12724852018-09-04 13:53:44 +01001935 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001936 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001937 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001938
Richard Hughes6a489a92020-12-22 10:32:06 +00001939 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
1940 g_return_val_if_fail (FU_IS_DEVICE (device), FALSE);
1941 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1942
Richard Hughescff38bc2016-12-12 12:03:37 +00001943 /* not enabled */
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001944 if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
Richard Hughescff38bc2016-12-12 12:03:37 +00001945 return TRUE;
1946
Richard Hughes639da472018-01-06 22:35:04 +00001947 /* no object loaded */
1948 if (priv->module == NULL)
1949 return TRUE;
1950
Richard Hughes65e44ca2018-01-30 17:26:30 +00001951 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00001952 g_module_symbol (priv->module, "fu_plugin_get_results", (gpointer *) &func);
Richard Hughes65e44ca2018-01-30 17:26:30 +00001953 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00001954 return TRUE;
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001955 g_debug ("get_results(%s)", fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001956 if (!func (self, device, &error_local)) {
1957 if (error_local == NULL) {
Mario Limonciello67a8b892020-09-28 13:44:39 -05001958 g_critical ("unset plugin error in get_results(%s)",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001959 fu_plugin_get_name (self));
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001960 g_set_error_literal (&error_local,
1961 FWUPD_ERROR,
1962 FWUPD_ERROR_INTERNAL,
1963 "unspecified error");
1964 }
1965 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1966 "failed to get_results using %s: ",
Richard Hughes7bcb8d42020-10-08 15:47:47 +01001967 fu_plugin_get_name (self));
Richard Hughescff38bc2016-12-12 12:03:37 +00001968 return FALSE;
1969 }
Richard Hughescff38bc2016-12-12 12:03:37 +00001970 return TRUE;
1971}
1972
Richard Hughes08a37992017-09-12 12:57:43 +01001973/**
1974 * fu_plugin_get_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001975 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01001976 *
1977 * Gets the plugin order, where higher numbers are run after lower
1978 * numbers.
1979 *
1980 * Returns: the integer value
Mario Limonciello1a680f32019-11-25 19:44:53 -06001981 *
1982 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01001983 **/
1984guint
Richard Hughes12724852018-09-04 13:53:44 +01001985fu_plugin_get_order (FuPlugin *self)
Richard Hughes08a37992017-09-12 12:57:43 +01001986{
Richard Hughes12724852018-09-04 13:53:44 +01001987 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01001988 return priv->order;
1989}
1990
1991/**
1992 * fu_plugin_set_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001993 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01001994 * @order: a integer value
1995 *
1996 * Sets the plugin order, where higher numbers are run after lower
1997 * numbers.
Mario Limonciello1a680f32019-11-25 19:44:53 -06001998 *
1999 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002000 **/
2001void
Richard Hughes12724852018-09-04 13:53:44 +01002002fu_plugin_set_order (FuPlugin *self, guint order)
Richard Hughes08a37992017-09-12 12:57:43 +01002003{
Richard Hughes12724852018-09-04 13:53:44 +01002004 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002005 priv->order = order;
2006}
2007
2008/**
Richard Hughes81c427c2018-08-06 15:20:17 +01002009 * fu_plugin_get_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002010 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01002011 *
2012 * Gets the plugin priority, where higher numbers are better.
2013 *
2014 * Returns: the integer value
Mario Limonciello1a680f32019-11-25 19:44:53 -06002015 *
2016 * Since: 1.1.1
Richard Hughes81c427c2018-08-06 15:20:17 +01002017 **/
2018guint
Richard Hughes12724852018-09-04 13:53:44 +01002019fu_plugin_get_priority (FuPlugin *self)
Richard Hughes81c427c2018-08-06 15:20:17 +01002020{
Richard Hughes12724852018-09-04 13:53:44 +01002021 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01002022 return priv->priority;
2023}
2024
2025/**
2026 * fu_plugin_set_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002027 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01002028 * @priority: a integer value
2029 *
2030 * Sets the plugin priority, where higher numbers are better.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002031 *
2032 * Since: 1.0.0
Richard Hughes81c427c2018-08-06 15:20:17 +01002033 **/
2034void
Richard Hughes12724852018-09-04 13:53:44 +01002035fu_plugin_set_priority (FuPlugin *self, guint priority)
Richard Hughes81c427c2018-08-06 15:20:17 +01002036{
Richard Hughes12724852018-09-04 13:53:44 +01002037 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01002038 priv->priority = priority;
2039}
2040
2041/**
Richard Hughes08a37992017-09-12 12:57:43 +01002042 * fu_plugin_add_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002043 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002044 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
Richard Hughes4eada342017-10-03 21:20:32 +01002045 * @name: a plugin name, e.g. `upower`
Richard Hughes08a37992017-09-12 12:57:43 +01002046 *
2047 * If the plugin name is found, the rule will be used to sort the plugin list,
2048 * for example the plugin specified by @name will be ordered after this plugin
2049 * when %FU_PLUGIN_RULE_RUN_AFTER is used.
2050 *
2051 * NOTE: The depsolver is iterative and may not solve overly-complicated rules;
2052 * If depsolving fails then fwupd will not start.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002053 *
2054 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002055 **/
2056void
Richard Hughes12724852018-09-04 13:53:44 +01002057fu_plugin_add_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes08a37992017-09-12 12:57:43 +01002058{
Richard Hughes12724852018-09-04 13:53:44 +01002059 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes11c59412020-06-22 15:29:48 +01002060 if (priv->rules[rule] == NULL)
2061 priv->rules[rule] = g_ptr_array_new_with_free_func (g_free);
Richard Hughes08a37992017-09-12 12:57:43 +01002062 g_ptr_array_add (priv->rules[rule], g_strdup (name));
Richard Hughes75b965d2018-11-15 13:51:21 +00002063 g_signal_emit (self, signals[SIGNAL_RULES_CHANGED], 0);
Richard Hughes08a37992017-09-12 12:57:43 +01002064}
2065
2066/**
2067 * fu_plugin_get_rules:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002068 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002069 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
2070 *
2071 * Gets the plugin IDs that should be run after this plugin.
2072 *
Richard Hughes11c59412020-06-22 15:29:48 +01002073 * Returns: (element-type utf8) (transfer none) (nullable): the list of plugin names, e.g. ['appstream']
Mario Limonciello1a680f32019-11-25 19:44:53 -06002074 *
2075 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002076 **/
2077GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +01002078fu_plugin_get_rules (FuPlugin *self, FuPluginRule rule)
Richard Hughes08a37992017-09-12 12:57:43 +01002079{
Richard Hughes12724852018-09-04 13:53:44 +01002080 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughesdad35972019-12-06 11:00:25 +00002081 g_return_val_if_fail (rule < FU_PLUGIN_RULE_LAST, NULL);
Richard Hughes08a37992017-09-12 12:57:43 +01002082 return priv->rules[rule];
2083}
2084
Richard Hughes80b79bb2018-01-11 21:11:06 +00002085/**
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002086 * fu_plugin_has_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002087 * @self: a #FuPlugin
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002088 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
2089 * @name: a plugin name, e.g. `upower`
2090 *
Richard Hughes87fb9ff2018-06-28 12:55:59 +01002091 * Gets the plugin IDs that should be run after this plugin.
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002092 *
2093 * Returns: %TRUE if the name exists for the specific rule
Mario Limonciello1a680f32019-11-25 19:44:53 -06002094 *
2095 * Since: 1.0.0
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002096 **/
2097gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002098fu_plugin_has_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002099{
Richard Hughes12724852018-09-04 13:53:44 +01002100 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes11c59412020-06-22 15:29:48 +01002101 if (priv->rules[rule] == NULL)
2102 return FALSE;
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002103 for (guint i = 0; i < priv->rules[rule]->len; i++) {
2104 const gchar *tmp = g_ptr_array_index (priv->rules[rule], i);
2105 if (g_strcmp0 (tmp, name) == 0)
2106 return TRUE;
2107 }
2108 return FALSE;
2109}
2110
2111/**
Richard Hughes80b79bb2018-01-11 21:11:06 +00002112 * fu_plugin_add_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002113 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00002114 * @key: a string, e.g. `FwupdateVersion`
2115 * @value: a string, e.g. `10`
2116 *
2117 * Sets any additional metadata to be included in the firmware report to aid
2118 * debugging problems.
2119 *
2120 * Any data included here will be sent to the metadata server after user
2121 * confirmation.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002122 *
2123 * Since: 1.0.4
Richard Hughes80b79bb2018-01-11 21:11:06 +00002124 **/
2125void
Richard Hughes12724852018-09-04 13:53:44 +01002126fu_plugin_add_report_metadata (FuPlugin *self, const gchar *key, const gchar *value)
Richard Hughes80b79bb2018-01-11 21:11:06 +00002127{
Richard Hughes12724852018-09-04 13:53:44 +01002128 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes1d900f72020-06-22 15:17:39 +01002129 if (priv->report_metadata == NULL) {
2130 priv->report_metadata = g_hash_table_new_full (g_str_hash,
2131 g_str_equal,
2132 g_free,
2133 g_free);
2134 }
Richard Hughes80b79bb2018-01-11 21:11:06 +00002135 g_hash_table_insert (priv->report_metadata, g_strdup (key), g_strdup (value));
2136}
2137
2138/**
2139 * fu_plugin_get_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002140 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00002141 *
2142 * Returns the list of additional metadata to be added when filing a report.
2143 *
Richard Hughes1d900f72020-06-22 15:17:39 +01002144 * Returns: (transfer none) (nullable): the map of report metadata
Mario Limonciello1a680f32019-11-25 19:44:53 -06002145 *
2146 * Since: 1.0.4
Richard Hughes80b79bb2018-01-11 21:11:06 +00002147 **/
2148GHashTable *
Richard Hughes12724852018-09-04 13:53:44 +01002149fu_plugin_get_report_metadata (FuPlugin *self)
Richard Hughes80b79bb2018-01-11 21:11:06 +00002150{
Richard Hughes12724852018-09-04 13:53:44 +01002151 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002152 return priv->report_metadata;
2153}
2154
Mario Limonciello963dc422018-02-27 14:26:58 -06002155/**
2156 * fu_plugin_get_config_value:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002157 * @self: a #FuPlugin
Mario Limonciello963dc422018-02-27 14:26:58 -06002158 * @key: A settings key
2159 *
2160 * Return the value of a key if it's been configured
2161 *
2162 * Since: 1.0.6
2163 **/
2164gchar *
Richard Hughes12724852018-09-04 13:53:44 +01002165fu_plugin_get_config_value (FuPlugin *self, const gchar *key)
Mario Limonciello963dc422018-02-27 14:26:58 -06002166{
Richard Hughes4be17d12018-05-30 20:36:29 +01002167 g_autofree gchar *conf_dir = NULL;
Mario Limonciello963dc422018-02-27 14:26:58 -06002168 g_autofree gchar *conf_file = NULL;
2169 g_autofree gchar *conf_path = NULL;
2170 g_autoptr(GKeyFile) keyfile = NULL;
2171 const gchar *plugin_name;
2172
Richard Hughes4be17d12018-05-30 20:36:29 +01002173 conf_dir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR_PKG);
Richard Hughes12724852018-09-04 13:53:44 +01002174 plugin_name = fu_plugin_get_name (self);
Mario Limonciello963dc422018-02-27 14:26:58 -06002175 conf_file = g_strdup_printf ("%s.conf", plugin_name);
Richard Hughes4be17d12018-05-30 20:36:29 +01002176 conf_path = g_build_filename (conf_dir, conf_file, NULL);
Mario Limonciello963dc422018-02-27 14:26:58 -06002177 if (!g_file_test (conf_path, G_FILE_TEST_IS_REGULAR))
2178 return NULL;
2179 keyfile = g_key_file_new ();
2180 if (!g_key_file_load_from_file (keyfile, conf_path,
2181 G_KEY_FILE_NONE, NULL))
2182 return NULL;
2183 return g_key_file_get_string (keyfile, plugin_name, key, NULL);
2184}
2185
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002186/**
Richard Hughes334ba792020-02-19 20:44:56 +00002187 * fu_plugin_get_config_value_boolean:
2188 * @self: a #FuPlugin
2189 * @key: A settings key
2190 *
2191 * Return the boolean value of a key if it's been configured
2192 *
2193 * Returns: %TRUE if the value is `true` (case insensitive), %FALSE otherwise
2194 *
Mario Limonciello96117d12020-02-28 10:17:56 -06002195 * Since: 1.4.0
Richard Hughes334ba792020-02-19 20:44:56 +00002196 **/
2197gboolean
2198fu_plugin_get_config_value_boolean (FuPlugin *self, const gchar *key)
2199{
2200 g_autofree gchar *tmp = fu_plugin_get_config_value (self, key);
2201 if (tmp == NULL)
2202 return FALSE;
Richard Hughes5337a432020-02-21 12:04:32 +00002203 return g_ascii_strcasecmp (tmp, "true") == 0;
Richard Hughes334ba792020-02-19 20:44:56 +00002204}
2205
2206/**
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002207 * fu_plugin_name_compare:
2208 * @plugin1: first #FuPlugin to compare.
2209 * @plugin2: second #FuPlugin to compare.
2210 *
2211 * Compares two plugins by their names.
2212 *
2213 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002214 *
2215 * Since: 1.0.8
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002216 **/
2217gint
2218fu_plugin_name_compare (FuPlugin *plugin1, FuPlugin *plugin2)
2219{
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002220 return g_strcmp0 (fu_plugin_get_name (plugin1), fu_plugin_get_name (plugin2));
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002221}
2222
2223/**
2224 * fu_plugin_order_compare:
2225 * @plugin1: first #FuPlugin to compare.
2226 * @plugin2: second #FuPlugin to compare.
2227 *
2228 * Compares two plugins by their depsolved order.
2229 *
2230 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002231 *
2232 * Since: 1.0.8
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002233 **/
2234gint
2235fu_plugin_order_compare (FuPlugin *plugin1, FuPlugin *plugin2)
2236{
2237 FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1);
2238 FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2);
2239 if (priv1->order < priv2->order)
2240 return -1;
2241 if (priv1->order > priv2->order)
2242 return 1;
2243 return 0;
2244}
2245
Richard Hughescff38bc2016-12-12 12:03:37 +00002246static void
2247fu_plugin_class_init (FuPluginClass *klass)
2248{
2249 GObjectClass *object_class = G_OBJECT_CLASS (klass);
2250 object_class->finalize = fu_plugin_finalize;
2251 signals[SIGNAL_DEVICE_ADDED] =
2252 g_signal_new ("device-added",
2253 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2254 G_STRUCT_OFFSET (FuPluginClass, device_added),
2255 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2256 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
2257 signals[SIGNAL_DEVICE_REMOVED] =
2258 g_signal_new ("device-removed",
2259 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2260 G_STRUCT_OFFSET (FuPluginClass, device_removed),
2261 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2262 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughese1fd34d2017-08-24 14:19:51 +01002263 signals[SIGNAL_DEVICE_REGISTER] =
2264 g_signal_new ("device-register",
2265 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2266 G_STRUCT_OFFSET (FuPluginClass, device_register),
2267 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2268 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughesaabdc372018-11-14 10:11:08 +00002269 signals[SIGNAL_CHECK_SUPPORTED] =
2270 g_signal_new ("check-supported",
2271 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2272 G_STRUCT_OFFSET (FuPluginClass, check_supported),
2273 NULL, NULL, g_cclosure_marshal_generic,
2274 G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
Richard Hughes75b965d2018-11-15 13:51:21 +00002275 signals[SIGNAL_RULES_CHANGED] =
2276 g_signal_new ("rules-changed",
2277 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2278 G_STRUCT_OFFSET (FuPluginClass, rules_changed),
2279 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2280 G_TYPE_NONE, 0);
Richard Hughescff38bc2016-12-12 12:03:37 +00002281}
2282
2283static void
Richard Hughes12724852018-09-04 13:53:44 +01002284fu_plugin_init (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +00002285{
Richard Hughes12724852018-09-04 13:53:44 +01002286 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesfaf2afe2021-01-13 14:00:20 +00002287 g_rw_lock_init (&priv->cache_mutex);
Richard Hughescff38bc2016-12-12 12:03:37 +00002288}
2289
2290static void
2291fu_plugin_finalize (GObject *object)
2292{
Richard Hughes12724852018-09-04 13:53:44 +01002293 FuPlugin *self = FU_PLUGIN (object);
2294 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002295 FuPluginInitFunc func = NULL;
2296
Richard Hughesfaf2afe2021-01-13 14:00:20 +00002297 g_rw_lock_clear (&priv->cache_mutex);
Richard Hughesaae22e42020-06-22 21:32:59 +01002298
Richard Hughescff38bc2016-12-12 12:03:37 +00002299 /* optional */
2300 if (priv->module != NULL) {
2301 g_module_symbol (priv->module, "fu_plugin_destroy", (gpointer *) &func);
2302 if (func != NULL) {
Richard Hughes7bcb8d42020-10-08 15:47:47 +01002303 g_debug ("destroy(%s)", fu_plugin_get_name (self));
Richard Hughes12724852018-09-04 13:53:44 +01002304 func (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002305 }
2306 }
2307
Richard Hughes11c59412020-06-22 15:29:48 +01002308 for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++) {
2309 if (priv->rules[i] != NULL)
2310 g_ptr_array_unref (priv->rules[i]);
2311 }
Richard Hughes68ab1e42021-01-13 14:01:17 +00002312 if (priv->devices != NULL)
2313 g_ptr_array_unref (priv->devices);
Richard Hughesb333e002021-04-01 10:40:02 +01002314 if (priv->ctx != NULL)
2315 g_object_unref (priv->ctx);
Richard Hughes275d3b42018-04-20 16:40:37 +01002316 if (priv->runtime_versions != NULL)
2317 g_hash_table_unref (priv->runtime_versions);
Richard Hughes34e0dab2018-04-20 16:43:00 +01002318 if (priv->compile_versions != NULL)
2319 g_hash_table_unref (priv->compile_versions);
Richard Hughes1d900f72020-06-22 15:17:39 +01002320 if (priv->report_metadata != NULL)
2321 g_hash_table_unref (priv->report_metadata);
Richard Hughesfaf2afe2021-01-13 14:00:20 +00002322 if (priv->cache != NULL)
2323 g_hash_table_unref (priv->cache);
Richard Hughesfaa35e42021-04-15 09:38:03 +01002324 if (priv->device_gtypes != NULL)
2325 g_array_unref (priv->device_gtypes);
Richard Hughes84999302019-05-02 10:18:32 +01002326 g_free (priv->build_hash);
Richard Hughescff38bc2016-12-12 12:03:37 +00002327 g_free (priv->data);
2328
2329 G_OBJECT_CLASS (fu_plugin_parent_class)->finalize (object);
2330}
2331
Mario Limonciello1a680f32019-11-25 19:44:53 -06002332/**
2333 * fu_plugin_new:
2334 *
2335 * Creates a new #FuPlugin
2336 *
2337 * Since: 0.8.0
2338 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002339FuPlugin *
Richard Hughesb333e002021-04-01 10:40:02 +01002340fu_plugin_new (FuContext *ctx)
Richard Hughescff38bc2016-12-12 12:03:37 +00002341{
Richard Hughesb333e002021-04-01 10:40:02 +01002342 FuPlugin *self = FU_PLUGIN (g_object_new (FU_TYPE_PLUGIN, NULL));
2343 FuPluginPrivate *priv = GET_PRIVATE (self);
2344 if (ctx != NULL)
2345 priv->ctx = g_object_ref (ctx);
2346 return self;
Richard Hughescff38bc2016-12-12 12:03:37 +00002347}