blob: 75c199b55660490949b8594be7ba1fdf2dd233dd [file] [log] [blame]
Richard Hughes02c90d82018-08-09 12:13:03 +01001/*
Richard Hughes2de8f132018-01-17 09:12:02 +00002 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
Richard Hughesd0905142016-03-13 09:46:49 +00003 *
Mario Limonciello51308e62018-05-28 20:05:46 -05004 * SPDX-License-Identifier: LGPL-2.1+
Richard Hughesd0905142016-03-13 09:46:49 +00005 */
6
Richard Hughesb08e7bc2018-09-11 10:51:13 +01007#define G_LOG_DOMAIN "FuPlugin"
8
Richard Hughesd0905142016-03-13 09:46:49 +00009#include "config.h"
10
Richard Hughescff38bc2016-12-12 12:03:37 +000011#include <fwupd.h>
12#include <gmodule.h>
Richard Hughescff38bc2016-12-12 12:03:37 +000013#include <errno.h>
14#include <string.h>
Richard Hughes68f12dd2018-08-09 14:43:31 +010015#include <unistd.h>
Mario Limonciello6d0aa3d2017-02-28 08:22:27 -060016#ifdef HAVE_VALGRIND
Richard Hughes576c0122017-02-24 09:47:00 +000017#include <valgrind.h>
Mario Limonciello6d0aa3d2017-02-28 08:22:27 -060018#endif /* HAVE_VALGRIND */
Richard Hughesd0905142016-03-13 09:46:49 +000019
Richard Hughes9dde04f2017-09-13 12:07:15 +010020#include "fu-device-private.h"
Richard Hughescff38bc2016-12-12 12:03:37 +000021#include "fu-plugin-private.h"
Richard Hughes37d09432018-09-09 10:39:45 +010022#include "fu-mutex.h"
Richard Hughesd0905142016-03-13 09:46:49 +000023
Richard Hughes4eada342017-10-03 21:20:32 +010024/**
25 * SECTION:fu-plugin
26 * @short_description: a daemon plugin
27 *
28 * An object that represents a plugin run by the daemon.
29 *
30 * See also: #FuDevice
31 */
32
Richard Hughesb0829032017-01-10 09:27:08 +000033#define FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM 3000u /* ms */
34
Richard Hughescff38bc2016-12-12 12:03:37 +000035static void fu_plugin_finalize (GObject *object);
36
37typedef struct {
38 GModule *module;
39 GUsbContext *usb_ctx;
40 gboolean enabled;
Richard Hughes08a37992017-09-12 12:57:43 +010041 guint order;
Richard Hughes81c427c2018-08-06 15:20:17 +010042 guint priority;
Richard Hughes08a37992017-09-12 12:57:43 +010043 GPtrArray *rules[FU_PLUGIN_RULE_LAST];
Richard Hughescff38bc2016-12-12 12:03:37 +000044 gchar *name;
Richard Hughesf425d292019-01-18 17:57:39 +000045 gchar *build_hash;
Richard Hughesd7704d42017-08-08 20:29:09 +010046 FuHwids *hwids;
Richard Hughes9c028f02017-10-28 21:14:28 +010047 FuQuirks *quirks;
Richard Hughes0eb123b2018-04-19 12:00:04 +010048 GHashTable *runtime_versions;
Richard Hughes34e0dab2018-04-20 16:43:00 +010049 GHashTable *compile_versions;
Richard Hughes9d6e0e72018-08-24 20:20:17 +010050 GPtrArray *udev_subsystems;
Richard Hughes1354ea92017-09-19 15:58:31 +010051 FuSmbios *smbios;
Richard Hughes989acf12019-10-05 20:16:47 +010052 GType device_gtype;
Richard Hughescff38bc2016-12-12 12:03:37 +000053 GHashTable *devices; /* platform_id:GObject */
Richard Hughes161e9b52019-06-12 14:22:45 +010054 GRWLock devices_mutex;
Richard Hughes80b79bb2018-01-11 21:11:06 +000055 GHashTable *report_metadata; /* key:value */
Richard Hughescff38bc2016-12-12 12:03:37 +000056 FuPluginData *data;
57} FuPluginPrivate;
58
59enum {
60 SIGNAL_DEVICE_ADDED,
61 SIGNAL_DEVICE_REMOVED,
Richard Hughese1fd34d2017-08-24 14:19:51 +010062 SIGNAL_DEVICE_REGISTER,
Richard Hughes75b965d2018-11-15 13:51:21 +000063 SIGNAL_RULES_CHANGED,
Richard Hughes362d6d72017-01-07 21:42:14 +000064 SIGNAL_RECOLDPLUG,
Richard Hughesb0829032017-01-10 09:27:08 +000065 SIGNAL_SET_COLDPLUG_DELAY,
Richard Hughesaabdc372018-11-14 10:11:08 +000066 SIGNAL_CHECK_SUPPORTED,
Richard Hughes95c98a92019-10-22 16:03:15 +010067 SIGNAL_ADD_FIRMWARE_GTYPE,
Richard Hughes399859e2020-05-11 19:44:03 +010068 SIGNAL_SECURITY_CHANGED,
Richard Hughescff38bc2016-12-12 12:03:37 +000069 SIGNAL_LAST
70};
71
72static guint signals[SIGNAL_LAST] = { 0 };
73
74G_DEFINE_TYPE_WITH_PRIVATE (FuPlugin, fu_plugin, G_TYPE_OBJECT)
75#define GET_PRIVATE(o) (fu_plugin_get_instance_private (o))
76
77typedef const gchar *(*FuPluginGetNameFunc) (void);
Richard Hughes12724852018-09-04 13:53:44 +010078typedef void (*FuPluginInitFunc) (FuPlugin *self);
79typedef gboolean (*FuPluginStartupFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000080 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010081typedef void (*FuPluginDeviceRegisterFunc) (FuPlugin *self,
Richard Hughese1fd34d2017-08-24 14:19:51 +010082 FuDevice *device);
Richard Hughes12724852018-09-04 13:53:44 +010083typedef gboolean (*FuPluginDeviceFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000084 FuDevice *device,
85 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010086typedef gboolean (*FuPluginFlaggedDeviceFunc) (FuPlugin *self,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -050087 FwupdInstallFlags flags,
88 FuDevice *device,
89 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010090typedef gboolean (*FuPluginDeviceArrayFunc) (FuPlugin *self,
Richard Hughesdbd8c762018-06-15 20:31:40 +010091 GPtrArray *devices,
92 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010093typedef gboolean (*FuPluginVerifyFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000094 FuDevice *device,
95 FuPluginVerifyFlags flags,
96 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010097typedef gboolean (*FuPluginUpdateFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000098 FuDevice *device,
99 GBytes *blob_fw,
100 FwupdInstallFlags flags,
101 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +0100102typedef gboolean (*FuPluginUsbDeviceAddedFunc) (FuPlugin *self,
Richard Hughesff704412018-09-04 11:28:32 +0100103 FuUsbDevice *device,
Richard Hughes104f6512017-11-24 11:44:57 +0000104 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +0100105typedef gboolean (*FuPluginUdevDeviceAddedFunc) (FuPlugin *self,
Richard Hughesff704412018-09-04 11:28:32 +0100106 FuUdevDevice *device,
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100107 GError **error);
Richard Hughesf58ac732020-05-12 15:23:44 +0100108typedef void (*FuPluginSecurityAttrsFunc) (FuPlugin *self,
109 FuSecurityAttrs *attrs);
Richard Hughescff38bc2016-12-12 12:03:37 +0000110
Richard Hughes57d18222017-01-10 16:02:59 +0000111/**
Mario Limonciello52e75ba2019-11-22 13:21:19 -0600112 * fu_plugin_is_open:
113 * @self: A #FuPlugin
114 *
115 * Determines if the plugin is opened
116 *
117 * Returns: TRUE for opened, FALSE for not
118 *
119 * Since: 1.3.5
120 **/
121gboolean
122fu_plugin_is_open (FuPlugin *self)
123{
124 FuPluginPrivate *priv = GET_PRIVATE (self);
125 return priv->module != NULL;
126}
127
128/**
Richard Hughes57d18222017-01-10 16:02:59 +0000129 * fu_plugin_get_name:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100130 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000131 *
132 * Gets the plugin name.
133 *
134 * Returns: a plugin name, or %NULL for unknown.
135 *
136 * Since: 0.8.0
137 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000138const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100139fu_plugin_get_name (FuPlugin *self)
Richard Hughesd0905142016-03-13 09:46:49 +0000140{
Richard Hughes12724852018-09-04 13:53:44 +0100141 FuPluginPrivate *priv = GET_PRIVATE (self);
142 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000143 return priv->name;
144}
Richard Hughesd0905142016-03-13 09:46:49 +0000145
Mario Limonciello1a680f32019-11-25 19:44:53 -0600146/**
147 * fu_plugin_set_name:
148 * @self: A #FuPlugin
149 * @name: A string
150 *
151 * Sets the plugin name.
152 *
153 * Since: 0.8.0
154 **/
Richard Hughes34834102017-11-21 21:55:00 +0000155void
Richard Hughes12724852018-09-04 13:53:44 +0100156fu_plugin_set_name (FuPlugin *self, const gchar *name)
Richard Hughes34834102017-11-21 21:55:00 +0000157{
Richard Hughes12724852018-09-04 13:53:44 +0100158 FuPluginPrivate *priv = GET_PRIVATE (self);
159 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughes34834102017-11-21 21:55:00 +0000160 g_return_if_fail (name != NULL);
161 g_free (priv->name);
162 priv->name = g_strdup (name);
163}
164
Richard Hughes57d18222017-01-10 16:02:59 +0000165/**
Richard Hughesf425d292019-01-18 17:57:39 +0000166 * fu_plugin_set_build_hash:
167 * @self: A #FuPlugin
168 * @build_hash: A checksum
169 *
170 * Sets the plugin build hash, typically a SHA256 checksum. All plugins must
171 * set the correct checksum to avoid the daemon being marked as tainted.
172 *
173 * Since: 1.2.4
174 **/
175void
176fu_plugin_set_build_hash (FuPlugin *self, const gchar *build_hash)
177{
178 FuPluginPrivate *priv = GET_PRIVATE (self);
179 g_return_if_fail (FU_IS_PLUGIN (self));
180 g_return_if_fail (build_hash != NULL);
181 g_free (priv->build_hash);
182 priv->build_hash = g_strdup (build_hash);
183}
184
Mario Limonciello1a680f32019-11-25 19:44:53 -0600185/**
186 * fu_plugin_get_build_hash:
187 * @self: A #FuPlugin
188 *
189 * Gets the build hash a plugin was generated with.
190 *
191 * Returns: (transfer none): a #gchar, or %NULL for unset.
192 *
193 * Since: 1.2.4
194 **/
Richard Hughesf425d292019-01-18 17:57:39 +0000195const gchar *
196fu_plugin_get_build_hash (FuPlugin *self)
197{
198 FuPluginPrivate *priv = GET_PRIVATE (self);
199 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
200 return priv->build_hash;
201}
202
203/**
Richard Hughes57d18222017-01-10 16:02:59 +0000204 * fu_plugin_cache_lookup:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100205 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000206 * @id: the key
207 *
208 * Finds an object in the per-plugin cache.
209 *
210 * Returns: (transfer none): a #GObject, or %NULL for unfound.
211 *
212 * Since: 0.8.0
213 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000214gpointer
Richard Hughes12724852018-09-04 13:53:44 +0100215fu_plugin_cache_lookup (FuPlugin *self, const gchar *id)
Richard Hughescff38bc2016-12-12 12:03:37 +0000216{
Richard Hughes12724852018-09-04 13:53:44 +0100217 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes161e9b52019-06-12 14:22:45 +0100218 g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100219 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughesccd78a92017-01-11 16:57:41 +0000220 g_return_val_if_fail (id != NULL, NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100221 g_return_val_if_fail (locker != NULL, NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000222 return g_hash_table_lookup (priv->devices, id);
223}
Richard Hughesd0905142016-03-13 09:46:49 +0000224
Richard Hughes57d18222017-01-10 16:02:59 +0000225/**
226 * fu_plugin_cache_add:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100227 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000228 * @id: the key
229 * @dev: a #GObject, typically a #FuDevice
230 *
231 * Adds an object to the per-plugin cache.
232 *
233 * Since: 0.8.0
234 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000235void
Richard Hughes12724852018-09-04 13:53:44 +0100236fu_plugin_cache_add (FuPlugin *self, const gchar *id, gpointer dev)
Richard Hughescff38bc2016-12-12 12:03:37 +0000237{
Richard Hughes12724852018-09-04 13:53:44 +0100238 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0fe49142019-11-22 16:56:38 +0000239 g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100240 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000241 g_return_if_fail (id != NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100242 g_return_if_fail (locker != NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000243 g_hash_table_insert (priv->devices, g_strdup (id), g_object_ref (dev));
244}
245
Richard Hughes57d18222017-01-10 16:02:59 +0000246/**
247 * fu_plugin_cache_remove:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100248 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000249 * @id: the key
250 *
251 * Removes an object from the per-plugin cache.
252 *
253 * Since: 0.8.0
254 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000255void
Richard Hughes12724852018-09-04 13:53:44 +0100256fu_plugin_cache_remove (FuPlugin *self, const gchar *id)
Richard Hughescff38bc2016-12-12 12:03:37 +0000257{
Richard Hughes12724852018-09-04 13:53:44 +0100258 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0fe49142019-11-22 16:56:38 +0000259 g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100260 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000261 g_return_if_fail (id != NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100262 g_return_if_fail (locker != NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000263 g_hash_table_remove (priv->devices, id);
264}
265
Richard Hughes57d18222017-01-10 16:02:59 +0000266/**
267 * fu_plugin_get_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100268 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000269 *
Richard Hughes4eada342017-10-03 21:20:32 +0100270 * Gets the per-plugin allocated private data. This will return %NULL unless
271 * fu_plugin_alloc_data() has been called by the plugin.
Richard Hughes57d18222017-01-10 16:02:59 +0000272 *
Richard Hughes4eada342017-10-03 21:20:32 +0100273 * Returns: (transfer none): a pointer to a structure, or %NULL for unset.
Richard Hughes57d18222017-01-10 16:02:59 +0000274 *
275 * Since: 0.8.0
276 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000277FuPluginData *
Richard Hughes12724852018-09-04 13:53:44 +0100278fu_plugin_get_data (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +0000279{
Richard Hughes12724852018-09-04 13:53:44 +0100280 FuPluginPrivate *priv = GET_PRIVATE (self);
281 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000282 return priv->data;
283}
284
Richard Hughes57d18222017-01-10 16:02:59 +0000285/**
Richard Hughes00f66f62019-11-27 11:42:53 +0000286 * fu_plugin_alloc_data: (skip):
Richard Hughes2c0635a2018-09-04 14:52:46 +0100287 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000288 * @data_sz: the size to allocate
289 *
290 * Allocates the per-plugin allocated private data.
291 *
292 * Returns: (transfer full): a pointer to a structure, or %NULL for unset.
293 *
294 * Since: 0.8.0
295 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000296FuPluginData *
Richard Hughes12724852018-09-04 13:53:44 +0100297fu_plugin_alloc_data (FuPlugin *self, gsize data_sz)
Richard Hughescff38bc2016-12-12 12:03:37 +0000298{
Richard Hughes12724852018-09-04 13:53:44 +0100299 FuPluginPrivate *priv = GET_PRIVATE (self);
300 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes44dee882017-01-11 08:31:10 +0000301 if (priv->data != NULL) {
302 g_critical ("fu_plugin_alloc_data() already used by plugin");
303 return priv->data;
304 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000305 priv->data = g_malloc0 (data_sz);
306 return priv->data;
Richard Hughesd0905142016-03-13 09:46:49 +0000307}
308
Richard Hughes57d18222017-01-10 16:02:59 +0000309/**
310 * fu_plugin_get_usb_context:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100311 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000312 *
313 * Gets the shared USB context that all plugins can use.
314 *
315 * Returns: (transfer none): a #GUsbContext.
316 *
317 * Since: 0.8.0
318 **/
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000319GUsbContext *
Richard Hughes12724852018-09-04 13:53:44 +0100320fu_plugin_get_usb_context (FuPlugin *self)
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000321{
Richard Hughes12724852018-09-04 13:53:44 +0100322 FuPluginPrivate *priv = GET_PRIVATE (self);
323 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000324 return priv->usb_ctx;
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000325}
326
Mario Limonciello1a680f32019-11-25 19:44:53 -0600327/**
328 * fu_plugin_set_usb_context:
329 * @self: A #FuPlugin
330 * @usb_ctx: A #FGUsbContext
331 *
332 * Sets the shared USB context for a plugin
333 *
334 * Since: 0.8.0
335 **/
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000336void
Richard Hughes12724852018-09-04 13:53:44 +0100337fu_plugin_set_usb_context (FuPlugin *self, GUsbContext *usb_ctx)
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000338{
Richard Hughes12724852018-09-04 13:53:44 +0100339 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +0000340 g_set_object (&priv->usb_ctx, usb_ctx);
341}
342
Richard Hughes57d18222017-01-10 16:02:59 +0000343/**
344 * fu_plugin_get_enabled:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100345 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000346 *
Richard Hughes4eada342017-10-03 21:20:32 +0100347 * Returns if the plugin is enabled. Plugins may self-disable using
348 * fu_plugin_set_enabled() or can be disabled by the daemon.
Richard Hughes57d18222017-01-10 16:02:59 +0000349 *
350 * Returns: %TRUE if the plugin is currently enabled.
351 *
352 * Since: 0.8.0
353 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000354gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100355fu_plugin_get_enabled (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +0000356{
Richard Hughes12724852018-09-04 13:53:44 +0100357 FuPluginPrivate *priv = GET_PRIVATE (self);
358 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
Richard Hughescff38bc2016-12-12 12:03:37 +0000359 return priv->enabled;
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000360}
361
Richard Hughes57d18222017-01-10 16:02:59 +0000362/**
363 * fu_plugin_set_enabled:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100364 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000365 * @enabled: the enabled value
366 *
367 * Enables or disables a plugin. Plugins can self-disable at any point.
368 *
369 * Since: 0.8.0
370 **/
Richard Hughesd0905142016-03-13 09:46:49 +0000371void
Richard Hughes12724852018-09-04 13:53:44 +0100372fu_plugin_set_enabled (FuPlugin *self, gboolean enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000373{
Richard Hughes12724852018-09-04 13:53:44 +0100374 FuPluginPrivate *priv = GET_PRIVATE (self);
375 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughescff38bc2016-12-12 12:03:37 +0000376 priv->enabled = enabled;
377}
378
Mario Limonciello1a680f32019-11-25 19:44:53 -0600379/**
380 * fu_plugin_guess_name_from_fn:
381 * @filename: filename to guess
382 *
383 * Tries to guess the name of the plugin from a filename
384 *
385 * Returns: (transfer full): the guessed name of the plugin
386 *
387 * Since: 1.0.8
388 **/
Richard Hughes1e456bc2018-05-10 20:16:16 +0100389gchar *
390fu_plugin_guess_name_from_fn (const gchar *filename)
391{
392 const gchar *prefix = "libfu_plugin_";
393 gchar *name;
394 gchar *str = g_strstr_len (filename, -1, prefix);
395 if (str == NULL)
396 return NULL;
397 name = g_strdup (str + strlen (prefix));
398 g_strdelimit (name, ".", '\0');
399 return name;
400}
401
Mario Limonciello1a680f32019-11-25 19:44:53 -0600402/**
403 * fu_plugin_open:
404 * @self: A #FuPlugin
405 * @filename: The shared object filename to open
406 * @error: A #GError or NULL
407 *
408 * Opens the plugin module
409 *
410 * Returns: TRUE for success, FALSE for fail
411 *
412 * Since: 0.8.0
413 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000414gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100415fu_plugin_open (FuPlugin *self, const gchar *filename, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +0000416{
Richard Hughes12724852018-09-04 13:53:44 +0100417 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +0000418 FuPluginInitFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000419
420 priv->module = g_module_open (filename, 0);
421 if (priv->module == NULL) {
422 g_set_error (error,
423 G_IO_ERROR,
424 G_IO_ERROR_FAILED,
Mario Limonciellof5605532019-11-04 07:49:50 -0600425 "failed to open plugin %s: %s",
426 filename, g_module_error ());
Richard Hughescff38bc2016-12-12 12:03:37 +0000427 return FALSE;
428 }
429
430 /* set automatically */
Richard Hughes1e456bc2018-05-10 20:16:16 +0100431 if (priv->name == NULL)
432 priv->name = fu_plugin_guess_name_from_fn (filename);
Richard Hughesd0905142016-03-13 09:46:49 +0000433
434 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000435 g_module_symbol (priv->module, "fu_plugin_init", (gpointer *) &func);
436 if (func != NULL) {
437 g_debug ("performing init() on %s", filename);
Richard Hughes12724852018-09-04 13:53:44 +0100438 func (self);
Richard Hughesd0905142016-03-13 09:46:49 +0000439 }
440
Richard Hughescff38bc2016-12-12 12:03:37 +0000441 return TRUE;
442}
443
Richard Hughes57d18222017-01-10 16:02:59 +0000444/**
445 * fu_plugin_device_add:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100446 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000447 * @device: A #FuDevice
448 *
449 * Asks the daemon to add a device to the exported list. If this device ID
450 * has already been added by a different plugin then this request will be
451 * ignored.
452 *
453 * Plugins should use fu_plugin_device_add_delay() if they are not capable of
454 * actually flashing an image to the hardware so that higher-priority plugins
455 * can add the device themselves.
456 *
457 * Since: 0.8.0
458 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000459void
Richard Hughes12724852018-09-04 13:53:44 +0100460fu_plugin_device_add (FuPlugin *self, FuDevice *device)
Richard Hughescff38bc2016-12-12 12:03:37 +0000461{
Richard Hughes5e447292018-04-27 14:25:54 +0100462 GPtrArray *children;
Richard Hughesc125ec02018-09-05 19:35:17 +0100463 g_autoptr(GError) error = NULL;
Richard Hughes5e447292018-04-27 14:25:54 +0100464
Richard Hughes12724852018-09-04 13:53:44 +0100465 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000466 g_return_if_fail (FU_IS_DEVICE (device));
467
Richard Hughesc125ec02018-09-05 19:35:17 +0100468 /* ensure the device ID is set from the physical and logical IDs */
469 if (!fu_device_ensure_id (device, &error)) {
470 g_warning ("ignoring add: %s", error->message);
471 return;
472 }
473
Richard Hughescff38bc2016-12-12 12:03:37 +0000474 g_debug ("emit added from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100475 fu_plugin_get_name (self),
Richard Hughescff38bc2016-12-12 12:03:37 +0000476 fu_device_get_id (device));
477 fu_device_set_created (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
Richard Hughes12724852018-09-04 13:53:44 +0100478 fu_device_set_plugin (device, fu_plugin_get_name (self));
479 g_signal_emit (self, signals[SIGNAL_DEVICE_ADDED], 0, device);
Richard Hughes5e447292018-04-27 14:25:54 +0100480
Richard Hughes128c0162018-08-10 11:00:29 +0100481 /* add children if they have not already been added */
Richard Hughes5e447292018-04-27 14:25:54 +0100482 children = fu_device_get_children (device);
483 for (guint i = 0; i < children->len; i++) {
484 FuDevice *child = g_ptr_array_index (children, i);
Richard Hughes128c0162018-08-10 11:00:29 +0100485 if (fu_device_get_created (child) == 0)
Richard Hughes12724852018-09-04 13:53:44 +0100486 fu_plugin_device_add (self, child);
Richard Hughes5e447292018-04-27 14:25:54 +0100487 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000488}
489
Richard Hughese1fd34d2017-08-24 14:19:51 +0100490/**
491 * fu_plugin_device_register:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100492 * @self: A #FuPlugin
Richard Hughese1fd34d2017-08-24 14:19:51 +0100493 * @device: A #FuDevice
494 *
495 * Registers the device with other plugins so they can set metadata.
496 *
497 * Plugins do not have to call this manually as this is done automatically
498 * when using fu_plugin_device_add(). They may wish to use this manually
Richard Hughes21eaeef2020-01-14 12:10:01 +0000499 * if for instance the coldplug should be ignored based on the metadata
Richard Hughese1fd34d2017-08-24 14:19:51 +0100500 * set from other plugins.
501 *
502 * Since: 0.9.7
503 **/
504void
Richard Hughes12724852018-09-04 13:53:44 +0100505fu_plugin_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +0100506{
Richard Hughesc125ec02018-09-05 19:35:17 +0100507 g_autoptr(GError) error = NULL;
508
Richard Hughes12724852018-09-04 13:53:44 +0100509 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughese1fd34d2017-08-24 14:19:51 +0100510 g_return_if_fail (FU_IS_DEVICE (device));
511
Richard Hughesc125ec02018-09-05 19:35:17 +0100512 /* ensure the device ID is set from the physical and logical IDs */
513 if (!fu_device_ensure_id (device, &error)) {
514 g_warning ("ignoring registration: %s", error->message);
515 return;
516 }
517
Richard Hughese1fd34d2017-08-24 14:19:51 +0100518 g_debug ("emit device-register from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100519 fu_plugin_get_name (self),
Richard Hughese1fd34d2017-08-24 14:19:51 +0100520 fu_device_get_id (device));
Richard Hughes12724852018-09-04 13:53:44 +0100521 g_signal_emit (self, signals[SIGNAL_DEVICE_REGISTER], 0, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +0100522}
523
Richard Hughes57d18222017-01-10 16:02:59 +0000524/**
Richard Hughes4eada342017-10-03 21:20:32 +0100525 * fu_plugin_device_remove:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100526 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000527 * @device: A #FuDevice
528 *
529 * Asks the daemon to remove a device from the exported list.
530 *
531 * Since: 0.8.0
532 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000533void
Richard Hughes12724852018-09-04 13:53:44 +0100534fu_plugin_device_remove (FuPlugin *self, FuDevice *device)
Richard Hughescff38bc2016-12-12 12:03:37 +0000535{
Richard Hughes12724852018-09-04 13:53:44 +0100536 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000537 g_return_if_fail (FU_IS_DEVICE (device));
538
Richard Hughescff38bc2016-12-12 12:03:37 +0000539 g_debug ("emit removed from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100540 fu_plugin_get_name (self),
Richard Hughescff38bc2016-12-12 12:03:37 +0000541 fu_device_get_id (device));
Richard Hughes12724852018-09-04 13:53:44 +0100542 g_signal_emit (self, signals[SIGNAL_DEVICE_REMOVED], 0, device);
Richard Hughescff38bc2016-12-12 12:03:37 +0000543}
544
Richard Hughes57d18222017-01-10 16:02:59 +0000545/**
Richard Hughes2de8f132018-01-17 09:12:02 +0000546 * fu_plugin_request_recoldplug:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100547 * @self: A #FuPlugin
Richard Hughes362d6d72017-01-07 21:42:14 +0000548 *
549 * Ask all the plugins to coldplug all devices, which will include the prepare()
550 * and cleanup() phases. Duplicate devices added will be ignored.
551 *
552 * Since: 0.8.0
553 **/
554void
Richard Hughes12724852018-09-04 13:53:44 +0100555fu_plugin_request_recoldplug (FuPlugin *self)
Richard Hughes362d6d72017-01-07 21:42:14 +0000556{
Richard Hughes12724852018-09-04 13:53:44 +0100557 g_return_if_fail (FU_IS_PLUGIN (self));
558 g_signal_emit (self, signals[SIGNAL_RECOLDPLUG], 0);
Richard Hughes362d6d72017-01-07 21:42:14 +0000559}
560
Richard Hughesb0829032017-01-10 09:27:08 +0000561/**
Richard Hughes399859e2020-05-11 19:44:03 +0100562 * fu_plugin_security_changed:
563 * @self: A #FuPlugin
564 *
565 * Informs the daemon that the HSI state may have changed.
566 *
567 * Since: 1.5.0
568 **/
569void
570fu_plugin_security_changed (FuPlugin *self)
571{
572 g_return_if_fail (FU_IS_PLUGIN (self));
573 g_signal_emit (self, signals[SIGNAL_SECURITY_CHANGED], 0);
574}
575
576/**
Richard Hughesb8f8db22017-04-25 15:56:00 +0100577 * fu_plugin_check_hwid:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100578 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100579 * @hwid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
Richard Hughesb8f8db22017-04-25 15:56:00 +0100580 *
Richard Hughesd7704d42017-08-08 20:29:09 +0100581 * Checks to see if a specific GUID exists. All hardware IDs on a
Richard Hughesb8f8db22017-04-25 15:56:00 +0100582 * specific system can be shown using the `fwupdmgr hwids` command.
583 *
Richard Hughes4eada342017-10-03 21:20:32 +0100584 * Returns: %TRUE if the HwId is found on the system.
585 *
Richard Hughesb8f8db22017-04-25 15:56:00 +0100586 * Since: 0.9.1
587 **/
588gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100589fu_plugin_check_hwid (FuPlugin *self, const gchar *hwid)
Richard Hughesb8f8db22017-04-25 15:56:00 +0100590{
Richard Hughes12724852018-09-04 13:53:44 +0100591 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100592 if (priv->hwids == NULL)
593 return FALSE;
Richard Hughesd7704d42017-08-08 20:29:09 +0100594 return fu_hwids_has_guid (priv->hwids, hwid);
595}
596
597/**
Patrick Rudolpha60b5472019-10-16 10:43:03 +0200598 * fu_plugin_get_hwid_replace_value:
599 * @self: A #FuPlugin
600 * @keys: A key, e.g. `HardwareID-3` or %FU_HWIDS_KEY_PRODUCT_SKU
601 * @error: A #GError or %NULL
602 *
603 * Gets the replacement value for a specific key. All hardware IDs on a
604 * specific system can be shown using the `fwupdmgr hwids` command.
605 *
606 * Returns: (transfer full): a string, or %NULL for error.
607 *
608 * Since: 1.3.3
609 **/
610gchar *
611fu_plugin_get_hwid_replace_value (FuPlugin *self, const gchar *keys, GError **error)
612{
613 FuPluginPrivate *priv = GET_PRIVATE (self);
614 if (priv->hwids == NULL)
615 return NULL;
616
617 return fu_hwids_get_replace_values (priv->hwids, keys, error);
618}
619
620/**
Richard Hughes69a5f352018-08-08 11:58:15 +0100621 * fu_plugin_get_hwids:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100622 * @self: A #FuPlugin
Richard Hughes69a5f352018-08-08 11:58:15 +0100623 *
624 * Returns all the HWIDs defined in the system. All hardware IDs on a
625 * specific system can be shown using the `fwupdmgr hwids` command.
626 *
Mario Limonciello1a680f32019-11-25 19:44:53 -0600627 * Returns: (transfer none) (element-type utf8): An array of GUIDs
Richard Hughes69a5f352018-08-08 11:58:15 +0100628 *
629 * Since: 1.1.1
630 **/
631GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +0100632fu_plugin_get_hwids (FuPlugin *self)
Richard Hughes69a5f352018-08-08 11:58:15 +0100633{
Richard Hughes12724852018-09-04 13:53:44 +0100634 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes69a5f352018-08-08 11:58:15 +0100635 if (priv->hwids == NULL)
636 return NULL;
637 return fu_hwids_get_guids (priv->hwids);
638}
639
640/**
Richard Hughes19841802019-09-10 16:48:00 +0100641 * fu_plugin_has_custom_flag:
642 * @self: A #FuPlugin
643 * @flag: A custom text flag, specific to the plugin, e.g. `uefi-force-enable`
644 *
645 * Returns if a per-plugin HwId custom flag exists, typically added from a DMI quirk.
646 *
647 * Returns: %TRUE if the quirk entry exists
648 *
649 * Since: 1.3.1
650 **/
651gboolean
652fu_plugin_has_custom_flag (FuPlugin *self, const gchar *flag)
653{
654 FuPluginPrivate *priv = GET_PRIVATE (self);
655 GPtrArray *hwids = fu_plugin_get_hwids (self);
656
657 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
658 g_return_val_if_fail (flag != NULL, FALSE);
659
660 /* never set up, e.g. in tests */
661 if (hwids == NULL)
662 return FALSE;
663
664 /* search each hwid */
665 for (guint i = 0; i < hwids->len; i++) {
666 const gchar *hwid = g_ptr_array_index (hwids, i);
667 const gchar *value;
668 g_autofree gchar *key = g_strdup_printf ("HwId=%s", hwid);
669
670 /* does prefixed quirk exist */
671 value = fu_quirks_lookup_by_id (priv->quirks, key, FU_QUIRKS_FLAGS);
672 if (value != NULL) {
673 g_auto(GStrv) quirks = g_strsplit (value, ",", -1);
674 if (g_strv_contains ((const gchar * const *) quirks, flag))
675 return TRUE;
676 }
677 }
678 return FALSE;
679}
680
681/**
Richard Hughes1354ea92017-09-19 15:58:31 +0100682 * fu_plugin_check_supported:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100683 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100684 * @guid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
Richard Hughes1354ea92017-09-19 15:58:31 +0100685 *
686 * Checks to see if a specific device GUID is supported, i.e. available in the
687 * AppStream metadata.
688 *
Richard Hughes4eada342017-10-03 21:20:32 +0100689 * Returns: %TRUE if the device is supported.
690 *
Richard Hughes1354ea92017-09-19 15:58:31 +0100691 * Since: 1.0.0
692 **/
Richard Hughesd8a8d5e2019-10-08 13:05:02 +0100693static gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100694fu_plugin_check_supported (FuPlugin *self, const gchar *guid)
Richard Hughes1354ea92017-09-19 15:58:31 +0100695{
Richard Hughesaabdc372018-11-14 10:11:08 +0000696 gboolean retval = FALSE;
697 g_signal_emit (self, signals[SIGNAL_CHECK_SUPPORTED], 0, guid, &retval);
698 return retval;
Richard Hughes1354ea92017-09-19 15:58:31 +0100699}
700
701/**
Richard Hughesd7704d42017-08-08 20:29:09 +0100702 * fu_plugin_get_dmi_value:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100703 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100704 * @dmi_id: A DMI ID, e.g. `BiosVersion`
Richard Hughesd7704d42017-08-08 20:29:09 +0100705 *
706 * Gets a hardware DMI value.
707 *
Richard Hughes4eada342017-10-03 21:20:32 +0100708 * Returns: The string, or %NULL
709 *
Richard Hughesd7704d42017-08-08 20:29:09 +0100710 * Since: 0.9.7
711 **/
712const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100713fu_plugin_get_dmi_value (FuPlugin *self, const gchar *dmi_id)
Richard Hughesd7704d42017-08-08 20:29:09 +0100714{
Richard Hughes12724852018-09-04 13:53:44 +0100715 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd7704d42017-08-08 20:29:09 +0100716 if (priv->hwids == NULL)
Richard Hughes7ef96b82017-08-23 18:28:24 +0100717 return NULL;
Richard Hughesd7704d42017-08-08 20:29:09 +0100718 return fu_hwids_get_value (priv->hwids, dmi_id);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100719}
720
Richard Hughes49e5e052017-09-03 12:15:41 +0100721/**
722 * fu_plugin_get_smbios_string:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100723 * @self: A #FuPlugin
Richard Hughes49e5e052017-09-03 12:15:41 +0100724 * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
725 * @offset: A SMBIOS offset
726 *
727 * Gets a hardware SMBIOS string.
728 *
729 * The @type and @offset can be referenced from the DMTF SMBIOS specification:
730 * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.1.1.pdf
731 *
Richard Hughes4eada342017-10-03 21:20:32 +0100732 * Returns: A string, or %NULL
733 *
Richard Hughes49e5e052017-09-03 12:15:41 +0100734 * Since: 0.9.8
735 **/
736const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100737fu_plugin_get_smbios_string (FuPlugin *self, guint8 structure_type, guint8 offset)
Richard Hughes49e5e052017-09-03 12:15:41 +0100738{
Richard Hughes12724852018-09-04 13:53:44 +0100739 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100740 if (priv->smbios == NULL)
741 return NULL;
742 return fu_smbios_get_string (priv->smbios, structure_type, offset, NULL);
743}
744
745/**
746 * fu_plugin_get_smbios_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100747 * @self: A #FuPlugin
Richard Hughes49e5e052017-09-03 12:15:41 +0100748 * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
749 *
750 * Gets a hardware SMBIOS data.
751 *
Richard Hughesdfaca2d2019-08-01 08:08:03 +0100752 * Returns: (transfer full): A #GBytes, or %NULL
Richard Hughes4eada342017-10-03 21:20:32 +0100753 *
Richard Hughes49e5e052017-09-03 12:15:41 +0100754 * Since: 0.9.8
755 **/
756GBytes *
Richard Hughes12724852018-09-04 13:53:44 +0100757fu_plugin_get_smbios_data (FuPlugin *self, guint8 structure_type)
Richard Hughes49e5e052017-09-03 12:15:41 +0100758{
Richard Hughes12724852018-09-04 13:53:44 +0100759 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100760 if (priv->smbios == NULL)
761 return NULL;
762 return fu_smbios_get_data (priv->smbios, structure_type, NULL);
763}
764
Mario Limonciello1a680f32019-11-25 19:44:53 -0600765/**
766 * fu_plugin_set_hwids:
767 * @self: A #FuPlugin
768 * @hwids: A #FuHwids
769 *
770 * Sets the hwids for a plugin
771 *
772 * Since: 0.9.7
773 **/
Richard Hughesb8f8db22017-04-25 15:56:00 +0100774void
Richard Hughes12724852018-09-04 13:53:44 +0100775fu_plugin_set_hwids (FuPlugin *self, FuHwids *hwids)
Richard Hughesb8f8db22017-04-25 15:56:00 +0100776{
Richard Hughes12724852018-09-04 13:53:44 +0100777 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd7704d42017-08-08 20:29:09 +0100778 g_set_object (&priv->hwids, hwids);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100779}
780
Mario Limonciello1a680f32019-11-25 19:44:53 -0600781/**
782 * fu_plugin_set_udev_subsystems:
783 * @self: A #FuPlugin
Richard Hughesa0d81c72019-11-27 11:41:54 +0000784 * @udev_subsystems: (element-type utf8): A #GPtrArray
Mario Limonciello1a680f32019-11-25 19:44:53 -0600785 *
786 * Sets the udev subsystems used by a plugin
787 *
788 * Since: 1.1.2
789 **/
Richard Hughes49e5e052017-09-03 12:15:41 +0100790void
Richard Hughes12724852018-09-04 13:53:44 +0100791fu_plugin_set_udev_subsystems (FuPlugin *self, GPtrArray *udev_subsystems)
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100792{
Richard Hughes12724852018-09-04 13:53:44 +0100793 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100794 if (priv->udev_subsystems != NULL)
795 g_ptr_array_unref (priv->udev_subsystems);
796 priv->udev_subsystems = g_ptr_array_ref (udev_subsystems);
797}
798
Mario Limonciello1a680f32019-11-25 19:44:53 -0600799/**
800 * fu_plugin_set_quirks:
801 * @self: A #FuPlugin
802 * @quirks: A #FuQuirks
803 *
804 * Sets the quirks for a plugin
805 *
806 * Since: 1.0.1
807 **/
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100808void
Richard Hughes12724852018-09-04 13:53:44 +0100809fu_plugin_set_quirks (FuPlugin *self, FuQuirks *quirks)
Richard Hughes9c028f02017-10-28 21:14:28 +0100810{
Richard Hughes12724852018-09-04 13:53:44 +0100811 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9c028f02017-10-28 21:14:28 +0100812 g_set_object (&priv->quirks, quirks);
813}
814
815/**
816 * fu_plugin_get_quirks:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100817 * @self: A #FuPlugin
Richard Hughes9c028f02017-10-28 21:14:28 +0100818 *
819 * Returns the hardware database object. This can be used to discover device
820 * quirks or other device-specific settings.
821 *
822 * Returns: (transfer none): a #FuQuirks, or %NULL if not set
823 *
824 * Since: 1.0.1
825 **/
826FuQuirks *
Richard Hughes12724852018-09-04 13:53:44 +0100827fu_plugin_get_quirks (FuPlugin *self)
Richard Hughes9c028f02017-10-28 21:14:28 +0100828{
Richard Hughes12724852018-09-04 13:53:44 +0100829 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9c028f02017-10-28 21:14:28 +0100830 return priv->quirks;
831}
832
Mario Limonciello1a680f32019-11-25 19:44:53 -0600833/**
834 * fu_plugin_set_runtime_versions:
835 * @self: A #FuPlugin
836 * @runtime_versions: A #GHashTables
837 *
838 * Sets the runtime versions for a plugin
839 *
840 * Since: 1.0.7
841 **/
Richard Hughes0eb123b2018-04-19 12:00:04 +0100842void
Richard Hughes12724852018-09-04 13:53:44 +0100843fu_plugin_set_runtime_versions (FuPlugin *self, GHashTable *runtime_versions)
Richard Hughes0eb123b2018-04-19 12:00:04 +0100844{
Richard Hughes12724852018-09-04 13:53:44 +0100845 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0eb123b2018-04-19 12:00:04 +0100846 priv->runtime_versions = g_hash_table_ref (runtime_versions);
847}
848
849/**
850 * fu_plugin_add_runtime_version:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100851 * @self: A #FuPlugin
Richard Hughes0eb123b2018-04-19 12:00:04 +0100852 * @component_id: An AppStream component id, e.g. "org.gnome.Software"
853 * @version: A version string, e.g. "1.2.3"
854 *
Richard Hughesdce91202019-04-08 12:47:45 +0100855 * Sets a runtime version of a specific dependency.
Richard Hughes0eb123b2018-04-19 12:00:04 +0100856 *
857 * Since: 1.0.7
858 **/
859void
Richard Hughes12724852018-09-04 13:53:44 +0100860fu_plugin_add_runtime_version (FuPlugin *self,
Richard Hughes0eb123b2018-04-19 12:00:04 +0100861 const gchar *component_id,
862 const gchar *version)
863{
Richard Hughes12724852018-09-04 13:53:44 +0100864 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesb01b4862018-04-20 16:39:48 +0100865 if (priv->runtime_versions == NULL)
866 return;
Richard Hughes0eb123b2018-04-19 12:00:04 +0100867 g_hash_table_insert (priv->runtime_versions,
868 g_strdup (component_id),
869 g_strdup (version));
870}
871
Mario Limonciello1a680f32019-11-25 19:44:53 -0600872/**
873 * fu_plugin_set_compile_versions:
874 * @self: A #FuPlugin
875 * @compile_versions: A #GHashTables
876 *
877 * Sets the compile time versions for a plugin
878 *
879 * Since: 1.0.7
880 **/
Richard Hughes34e0dab2018-04-20 16:43:00 +0100881void
Richard Hughes12724852018-09-04 13:53:44 +0100882fu_plugin_set_compile_versions (FuPlugin *self, GHashTable *compile_versions)
Richard Hughes34e0dab2018-04-20 16:43:00 +0100883{
Richard Hughes12724852018-09-04 13:53:44 +0100884 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes34e0dab2018-04-20 16:43:00 +0100885 priv->compile_versions = g_hash_table_ref (compile_versions);
886}
887
888/**
889 * fu_plugin_add_compile_version:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100890 * @self: A #FuPlugin
Richard Hughes34e0dab2018-04-20 16:43:00 +0100891 * @component_id: An AppStream component id, e.g. "org.gnome.Software"
892 * @version: A version string, e.g. "1.2.3"
893 *
Richard Hughesdce91202019-04-08 12:47:45 +0100894 * Sets a compile-time version of a specific dependency.
Richard Hughes34e0dab2018-04-20 16:43:00 +0100895 *
896 * Since: 1.0.7
897 **/
898void
Richard Hughes12724852018-09-04 13:53:44 +0100899fu_plugin_add_compile_version (FuPlugin *self,
Richard Hughes34e0dab2018-04-20 16:43:00 +0100900 const gchar *component_id,
901 const gchar *version)
902{
Richard Hughes12724852018-09-04 13:53:44 +0100903 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes34e0dab2018-04-20 16:43:00 +0100904 if (priv->compile_versions == NULL)
905 return;
906 g_hash_table_insert (priv->compile_versions,
907 g_strdup (component_id),
908 g_strdup (version));
909}
910
Richard Hughes9c028f02017-10-28 21:14:28 +0100911/**
912 * fu_plugin_lookup_quirk_by_id:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100913 * @self: A #FuPlugin
Richard Hughes87fb9ff2018-06-28 12:55:59 +0100914 * @group: A string, e.g. "DfuFlags"
915 * @key: An ID to match the entry, e.g. "Summary"
Richard Hughes9c028f02017-10-28 21:14:28 +0100916 *
917 * Looks up an entry in the hardware database using a string value.
918 *
919 * Returns: (transfer none): values from the database, or %NULL if not found
920 *
921 * Since: 1.0.1
922 **/
923const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100924fu_plugin_lookup_quirk_by_id (FuPlugin *self, const gchar *group, const gchar *key)
Richard Hughes9c028f02017-10-28 21:14:28 +0100925{
Richard Hughes12724852018-09-04 13:53:44 +0100926 FuPluginPrivate *priv = GET_PRIVATE (self);
927 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes9c028f02017-10-28 21:14:28 +0100928
Richard Hughes9c028f02017-10-28 21:14:28 +0100929 /* exact ID */
Richard Hughes87fb9ff2018-06-28 12:55:59 +0100930 return fu_quirks_lookup_by_id (priv->quirks, group, key);
Richard Hughes9c028f02017-10-28 21:14:28 +0100931}
932
933/**
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100934 * fu_plugin_lookup_quirk_by_id_as_uint64:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100935 * @self: A #FuPlugin
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100936 * @group: A string, e.g. "DfuFlags"
937 * @key: An ID to match the entry, e.g. "Size"
938 *
939 * Looks up an entry in the hardware database using a string key, returning
940 * an integer value. Values are assumed base 10, unless prefixed with "0x"
941 * where they are parsed as base 16.
942 *
Mario Limonciello1a680f32019-11-25 19:44:53 -0600943 * Returns: guint64 id or 0 if not found
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100944 *
945 * Since: 1.1.2
946 **/
947guint64
Richard Hughes12724852018-09-04 13:53:44 +0100948fu_plugin_lookup_quirk_by_id_as_uint64 (FuPlugin *self, const gchar *group, const gchar *key)
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100949{
Richard Hughes12724852018-09-04 13:53:44 +0100950 return fu_common_strtoull (fu_plugin_lookup_quirk_by_id (self, group, key));
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100951}
952
Mario Limonciello1a680f32019-11-25 19:44:53 -0600953/**
954 * fu_plugin_set_smbios:
955 * @self: A #FuPlugin
956 * @smbios: A #FuSmbios
957 *
958 * Sets the smbios for a plugin
959 *
960 * Since: 1.0.0
961 **/
Richard Hughes1354ea92017-09-19 15:58:31 +0100962void
Richard Hughes12724852018-09-04 13:53:44 +0100963fu_plugin_set_smbios (FuPlugin *self, FuSmbios *smbios)
Richard Hughes49e5e052017-09-03 12:15:41 +0100964{
Richard Hughes12724852018-09-04 13:53:44 +0100965 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100966 g_set_object (&priv->smbios, smbios);
967}
968
Richard Hughesb8f8db22017-04-25 15:56:00 +0100969/**
Richard Hughesb0829032017-01-10 09:27:08 +0000970 * fu_plugin_set_coldplug_delay:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100971 * @self: A #FuPlugin
Richard Hughesb0829032017-01-10 09:27:08 +0000972 * @duration: A delay in milliseconds
973 *
Richard Hughes21eaeef2020-01-14 12:10:01 +0000974 * Set the minimum time that should be waited in-between the call to
Richard Hughesb0829032017-01-10 09:27:08 +0000975 * fu_plugin_coldplug_prepare() and fu_plugin_coldplug(). This is usually going
976 * to be the minimum hardware initialisation time from a datasheet.
977 *
978 * It is better to use this function rather than using a sleep() in the plugin
979 * itself as then only one delay is done in the daemon rather than waiting for
980 * each coldplug prepare in a serial way.
981 *
982 * Additionally, very long delays should be avoided as the daemon will be
983 * blocked from processing requests whilst the coldplug delay is being
984 * performed.
985 *
986 * Since: 0.8.0
987 **/
988void
Richard Hughes12724852018-09-04 13:53:44 +0100989fu_plugin_set_coldplug_delay (FuPlugin *self, guint duration)
Richard Hughesb0829032017-01-10 09:27:08 +0000990{
Richard Hughes12724852018-09-04 13:53:44 +0100991 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesb0829032017-01-10 09:27:08 +0000992 g_return_if_fail (duration > 0);
993
994 /* check sanity */
995 if (duration > FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM) {
996 g_warning ("duration of %ums is crazy, truncating to %ums",
997 duration,
998 FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM);
999 duration = FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM;
1000 }
1001
1002 /* emit */
Richard Hughes12724852018-09-04 13:53:44 +01001003 g_signal_emit (self, signals[SIGNAL_SET_COLDPLUG_DELAY], 0, duration);
Richard Hughesb0829032017-01-10 09:27:08 +00001004}
1005
Richard Hughes4b303802019-10-04 13:22:51 +01001006static gboolean
1007fu_plugin_device_attach (FuPlugin *self, FuDevice *device, GError **error)
1008{
1009 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughes4b303802019-10-04 13:22:51 +01001010 locker = fu_device_locker_new (device, error);
1011 if (locker == NULL)
1012 return FALSE;
1013 return fu_device_attach (device, error);
1014}
1015
1016static gboolean
1017fu_plugin_device_detach (FuPlugin *self, FuDevice *device, GError **error)
1018{
1019 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughes4b303802019-10-04 13:22:51 +01001020 locker = fu_device_locker_new (device, error);
1021 if (locker == NULL)
1022 return FALSE;
1023 return fu_device_detach (device, error);
1024}
1025
1026static gboolean
Richard Hughes4b303802019-10-04 13:22:51 +01001027fu_plugin_device_activate (FuPlugin *self, FuDevice *device, GError **error)
1028{
1029 g_autoptr(FuDeviceLocker) locker = NULL;
1030 locker = fu_device_locker_new (device, error);
1031 if (locker == NULL)
1032 return FALSE;
1033 return fu_device_activate (device, error);
1034}
1035
1036static gboolean
1037fu_plugin_device_write_firmware (FuPlugin *self, FuDevice *device,
1038 GBytes *fw, FwupdInstallFlags flags,
1039 GError **error)
1040{
1041 g_autoptr(FuDeviceLocker) locker = NULL;
1042 locker = fu_device_locker_new (device, error);
1043 if (locker == NULL)
1044 return FALSE;
1045 return fu_device_write_firmware (device, fw, flags, error);
1046}
1047
Richard Hughes7f677212019-10-05 16:19:40 +01001048static gboolean
1049fu_plugin_device_read_firmware (FuPlugin *self, FuDevice *device, GError **error)
1050{
1051 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughesf0eb0912019-10-10 11:37:22 +01001052 g_autoptr(FuFirmware) firmware = NULL;
Richard Hughes7f677212019-10-05 16:19:40 +01001053 g_autoptr(GBytes) fw = NULL;
1054 GChecksumType checksum_types[] = {
1055 G_CHECKSUM_SHA1,
1056 G_CHECKSUM_SHA256,
1057 0 };
1058 locker = fu_device_locker_new (device, error);
1059 if (locker == NULL)
1060 return FALSE;
1061 if (!fu_device_detach (device, error))
1062 return FALSE;
Richard Hughesf0eb0912019-10-10 11:37:22 +01001063 firmware = fu_device_read_firmware (device, error);
1064 if (firmware == NULL) {
1065 g_autoptr(GError) error_local = NULL;
1066 if (!fu_device_attach (device, &error_local))
1067 g_debug ("ignoring attach failure: %s", error_local->message);
1068 g_prefix_error (error, "failed to read firmware: ");
1069 return FALSE;
1070 }
1071 fw = fu_firmware_write (firmware, error);
Richard Hughes7f677212019-10-05 16:19:40 +01001072 if (fw == NULL) {
1073 g_autoptr(GError) error_local = NULL;
1074 if (!fu_device_attach (device, &error_local))
Richard Hughesf0eb0912019-10-10 11:37:22 +01001075 g_debug ("ignoring attach failure: %s", error_local->message);
1076 g_prefix_error (error, "failed to write firmware: ");
Richard Hughes7f677212019-10-05 16:19:40 +01001077 return FALSE;
1078 }
1079 for (guint i = 0; checksum_types[i] != 0; i++) {
1080 g_autofree gchar *hash = NULL;
1081 hash = g_compute_checksum_for_bytes (checksum_types[i], fw);
1082 fu_device_add_checksum (device, hash);
1083 }
1084 return fu_device_attach (device, error);
1085}
1086
Mario Limonciello1a680f32019-11-25 19:44:53 -06001087/**
1088 * fu_plugin_runner_startup:
1089 * @self: a #FuPlugin
1090 * @error: a #GError or NULL
1091 *
1092 * Runs the startup routine for the plugin
1093 *
1094 * Returns: #TRUE for success, #FALSE for failure
1095 *
1096 * Since: 0.8.0
1097 **/
Richard Hughesd0905142016-03-13 09:46:49 +00001098gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001099fu_plugin_runner_startup (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00001100{
Richard Hughes12724852018-09-04 13:53:44 +01001101 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001102 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001103 g_autoptr(GError) error_local = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +00001104
1105 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +00001106 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +00001107 return TRUE;
1108
Richard Hughes639da472018-01-06 22:35:04 +00001109 /* no object loaded */
1110 if (priv->module == NULL)
1111 return TRUE;
1112
Richard Hughesd0905142016-03-13 09:46:49 +00001113 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00001114 g_module_symbol (priv->module, "fu_plugin_startup", (gpointer *) &func);
1115 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +00001116 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001117 g_debug ("performing startup() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001118 if (!func (self, &error_local)) {
1119 if (error_local == NULL) {
1120 g_critical ("unset error in plugin %s for startup()",
1121 priv->name);
1122 g_set_error_literal (&error_local,
1123 FWUPD_ERROR,
1124 FWUPD_ERROR_INTERNAL,
1125 "unspecified error");
1126 }
1127 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1128 "failed to startup using %s: ",
1129 priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00001130 return FALSE;
1131 }
1132 return TRUE;
1133}
1134
1135static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001136fu_plugin_runner_device_generic (FuPlugin *self, FuDevice *device,
Richard Hughes4b303802019-10-04 13:22:51 +01001137 const gchar *symbol_name,
1138 FuPluginDeviceFunc device_func,
1139 GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001140{
Richard Hughes12724852018-09-04 13:53:44 +01001141 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001142 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001143 g_autoptr(GError) error_local = NULL;
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001144
1145 /* not enabled */
1146 if (!priv->enabled)
1147 return TRUE;
1148
Richard Hughesd3d96cc2017-11-14 11:34:33 +00001149 /* no object loaded */
1150 if (priv->module == NULL)
1151 return TRUE;
1152
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001153 /* optional */
1154 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
Richard Hughes4b303802019-10-04 13:22:51 +01001155 if (func == NULL) {
1156 if (device_func != NULL) {
1157 g_debug ("running superclassed %s() on %s",
1158 symbol_name + 10, priv->name);
1159 return device_func (self, device, error);
1160 }
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001161 return TRUE;
Richard Hughes4b303802019-10-04 13:22:51 +01001162 }
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001163 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001164 if (!func (self, device, &error_local)) {
1165 if (error_local == NULL) {
1166 g_critical ("unset error in plugin %s for %s()",
1167 priv->name, symbol_name + 10);
1168 g_set_error_literal (&error_local,
1169 FWUPD_ERROR,
1170 FWUPD_ERROR_INTERNAL,
1171 "unspecified error");
1172 }
1173 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1174 "failed to %s using %s: ",
1175 symbol_name + 10, priv->name);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001176 return FALSE;
1177 }
1178 return TRUE;
1179}
1180
Richard Hughesdbd8c762018-06-15 20:31:40 +01001181static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001182fu_plugin_runner_flagged_device_generic (FuPlugin *self, FwupdInstallFlags flags,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001183 FuDevice *device,
1184 const gchar *symbol_name, GError **error)
1185{
Richard Hughes12724852018-09-04 13:53:44 +01001186 FuPluginPrivate *priv = GET_PRIVATE (self);
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001187 FuPluginFlaggedDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001188 g_autoptr(GError) error_local = NULL;
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001189
1190 /* not enabled */
1191 if (!priv->enabled)
1192 return TRUE;
1193
1194 /* no object loaded */
1195 if (priv->module == NULL)
1196 return TRUE;
1197
1198 /* optional */
1199 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1200 if (func == NULL)
1201 return TRUE;
1202 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001203 if (!func (self, flags, device, &error_local)) {
1204 if (error_local == NULL) {
1205 g_critical ("unset error in plugin %s for %s()",
1206 priv->name, symbol_name + 10);
1207 g_set_error_literal (&error_local,
1208 FWUPD_ERROR,
1209 FWUPD_ERROR_INTERNAL,
1210 "unspecified error");
1211 }
1212 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1213 "failed to %s using %s: ",
1214 symbol_name + 10, priv->name);
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001215 return FALSE;
1216 }
1217 return TRUE;
1218
1219}
1220
1221static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001222fu_plugin_runner_device_array_generic (FuPlugin *self, GPtrArray *devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001223 const gchar *symbol_name, GError **error)
1224{
Richard Hughes12724852018-09-04 13:53:44 +01001225 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesdbd8c762018-06-15 20:31:40 +01001226 FuPluginDeviceArrayFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001227 g_autoptr(GError) error_local = NULL;
Richard Hughesdbd8c762018-06-15 20:31:40 +01001228
1229 /* not enabled */
1230 if (!priv->enabled)
1231 return TRUE;
1232
1233 /* no object loaded */
1234 if (priv->module == NULL)
1235 return TRUE;
1236
1237 /* optional */
1238 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1239 if (func == NULL)
1240 return TRUE;
1241 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001242 if (!func (self, devices, &error_local)) {
1243 if (error_local == NULL) {
1244 g_critical ("unset error in plugin %s for %s()",
1245 priv->name, symbol_name + 10);
1246 g_set_error_literal (&error_local,
1247 FWUPD_ERROR,
1248 FWUPD_ERROR_INTERNAL,
1249 "unspecified error");
1250 }
1251 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1252 "failed to %s using %s: ",
1253 symbol_name + 10, priv->name);
Richard Hughesdbd8c762018-06-15 20:31:40 +01001254 return FALSE;
1255 }
1256 return TRUE;
1257}
1258
Mario Limonciello1a680f32019-11-25 19:44:53 -06001259/**
1260 * fu_plugin_runner_coldplug:
1261 * @self: a #FuPlugin
1262 * @error: a #GError or NULL
1263 *
1264 * Runs the coldplug routine for the plugin
1265 *
1266 * Returns: #TRUE for success, #FALSE for failure
1267 *
1268 * Since: 0.8.0
1269 **/
Richard Hughesd0905142016-03-13 09:46:49 +00001270gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001271fu_plugin_runner_coldplug (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00001272{
Richard Hughes12724852018-09-04 13:53:44 +01001273 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001274 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001275 g_autoptr(GError) error_local = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +00001276
1277 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +00001278 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +00001279 return TRUE;
1280
Richard Hughes639da472018-01-06 22:35:04 +00001281 /* no object loaded */
1282 if (priv->module == NULL)
1283 return TRUE;
1284
Richard Hughesd0905142016-03-13 09:46:49 +00001285 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00001286 g_module_symbol (priv->module, "fu_plugin_coldplug", (gpointer *) &func);
1287 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +00001288 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001289 g_debug ("performing coldplug() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001290 if (!func (self, &error_local)) {
1291 if (error_local == NULL) {
1292 g_critical ("unset error in plugin %s for coldplug()",
1293 priv->name);
1294 g_set_error_literal (&error_local,
1295 FWUPD_ERROR,
1296 FWUPD_ERROR_INTERNAL,
1297 "unspecified error");
1298 }
1299 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1300 "failed to coldplug using %s: ", priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00001301 return FALSE;
1302 }
1303 return TRUE;
1304}
1305
Mario Limonciello1a680f32019-11-25 19:44:53 -06001306/**
1307 * fu_plugin_runner_recoldplug:
1308 * @self: a #FuPlugin
1309 * @error: a #GError or NULL
1310 *
1311 * Runs the recoldplug routine for the plugin
1312 *
1313 * Returns: #TRUE for success, #FALSE for failure
1314 *
1315 * Since: 1.0.4
1316 **/
Richard Hughes7b8b2022016-12-12 16:15:03 +00001317gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001318fu_plugin_runner_recoldplug (FuPlugin *self, GError **error)
Richard Hughes2de8f132018-01-17 09:12:02 +00001319{
Richard Hughes12724852018-09-04 13:53:44 +01001320 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes2de8f132018-01-17 09:12:02 +00001321 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001322 g_autoptr(GError) error_local = NULL;
Richard Hughes2de8f132018-01-17 09:12:02 +00001323
1324 /* not enabled */
1325 if (!priv->enabled)
1326 return TRUE;
1327
1328 /* no object loaded */
1329 if (priv->module == NULL)
1330 return TRUE;
1331
1332 /* optional */
1333 g_module_symbol (priv->module, "fu_plugin_recoldplug", (gpointer *) &func);
1334 if (func == NULL)
1335 return TRUE;
1336 g_debug ("performing recoldplug() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001337 if (!func (self, &error_local)) {
1338 if (error_local == NULL) {
1339 g_critical ("unset error in plugin %s for recoldplug()",
1340 priv->name);
1341 g_set_error_literal (&error_local,
1342 FWUPD_ERROR,
1343 FWUPD_ERROR_INTERNAL,
1344 "unspecified error");
1345 }
1346 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1347 "failed to recoldplug using %s: ",
1348 priv->name);
Richard Hughes2de8f132018-01-17 09:12:02 +00001349 return FALSE;
1350 }
1351 return TRUE;
1352}
1353
Mario Limonciello1a680f32019-11-25 19:44:53 -06001354/**
1355 * fu_plugin_runner_coldplug_prepare:
1356 * @self: a #FuPlugin
1357 * @error: a #GError or NULL
1358 *
1359 * Runs the coldplug_prepare routine for the plugin
1360 *
1361 * Returns: #TRUE for success, #FALSE for failure
1362 *
1363 * Since: 0.8.0
1364 **/
Richard Hughes2de8f132018-01-17 09:12:02 +00001365gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001366fu_plugin_runner_coldplug_prepare (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001367{
Richard Hughes12724852018-09-04 13:53:44 +01001368 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001369 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001370 g_autoptr(GError) error_local = NULL;
Richard Hughes46487c92017-01-07 21:26:34 +00001371
1372 /* not enabled */
1373 if (!priv->enabled)
1374 return TRUE;
1375
Richard Hughes639da472018-01-06 22:35:04 +00001376 /* no object loaded */
1377 if (priv->module == NULL)
1378 return TRUE;
1379
Richard Hughes46487c92017-01-07 21:26:34 +00001380 /* optional */
1381 g_module_symbol (priv->module, "fu_plugin_coldplug_prepare", (gpointer *) &func);
1382 if (func == NULL)
1383 return TRUE;
1384 g_debug ("performing coldplug_prepare() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001385 if (!func (self, &error_local)) {
1386 if (error_local == NULL) {
1387 g_critical ("unset error in plugin %s for coldplug_prepare()",
1388 priv->name);
1389 g_set_error_literal (&error_local,
1390 FWUPD_ERROR,
1391 FWUPD_ERROR_INTERNAL,
1392 "unspecified error");
1393 }
1394 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1395 "failed to coldplug_prepare using %s: ",
1396 priv->name);
Richard Hughes46487c92017-01-07 21:26:34 +00001397 return FALSE;
1398 }
1399 return TRUE;
1400}
1401
Mario Limonciello1a680f32019-11-25 19:44:53 -06001402/**
1403 * fu_plugin_runner_coldplug_cleanup:
1404 * @self: a #FuPlugin
1405 * @error: a #GError or NULL
1406 *
1407 * Runs the coldplug_cleanup routine for the plugin
1408 *
1409 * Returns: #TRUE for success, #FALSE for failure
1410 *
1411 * Since: 0.8.0
1412 **/
Richard Hughes46487c92017-01-07 21:26:34 +00001413gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001414fu_plugin_runner_coldplug_cleanup (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001415{
Richard Hughes12724852018-09-04 13:53:44 +01001416 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001417 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001418 g_autoptr(GError) error_local = NULL;
Richard Hughes46487c92017-01-07 21:26:34 +00001419
1420 /* not enabled */
1421 if (!priv->enabled)
1422 return TRUE;
1423
Richard Hughes639da472018-01-06 22:35:04 +00001424 /* no object loaded */
1425 if (priv->module == NULL)
1426 return TRUE;
1427
Richard Hughes46487c92017-01-07 21:26:34 +00001428 /* optional */
1429 g_module_symbol (priv->module, "fu_plugin_coldplug_cleanup", (gpointer *) &func);
1430 if (func == NULL)
1431 return TRUE;
1432 g_debug ("performing coldplug_cleanup() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001433 if (!func (self, &error_local)) {
1434 if (error_local == NULL) {
1435 g_critical ("unset error in plugin %s for coldplug_cleanup()",
1436 priv->name);
1437 g_set_error_literal (&error_local,
1438 FWUPD_ERROR,
1439 FWUPD_ERROR_INTERNAL,
1440 "unspecified error");
1441 }
1442 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1443 "failed to coldplug_cleanup using %s: ",
1444 priv->name);
Richard Hughes46487c92017-01-07 21:26:34 +00001445 return FALSE;
1446 }
1447 return TRUE;
1448}
1449
Mario Limonciello1a680f32019-11-25 19:44:53 -06001450/**
1451 * fu_plugin_runner_composite_prepare:
1452 * @self: a #FuPlugin
Richard Hughesa0d81c72019-11-27 11:41:54 +00001453 * @devices: (element-type FuDevice): a #GPtrArray of devices
Mario Limonciello1a680f32019-11-25 19:44:53 -06001454 * @error: a #GError or NULL
1455 *
1456 * Runs the composite_prepare routine for the plugin
1457 *
1458 * Returns: #TRUE for success, #FALSE for failure
1459 *
1460 * Since: 1.0.9
1461 **/
Richard Hughes46487c92017-01-07 21:26:34 +00001462gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001463fu_plugin_runner_composite_prepare (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001464{
Richard Hughes12724852018-09-04 13:53:44 +01001465 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001466 "fu_plugin_composite_prepare",
1467 error);
1468}
1469
Mario Limonciello1a680f32019-11-25 19:44:53 -06001470/**
1471 * fu_plugin_runner_composite_cleanup:
1472 * @self: a #FuPlugin
Richard Hughesa0d81c72019-11-27 11:41:54 +00001473 * @devices: (element-type FuDevice): a #GPtrArray of devices
Mario Limonciello1a680f32019-11-25 19:44:53 -06001474 * @error: a #GError or NULL
1475 *
1476 * Runs the composite_cleanup routine for the plugin
1477 *
1478 * Returns: #TRUE for success, #FALSE for failure
1479 *
1480 * Since: 1.0.9
1481 **/
Richard Hughesdbd8c762018-06-15 20:31:40 +01001482gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001483fu_plugin_runner_composite_cleanup (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001484{
Richard Hughes12724852018-09-04 13:53:44 +01001485 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001486 "fu_plugin_composite_cleanup",
1487 error);
1488}
1489
Mario Limonciello1a680f32019-11-25 19:44:53 -06001490/**
1491 * fu_plugin_runner_update_prepare:
1492 * @self: a #FuPlugin
1493 * @error: a #GError or NULL
1494 *
1495 * Runs the update_prepare routine for the plugin
1496 *
1497 * Returns: #TRUE for success, #FALSE for failure
1498 *
1499 * Since: 1.1.2
1500 **/
Richard Hughesdbd8c762018-06-15 20:31:40 +01001501gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001502fu_plugin_runner_update_prepare (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001503 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001504{
Richard Hughes12724852018-09-04 13:53:44 +01001505 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001506 "fu_plugin_update_prepare",
1507 error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001508}
1509
Mario Limonciello1a680f32019-11-25 19:44:53 -06001510/**
1511 * fu_plugin_runner_update_cleanup:
1512 * @self: a #FuPlugin
1513 * @error: a #GError or NULL
1514 *
1515 * Runs the update_cleanup routine for the plugin
1516 *
1517 * Returns: #TRUE for success, #FALSE for failure
1518 *
1519 * Since: 1.1.2
1520 **/
Richard Hughes7b8b2022016-12-12 16:15:03 +00001521gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001522fu_plugin_runner_update_cleanup (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001523 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001524{
Richard Hughes12724852018-09-04 13:53:44 +01001525 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001526 "fu_plugin_update_cleanup",
1527 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001528}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001529
Mario Limonciello1a680f32019-11-25 19:44:53 -06001530/**
1531 * fu_plugin_runner_update_attach:
1532 * @self: a #FuPlugin
1533 * @device: a #FuDevice
1534 * @error: a #GError or NULL
1535 *
1536 * Runs the update_attach routine for the plugin
1537 *
1538 * Returns: #TRUE for success, #FALSE for failure
1539 *
1540 * Since: 1.1.2
1541 **/
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001542gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001543fu_plugin_runner_update_attach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001544{
Richard Hughes12724852018-09-04 13:53:44 +01001545 return fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001546 "fu_plugin_update_attach",
1547 fu_plugin_device_attach,
1548 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001549}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001550
Mario Limonciello1a680f32019-11-25 19:44:53 -06001551/**
1552 * fu_plugin_runner_update_detach:
1553 * @self: a #FuPlugin
1554 * @device: A #FuDevice
1555 * @error: a #GError or NULL
1556 *
1557 * Runs the update_detach routine for the plugin
1558 *
1559 * Returns: #TRUE for success, #FALSE for failure
1560 *
1561 * Since: 1.1.2
1562 **/
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001563gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001564fu_plugin_runner_update_detach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001565{
Richard Hughes12724852018-09-04 13:53:44 +01001566 return fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001567 "fu_plugin_update_detach",
1568 fu_plugin_device_detach,
1569 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001570}
1571
Mario Limonciello1a680f32019-11-25 19:44:53 -06001572/**
1573 * fu_plugin_runner_update_reload:
1574 * @self: a #FuPlugin
1575 * @error: a #GError or NULL
1576 *
1577 * Runs reload routine for a device
1578 *
1579 * Returns: #TRUE for success, #FALSE for failure
1580 *
1581 * Since: 1.1.2
1582 **/
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001583gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001584fu_plugin_runner_update_reload (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001585{
Richard Hughes42f33df2019-10-05 20:52:33 +01001586 FuPluginPrivate *priv = GET_PRIVATE (self);
1587 g_autoptr(FuDeviceLocker) locker = NULL;
1588
1589 /* not enabled */
1590 if (!priv->enabled)
1591 return TRUE;
1592
1593 /* no object loaded */
1594 locker = fu_device_locker_new (device, error);
1595 if (locker == NULL)
1596 return FALSE;
1597 return fu_device_reload (device, error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001598}
1599
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001600/**
Richard Hughes196c6c62020-05-11 19:42:47 +01001601 * fu_plugin_runner_add_security_attrs:
1602 * @self: a #FuPlugin
1603 * @attrs: (element-type FwupdSecurityAttr): a #GPtrArray of attributes
Richard Hughes196c6c62020-05-11 19:42:47 +01001604 *
Richard Hughesf58ac732020-05-12 15:23:44 +01001605 * Runs the add_security_attrs routine for the plugin
Richard Hughes196c6c62020-05-11 19:42:47 +01001606 *
1607 * Since: 1.5.0
1608 **/
Richard Hughesf58ac732020-05-12 15:23:44 +01001609void
1610fu_plugin_runner_add_security_attrs (FuPlugin *self, FuSecurityAttrs *attrs)
Richard Hughes196c6c62020-05-11 19:42:47 +01001611{
Richard Hughesf58ac732020-05-12 15:23:44 +01001612 FuPluginPrivate *priv = GET_PRIVATE (self);
1613 FuPluginSecurityAttrsFunc func = NULL;
1614 const gchar *symbol_name = "fu_plugin_add_security_attrs";
1615
1616 /* no object loaded */
1617 if (priv->module == NULL)
1618 return;
1619
1620 /* optional, but gets called even for disabled plugins */
1621 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1622 if (func == NULL)
1623 return;
1624 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
1625 func (self, attrs);
Richard Hughes196c6c62020-05-11 19:42:47 +01001626}
1627
1628/**
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001629 * fu_plugin_add_udev_subsystem:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001630 * @self: a #FuPlugin
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001631 * @subsystem: a subsystem name, e.g. `pciport`
1632 *
1633 * Registers the udev subsystem to be watched by the daemon.
1634 *
1635 * Plugins can use this method only in fu_plugin_init()
Mario Limonciello1a680f32019-11-25 19:44:53 -06001636 *
1637 * Since: 1.1.2
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001638 **/
1639void
Richard Hughes12724852018-09-04 13:53:44 +01001640fu_plugin_add_udev_subsystem (FuPlugin *self, const gchar *subsystem)
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001641{
Richard Hughes12724852018-09-04 13:53:44 +01001642 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001643 for (guint i = 0; i < priv->udev_subsystems->len; i++) {
1644 const gchar *subsystem_tmp = g_ptr_array_index (priv->udev_subsystems, i);
1645 if (g_strcmp0 (subsystem_tmp, subsystem) == 0)
1646 return;
1647 }
1648 g_debug ("added udev subsystem watch of %s", subsystem);
1649 g_ptr_array_add (priv->udev_subsystems, g_strdup (subsystem));
1650}
1651
Richard Hughes989acf12019-10-05 20:16:47 +01001652/**
1653 * fu_plugin_set_device_gtype:
1654 * @self: a #FuPlugin
1655 * @device_gtype: a #GType `FU_TYPE_DEVICE`
1656 *
1657 * Sets the device #GType which is used when creating devices.
1658 *
1659 * If this method is used then fu_plugin_usb_device_added() is not called, and
1660 * instead the object is created in the daemon for the plugin.
1661 *
1662 * Plugins can use this method only in fu_plugin_init()
1663 *
1664 * Since: 1.3.3
1665 **/
1666void
1667fu_plugin_set_device_gtype (FuPlugin *self, GType device_gtype)
1668{
1669 FuPluginPrivate *priv = GET_PRIVATE (self);
1670 priv->device_gtype = device_gtype;
1671}
1672
Mario Limonciello1a680f32019-11-25 19:44:53 -06001673/**
1674 * fu_plugin_add_firmware_gtype:
1675 * @self: a #FuPlugin
1676 * @id: A string describing the type
1677 * @gtype: a #GType `FU_TYPE_DEVICE`
1678 *
1679 * Adds a firmware #GType which is used when creating devices.
1680 * *
1681 * Plugins can use this method only in fu_plugin_init()
1682 *
1683 * Since: 1.3.3
1684 **/
Richard Hughes95c98a92019-10-22 16:03:15 +01001685void
1686fu_plugin_add_firmware_gtype (FuPlugin *self, const gchar *id, GType gtype)
1687{
1688 g_signal_emit (self, signals[SIGNAL_ADD_FIRMWARE_GTYPE], 0, id, gtype);
1689}
1690
Richard Hughes989acf12019-10-05 20:16:47 +01001691static gboolean
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001692fu_plugin_check_supported_device (FuPlugin *self, FuDevice *device)
1693{
1694 GPtrArray *instance_ids = fu_device_get_instance_ids (device);
1695 for (guint i = 0; i < instance_ids->len; i++) {
1696 const gchar *instance_id = g_ptr_array_index (instance_ids, i);
1697 g_autofree gchar *guid = fwupd_guid_hash_string (instance_id);
1698 if (fu_plugin_check_supported (self, guid))
1699 return TRUE;
1700 }
1701 return FALSE;
1702}
1703
1704static gboolean
Richard Hughes989acf12019-10-05 20:16:47 +01001705fu_plugin_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error)
1706{
1707 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001708 GType device_gtype = fu_device_get_specialized_gtype (FU_DEVICE (device));
Richard Hughes989acf12019-10-05 20:16:47 +01001709 g_autoptr(FuDevice) dev = NULL;
1710 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001711
1712 /* fall back to plugin default */
1713 if (device_gtype == G_TYPE_INVALID)
1714 device_gtype = priv->device_gtype;
1715
1716 /* create new device and incorporate existing properties */
1717 dev = g_object_new (device_gtype, NULL);
1718 fu_device_incorporate (dev, FU_DEVICE (device));
Richard Hughes0f66a022020-02-19 18:54:38 +00001719 if (!fu_plugin_runner_device_created (self, dev, error))
1720 return FALSE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001721
1722 /* there are a lot of different devices that match, but not all respond
1723 * well to opening -- so limit some ones with issued updates */
1724 if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_ONLY_SUPPORTED)) {
1725 if (!fu_device_probe (dev, error))
1726 return FALSE;
1727 fu_device_convert_instance_ids (dev);
1728 if (!fu_plugin_check_supported_device (self, dev)) {
1729 g_autofree gchar *guids = fu_device_get_guids_as_str (dev);
1730 g_debug ("%s has no updates, so ignoring device", guids);
1731 return TRUE;
1732 }
1733 }
1734
1735 /* open and add */
1736 locker = fu_device_locker_new (dev, error);
1737 if (locker == NULL)
1738 return FALSE;
1739 fu_plugin_device_add (self, dev);
Richard Hughes6a078702020-05-09 20:36:33 +01001740 fu_plugin_runner_device_added (self, dev);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001741 return TRUE;
1742}
1743
1744static gboolean
Mario Limonciello096e3cf2020-04-28 15:01:33 -05001745fu_plugin_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GError **error)
1746{
1747 g_autoptr(FuDeviceLocker) locker = NULL;
1748
1749 /* open */
1750 locker = fu_device_locker_new (FU_DEVICE (device), error);
1751 if (locker == NULL)
1752 return FALSE;
1753 return fu_device_rescan (FU_DEVICE (device), error);
1754}
1755
1756static gboolean
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001757fu_plugin_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error)
1758{
1759 FuPluginPrivate *priv = GET_PRIVATE (self);
1760 GType device_gtype = fu_device_get_specialized_gtype (FU_DEVICE (device));
1761 g_autoptr(FuDevice) dev = NULL;
1762 g_autoptr(FuDeviceLocker) locker = NULL;
1763
1764 /* fall back to plugin default */
1765 if (device_gtype == G_TYPE_INVALID)
1766 device_gtype = priv->device_gtype;
1767
1768 /* create new device and incorporate existing properties */
1769 dev = g_object_new (device_gtype, NULL);
Richard Hughes989acf12019-10-05 20:16:47 +01001770 fu_device_incorporate (FU_DEVICE (dev), FU_DEVICE (device));
Richard Hughes0f66a022020-02-19 18:54:38 +00001771 if (!fu_plugin_runner_device_created (self, dev, error))
1772 return FALSE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001773
1774 /* there are a lot of different devices that match, but not all respond
1775 * well to opening -- so limit some ones with issued updates */
1776 if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_ONLY_SUPPORTED)) {
1777 if (!fu_device_probe (dev, error))
1778 return FALSE;
1779 fu_device_convert_instance_ids (dev);
1780 if (!fu_plugin_check_supported_device (self, dev)) {
1781 g_autofree gchar *guids = fu_device_get_guids_as_str (dev);
1782 g_debug ("%s has no updates, so ignoring device", guids);
1783 return TRUE;
1784 }
1785 }
1786
1787 /* open and add */
Richard Hughes989acf12019-10-05 20:16:47 +01001788 locker = fu_device_locker_new (dev, error);
1789 if (locker == NULL)
1790 return FALSE;
1791 fu_plugin_device_add (self, FU_DEVICE (dev));
Richard Hughes6a078702020-05-09 20:36:33 +01001792 fu_plugin_runner_device_added (self, dev);
Richard Hughes989acf12019-10-05 20:16:47 +01001793 return TRUE;
1794}
1795
Mario Limonciello1a680f32019-11-25 19:44:53 -06001796/**
1797 * fu_plugin_runner_usb_device_added:
1798 * @self: a #FuPlugin
1799 * @device: a #FuUsbDevice
1800 * @error: a #GError or NULL
1801 *
1802 * Call the usb_device_added routine for the plugin
1803 *
1804 * Returns: #TRUE for success, #FALSE for failure
1805 *
1806 * Since: 1.0.2
1807 **/
Richard Hughes104f6512017-11-24 11:44:57 +00001808gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001809fu_plugin_runner_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error)
Richard Hughes104f6512017-11-24 11:44:57 +00001810{
Richard Hughes12724852018-09-04 13:53:44 +01001811 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes104f6512017-11-24 11:44:57 +00001812 FuPluginUsbDeviceAddedFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001813 g_autoptr(GError) error_local = NULL;
Richard Hughes104f6512017-11-24 11:44:57 +00001814
1815 /* not enabled */
1816 if (!priv->enabled)
1817 return TRUE;
Richard Hughes639da472018-01-06 22:35:04 +00001818
1819 /* no object loaded */
Richard Hughes104f6512017-11-24 11:44:57 +00001820 if (priv->module == NULL)
1821 return TRUE;
1822
1823 /* optional */
1824 g_module_symbol (priv->module, "fu_plugin_usb_device_added", (gpointer *) &func);
Richard Hughes989acf12019-10-05 20:16:47 +01001825 if (func == NULL) {
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001826 if (priv->device_gtype != G_TYPE_INVALID ||
1827 fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) {
Mario Limonciello0e500322019-10-17 18:41:04 -05001828 if (!fu_plugin_usb_device_added (self, device, error))
Mario Limoncielloa9be5362019-10-12 13:17:45 -05001829 return FALSE;
Richard Hughes989acf12019-10-05 20:16:47 +01001830 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001831 return TRUE;
Richard Hughes989acf12019-10-05 20:16:47 +01001832 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001833 g_debug ("performing usb_device_added() on %s", priv->name);
1834 if (!func (self, device, &error_local)) {
1835 if (error_local == NULL) {
1836 g_critical ("unset error in plugin %s for usb_device_added()",
1837 priv->name);
1838 g_set_error_literal (&error_local,
1839 FWUPD_ERROR,
1840 FWUPD_ERROR_INTERNAL,
1841 "unspecified error");
1842 }
1843 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1844 "failed to add device using on %s: ",
1845 priv->name);
1846 return FALSE;
Richard Hughes104f6512017-11-24 11:44:57 +00001847 }
1848 return TRUE;
1849}
1850
Mario Limonciello1a680f32019-11-25 19:44:53 -06001851/**
1852 * fu_plugin_runner_udev_device_added:
1853 * @self: a #FuPlugin
1854 * @device: a #FuUdevDevice
1855 * @error: a #GError or NULL
1856 *
1857 * Call the udev_device_added routine for the plugin
1858 *
1859 * Returns: #TRUE for success, #FALSE for failure
1860 *
1861 * Since: 1.0.2
1862 **/
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001863gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001864fu_plugin_runner_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error)
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001865{
Richard Hughes12724852018-09-04 13:53:44 +01001866 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001867 FuPluginUdevDeviceAddedFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001868 g_autoptr(GError) error_local = NULL;
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001869
1870 /* not enabled */
1871 if (!priv->enabled)
1872 return TRUE;
1873
1874 /* no object loaded */
1875 if (priv->module == NULL)
1876 return TRUE;
1877
1878 /* optional */
1879 g_module_symbol (priv->module, "fu_plugin_udev_device_added", (gpointer *) &func);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001880 if (func == NULL) {
1881 if (priv->device_gtype != G_TYPE_INVALID ||
1882 fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) {
Mario Limonciello0e500322019-10-17 18:41:04 -05001883 if (!fu_plugin_udev_device_added (self, device, error))
Mario Limoncielloa9be5362019-10-12 13:17:45 -05001884 return FALSE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001885 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001886 return TRUE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001887 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001888 g_debug ("performing udev_device_added() on %s", priv->name);
1889 if (!func (self, device, &error_local)) {
1890 if (error_local == NULL) {
1891 g_critical ("unset error in plugin %s for udev_device_added()",
1892 priv->name);
1893 g_set_error_literal (&error_local,
1894 FWUPD_ERROR,
1895 FWUPD_ERROR_INTERNAL,
1896 "unspecified error");
1897 }
1898 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1899 "failed to add device using on %s: ",
1900 priv->name);
1901 return FALSE;
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001902 }
1903 return TRUE;
1904}
1905
Mario Limonciello1a680f32019-11-25 19:44:53 -06001906/**
1907 * fu_plugin_runner_udev_device_changed:
1908 * @self: a #FuPlugin
1909 * @device: a #FuUdevDevice
1910 * @error: a #GError or NULL
1911 *
1912 * Call the udev_device_changed routine for the plugin
1913 *
1914 * Returns: #TRUE for success, #FALSE for failure
1915 *
1916 * Since: 1.0.2
1917 **/
Richard Hughes5e952ce2019-08-26 11:09:46 +01001918gboolean
1919fu_plugin_runner_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GError **error)
1920{
1921 FuPluginPrivate *priv = GET_PRIVATE (self);
1922 FuPluginUdevDeviceAddedFunc func = NULL;
1923 g_autoptr(GError) error_local = NULL;
1924
1925 /* not enabled */
1926 if (!priv->enabled)
1927 return TRUE;
1928
1929 /* no object loaded */
1930 if (priv->module == NULL)
1931 return TRUE;
1932
1933 /* optional */
1934 g_module_symbol (priv->module, "fu_plugin_udev_device_changed", (gpointer *) &func);
Mario Limonciello096e3cf2020-04-28 15:01:33 -05001935 if (func == NULL) {
1936 if (priv->device_gtype != G_TYPE_INVALID ||
1937 fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) {
1938 if (!fu_plugin_udev_device_changed (self, device, error))
1939 return FALSE;
1940 }
Richard Hughes5e952ce2019-08-26 11:09:46 +01001941 return TRUE;
Mario Limonciello096e3cf2020-04-28 15:01:33 -05001942 }
Richard Hughes5e952ce2019-08-26 11:09:46 +01001943 g_debug ("performing udev_device_changed() on %s", priv->name);
1944 if (!func (self, device, &error_local)) {
1945 if (error_local == NULL) {
1946 g_critical ("unset error in plugin %s for udev_device_changed()",
1947 priv->name);
1948 g_set_error_literal (&error_local,
1949 FWUPD_ERROR,
1950 FWUPD_ERROR_INTERNAL,
1951 "unspecified error");
1952 }
1953 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1954 "failed to change device on %s: ",
1955 priv->name);
1956 return FALSE;
1957 }
1958 return TRUE;
1959}
1960
Mario Limonciello1a680f32019-11-25 19:44:53 -06001961/**
Richard Hughes6a078702020-05-09 20:36:33 +01001962 * fu_plugin_runner_device_added:
1963 * @self: a #FuPlugin
1964 * @device: a #FuDevice
1965 *
1966 * Call the device_added routine for the plugin
1967 *
1968 * Since: 1.5.0
1969 **/
1970void
1971fu_plugin_runner_device_added (FuPlugin *self, FuDevice *device)
1972{
1973 FuPluginPrivate *priv = GET_PRIVATE (self);
1974 FuPluginDeviceRegisterFunc func = NULL;
1975
1976 /* not enabled */
1977 if (!priv->enabled)
1978 return;
1979 if (priv->module == NULL)
1980 return;
1981
1982 /* optional */
1983 g_module_symbol (priv->module, "fu_plugin_device_added", (gpointer *) &func);
1984 if (func == NULL)
1985 return;
1986 g_debug ("performing fu_plugin_device_added() on %s", priv->name);
1987 func (self, device);
1988}
1989
1990/**
Mario Limonciello1a680f32019-11-25 19:44:53 -06001991 * fu_plugin_runner_device_removed:
1992 * @self: a #FuPlugin
1993 * @device: a #FuDevice
1994 *
1995 * Call the device_removed routine for the plugin
1996 *
1997 * Since: 1.1.2
1998 **/
Richard Hughese1fd34d2017-08-24 14:19:51 +01001999void
Richard Hughes12724852018-09-04 13:53:44 +01002000fu_plugin_runner_device_removed (FuPlugin *self, FuDevice *device)
Mario Limoncielloe260ead2018-09-01 09:19:24 -05002001{
2002 g_autoptr(GError) error_local= NULL;
2003
Richard Hughes12724852018-09-04 13:53:44 +01002004 if (!fu_plugin_runner_device_generic (self, device,
Mario Limoncielloe260ead2018-09-01 09:19:24 -05002005 "fu_plugin_device_removed",
Richard Hughes4b303802019-10-04 13:22:51 +01002006 NULL,
Mario Limoncielloe260ead2018-09-01 09:19:24 -05002007 &error_local))
2008 g_warning ("%s", error_local->message);
2009}
2010
Mario Limonciello1a680f32019-11-25 19:44:53 -06002011/**
2012 * fu_plugin_runner_device_register:
2013 * @self: a #FuPlugin
2014 * @device: a #FuDevice
2015 *
2016 * Call the device_registered routine for the plugin
2017 *
2018 * Since: 0.9.7
2019 **/
Mario Limoncielloe260ead2018-09-01 09:19:24 -05002020void
Richard Hughes12724852018-09-04 13:53:44 +01002021fu_plugin_runner_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +01002022{
Richard Hughes12724852018-09-04 13:53:44 +01002023 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughese1fd34d2017-08-24 14:19:51 +01002024 FuPluginDeviceRegisterFunc func = NULL;
2025
2026 /* not enabled */
2027 if (!priv->enabled)
2028 return;
Richard Hughes34834102017-11-21 21:55:00 +00002029 if (priv->module == NULL)
2030 return;
Richard Hughese1fd34d2017-08-24 14:19:51 +01002031
Mario Limonciello4910b242018-06-22 15:04:21 -05002032 /* don't notify plugins on their own devices */
Richard Hughes12724852018-09-04 13:53:44 +01002033 if (g_strcmp0 (fu_device_get_plugin (device), fu_plugin_get_name (self)) == 0)
Mario Limonciello4910b242018-06-22 15:04:21 -05002034 return;
2035
Richard Hughese1fd34d2017-08-24 14:19:51 +01002036 /* optional */
2037 g_module_symbol (priv->module, "fu_plugin_device_registered", (gpointer *) &func);
2038 if (func != NULL) {
Richard Hughes1bf7ff92018-08-24 20:21:35 +01002039 g_debug ("performing fu_plugin_device_registered() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01002040 func (self, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +01002041 }
2042}
2043
Mario Limonciello1a680f32019-11-25 19:44:53 -06002044/**
Richard Hughes0f66a022020-02-19 18:54:38 +00002045 * fu_plugin_runner_device_created:
2046 * @self: a #FuPlugin
2047 * @device: a #FuDevice
2048 * @error: a #GError or NULL
2049 *
2050 * Call the device_created routine for the plugin
2051 *
2052 * Returns: #TRUE for success, #FALSE for failure
2053 *
Mario Limonciello96117d12020-02-28 10:17:56 -06002054 * Since: 1.4.0
Richard Hughes0f66a022020-02-19 18:54:38 +00002055 **/
2056gboolean
2057fu_plugin_runner_device_created (FuPlugin *self, FuDevice *device, GError **error)
2058{
2059 FuPluginPrivate *priv = GET_PRIVATE (self);
2060 FuPluginDeviceFunc func = NULL;
2061
2062 /* not enabled */
2063 if (!priv->enabled)
2064 return TRUE;
2065 if (priv->module == NULL)
2066 return TRUE;
2067
2068 /* optional */
2069 g_module_symbol (priv->module, "fu_plugin_device_created", (gpointer *) &func);
2070 if (func == NULL)
2071 return TRUE;
2072 g_debug ("performing fu_plugin_device_created() on %s", priv->name);
2073 return func (self, device, error);
2074}
2075
2076/**
Mario Limonciello1a680f32019-11-25 19:44:53 -06002077 * fu_plugin_runner_verify:
2078 * @self: a #FuPlugin
2079 * @device: a #FuDevice
2080 * @flags: #FuPluginVerifyFlags
2081 * @error: A #GError or NULL
2082 *
2083 * Call into the plugin's verify routine
2084 *
2085 * Returns: #TRUE for success, #FALSE for failure
2086 *
2087 * Since: 0.8.0
2088 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002089gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002090fu_plugin_runner_verify (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +00002091 FuDevice *device,
2092 FuPluginVerifyFlags flags,
2093 GError **error)
2094{
Richard Hughes12724852018-09-04 13:53:44 +01002095 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00002096 FuPluginVerifyFunc func = NULL;
Richard Hughesababbb72017-06-15 20:18:36 +01002097 GPtrArray *checksums;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002098 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002099
2100 /* not enabled */
2101 if (!priv->enabled)
2102 return TRUE;
2103
Richard Hughes639da472018-01-06 22:35:04 +00002104 /* no object loaded */
2105 if (priv->module == NULL)
2106 return TRUE;
2107
Richard Hughescff38bc2016-12-12 12:03:37 +00002108 /* optional */
2109 g_module_symbol (priv->module, "fu_plugin_verify", (gpointer *) &func);
Richard Hughes7f677212019-10-05 16:19:40 +01002110 if (func == NULL) {
Richard Hughes7f677212019-10-05 16:19:40 +01002111 return fu_plugin_device_read_firmware (self, device, error);
2112 }
Richard Hughes1812fc72018-12-14 11:37:54 +00002113
2114 /* clear any existing verification checksums */
2115 checksums = fu_device_get_checksums (device);
2116 g_ptr_array_set_size (checksums, 0);
2117
Richard Hughesc9223be2019-03-18 08:46:42 +00002118 /* run additional detach */
2119 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01002120 "fu_plugin_update_detach",
Richard Hughes4b303802019-10-04 13:22:51 +01002121 fu_plugin_device_detach,
Richard Hughesc9223be2019-03-18 08:46:42 +00002122 error))
2123 return FALSE;
2124
Richard Hughes1812fc72018-12-14 11:37:54 +00002125 /* run vfunc */
Richard Hughescff38bc2016-12-12 12:03:37 +00002126 g_debug ("performing verify() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002127 if (!func (self, device, flags, &error_local)) {
Richard Hughesc9223be2019-03-18 08:46:42 +00002128 g_autoptr(GError) error_attach = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002129 if (error_local == NULL) {
2130 g_critical ("unset error in plugin %s for verify()",
2131 priv->name);
2132 g_set_error_literal (&error_local,
2133 FWUPD_ERROR,
2134 FWUPD_ERROR_INTERNAL,
2135 "unspecified error");
2136 }
2137 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2138 "failed to verify using %s: ",
2139 priv->name);
Richard Hughesc9223be2019-03-18 08:46:42 +00002140 /* make the device "work" again, but don't prefix the error */
2141 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01002142 "fu_plugin_update_attach",
Richard Hughes4b303802019-10-04 13:22:51 +01002143 fu_plugin_device_attach,
Richard Hughesc9223be2019-03-18 08:46:42 +00002144 &error_attach)) {
2145 g_warning ("failed to attach whilst aborting verify(): %s",
2146 error_attach->message);
2147 }
Richard Hughesd0905142016-03-13 09:46:49 +00002148 return FALSE;
2149 }
Richard Hughesc9223be2019-03-18 08:46:42 +00002150
2151 /* run optional attach */
2152 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01002153 "fu_plugin_update_attach",
Richard Hughes4b303802019-10-04 13:22:51 +01002154 fu_plugin_device_attach,
Richard Hughesc9223be2019-03-18 08:46:42 +00002155 error))
2156 return FALSE;
2157
2158 /* success */
Richard Hughesd0905142016-03-13 09:46:49 +00002159 return TRUE;
2160}
2161
Mario Limonciello1a680f32019-11-25 19:44:53 -06002162/**
2163 * fu_plugin_runner_activate:
2164 * @self: a #FuPlugin
2165 * @device: a #FuDevice
2166 * @error: A #GError or NULL
2167 *
2168 * Call into the plugin's activate routine
2169 *
2170 * Returns: #TRUE for success, #FALSE for failure
2171 *
2172 * Since: 1.2.6
2173 **/
Richard Hughesd0905142016-03-13 09:46:49 +00002174gboolean
Mario Limonciello96a0dd52019-02-25 13:50:03 -06002175fu_plugin_runner_activate (FuPlugin *self, FuDevice *device, GError **error)
2176{
2177 guint64 flags;
2178
2179 /* final check */
2180 flags = fu_device_get_flags (device);
2181 if ((flags & FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION) == 0) {
2182 g_set_error (error,
2183 FWUPD_ERROR,
2184 FWUPD_ERROR_NOT_SUPPORTED,
2185 "Device %s does not need activation",
2186 fu_device_get_id (device));
2187 return FALSE;
2188 }
2189
2190 /* run vfunc */
2191 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01002192 "fu_plugin_activate",
2193 fu_plugin_device_activate,
2194 error))
Mario Limonciello96a0dd52019-02-25 13:50:03 -06002195 return FALSE;
2196
2197 /* update with correct flags */
2198 fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION);
2199 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
2200 return TRUE;
2201}
2202
Mario Limonciello1a680f32019-11-25 19:44:53 -06002203/**
2204 * fu_plugin_runner_unlock:
2205 * @self: a #FuPlugin
2206 * @device: a #FuDevice
2207 * @error: A #GError or NULL
2208 *
2209 * Call into the plugin's unlock routine
2210 *
2211 * Returns: #TRUE for success, #FALSE for failure
2212 *
2213 * Since: 0.8.0
2214 **/
Mario Limonciello96a0dd52019-02-25 13:50:03 -06002215gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002216fu_plugin_runner_unlock (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00002217{
Richard Hughescff38bc2016-12-12 12:03:37 +00002218 guint64 flags;
Richard Hughescff38bc2016-12-12 12:03:37 +00002219
2220 /* final check */
2221 flags = fu_device_get_flags (device);
2222 if ((flags & FWUPD_DEVICE_FLAG_LOCKED) == 0) {
2223 g_set_error (error,
2224 FWUPD_ERROR,
2225 FWUPD_ERROR_NOT_SUPPORTED,
2226 "Device %s is not locked",
2227 fu_device_get_id (device));
2228 return FALSE;
2229 }
2230
Richard Hughes9c4b5312017-11-14 11:34:53 +00002231 /* run vfunc */
Richard Hughes12724852018-09-04 13:53:44 +01002232 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01002233 "fu_plugin_unlock",
2234 NULL,
2235 error))
Richard Hughes9c4b5312017-11-14 11:34:53 +00002236 return FALSE;
Richard Hughescff38bc2016-12-12 12:03:37 +00002237
2238 /* update with correct flags */
2239 flags = fu_device_get_flags (device);
2240 fu_device_set_flags (device, flags &= ~FWUPD_DEVICE_FLAG_LOCKED);
2241 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
2242 return TRUE;
2243}
2244
Mario Limonciello1a680f32019-11-25 19:44:53 -06002245/**
2246 * fu_plugin_runner_update:
2247 * @self: a #FuPlugin
2248 * @device: a #FuDevice
2249 * @blob_fw: A #GBytes
2250 * @flags: A #FwupdInstallFlags
2251 * @error: A #GError or NULL
2252 *
2253 * Call into the plugin's update routine
2254 *
2255 * Returns: #TRUE for success, #FALSE for failure
2256 *
2257 * Since: 0.8.0
2258 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002259gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002260fu_plugin_runner_update (FuPlugin *self,
Richard Hughesa785a1c2017-08-25 16:00:58 +01002261 FuDevice *device,
Richard Hughesa785a1c2017-08-25 16:00:58 +01002262 GBytes *blob_fw,
2263 FwupdInstallFlags flags,
2264 GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00002265{
Richard Hughes12724852018-09-04 13:53:44 +01002266 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesa785a1c2017-08-25 16:00:58 +01002267 FuPluginUpdateFunc update_func;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002268 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002269
2270 /* not enabled */
Richard Hughes41c15482018-02-01 22:07:21 +00002271 if (!priv->enabled) {
2272 g_debug ("plugin not enabled, skipping");
Richard Hughesd0905142016-03-13 09:46:49 +00002273 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00002274 }
Richard Hughesd0905142016-03-13 09:46:49 +00002275
Richard Hughes639da472018-01-06 22:35:04 +00002276 /* no object loaded */
Richard Hughes41c15482018-02-01 22:07:21 +00002277 if (priv->module == NULL) {
2278 g_debug ("module not enabled, skipping");
Richard Hughes639da472018-01-06 22:35:04 +00002279 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00002280 }
Richard Hughes639da472018-01-06 22:35:04 +00002281
Richard Hughesd0905142016-03-13 09:46:49 +00002282 /* optional */
Richard Hughesa785a1c2017-08-25 16:00:58 +01002283 g_module_symbol (priv->module, "fu_plugin_update", (gpointer *) &update_func);
2284 if (update_func == NULL) {
Richard Hughes4b303802019-10-04 13:22:51 +01002285 g_debug ("running superclassed write_firmware() on %s", priv->name);
2286 return fu_plugin_device_write_firmware (self, device, blob_fw, flags, error);
Richard Hughesa785a1c2017-08-25 16:00:58 +01002287 }
Richard Hughesd0905142016-03-13 09:46:49 +00002288
Richard Hughescff38bc2016-12-12 12:03:37 +00002289 /* online */
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002290 if (!update_func (self, device, blob_fw, flags, &error_local)) {
2291 if (error_local == NULL) {
2292 g_critical ("unset error in plugin %s for update()",
2293 priv->name);
2294 g_set_error_literal (&error_local,
Richard Hughes3c8ada32018-10-12 10:08:58 +01002295 FWUPD_ERROR,
2296 FWUPD_ERROR_INTERNAL,
2297 "unspecified error");
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002298 return FALSE;
Richard Hughes3c8ada32018-10-12 10:08:58 +01002299 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002300 fu_device_set_update_error (device, error_local->message);
2301 g_propagate_error (error, g_steal_pointer (&error_local));
Richard Hughescff38bc2016-12-12 12:03:37 +00002302 return FALSE;
2303 }
2304
Richard Hughesf556d372017-06-15 19:49:18 +01002305 /* no longer valid */
Richard Hughesf8039642019-01-16 12:22:22 +00002306 if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT) &&
2307 !fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) {
Richard Hughes08435162018-12-12 10:34:16 +00002308 GPtrArray *checksums = fu_device_get_checksums (device);
2309 g_ptr_array_set_size (checksums, 0);
2310 }
Richard Hughesf556d372017-06-15 19:49:18 +01002311
Richard Hughes019a1bc2019-11-26 10:19:33 +00002312 /* success */
Richard Hughesd0905142016-03-13 09:46:49 +00002313 return TRUE;
2314}
Richard Hughescff38bc2016-12-12 12:03:37 +00002315
Mario Limonciello1a680f32019-11-25 19:44:53 -06002316/**
2317 * fu_plugin_runner_clear_results:
2318 * @self: a #FuPlugin
2319 * @device: a #FuDevice
2320 * @error: A #GError or NULL
2321 *
2322 * Call into the plugin's clear results routine
2323 *
2324 * Returns: #TRUE for success, #FALSE for failure
2325 *
2326 * Since: 0.8.0
2327 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002328gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002329fu_plugin_runner_clear_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00002330{
Richard Hughes12724852018-09-04 13:53:44 +01002331 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00002332 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002333 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002334
2335 /* not enabled */
2336 if (!priv->enabled)
2337 return TRUE;
2338
Richard Hughes639da472018-01-06 22:35:04 +00002339 /* no object loaded */
2340 if (priv->module == NULL)
2341 return TRUE;
2342
Richard Hughes65e44ca2018-01-30 17:26:30 +00002343 /* optional */
Richard Hughescd644902019-11-01 12:35:17 +00002344 g_module_symbol (priv->module, "fu_plugin_clear_results", (gpointer *) &func);
Richard Hughes65e44ca2018-01-30 17:26:30 +00002345 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00002346 return TRUE;
Richard Hughes65e44ca2018-01-30 17:26:30 +00002347 g_debug ("performing clear_result() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002348 if (!func (self, device, &error_local)) {
2349 if (error_local == NULL) {
2350 g_critical ("unset error in plugin %s for clear_result()",
2351 priv->name);
2352 g_set_error_literal (&error_local,
2353 FWUPD_ERROR,
2354 FWUPD_ERROR_INTERNAL,
2355 "unspecified error");
2356 }
2357 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2358 "failed to clear_result using %s: ",
2359 priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00002360 return FALSE;
2361 }
Richard Hughes65e44ca2018-01-30 17:26:30 +00002362 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00002363}
2364
Mario Limonciello1a680f32019-11-25 19:44:53 -06002365/**
2366 * fu_plugin_runner_get_results:
2367 * @self: a #FuPlugin
2368 * @device: a #FuDevice
2369 * @error: A #GError or NULL
2370 *
2371 * Call into the plugin's get results routine
2372 *
2373 * Returns: #TRUE for success, #FALSE for failure
2374 *
2375 * Since: 0.8.0
2376 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002377gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002378fu_plugin_runner_get_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00002379{
Richard Hughes12724852018-09-04 13:53:44 +01002380 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00002381 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002382 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002383
2384 /* not enabled */
2385 if (!priv->enabled)
2386 return TRUE;
2387
Richard Hughes639da472018-01-06 22:35:04 +00002388 /* no object loaded */
2389 if (priv->module == NULL)
2390 return TRUE;
2391
Richard Hughes65e44ca2018-01-30 17:26:30 +00002392 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00002393 g_module_symbol (priv->module, "fu_plugin_get_results", (gpointer *) &func);
Richard Hughes65e44ca2018-01-30 17:26:30 +00002394 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00002395 return TRUE;
Richard Hughes65e44ca2018-01-30 17:26:30 +00002396 g_debug ("performing get_results() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002397 if (!func (self, device, &error_local)) {
2398 if (error_local == NULL) {
2399 g_critical ("unset error in plugin %s for get_results()",
2400 priv->name);
2401 g_set_error_literal (&error_local,
2402 FWUPD_ERROR,
2403 FWUPD_ERROR_INTERNAL,
2404 "unspecified error");
2405 }
2406 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2407 "failed to get_results using %s: ",
2408 priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00002409 return FALSE;
2410 }
Richard Hughescff38bc2016-12-12 12:03:37 +00002411 return TRUE;
2412}
2413
Richard Hughes08a37992017-09-12 12:57:43 +01002414/**
2415 * fu_plugin_get_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002416 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002417 *
2418 * Gets the plugin order, where higher numbers are run after lower
2419 * numbers.
2420 *
2421 * Returns: the integer value
Mario Limonciello1a680f32019-11-25 19:44:53 -06002422 *
2423 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002424 **/
2425guint
Richard Hughes12724852018-09-04 13:53:44 +01002426fu_plugin_get_order (FuPlugin *self)
Richard Hughes08a37992017-09-12 12:57:43 +01002427{
Richard Hughes12724852018-09-04 13:53:44 +01002428 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002429 return priv->order;
2430}
2431
2432/**
2433 * fu_plugin_set_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002434 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002435 * @order: a integer value
2436 *
2437 * Sets the plugin order, where higher numbers are run after lower
2438 * numbers.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002439 *
2440 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002441 **/
2442void
Richard Hughes12724852018-09-04 13:53:44 +01002443fu_plugin_set_order (FuPlugin *self, guint order)
Richard Hughes08a37992017-09-12 12:57:43 +01002444{
Richard Hughes12724852018-09-04 13:53:44 +01002445 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002446 priv->order = order;
2447}
2448
2449/**
Richard Hughes81c427c2018-08-06 15:20:17 +01002450 * fu_plugin_get_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002451 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01002452 *
2453 * Gets the plugin priority, where higher numbers are better.
2454 *
2455 * Returns: the integer value
Mario Limonciello1a680f32019-11-25 19:44:53 -06002456 *
2457 * Since: 1.1.1
Richard Hughes81c427c2018-08-06 15:20:17 +01002458 **/
2459guint
Richard Hughes12724852018-09-04 13:53:44 +01002460fu_plugin_get_priority (FuPlugin *self)
Richard Hughes81c427c2018-08-06 15:20:17 +01002461{
Richard Hughes12724852018-09-04 13:53:44 +01002462 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01002463 return priv->priority;
2464}
2465
2466/**
2467 * fu_plugin_set_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002468 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01002469 * @priority: a integer value
2470 *
2471 * Sets the plugin priority, where higher numbers are better.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002472 *
2473 * Since: 1.0.0
Richard Hughes81c427c2018-08-06 15:20:17 +01002474 **/
2475void
Richard Hughes12724852018-09-04 13:53:44 +01002476fu_plugin_set_priority (FuPlugin *self, guint priority)
Richard Hughes81c427c2018-08-06 15:20:17 +01002477{
Richard Hughes12724852018-09-04 13:53:44 +01002478 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01002479 priv->priority = priority;
2480}
2481
2482/**
Richard Hughes08a37992017-09-12 12:57:43 +01002483 * fu_plugin_add_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002484 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002485 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
Richard Hughes4eada342017-10-03 21:20:32 +01002486 * @name: a plugin name, e.g. `upower`
Richard Hughes08a37992017-09-12 12:57:43 +01002487 *
2488 * If the plugin name is found, the rule will be used to sort the plugin list,
2489 * for example the plugin specified by @name will be ordered after this plugin
2490 * when %FU_PLUGIN_RULE_RUN_AFTER is used.
2491 *
2492 * NOTE: The depsolver is iterative and may not solve overly-complicated rules;
2493 * If depsolving fails then fwupd will not start.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002494 *
2495 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002496 **/
2497void
Richard Hughes12724852018-09-04 13:53:44 +01002498fu_plugin_add_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes08a37992017-09-12 12:57:43 +01002499{
Richard Hughes12724852018-09-04 13:53:44 +01002500 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002501 g_ptr_array_add (priv->rules[rule], g_strdup (name));
Richard Hughes75b965d2018-11-15 13:51:21 +00002502 g_signal_emit (self, signals[SIGNAL_RULES_CHANGED], 0);
Richard Hughes08a37992017-09-12 12:57:43 +01002503}
2504
2505/**
2506 * fu_plugin_get_rules:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002507 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002508 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
2509 *
2510 * Gets the plugin IDs that should be run after this plugin.
2511 *
2512 * Returns: (element-type utf8) (transfer none): the list of plugin names, e.g. ['appstream']
Mario Limonciello1a680f32019-11-25 19:44:53 -06002513 *
2514 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002515 **/
2516GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +01002517fu_plugin_get_rules (FuPlugin *self, FuPluginRule rule)
Richard Hughes08a37992017-09-12 12:57:43 +01002518{
Richard Hughes12724852018-09-04 13:53:44 +01002519 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughesdad35972019-12-06 11:00:25 +00002520 g_return_val_if_fail (rule < FU_PLUGIN_RULE_LAST, NULL);
Richard Hughes08a37992017-09-12 12:57:43 +01002521 return priv->rules[rule];
2522}
2523
Richard Hughes80b79bb2018-01-11 21:11:06 +00002524/**
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002525 * fu_plugin_has_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002526 * @self: a #FuPlugin
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002527 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
2528 * @name: a plugin name, e.g. `upower`
2529 *
Richard Hughes87fb9ff2018-06-28 12:55:59 +01002530 * Gets the plugin IDs that should be run after this plugin.
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002531 *
2532 * Returns: %TRUE if the name exists for the specific rule
Mario Limonciello1a680f32019-11-25 19:44:53 -06002533 *
2534 * Since: 1.0.0
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002535 **/
2536gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002537fu_plugin_has_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002538{
Richard Hughes12724852018-09-04 13:53:44 +01002539 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002540 for (guint i = 0; i < priv->rules[rule]->len; i++) {
2541 const gchar *tmp = g_ptr_array_index (priv->rules[rule], i);
2542 if (g_strcmp0 (tmp, name) == 0)
2543 return TRUE;
2544 }
2545 return FALSE;
2546}
2547
2548/**
Richard Hughes80b79bb2018-01-11 21:11:06 +00002549 * fu_plugin_add_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002550 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00002551 * @key: a string, e.g. `FwupdateVersion`
2552 * @value: a string, e.g. `10`
2553 *
2554 * Sets any additional metadata to be included in the firmware report to aid
2555 * debugging problems.
2556 *
2557 * Any data included here will be sent to the metadata server after user
2558 * confirmation.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002559 *
2560 * Since: 1.0.4
Richard Hughes80b79bb2018-01-11 21:11:06 +00002561 **/
2562void
Richard Hughes12724852018-09-04 13:53:44 +01002563fu_plugin_add_report_metadata (FuPlugin *self, const gchar *key, const gchar *value)
Richard Hughes80b79bb2018-01-11 21:11:06 +00002564{
Richard Hughes12724852018-09-04 13:53:44 +01002565 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002566 g_hash_table_insert (priv->report_metadata, g_strdup (key), g_strdup (value));
2567}
2568
2569/**
2570 * fu_plugin_get_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002571 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00002572 *
2573 * Returns the list of additional metadata to be added when filing a report.
2574 *
2575 * Returns: (transfer none): the map of report metadata
Mario Limonciello1a680f32019-11-25 19:44:53 -06002576 *
2577 * Since: 1.0.4
Richard Hughes80b79bb2018-01-11 21:11:06 +00002578 **/
2579GHashTable *
Richard Hughes12724852018-09-04 13:53:44 +01002580fu_plugin_get_report_metadata (FuPlugin *self)
Richard Hughes80b79bb2018-01-11 21:11:06 +00002581{
Richard Hughes12724852018-09-04 13:53:44 +01002582 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002583 return priv->report_metadata;
2584}
2585
Mario Limonciello963dc422018-02-27 14:26:58 -06002586/**
2587 * fu_plugin_get_config_value:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002588 * @self: a #FuPlugin
Mario Limonciello963dc422018-02-27 14:26:58 -06002589 * @key: A settings key
2590 *
2591 * Return the value of a key if it's been configured
2592 *
2593 * Since: 1.0.6
2594 **/
2595gchar *
Richard Hughes12724852018-09-04 13:53:44 +01002596fu_plugin_get_config_value (FuPlugin *self, const gchar *key)
Mario Limonciello963dc422018-02-27 14:26:58 -06002597{
Richard Hughes4be17d12018-05-30 20:36:29 +01002598 g_autofree gchar *conf_dir = NULL;
Mario Limonciello963dc422018-02-27 14:26:58 -06002599 g_autofree gchar *conf_file = NULL;
2600 g_autofree gchar *conf_path = NULL;
2601 g_autoptr(GKeyFile) keyfile = NULL;
2602 const gchar *plugin_name;
2603
Richard Hughes4be17d12018-05-30 20:36:29 +01002604 conf_dir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR_PKG);
Richard Hughes12724852018-09-04 13:53:44 +01002605 plugin_name = fu_plugin_get_name (self);
Mario Limonciello963dc422018-02-27 14:26:58 -06002606 conf_file = g_strdup_printf ("%s.conf", plugin_name);
Richard Hughes4be17d12018-05-30 20:36:29 +01002607 conf_path = g_build_filename (conf_dir, conf_file, NULL);
Mario Limonciello963dc422018-02-27 14:26:58 -06002608 if (!g_file_test (conf_path, G_FILE_TEST_IS_REGULAR))
2609 return NULL;
2610 keyfile = g_key_file_new ();
2611 if (!g_key_file_load_from_file (keyfile, conf_path,
2612 G_KEY_FILE_NONE, NULL))
2613 return NULL;
2614 return g_key_file_get_string (keyfile, plugin_name, key, NULL);
2615}
2616
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002617/**
Richard Hughes334ba792020-02-19 20:44:56 +00002618 * fu_plugin_get_config_value_boolean:
2619 * @self: a #FuPlugin
2620 * @key: A settings key
2621 *
2622 * Return the boolean value of a key if it's been configured
2623 *
2624 * Returns: %TRUE if the value is `true` (case insensitive), %FALSE otherwise
2625 *
Mario Limonciello96117d12020-02-28 10:17:56 -06002626 * Since: 1.4.0
Richard Hughes334ba792020-02-19 20:44:56 +00002627 **/
2628gboolean
2629fu_plugin_get_config_value_boolean (FuPlugin *self, const gchar *key)
2630{
2631 g_autofree gchar *tmp = fu_plugin_get_config_value (self, key);
2632 if (tmp == NULL)
2633 return FALSE;
Richard Hughes5337a432020-02-21 12:04:32 +00002634 return g_ascii_strcasecmp (tmp, "true") == 0;
Richard Hughes334ba792020-02-19 20:44:56 +00002635}
2636
2637/**
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002638 * fu_plugin_name_compare:
2639 * @plugin1: first #FuPlugin to compare.
2640 * @plugin2: second #FuPlugin to compare.
2641 *
2642 * Compares two plugins by their names.
2643 *
2644 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002645 *
2646 * Since: 1.0.8
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002647 **/
2648gint
2649fu_plugin_name_compare (FuPlugin *plugin1, FuPlugin *plugin2)
2650{
2651 FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1);
2652 FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2);
2653 return g_strcmp0 (priv1->name, priv2->name);
2654}
2655
2656/**
2657 * fu_plugin_order_compare:
2658 * @plugin1: first #FuPlugin to compare.
2659 * @plugin2: second #FuPlugin to compare.
2660 *
2661 * Compares two plugins by their depsolved order.
2662 *
2663 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002664 *
2665 * Since: 1.0.8
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002666 **/
2667gint
2668fu_plugin_order_compare (FuPlugin *plugin1, FuPlugin *plugin2)
2669{
2670 FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1);
2671 FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2);
2672 if (priv1->order < priv2->order)
2673 return -1;
2674 if (priv1->order > priv2->order)
2675 return 1;
2676 return 0;
2677}
2678
Richard Hughescff38bc2016-12-12 12:03:37 +00002679static void
2680fu_plugin_class_init (FuPluginClass *klass)
2681{
2682 GObjectClass *object_class = G_OBJECT_CLASS (klass);
2683 object_class->finalize = fu_plugin_finalize;
2684 signals[SIGNAL_DEVICE_ADDED] =
2685 g_signal_new ("device-added",
2686 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2687 G_STRUCT_OFFSET (FuPluginClass, device_added),
2688 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2689 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
2690 signals[SIGNAL_DEVICE_REMOVED] =
2691 g_signal_new ("device-removed",
2692 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2693 G_STRUCT_OFFSET (FuPluginClass, device_removed),
2694 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2695 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughese1fd34d2017-08-24 14:19:51 +01002696 signals[SIGNAL_DEVICE_REGISTER] =
2697 g_signal_new ("device-register",
2698 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2699 G_STRUCT_OFFSET (FuPluginClass, device_register),
2700 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2701 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughes362d6d72017-01-07 21:42:14 +00002702 signals[SIGNAL_RECOLDPLUG] =
2703 g_signal_new ("recoldplug",
2704 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2705 G_STRUCT_OFFSET (FuPluginClass, recoldplug),
2706 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2707 G_TYPE_NONE, 0);
Richard Hughes399859e2020-05-11 19:44:03 +01002708 signals[SIGNAL_SECURITY_CHANGED] =
2709 g_signal_new ("security-changed",
2710 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2711 G_STRUCT_OFFSET (FuPluginClass, security_changed),
2712 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2713 G_TYPE_NONE, 0);
Richard Hughesb0829032017-01-10 09:27:08 +00002714 signals[SIGNAL_SET_COLDPLUG_DELAY] =
2715 g_signal_new ("set-coldplug-delay",
2716 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2717 G_STRUCT_OFFSET (FuPluginClass, set_coldplug_delay),
2718 NULL, NULL, g_cclosure_marshal_VOID__UINT,
2719 G_TYPE_NONE, 1, G_TYPE_UINT);
Richard Hughesaabdc372018-11-14 10:11:08 +00002720 signals[SIGNAL_CHECK_SUPPORTED] =
2721 g_signal_new ("check-supported",
2722 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2723 G_STRUCT_OFFSET (FuPluginClass, check_supported),
2724 NULL, NULL, g_cclosure_marshal_generic,
2725 G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
Richard Hughes75b965d2018-11-15 13:51:21 +00002726 signals[SIGNAL_RULES_CHANGED] =
2727 g_signal_new ("rules-changed",
2728 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2729 G_STRUCT_OFFSET (FuPluginClass, rules_changed),
2730 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2731 G_TYPE_NONE, 0);
Richard Hughes95c98a92019-10-22 16:03:15 +01002732 signals[SIGNAL_ADD_FIRMWARE_GTYPE] =
2733 g_signal_new ("add-firmware-gtype",
2734 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2735 G_STRUCT_OFFSET (FuPluginClass, add_firmware_gtype),
2736 NULL, NULL, g_cclosure_marshal_generic,
2737 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_GTYPE);
Richard Hughescff38bc2016-12-12 12:03:37 +00002738}
2739
2740static void
Richard Hughes12724852018-09-04 13:53:44 +01002741fu_plugin_init (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +00002742{
Richard Hughes12724852018-09-04 13:53:44 +01002743 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002744 priv->enabled = TRUE;
Richard Hughesb1065422019-08-15 16:44:34 +01002745 priv->udev_subsystems = g_ptr_array_new_with_free_func (g_free);
Richard Hughescff38bc2016-12-12 12:03:37 +00002746 priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal,
2747 g_free, (GDestroyNotify) g_object_unref);
Richard Hughes161e9b52019-06-12 14:22:45 +01002748 g_rw_lock_init (&priv->devices_mutex);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002749 priv->report_metadata = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
Richard Hughes08a37992017-09-12 12:57:43 +01002750 for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++)
2751 priv->rules[i] = g_ptr_array_new_with_free_func (g_free);
Richard Hughescff38bc2016-12-12 12:03:37 +00002752}
2753
2754static void
2755fu_plugin_finalize (GObject *object)
2756{
Richard Hughes12724852018-09-04 13:53:44 +01002757 FuPlugin *self = FU_PLUGIN (object);
2758 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002759 FuPluginInitFunc func = NULL;
2760
2761 /* optional */
2762 if (priv->module != NULL) {
2763 g_module_symbol (priv->module, "fu_plugin_destroy", (gpointer *) &func);
2764 if (func != NULL) {
2765 g_debug ("performing destroy() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01002766 func (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002767 }
2768 }
2769
Richard Hughes08a37992017-09-12 12:57:43 +01002770 for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++)
2771 g_ptr_array_unref (priv->rules[i]);
2772
Richard Hughescff38bc2016-12-12 12:03:37 +00002773 if (priv->usb_ctx != NULL)
2774 g_object_unref (priv->usb_ctx);
Richard Hughesb8f8db22017-04-25 15:56:00 +01002775 if (priv->hwids != NULL)
Richard Hughesd7704d42017-08-08 20:29:09 +01002776 g_object_unref (priv->hwids);
Richard Hughes9c028f02017-10-28 21:14:28 +01002777 if (priv->quirks != NULL)
2778 g_object_unref (priv->quirks);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01002779 if (priv->udev_subsystems != NULL)
2780 g_ptr_array_unref (priv->udev_subsystems);
Richard Hughes49e5e052017-09-03 12:15:41 +01002781 if (priv->smbios != NULL)
2782 g_object_unref (priv->smbios);
Richard Hughes275d3b42018-04-20 16:40:37 +01002783 if (priv->runtime_versions != NULL)
2784 g_hash_table_unref (priv->runtime_versions);
Richard Hughes34e0dab2018-04-20 16:43:00 +01002785 if (priv->compile_versions != NULL)
2786 g_hash_table_unref (priv->compile_versions);
Richard Hughescff38bc2016-12-12 12:03:37 +00002787 g_hash_table_unref (priv->devices);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002788 g_hash_table_unref (priv->report_metadata);
Richard Hughes161e9b52019-06-12 14:22:45 +01002789 g_rw_lock_clear (&priv->devices_mutex);
Richard Hughes84999302019-05-02 10:18:32 +01002790 g_free (priv->build_hash);
Richard Hughescff38bc2016-12-12 12:03:37 +00002791 g_free (priv->name);
2792 g_free (priv->data);
Mario Limonciello3f9a1c12018-06-06 14:06:40 -05002793 /* Must happen as the last step to avoid prematurely
2794 * freeing memory held by the plugin */
2795#ifndef RUNNING_ON_VALGRIND
2796 if (priv->module != NULL)
2797 g_module_close (priv->module);
2798#endif
Richard Hughescff38bc2016-12-12 12:03:37 +00002799
2800 G_OBJECT_CLASS (fu_plugin_parent_class)->finalize (object);
2801}
2802
Mario Limonciello1a680f32019-11-25 19:44:53 -06002803/**
2804 * fu_plugin_new:
2805 *
2806 * Creates a new #FuPlugin
2807 *
2808 * Since: 0.8.0
2809 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002810FuPlugin *
2811fu_plugin_new (void)
2812{
Richard Hughes12724852018-09-04 13:53:44 +01002813 return FU_PLUGIN (g_object_new (FU_TYPE_PLUGIN, NULL));
Richard Hughescff38bc2016-12-12 12:03:37 +00002814}