blob: 80e57cc26a5047b6381acdc13929251fed145ba6 [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 Hughesbc3a4e12018-01-06 22:41:47 +000022#include "fu-history.h"
Richard Hughes37d09432018-09-09 10:39:45 +010023#include "fu-mutex.h"
Richard Hughesd0905142016-03-13 09:46:49 +000024
Richard Hughes4eada342017-10-03 21:20:32 +010025/**
26 * SECTION:fu-plugin
27 * @short_description: a daemon plugin
28 *
29 * An object that represents a plugin run by the daemon.
30 *
31 * See also: #FuDevice
32 */
33
Richard Hughesb0829032017-01-10 09:27:08 +000034#define FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM 3000u /* ms */
35
Richard Hughescff38bc2016-12-12 12:03:37 +000036static void fu_plugin_finalize (GObject *object);
37
38typedef struct {
39 GModule *module;
40 GUsbContext *usb_ctx;
41 gboolean enabled;
Richard Hughes08a37992017-09-12 12:57:43 +010042 guint order;
Richard Hughes81c427c2018-08-06 15:20:17 +010043 guint priority;
Richard Hughes08a37992017-09-12 12:57:43 +010044 GPtrArray *rules[FU_PLUGIN_RULE_LAST];
Richard Hughescff38bc2016-12-12 12:03:37 +000045 gchar *name;
Richard Hughesf425d292019-01-18 17:57:39 +000046 gchar *build_hash;
Richard Hughesd7704d42017-08-08 20:29:09 +010047 FuHwids *hwids;
Richard Hughes9c028f02017-10-28 21:14:28 +010048 FuQuirks *quirks;
Richard Hughes0eb123b2018-04-19 12:00:04 +010049 GHashTable *runtime_versions;
Richard Hughes34e0dab2018-04-20 16:43:00 +010050 GHashTable *compile_versions;
Richard Hughes9d6e0e72018-08-24 20:20:17 +010051 GPtrArray *udev_subsystems;
Richard Hughes1354ea92017-09-19 15:58:31 +010052 FuSmbios *smbios;
Richard Hughes989acf12019-10-05 20:16:47 +010053 GType device_gtype;
Richard Hughescff38bc2016-12-12 12:03:37 +000054 GHashTable *devices; /* platform_id:GObject */
Richard Hughes161e9b52019-06-12 14:22:45 +010055 GRWLock devices_mutex;
Richard Hughes80b79bb2018-01-11 21:11:06 +000056 GHashTable *report_metadata; /* key:value */
Richard Hughescff38bc2016-12-12 12:03:37 +000057 FuPluginData *data;
58} FuPluginPrivate;
59
60enum {
61 SIGNAL_DEVICE_ADDED,
62 SIGNAL_DEVICE_REMOVED,
Richard Hughese1fd34d2017-08-24 14:19:51 +010063 SIGNAL_DEVICE_REGISTER,
Richard Hughes75b965d2018-11-15 13:51:21 +000064 SIGNAL_RULES_CHANGED,
Richard Hughes362d6d72017-01-07 21:42:14 +000065 SIGNAL_RECOLDPLUG,
Richard Hughesb0829032017-01-10 09:27:08 +000066 SIGNAL_SET_COLDPLUG_DELAY,
Richard Hughesaabdc372018-11-14 10:11:08 +000067 SIGNAL_CHECK_SUPPORTED,
Richard Hughes95c98a92019-10-22 16:03:15 +010068 SIGNAL_ADD_FIRMWARE_GTYPE,
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 Hughescff38bc2016-12-12 12:03:37 +0000108
Richard Hughes57d18222017-01-10 16:02:59 +0000109/**
Mario Limonciello52e75ba2019-11-22 13:21:19 -0600110 * fu_plugin_is_open:
111 * @self: A #FuPlugin
112 *
113 * Determines if the plugin is opened
114 *
115 * Returns: TRUE for opened, FALSE for not
116 *
117 * Since: 1.3.5
118 **/
119gboolean
120fu_plugin_is_open (FuPlugin *self)
121{
122 FuPluginPrivate *priv = GET_PRIVATE (self);
123 return priv->module != NULL;
124}
125
126/**
Richard Hughes57d18222017-01-10 16:02:59 +0000127 * fu_plugin_get_name:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100128 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000129 *
130 * Gets the plugin name.
131 *
132 * Returns: a plugin name, or %NULL for unknown.
133 *
134 * Since: 0.8.0
135 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000136const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100137fu_plugin_get_name (FuPlugin *self)
Richard Hughesd0905142016-03-13 09:46:49 +0000138{
Richard Hughes12724852018-09-04 13:53:44 +0100139 FuPluginPrivate *priv = GET_PRIVATE (self);
140 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000141 return priv->name;
142}
Richard Hughesd0905142016-03-13 09:46:49 +0000143
Mario Limonciello1a680f32019-11-25 19:44:53 -0600144/**
145 * fu_plugin_set_name:
146 * @self: A #FuPlugin
147 * @name: A string
148 *
149 * Sets the plugin name.
150 *
151 * Since: 0.8.0
152 **/
Richard Hughes34834102017-11-21 21:55:00 +0000153void
Richard Hughes12724852018-09-04 13:53:44 +0100154fu_plugin_set_name (FuPlugin *self, const gchar *name)
Richard Hughes34834102017-11-21 21:55:00 +0000155{
Richard Hughes12724852018-09-04 13:53:44 +0100156 FuPluginPrivate *priv = GET_PRIVATE (self);
157 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughes34834102017-11-21 21:55:00 +0000158 g_return_if_fail (name != NULL);
159 g_free (priv->name);
160 priv->name = g_strdup (name);
161}
162
Richard Hughes57d18222017-01-10 16:02:59 +0000163/**
Richard Hughesf425d292019-01-18 17:57:39 +0000164 * fu_plugin_set_build_hash:
165 * @self: A #FuPlugin
166 * @build_hash: A checksum
167 *
168 * Sets the plugin build hash, typically a SHA256 checksum. All plugins must
169 * set the correct checksum to avoid the daemon being marked as tainted.
170 *
171 * Since: 1.2.4
172 **/
173void
174fu_plugin_set_build_hash (FuPlugin *self, const gchar *build_hash)
175{
176 FuPluginPrivate *priv = GET_PRIVATE (self);
177 g_return_if_fail (FU_IS_PLUGIN (self));
178 g_return_if_fail (build_hash != NULL);
179 g_free (priv->build_hash);
180 priv->build_hash = g_strdup (build_hash);
181}
182
Mario Limonciello1a680f32019-11-25 19:44:53 -0600183/**
184 * fu_plugin_get_build_hash:
185 * @self: A #FuPlugin
186 *
187 * Gets the build hash a plugin was generated with.
188 *
189 * Returns: (transfer none): a #gchar, or %NULL for unset.
190 *
191 * Since: 1.2.4
192 **/
Richard Hughesf425d292019-01-18 17:57:39 +0000193const gchar *
194fu_plugin_get_build_hash (FuPlugin *self)
195{
196 FuPluginPrivate *priv = GET_PRIVATE (self);
197 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
198 return priv->build_hash;
199}
200
201/**
Richard Hughes57d18222017-01-10 16:02:59 +0000202 * fu_plugin_cache_lookup:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100203 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000204 * @id: the key
205 *
206 * Finds an object in the per-plugin cache.
207 *
208 * Returns: (transfer none): a #GObject, or %NULL for unfound.
209 *
210 * Since: 0.8.0
211 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000212gpointer
Richard Hughes12724852018-09-04 13:53:44 +0100213fu_plugin_cache_lookup (FuPlugin *self, const gchar *id)
Richard Hughescff38bc2016-12-12 12:03:37 +0000214{
Richard Hughes12724852018-09-04 13:53:44 +0100215 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes161e9b52019-06-12 14:22:45 +0100216 g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100217 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughesccd78a92017-01-11 16:57:41 +0000218 g_return_val_if_fail (id != NULL, NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100219 g_return_val_if_fail (locker != NULL, NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000220 return g_hash_table_lookup (priv->devices, id);
221}
Richard Hughesd0905142016-03-13 09:46:49 +0000222
Richard Hughes57d18222017-01-10 16:02:59 +0000223/**
224 * fu_plugin_cache_add:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100225 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000226 * @id: the key
227 * @dev: a #GObject, typically a #FuDevice
228 *
229 * Adds an object to the per-plugin cache.
230 *
231 * Since: 0.8.0
232 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000233void
Richard Hughes12724852018-09-04 13:53:44 +0100234fu_plugin_cache_add (FuPlugin *self, const gchar *id, gpointer dev)
Richard Hughescff38bc2016-12-12 12:03:37 +0000235{
Richard Hughes12724852018-09-04 13:53:44 +0100236 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0fe49142019-11-22 16:56:38 +0000237 g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100238 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000239 g_return_if_fail (id != NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100240 g_return_if_fail (locker != NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000241 g_hash_table_insert (priv->devices, g_strdup (id), g_object_ref (dev));
242}
243
Richard Hughes57d18222017-01-10 16:02:59 +0000244/**
245 * fu_plugin_cache_remove:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100246 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000247 * @id: the key
248 *
249 * Removes an object from the per-plugin cache.
250 *
251 * Since: 0.8.0
252 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000253void
Richard Hughes12724852018-09-04 13:53:44 +0100254fu_plugin_cache_remove (FuPlugin *self, const gchar *id)
Richard Hughescff38bc2016-12-12 12:03:37 +0000255{
Richard Hughes12724852018-09-04 13:53:44 +0100256 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0fe49142019-11-22 16:56:38 +0000257 g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100258 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000259 g_return_if_fail (id != NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100260 g_return_if_fail (locker != NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000261 g_hash_table_remove (priv->devices, id);
262}
263
Richard Hughes57d18222017-01-10 16:02:59 +0000264/**
265 * fu_plugin_get_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100266 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000267 *
Richard Hughes4eada342017-10-03 21:20:32 +0100268 * Gets the per-plugin allocated private data. This will return %NULL unless
269 * fu_plugin_alloc_data() has been called by the plugin.
Richard Hughes57d18222017-01-10 16:02:59 +0000270 *
Richard Hughes4eada342017-10-03 21:20:32 +0100271 * Returns: (transfer none): a pointer to a structure, or %NULL for unset.
Richard Hughes57d18222017-01-10 16:02:59 +0000272 *
273 * Since: 0.8.0
274 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000275FuPluginData *
Richard Hughes12724852018-09-04 13:53:44 +0100276fu_plugin_get_data (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +0000277{
Richard Hughes12724852018-09-04 13:53:44 +0100278 FuPluginPrivate *priv = GET_PRIVATE (self);
279 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000280 return priv->data;
281}
282
Richard Hughes57d18222017-01-10 16:02:59 +0000283/**
284 * fu_plugin_alloc_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100285 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000286 * @data_sz: the size to allocate
287 *
288 * Allocates the per-plugin allocated private data.
289 *
290 * Returns: (transfer full): a pointer to a structure, or %NULL for unset.
291 *
292 * Since: 0.8.0
293 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000294FuPluginData *
Richard Hughes12724852018-09-04 13:53:44 +0100295fu_plugin_alloc_data (FuPlugin *self, gsize data_sz)
Richard Hughescff38bc2016-12-12 12:03:37 +0000296{
Richard Hughes12724852018-09-04 13:53:44 +0100297 FuPluginPrivate *priv = GET_PRIVATE (self);
298 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes44dee882017-01-11 08:31:10 +0000299 if (priv->data != NULL) {
300 g_critical ("fu_plugin_alloc_data() already used by plugin");
301 return priv->data;
302 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000303 priv->data = g_malloc0 (data_sz);
304 return priv->data;
Richard Hughesd0905142016-03-13 09:46:49 +0000305}
306
Richard Hughes57d18222017-01-10 16:02:59 +0000307/**
308 * fu_plugin_get_usb_context:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100309 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000310 *
311 * Gets the shared USB context that all plugins can use.
312 *
313 * Returns: (transfer none): a #GUsbContext.
314 *
315 * Since: 0.8.0
316 **/
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000317GUsbContext *
Richard Hughes12724852018-09-04 13:53:44 +0100318fu_plugin_get_usb_context (FuPlugin *self)
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000319{
Richard Hughes12724852018-09-04 13:53:44 +0100320 FuPluginPrivate *priv = GET_PRIVATE (self);
321 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000322 return priv->usb_ctx;
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000323}
324
Mario Limonciello1a680f32019-11-25 19:44:53 -0600325/**
326 * fu_plugin_set_usb_context:
327 * @self: A #FuPlugin
328 * @usb_ctx: A #FGUsbContext
329 *
330 * Sets the shared USB context for a plugin
331 *
332 * Since: 0.8.0
333 **/
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000334void
Richard Hughes12724852018-09-04 13:53:44 +0100335fu_plugin_set_usb_context (FuPlugin *self, GUsbContext *usb_ctx)
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000336{
Richard Hughes12724852018-09-04 13:53:44 +0100337 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +0000338 g_set_object (&priv->usb_ctx, usb_ctx);
339}
340
Richard Hughes57d18222017-01-10 16:02:59 +0000341/**
342 * fu_plugin_get_enabled:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100343 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000344 *
Richard Hughes4eada342017-10-03 21:20:32 +0100345 * Returns if the plugin is enabled. Plugins may self-disable using
346 * fu_plugin_set_enabled() or can be disabled by the daemon.
Richard Hughes57d18222017-01-10 16:02:59 +0000347 *
348 * Returns: %TRUE if the plugin is currently enabled.
349 *
350 * Since: 0.8.0
351 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000352gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100353fu_plugin_get_enabled (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +0000354{
Richard Hughes12724852018-09-04 13:53:44 +0100355 FuPluginPrivate *priv = GET_PRIVATE (self);
356 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
Richard Hughescff38bc2016-12-12 12:03:37 +0000357 return priv->enabled;
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000358}
359
Richard Hughes57d18222017-01-10 16:02:59 +0000360/**
361 * fu_plugin_set_enabled:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100362 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000363 * @enabled: the enabled value
364 *
365 * Enables or disables a plugin. Plugins can self-disable at any point.
366 *
367 * Since: 0.8.0
368 **/
Richard Hughesd0905142016-03-13 09:46:49 +0000369void
Richard Hughes12724852018-09-04 13:53:44 +0100370fu_plugin_set_enabled (FuPlugin *self, gboolean enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000371{
Richard Hughes12724852018-09-04 13:53:44 +0100372 FuPluginPrivate *priv = GET_PRIVATE (self);
373 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughescff38bc2016-12-12 12:03:37 +0000374 priv->enabled = enabled;
375}
376
Mario Limonciello1a680f32019-11-25 19:44:53 -0600377/**
378 * fu_plugin_guess_name_from_fn:
379 * @filename: filename to guess
380 *
381 * Tries to guess the name of the plugin from a filename
382 *
383 * Returns: (transfer full): the guessed name of the plugin
384 *
385 * Since: 1.0.8
386 **/
Richard Hughes1e456bc2018-05-10 20:16:16 +0100387gchar *
388fu_plugin_guess_name_from_fn (const gchar *filename)
389{
390 const gchar *prefix = "libfu_plugin_";
391 gchar *name;
392 gchar *str = g_strstr_len (filename, -1, prefix);
393 if (str == NULL)
394 return NULL;
395 name = g_strdup (str + strlen (prefix));
396 g_strdelimit (name, ".", '\0');
397 return name;
398}
399
Mario Limonciello1a680f32019-11-25 19:44:53 -0600400/**
401 * fu_plugin_open:
402 * @self: A #FuPlugin
403 * @filename: The shared object filename to open
404 * @error: A #GError or NULL
405 *
406 * Opens the plugin module
407 *
408 * Returns: TRUE for success, FALSE for fail
409 *
410 * Since: 0.8.0
411 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000412gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100413fu_plugin_open (FuPlugin *self, const gchar *filename, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +0000414{
Richard Hughes12724852018-09-04 13:53:44 +0100415 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +0000416 FuPluginInitFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000417
418 priv->module = g_module_open (filename, 0);
419 if (priv->module == NULL) {
420 g_set_error (error,
421 G_IO_ERROR,
422 G_IO_ERROR_FAILED,
Mario Limonciellof5605532019-11-04 07:49:50 -0600423 "failed to open plugin %s: %s",
424 filename, g_module_error ());
Richard Hughescff38bc2016-12-12 12:03:37 +0000425 return FALSE;
426 }
427
428 /* set automatically */
Richard Hughes1e456bc2018-05-10 20:16:16 +0100429 if (priv->name == NULL)
430 priv->name = fu_plugin_guess_name_from_fn (filename);
Richard Hughesd0905142016-03-13 09:46:49 +0000431
432 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000433 g_module_symbol (priv->module, "fu_plugin_init", (gpointer *) &func);
434 if (func != NULL) {
435 g_debug ("performing init() on %s", filename);
Richard Hughes12724852018-09-04 13:53:44 +0100436 func (self);
Richard Hughesd0905142016-03-13 09:46:49 +0000437 }
438
Richard Hughescff38bc2016-12-12 12:03:37 +0000439 return TRUE;
440}
441
Richard Hughes57d18222017-01-10 16:02:59 +0000442/**
443 * fu_plugin_device_add:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100444 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000445 * @device: A #FuDevice
446 *
447 * Asks the daemon to add a device to the exported list. If this device ID
448 * has already been added by a different plugin then this request will be
449 * ignored.
450 *
451 * Plugins should use fu_plugin_device_add_delay() if they are not capable of
452 * actually flashing an image to the hardware so that higher-priority plugins
453 * can add the device themselves.
454 *
455 * Since: 0.8.0
456 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000457void
Richard Hughes12724852018-09-04 13:53:44 +0100458fu_plugin_device_add (FuPlugin *self, FuDevice *device)
Richard Hughescff38bc2016-12-12 12:03:37 +0000459{
Richard Hughes5e447292018-04-27 14:25:54 +0100460 GPtrArray *children;
Richard Hughesc125ec02018-09-05 19:35:17 +0100461 g_autoptr(GError) error = NULL;
Richard Hughes5e447292018-04-27 14:25:54 +0100462
Richard Hughes12724852018-09-04 13:53:44 +0100463 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000464 g_return_if_fail (FU_IS_DEVICE (device));
465
Richard Hughesc125ec02018-09-05 19:35:17 +0100466 /* ensure the device ID is set from the physical and logical IDs */
467 if (!fu_device_ensure_id (device, &error)) {
468 g_warning ("ignoring add: %s", error->message);
469 return;
470 }
471
Richard Hughescff38bc2016-12-12 12:03:37 +0000472 g_debug ("emit added from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100473 fu_plugin_get_name (self),
Richard Hughescff38bc2016-12-12 12:03:37 +0000474 fu_device_get_id (device));
475 fu_device_set_created (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
Richard Hughes12724852018-09-04 13:53:44 +0100476 fu_device_set_plugin (device, fu_plugin_get_name (self));
477 g_signal_emit (self, signals[SIGNAL_DEVICE_ADDED], 0, device);
Richard Hughes5e447292018-04-27 14:25:54 +0100478
Richard Hughes128c0162018-08-10 11:00:29 +0100479 /* add children if they have not already been added */
Richard Hughes5e447292018-04-27 14:25:54 +0100480 children = fu_device_get_children (device);
481 for (guint i = 0; i < children->len; i++) {
482 FuDevice *child = g_ptr_array_index (children, i);
Richard Hughes128c0162018-08-10 11:00:29 +0100483 if (fu_device_get_created (child) == 0)
Richard Hughes12724852018-09-04 13:53:44 +0100484 fu_plugin_device_add (self, child);
Richard Hughes5e447292018-04-27 14:25:54 +0100485 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000486}
487
Richard Hughese1fd34d2017-08-24 14:19:51 +0100488/**
489 * fu_plugin_device_register:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100490 * @self: A #FuPlugin
Richard Hughese1fd34d2017-08-24 14:19:51 +0100491 * @device: A #FuDevice
492 *
493 * Registers the device with other plugins so they can set metadata.
494 *
495 * Plugins do not have to call this manually as this is done automatically
496 * when using fu_plugin_device_add(). They may wish to use this manually
497 * if for intance the coldplug should be ignored based on the metadata
498 * set from other plugins.
499 *
500 * Since: 0.9.7
501 **/
502void
Richard Hughes12724852018-09-04 13:53:44 +0100503fu_plugin_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +0100504{
Richard Hughesc125ec02018-09-05 19:35:17 +0100505 g_autoptr(GError) error = NULL;
506
Richard Hughes12724852018-09-04 13:53:44 +0100507 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughese1fd34d2017-08-24 14:19:51 +0100508 g_return_if_fail (FU_IS_DEVICE (device));
509
Richard Hughesc125ec02018-09-05 19:35:17 +0100510 /* ensure the device ID is set from the physical and logical IDs */
511 if (!fu_device_ensure_id (device, &error)) {
512 g_warning ("ignoring registration: %s", error->message);
513 return;
514 }
515
Richard Hughese1fd34d2017-08-24 14:19:51 +0100516 g_debug ("emit device-register from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100517 fu_plugin_get_name (self),
Richard Hughese1fd34d2017-08-24 14:19:51 +0100518 fu_device_get_id (device));
Richard Hughes12724852018-09-04 13:53:44 +0100519 g_signal_emit (self, signals[SIGNAL_DEVICE_REGISTER], 0, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +0100520}
521
Richard Hughes57d18222017-01-10 16:02:59 +0000522/**
Richard Hughes4eada342017-10-03 21:20:32 +0100523 * fu_plugin_device_remove:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100524 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000525 * @device: A #FuDevice
526 *
527 * Asks the daemon to remove a device from the exported list.
528 *
529 * Since: 0.8.0
530 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000531void
Richard Hughes12724852018-09-04 13:53:44 +0100532fu_plugin_device_remove (FuPlugin *self, FuDevice *device)
Richard Hughescff38bc2016-12-12 12:03:37 +0000533{
Richard Hughes12724852018-09-04 13:53:44 +0100534 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000535 g_return_if_fail (FU_IS_DEVICE (device));
536
Richard Hughescff38bc2016-12-12 12:03:37 +0000537 g_debug ("emit removed from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100538 fu_plugin_get_name (self),
Richard Hughescff38bc2016-12-12 12:03:37 +0000539 fu_device_get_id (device));
Richard Hughes12724852018-09-04 13:53:44 +0100540 g_signal_emit (self, signals[SIGNAL_DEVICE_REMOVED], 0, device);
Richard Hughescff38bc2016-12-12 12:03:37 +0000541}
542
Richard Hughes57d18222017-01-10 16:02:59 +0000543/**
Richard Hughes2de8f132018-01-17 09:12:02 +0000544 * fu_plugin_request_recoldplug:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100545 * @self: A #FuPlugin
Richard Hughes362d6d72017-01-07 21:42:14 +0000546 *
547 * Ask all the plugins to coldplug all devices, which will include the prepare()
548 * and cleanup() phases. Duplicate devices added will be ignored.
549 *
550 * Since: 0.8.0
551 **/
552void
Richard Hughes12724852018-09-04 13:53:44 +0100553fu_plugin_request_recoldplug (FuPlugin *self)
Richard Hughes362d6d72017-01-07 21:42:14 +0000554{
Richard Hughes12724852018-09-04 13:53:44 +0100555 g_return_if_fail (FU_IS_PLUGIN (self));
556 g_signal_emit (self, signals[SIGNAL_RECOLDPLUG], 0);
Richard Hughes362d6d72017-01-07 21:42:14 +0000557}
558
Richard Hughesb0829032017-01-10 09:27:08 +0000559/**
Richard Hughesb8f8db22017-04-25 15:56:00 +0100560 * fu_plugin_check_hwid:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100561 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100562 * @hwid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
Richard Hughesb8f8db22017-04-25 15:56:00 +0100563 *
Richard Hughesd7704d42017-08-08 20:29:09 +0100564 * Checks to see if a specific GUID exists. All hardware IDs on a
Richard Hughesb8f8db22017-04-25 15:56:00 +0100565 * specific system can be shown using the `fwupdmgr hwids` command.
566 *
Richard Hughes4eada342017-10-03 21:20:32 +0100567 * Returns: %TRUE if the HwId is found on the system.
568 *
Richard Hughesb8f8db22017-04-25 15:56:00 +0100569 * Since: 0.9.1
570 **/
571gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100572fu_plugin_check_hwid (FuPlugin *self, const gchar *hwid)
Richard Hughesb8f8db22017-04-25 15:56:00 +0100573{
Richard Hughes12724852018-09-04 13:53:44 +0100574 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100575 if (priv->hwids == NULL)
576 return FALSE;
Richard Hughesd7704d42017-08-08 20:29:09 +0100577 return fu_hwids_has_guid (priv->hwids, hwid);
578}
579
580/**
Patrick Rudolpha60b5472019-10-16 10:43:03 +0200581 * fu_plugin_get_hwid_replace_value:
582 * @self: A #FuPlugin
583 * @keys: A key, e.g. `HardwareID-3` or %FU_HWIDS_KEY_PRODUCT_SKU
584 * @error: A #GError or %NULL
585 *
586 * Gets the replacement value for a specific key. All hardware IDs on a
587 * specific system can be shown using the `fwupdmgr hwids` command.
588 *
589 * Returns: (transfer full): a string, or %NULL for error.
590 *
591 * Since: 1.3.3
592 **/
593gchar *
594fu_plugin_get_hwid_replace_value (FuPlugin *self, const gchar *keys, GError **error)
595{
596 FuPluginPrivate *priv = GET_PRIVATE (self);
597 if (priv->hwids == NULL)
598 return NULL;
599
600 return fu_hwids_get_replace_values (priv->hwids, keys, error);
601}
602
603/**
Richard Hughes69a5f352018-08-08 11:58:15 +0100604 * fu_plugin_get_hwids:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100605 * @self: A #FuPlugin
Richard Hughes69a5f352018-08-08 11:58:15 +0100606 *
607 * Returns all the HWIDs defined in the system. All hardware IDs on a
608 * specific system can be shown using the `fwupdmgr hwids` command.
609 *
Mario Limonciello1a680f32019-11-25 19:44:53 -0600610 * Returns: (transfer none) (element-type utf8): An array of GUIDs
Richard Hughes69a5f352018-08-08 11:58:15 +0100611 *
612 * Since: 1.1.1
613 **/
614GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +0100615fu_plugin_get_hwids (FuPlugin *self)
Richard Hughes69a5f352018-08-08 11:58:15 +0100616{
Richard Hughes12724852018-09-04 13:53:44 +0100617 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes69a5f352018-08-08 11:58:15 +0100618 if (priv->hwids == NULL)
619 return NULL;
620 return fu_hwids_get_guids (priv->hwids);
621}
622
623/**
Richard Hughes19841802019-09-10 16:48:00 +0100624 * fu_plugin_has_custom_flag:
625 * @self: A #FuPlugin
626 * @flag: A custom text flag, specific to the plugin, e.g. `uefi-force-enable`
627 *
628 * Returns if a per-plugin HwId custom flag exists, typically added from a DMI quirk.
629 *
630 * Returns: %TRUE if the quirk entry exists
631 *
632 * Since: 1.3.1
633 **/
634gboolean
635fu_plugin_has_custom_flag (FuPlugin *self, const gchar *flag)
636{
637 FuPluginPrivate *priv = GET_PRIVATE (self);
638 GPtrArray *hwids = fu_plugin_get_hwids (self);
639
640 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
641 g_return_val_if_fail (flag != NULL, FALSE);
642
643 /* never set up, e.g. in tests */
644 if (hwids == NULL)
645 return FALSE;
646
647 /* search each hwid */
648 for (guint i = 0; i < hwids->len; i++) {
649 const gchar *hwid = g_ptr_array_index (hwids, i);
650 const gchar *value;
651 g_autofree gchar *key = g_strdup_printf ("HwId=%s", hwid);
652
653 /* does prefixed quirk exist */
654 value = fu_quirks_lookup_by_id (priv->quirks, key, FU_QUIRKS_FLAGS);
655 if (value != NULL) {
656 g_auto(GStrv) quirks = g_strsplit (value, ",", -1);
657 if (g_strv_contains ((const gchar * const *) quirks, flag))
658 return TRUE;
659 }
660 }
661 return FALSE;
662}
663
664/**
Richard Hughes1354ea92017-09-19 15:58:31 +0100665 * fu_plugin_check_supported:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100666 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100667 * @guid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
Richard Hughes1354ea92017-09-19 15:58:31 +0100668 *
669 * Checks to see if a specific device GUID is supported, i.e. available in the
670 * AppStream metadata.
671 *
Richard Hughes4eada342017-10-03 21:20:32 +0100672 * Returns: %TRUE if the device is supported.
673 *
Richard Hughes1354ea92017-09-19 15:58:31 +0100674 * Since: 1.0.0
675 **/
Richard Hughesd8a8d5e2019-10-08 13:05:02 +0100676static gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100677fu_plugin_check_supported (FuPlugin *self, const gchar *guid)
Richard Hughes1354ea92017-09-19 15:58:31 +0100678{
Richard Hughesaabdc372018-11-14 10:11:08 +0000679 gboolean retval = FALSE;
680 g_signal_emit (self, signals[SIGNAL_CHECK_SUPPORTED], 0, guid, &retval);
681 return retval;
Richard Hughes1354ea92017-09-19 15:58:31 +0100682}
683
684/**
Richard Hughesd7704d42017-08-08 20:29:09 +0100685 * fu_plugin_get_dmi_value:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100686 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100687 * @dmi_id: A DMI ID, e.g. `BiosVersion`
Richard Hughesd7704d42017-08-08 20:29:09 +0100688 *
689 * Gets a hardware DMI value.
690 *
Richard Hughes4eada342017-10-03 21:20:32 +0100691 * Returns: The string, or %NULL
692 *
Richard Hughesd7704d42017-08-08 20:29:09 +0100693 * Since: 0.9.7
694 **/
695const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100696fu_plugin_get_dmi_value (FuPlugin *self, const gchar *dmi_id)
Richard Hughesd7704d42017-08-08 20:29:09 +0100697{
Richard Hughes12724852018-09-04 13:53:44 +0100698 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd7704d42017-08-08 20:29:09 +0100699 if (priv->hwids == NULL)
Richard Hughes7ef96b82017-08-23 18:28:24 +0100700 return NULL;
Richard Hughesd7704d42017-08-08 20:29:09 +0100701 return fu_hwids_get_value (priv->hwids, dmi_id);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100702}
703
Richard Hughes49e5e052017-09-03 12:15:41 +0100704/**
705 * fu_plugin_get_smbios_string:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100706 * @self: A #FuPlugin
Richard Hughes49e5e052017-09-03 12:15:41 +0100707 * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
708 * @offset: A SMBIOS offset
709 *
710 * Gets a hardware SMBIOS string.
711 *
712 * The @type and @offset can be referenced from the DMTF SMBIOS specification:
713 * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.1.1.pdf
714 *
Richard Hughes4eada342017-10-03 21:20:32 +0100715 * Returns: A string, or %NULL
716 *
Richard Hughes49e5e052017-09-03 12:15:41 +0100717 * Since: 0.9.8
718 **/
719const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100720fu_plugin_get_smbios_string (FuPlugin *self, guint8 structure_type, guint8 offset)
Richard Hughes49e5e052017-09-03 12:15:41 +0100721{
Richard Hughes12724852018-09-04 13:53:44 +0100722 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100723 if (priv->smbios == NULL)
724 return NULL;
725 return fu_smbios_get_string (priv->smbios, structure_type, offset, NULL);
726}
727
728/**
729 * fu_plugin_get_smbios_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100730 * @self: A #FuPlugin
Richard Hughes49e5e052017-09-03 12:15:41 +0100731 * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
732 *
733 * Gets a hardware SMBIOS data.
734 *
Richard Hughesdfaca2d2019-08-01 08:08:03 +0100735 * Returns: (transfer full): A #GBytes, or %NULL
Richard Hughes4eada342017-10-03 21:20:32 +0100736 *
Richard Hughes49e5e052017-09-03 12:15:41 +0100737 * Since: 0.9.8
738 **/
739GBytes *
Richard Hughes12724852018-09-04 13:53:44 +0100740fu_plugin_get_smbios_data (FuPlugin *self, guint8 structure_type)
Richard Hughes49e5e052017-09-03 12:15:41 +0100741{
Richard Hughes12724852018-09-04 13:53:44 +0100742 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100743 if (priv->smbios == NULL)
744 return NULL;
745 return fu_smbios_get_data (priv->smbios, structure_type, NULL);
746}
747
Mario Limonciello1a680f32019-11-25 19:44:53 -0600748/**
749 * fu_plugin_set_hwids:
750 * @self: A #FuPlugin
751 * @hwids: A #FuHwids
752 *
753 * Sets the hwids for a plugin
754 *
755 * Since: 0.9.7
756 **/
Richard Hughesb8f8db22017-04-25 15:56:00 +0100757void
Richard Hughes12724852018-09-04 13:53:44 +0100758fu_plugin_set_hwids (FuPlugin *self, FuHwids *hwids)
Richard Hughesb8f8db22017-04-25 15:56:00 +0100759{
Richard Hughes12724852018-09-04 13:53:44 +0100760 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd7704d42017-08-08 20:29:09 +0100761 g_set_object (&priv->hwids, hwids);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100762}
763
Mario Limonciello1a680f32019-11-25 19:44:53 -0600764/**
765 * fu_plugin_set_udev_subsystems:
766 * @self: A #FuPlugin
767 * @udev_subsystems: A #GPtrArray
768 *
769 * Sets the udev subsystems used by a plugin
770 *
771 * Since: 1.1.2
772 **/
Richard Hughes49e5e052017-09-03 12:15:41 +0100773void
Richard Hughes12724852018-09-04 13:53:44 +0100774fu_plugin_set_udev_subsystems (FuPlugin *self, GPtrArray *udev_subsystems)
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100775{
Richard Hughes12724852018-09-04 13:53:44 +0100776 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100777 if (priv->udev_subsystems != NULL)
778 g_ptr_array_unref (priv->udev_subsystems);
779 priv->udev_subsystems = g_ptr_array_ref (udev_subsystems);
780}
781
Mario Limonciello1a680f32019-11-25 19:44:53 -0600782/**
783 * fu_plugin_set_quirks:
784 * @self: A #FuPlugin
785 * @quirks: A #FuQuirks
786 *
787 * Sets the quirks for a plugin
788 *
789 * Since: 1.0.1
790 **/
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100791void
Richard Hughes12724852018-09-04 13:53:44 +0100792fu_plugin_set_quirks (FuPlugin *self, FuQuirks *quirks)
Richard Hughes9c028f02017-10-28 21:14:28 +0100793{
Richard Hughes12724852018-09-04 13:53:44 +0100794 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9c028f02017-10-28 21:14:28 +0100795 g_set_object (&priv->quirks, quirks);
796}
797
798/**
799 * fu_plugin_get_quirks:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100800 * @self: A #FuPlugin
Richard Hughes9c028f02017-10-28 21:14:28 +0100801 *
802 * Returns the hardware database object. This can be used to discover device
803 * quirks or other device-specific settings.
804 *
805 * Returns: (transfer none): a #FuQuirks, or %NULL if not set
806 *
807 * Since: 1.0.1
808 **/
809FuQuirks *
Richard Hughes12724852018-09-04 13:53:44 +0100810fu_plugin_get_quirks (FuPlugin *self)
Richard Hughes9c028f02017-10-28 21:14:28 +0100811{
Richard Hughes12724852018-09-04 13:53:44 +0100812 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9c028f02017-10-28 21:14:28 +0100813 return priv->quirks;
814}
815
Mario Limonciello1a680f32019-11-25 19:44:53 -0600816/**
817 * fu_plugin_set_runtime_versions:
818 * @self: A #FuPlugin
819 * @runtime_versions: A #GHashTables
820 *
821 * Sets the runtime versions for a plugin
822 *
823 * Since: 1.0.7
824 **/
Richard Hughes0eb123b2018-04-19 12:00:04 +0100825void
Richard Hughes12724852018-09-04 13:53:44 +0100826fu_plugin_set_runtime_versions (FuPlugin *self, GHashTable *runtime_versions)
Richard Hughes0eb123b2018-04-19 12:00:04 +0100827{
Richard Hughes12724852018-09-04 13:53:44 +0100828 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0eb123b2018-04-19 12:00:04 +0100829 priv->runtime_versions = g_hash_table_ref (runtime_versions);
830}
831
832/**
833 * fu_plugin_add_runtime_version:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100834 * @self: A #FuPlugin
Richard Hughes0eb123b2018-04-19 12:00:04 +0100835 * @component_id: An AppStream component id, e.g. "org.gnome.Software"
836 * @version: A version string, e.g. "1.2.3"
837 *
Richard Hughesdce91202019-04-08 12:47:45 +0100838 * Sets a runtime version of a specific dependency.
Richard Hughes0eb123b2018-04-19 12:00:04 +0100839 *
840 * Since: 1.0.7
841 **/
842void
Richard Hughes12724852018-09-04 13:53:44 +0100843fu_plugin_add_runtime_version (FuPlugin *self,
Richard Hughes0eb123b2018-04-19 12:00:04 +0100844 const gchar *component_id,
845 const gchar *version)
846{
Richard Hughes12724852018-09-04 13:53:44 +0100847 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesb01b4862018-04-20 16:39:48 +0100848 if (priv->runtime_versions == NULL)
849 return;
Richard Hughes0eb123b2018-04-19 12:00:04 +0100850 g_hash_table_insert (priv->runtime_versions,
851 g_strdup (component_id),
852 g_strdup (version));
853}
854
Mario Limonciello1a680f32019-11-25 19:44:53 -0600855/**
856 * fu_plugin_set_compile_versions:
857 * @self: A #FuPlugin
858 * @compile_versions: A #GHashTables
859 *
860 * Sets the compile time versions for a plugin
861 *
862 * Since: 1.0.7
863 **/
Richard Hughes34e0dab2018-04-20 16:43:00 +0100864void
Richard Hughes12724852018-09-04 13:53:44 +0100865fu_plugin_set_compile_versions (FuPlugin *self, GHashTable *compile_versions)
Richard Hughes34e0dab2018-04-20 16:43:00 +0100866{
Richard Hughes12724852018-09-04 13:53:44 +0100867 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes34e0dab2018-04-20 16:43:00 +0100868 priv->compile_versions = g_hash_table_ref (compile_versions);
869}
870
871/**
872 * fu_plugin_add_compile_version:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100873 * @self: A #FuPlugin
Richard Hughes34e0dab2018-04-20 16:43:00 +0100874 * @component_id: An AppStream component id, e.g. "org.gnome.Software"
875 * @version: A version string, e.g. "1.2.3"
876 *
Richard Hughesdce91202019-04-08 12:47:45 +0100877 * Sets a compile-time version of a specific dependency.
Richard Hughes34e0dab2018-04-20 16:43:00 +0100878 *
879 * Since: 1.0.7
880 **/
881void
Richard Hughes12724852018-09-04 13:53:44 +0100882fu_plugin_add_compile_version (FuPlugin *self,
Richard Hughes34e0dab2018-04-20 16:43:00 +0100883 const gchar *component_id,
884 const gchar *version)
885{
Richard Hughes12724852018-09-04 13:53:44 +0100886 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes34e0dab2018-04-20 16:43:00 +0100887 if (priv->compile_versions == NULL)
888 return;
889 g_hash_table_insert (priv->compile_versions,
890 g_strdup (component_id),
891 g_strdup (version));
892}
893
Richard Hughes9c028f02017-10-28 21:14:28 +0100894/**
895 * fu_plugin_lookup_quirk_by_id:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100896 * @self: A #FuPlugin
Richard Hughes87fb9ff2018-06-28 12:55:59 +0100897 * @group: A string, e.g. "DfuFlags"
898 * @key: An ID to match the entry, e.g. "Summary"
Richard Hughes9c028f02017-10-28 21:14:28 +0100899 *
900 * Looks up an entry in the hardware database using a string value.
901 *
902 * Returns: (transfer none): values from the database, or %NULL if not found
903 *
904 * Since: 1.0.1
905 **/
906const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100907fu_plugin_lookup_quirk_by_id (FuPlugin *self, const gchar *group, const gchar *key)
Richard Hughes9c028f02017-10-28 21:14:28 +0100908{
Richard Hughes12724852018-09-04 13:53:44 +0100909 FuPluginPrivate *priv = GET_PRIVATE (self);
910 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes9c028f02017-10-28 21:14:28 +0100911
Richard Hughes9c028f02017-10-28 21:14:28 +0100912 /* exact ID */
Richard Hughes87fb9ff2018-06-28 12:55:59 +0100913 return fu_quirks_lookup_by_id (priv->quirks, group, key);
Richard Hughes9c028f02017-10-28 21:14:28 +0100914}
915
916/**
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100917 * fu_plugin_lookup_quirk_by_id_as_uint64:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100918 * @self: A #FuPlugin
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100919 * @group: A string, e.g. "DfuFlags"
920 * @key: An ID to match the entry, e.g. "Size"
921 *
922 * Looks up an entry in the hardware database using a string key, returning
923 * an integer value. Values are assumed base 10, unless prefixed with "0x"
924 * where they are parsed as base 16.
925 *
Mario Limonciello1a680f32019-11-25 19:44:53 -0600926 * Returns: guint64 id or 0 if not found
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100927 *
928 * Since: 1.1.2
929 **/
930guint64
Richard Hughes12724852018-09-04 13:53:44 +0100931fu_plugin_lookup_quirk_by_id_as_uint64 (FuPlugin *self, const gchar *group, const gchar *key)
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100932{
Richard Hughes12724852018-09-04 13:53:44 +0100933 return fu_common_strtoull (fu_plugin_lookup_quirk_by_id (self, group, key));
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100934}
935
Mario Limonciello1a680f32019-11-25 19:44:53 -0600936/**
937 * fu_plugin_set_smbios:
938 * @self: A #FuPlugin
939 * @smbios: A #FuSmbios
940 *
941 * Sets the smbios for a plugin
942 *
943 * Since: 1.0.0
944 **/
Richard Hughes1354ea92017-09-19 15:58:31 +0100945void
Richard Hughes12724852018-09-04 13:53:44 +0100946fu_plugin_set_smbios (FuPlugin *self, FuSmbios *smbios)
Richard Hughes49e5e052017-09-03 12:15:41 +0100947{
Richard Hughes12724852018-09-04 13:53:44 +0100948 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100949 g_set_object (&priv->smbios, smbios);
950}
951
Richard Hughesb8f8db22017-04-25 15:56:00 +0100952/**
Richard Hughesb0829032017-01-10 09:27:08 +0000953 * fu_plugin_set_coldplug_delay:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100954 * @self: A #FuPlugin
Richard Hughesb0829032017-01-10 09:27:08 +0000955 * @duration: A delay in milliseconds
956 *
957 * Set the minimum time that should be waited inbetween the call to
958 * fu_plugin_coldplug_prepare() and fu_plugin_coldplug(). This is usually going
959 * to be the minimum hardware initialisation time from a datasheet.
960 *
961 * It is better to use this function rather than using a sleep() in the plugin
962 * itself as then only one delay is done in the daemon rather than waiting for
963 * each coldplug prepare in a serial way.
964 *
965 * Additionally, very long delays should be avoided as the daemon will be
966 * blocked from processing requests whilst the coldplug delay is being
967 * performed.
968 *
969 * Since: 0.8.0
970 **/
971void
Richard Hughes12724852018-09-04 13:53:44 +0100972fu_plugin_set_coldplug_delay (FuPlugin *self, guint duration)
Richard Hughesb0829032017-01-10 09:27:08 +0000973{
Richard Hughes12724852018-09-04 13:53:44 +0100974 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesb0829032017-01-10 09:27:08 +0000975 g_return_if_fail (duration > 0);
976
977 /* check sanity */
978 if (duration > FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM) {
979 g_warning ("duration of %ums is crazy, truncating to %ums",
980 duration,
981 FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM);
982 duration = FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM;
983 }
984
985 /* emit */
Richard Hughes12724852018-09-04 13:53:44 +0100986 g_signal_emit (self, signals[SIGNAL_SET_COLDPLUG_DELAY], 0, duration);
Richard Hughesb0829032017-01-10 09:27:08 +0000987}
988
Richard Hughes4b303802019-10-04 13:22:51 +0100989static gboolean
990fu_plugin_device_attach (FuPlugin *self, FuDevice *device, GError **error)
991{
992 g_autoptr(FuDeviceLocker) locker = NULL;
993 if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) {
994 g_debug ("already in runtime mode, skipping");
995 return TRUE;
996 }
997 locker = fu_device_locker_new (device, error);
998 if (locker == NULL)
999 return FALSE;
1000 return fu_device_attach (device, error);
1001}
1002
1003static gboolean
1004fu_plugin_device_detach (FuPlugin *self, FuDevice *device, GError **error)
1005{
1006 g_autoptr(FuDeviceLocker) locker = NULL;
1007 if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) {
1008 g_debug ("already in bootloader mode, skipping");
1009 return TRUE;
1010 }
1011 locker = fu_device_locker_new (device, error);
1012 if (locker == NULL)
1013 return FALSE;
1014 return fu_device_detach (device, error);
1015}
1016
1017static gboolean
Richard Hughes4b303802019-10-04 13:22:51 +01001018fu_plugin_device_activate (FuPlugin *self, FuDevice *device, GError **error)
1019{
1020 g_autoptr(FuDeviceLocker) locker = NULL;
1021 locker = fu_device_locker_new (device, error);
1022 if (locker == NULL)
1023 return FALSE;
1024 return fu_device_activate (device, error);
1025}
1026
1027static gboolean
1028fu_plugin_device_write_firmware (FuPlugin *self, FuDevice *device,
1029 GBytes *fw, FwupdInstallFlags flags,
1030 GError **error)
1031{
1032 g_autoptr(FuDeviceLocker) locker = NULL;
1033 locker = fu_device_locker_new (device, error);
1034 if (locker == NULL)
1035 return FALSE;
1036 return fu_device_write_firmware (device, fw, flags, error);
1037}
1038
Richard Hughes7f677212019-10-05 16:19:40 +01001039static gboolean
1040fu_plugin_device_read_firmware (FuPlugin *self, FuDevice *device, GError **error)
1041{
1042 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughesf0eb0912019-10-10 11:37:22 +01001043 g_autoptr(FuFirmware) firmware = NULL;
Richard Hughes7f677212019-10-05 16:19:40 +01001044 g_autoptr(GBytes) fw = NULL;
1045 GChecksumType checksum_types[] = {
1046 G_CHECKSUM_SHA1,
1047 G_CHECKSUM_SHA256,
1048 0 };
1049 locker = fu_device_locker_new (device, error);
1050 if (locker == NULL)
1051 return FALSE;
1052 if (!fu_device_detach (device, error))
1053 return FALSE;
Richard Hughesf0eb0912019-10-10 11:37:22 +01001054 firmware = fu_device_read_firmware (device, error);
1055 if (firmware == NULL) {
1056 g_autoptr(GError) error_local = NULL;
1057 if (!fu_device_attach (device, &error_local))
1058 g_debug ("ignoring attach failure: %s", error_local->message);
1059 g_prefix_error (error, "failed to read firmware: ");
1060 return FALSE;
1061 }
1062 fw = fu_firmware_write (firmware, error);
Richard Hughes7f677212019-10-05 16:19:40 +01001063 if (fw == NULL) {
1064 g_autoptr(GError) error_local = NULL;
1065 if (!fu_device_attach (device, &error_local))
Richard Hughesf0eb0912019-10-10 11:37:22 +01001066 g_debug ("ignoring attach failure: %s", error_local->message);
1067 g_prefix_error (error, "failed to write firmware: ");
Richard Hughes7f677212019-10-05 16:19:40 +01001068 return FALSE;
1069 }
1070 for (guint i = 0; checksum_types[i] != 0; i++) {
1071 g_autofree gchar *hash = NULL;
1072 hash = g_compute_checksum_for_bytes (checksum_types[i], fw);
1073 fu_device_add_checksum (device, hash);
1074 }
1075 return fu_device_attach (device, error);
1076}
1077
Mario Limonciello1a680f32019-11-25 19:44:53 -06001078/**
1079 * fu_plugin_runner_startup:
1080 * @self: a #FuPlugin
1081 * @error: a #GError or NULL
1082 *
1083 * Runs the startup routine for the plugin
1084 *
1085 * Returns: #TRUE for success, #FALSE for failure
1086 *
1087 * Since: 0.8.0
1088 **/
Richard Hughesd0905142016-03-13 09:46:49 +00001089gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001090fu_plugin_runner_startup (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00001091{
Richard Hughes12724852018-09-04 13:53:44 +01001092 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001093 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001094 g_autoptr(GError) error_local = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +00001095
1096 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +00001097 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +00001098 return TRUE;
1099
Richard Hughes639da472018-01-06 22:35:04 +00001100 /* no object loaded */
1101 if (priv->module == NULL)
1102 return TRUE;
1103
Richard Hughesd0905142016-03-13 09:46:49 +00001104 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00001105 g_module_symbol (priv->module, "fu_plugin_startup", (gpointer *) &func);
1106 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +00001107 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001108 g_debug ("performing startup() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001109 if (!func (self, &error_local)) {
1110 if (error_local == NULL) {
1111 g_critical ("unset error in plugin %s for startup()",
1112 priv->name);
1113 g_set_error_literal (&error_local,
1114 FWUPD_ERROR,
1115 FWUPD_ERROR_INTERNAL,
1116 "unspecified error");
1117 }
1118 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1119 "failed to startup using %s: ",
1120 priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00001121 return FALSE;
1122 }
1123 return TRUE;
1124}
1125
1126static gboolean
1127fu_plugin_runner_offline_invalidate (GError **error)
1128{
Richard Hughesafdba372019-11-23 12:57:35 +00001129 g_autofree gchar *trigger = fu_common_get_path (FU_PATH_KIND_OFFLINE_TRIGGER);
Richard Hughescff38bc2016-12-12 12:03:37 +00001130 g_autoptr(GError) error_local = NULL;
1131 g_autoptr(GFile) file1 = NULL;
1132
1133 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1134
Richard Hughesafdba372019-11-23 12:57:35 +00001135 file1 = g_file_new_for_path (trigger);
Richard Hughescff38bc2016-12-12 12:03:37 +00001136 if (!g_file_query_exists (file1, NULL))
1137 return TRUE;
1138 if (!g_file_delete (file1, NULL, &error_local)) {
1139 g_set_error (error,
1140 FWUPD_ERROR,
1141 FWUPD_ERROR_INTERNAL,
1142 "Cannot delete %s: %s",
Richard Hughesafdba372019-11-23 12:57:35 +00001143 trigger,
Richard Hughescff38bc2016-12-12 12:03:37 +00001144 error_local->message);
1145 return FALSE;
1146 }
1147 return TRUE;
1148}
1149
1150static gboolean
1151fu_plugin_runner_offline_setup (GError **error)
1152{
1153 gint rc;
Richard Hughes484ee292019-03-22 16:10:50 +00001154 g_autofree gchar *filename = NULL;
Mario Limoncielloe1b4b202019-04-30 10:01:19 -05001155 g_autofree gchar *symlink_target = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG);
Richard Hughesafdba372019-11-23 12:57:35 +00001156 g_autofree gchar *trigger = fu_common_get_path (FU_PATH_KIND_OFFLINE_TRIGGER);
Richard Hughescff38bc2016-12-12 12:03:37 +00001157
1158 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1159
Richard Hughes484ee292019-03-22 16:10:50 +00001160 /* does already exist */
Richard Hughesafdba372019-11-23 12:57:35 +00001161 filename = fu_common_realpath (trigger, NULL);
Richard Hughes484ee292019-03-22 16:10:50 +00001162 if (g_strcmp0 (filename, symlink_target) == 0) {
1163 g_debug ("%s already points to %s, skipping creation",
Richard Hughesafdba372019-11-23 12:57:35 +00001164 trigger, symlink_target);
Richard Hughes484ee292019-03-22 16:10:50 +00001165 return TRUE;
1166 }
1167
Richard Hughescff38bc2016-12-12 12:03:37 +00001168 /* create symlink for the systemd-system-update-generator */
Richard Hughesafdba372019-11-23 12:57:35 +00001169 rc = symlink (symlink_target, trigger);
Richard Hughescff38bc2016-12-12 12:03:37 +00001170 if (rc < 0) {
1171 g_set_error (error,
1172 FWUPD_ERROR,
1173 FWUPD_ERROR_INTERNAL,
1174 "Failed to create symlink %s to %s: %s",
Richard Hughesafdba372019-11-23 12:57:35 +00001175 trigger,
Richard Hughescff38bc2016-12-12 12:03:37 +00001176 "/var/lib", strerror (errno));
Richard Hughesd0905142016-03-13 09:46:49 +00001177 return FALSE;
1178 }
1179 return TRUE;
1180}
1181
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001182static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001183fu_plugin_runner_device_generic (FuPlugin *self, FuDevice *device,
Richard Hughes4b303802019-10-04 13:22:51 +01001184 const gchar *symbol_name,
1185 FuPluginDeviceFunc device_func,
1186 GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001187{
Richard Hughes12724852018-09-04 13:53:44 +01001188 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001189 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001190 g_autoptr(GError) error_local = NULL;
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001191
1192 /* not enabled */
1193 if (!priv->enabled)
1194 return TRUE;
1195
Richard Hughesd3d96cc2017-11-14 11:34:33 +00001196 /* no object loaded */
1197 if (priv->module == NULL)
1198 return TRUE;
1199
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001200 /* optional */
1201 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
Richard Hughes4b303802019-10-04 13:22:51 +01001202 if (func == NULL) {
1203 if (device_func != NULL) {
1204 g_debug ("running superclassed %s() on %s",
1205 symbol_name + 10, priv->name);
1206 return device_func (self, device, error);
1207 }
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001208 return TRUE;
Richard Hughes4b303802019-10-04 13:22:51 +01001209 }
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001210 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001211 if (!func (self, device, &error_local)) {
1212 if (error_local == NULL) {
1213 g_critical ("unset error in plugin %s for %s()",
1214 priv->name, symbol_name + 10);
1215 g_set_error_literal (&error_local,
1216 FWUPD_ERROR,
1217 FWUPD_ERROR_INTERNAL,
1218 "unspecified error");
1219 }
1220 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1221 "failed to %s using %s: ",
1222 symbol_name + 10, priv->name);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001223 return FALSE;
1224 }
1225 return TRUE;
1226}
1227
Richard Hughesdbd8c762018-06-15 20:31:40 +01001228static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001229fu_plugin_runner_flagged_device_generic (FuPlugin *self, FwupdInstallFlags flags,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001230 FuDevice *device,
1231 const gchar *symbol_name, GError **error)
1232{
Richard Hughes12724852018-09-04 13:53:44 +01001233 FuPluginPrivate *priv = GET_PRIVATE (self);
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001234 FuPluginFlaggedDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001235 g_autoptr(GError) error_local = NULL;
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001236
1237 /* not enabled */
1238 if (!priv->enabled)
1239 return TRUE;
1240
1241 /* no object loaded */
1242 if (priv->module == NULL)
1243 return TRUE;
1244
1245 /* optional */
1246 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1247 if (func == NULL)
1248 return TRUE;
1249 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001250 if (!func (self, flags, device, &error_local)) {
1251 if (error_local == NULL) {
1252 g_critical ("unset error in plugin %s for %s()",
1253 priv->name, symbol_name + 10);
1254 g_set_error_literal (&error_local,
1255 FWUPD_ERROR,
1256 FWUPD_ERROR_INTERNAL,
1257 "unspecified error");
1258 }
1259 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1260 "failed to %s using %s: ",
1261 symbol_name + 10, priv->name);
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001262 return FALSE;
1263 }
1264 return TRUE;
1265
1266}
1267
1268static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001269fu_plugin_runner_device_array_generic (FuPlugin *self, GPtrArray *devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001270 const gchar *symbol_name, GError **error)
1271{
Richard Hughes12724852018-09-04 13:53:44 +01001272 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesdbd8c762018-06-15 20:31:40 +01001273 FuPluginDeviceArrayFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001274 g_autoptr(GError) error_local = NULL;
Richard Hughesdbd8c762018-06-15 20:31:40 +01001275
1276 /* not enabled */
1277 if (!priv->enabled)
1278 return TRUE;
1279
1280 /* no object loaded */
1281 if (priv->module == NULL)
1282 return TRUE;
1283
1284 /* optional */
1285 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1286 if (func == NULL)
1287 return TRUE;
1288 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001289 if (!func (self, devices, &error_local)) {
1290 if (error_local == NULL) {
1291 g_critical ("unset error in plugin %s for %s()",
1292 priv->name, symbol_name + 10);
1293 g_set_error_literal (&error_local,
1294 FWUPD_ERROR,
1295 FWUPD_ERROR_INTERNAL,
1296 "unspecified error");
1297 }
1298 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1299 "failed to %s using %s: ",
1300 symbol_name + 10, priv->name);
Richard Hughesdbd8c762018-06-15 20:31:40 +01001301 return FALSE;
1302 }
1303 return TRUE;
1304}
1305
Mario Limonciello1a680f32019-11-25 19:44:53 -06001306/**
1307 * fu_plugin_runner_coldplug:
1308 * @self: a #FuPlugin
1309 * @error: a #GError or NULL
1310 *
1311 * Runs the coldplug routine for the plugin
1312 *
1313 * Returns: #TRUE for success, #FALSE for failure
1314 *
1315 * Since: 0.8.0
1316 **/
Richard Hughesd0905142016-03-13 09:46:49 +00001317gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001318fu_plugin_runner_coldplug (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00001319{
Richard Hughes12724852018-09-04 13:53:44 +01001320 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001321 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001322 g_autoptr(GError) error_local = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +00001323
1324 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +00001325 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +00001326 return TRUE;
1327
Richard Hughes639da472018-01-06 22:35:04 +00001328 /* no object loaded */
1329 if (priv->module == NULL)
1330 return TRUE;
1331
Richard Hughesd0905142016-03-13 09:46:49 +00001332 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00001333 g_module_symbol (priv->module, "fu_plugin_coldplug", (gpointer *) &func);
1334 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +00001335 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001336 g_debug ("performing coldplug() 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 coldplug()",
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 coldplug using %s: ", priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00001348 return FALSE;
1349 }
1350 return TRUE;
1351}
1352
Mario Limonciello1a680f32019-11-25 19:44:53 -06001353/**
1354 * fu_plugin_runner_recoldplug:
1355 * @self: a #FuPlugin
1356 * @error: a #GError or NULL
1357 *
1358 * Runs the recoldplug routine for the plugin
1359 *
1360 * Returns: #TRUE for success, #FALSE for failure
1361 *
1362 * Since: 1.0.4
1363 **/
Richard Hughes7b8b2022016-12-12 16:15:03 +00001364gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001365fu_plugin_runner_recoldplug (FuPlugin *self, GError **error)
Richard Hughes2de8f132018-01-17 09:12:02 +00001366{
Richard Hughes12724852018-09-04 13:53:44 +01001367 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes2de8f132018-01-17 09:12:02 +00001368 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001369 g_autoptr(GError) error_local = NULL;
Richard Hughes2de8f132018-01-17 09:12:02 +00001370
1371 /* not enabled */
1372 if (!priv->enabled)
1373 return TRUE;
1374
1375 /* no object loaded */
1376 if (priv->module == NULL)
1377 return TRUE;
1378
1379 /* optional */
1380 g_module_symbol (priv->module, "fu_plugin_recoldplug", (gpointer *) &func);
1381 if (func == NULL)
1382 return TRUE;
1383 g_debug ("performing recoldplug() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001384 if (!func (self, &error_local)) {
1385 if (error_local == NULL) {
1386 g_critical ("unset error in plugin %s for recoldplug()",
1387 priv->name);
1388 g_set_error_literal (&error_local,
1389 FWUPD_ERROR,
1390 FWUPD_ERROR_INTERNAL,
1391 "unspecified error");
1392 }
1393 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1394 "failed to recoldplug using %s: ",
1395 priv->name);
Richard Hughes2de8f132018-01-17 09:12:02 +00001396 return FALSE;
1397 }
1398 return TRUE;
1399}
1400
Mario Limonciello1a680f32019-11-25 19:44:53 -06001401/**
1402 * fu_plugin_runner_coldplug_prepare:
1403 * @self: a #FuPlugin
1404 * @error: a #GError or NULL
1405 *
1406 * Runs the coldplug_prepare routine for the plugin
1407 *
1408 * Returns: #TRUE for success, #FALSE for failure
1409 *
1410 * Since: 0.8.0
1411 **/
Richard Hughes2de8f132018-01-17 09:12:02 +00001412gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001413fu_plugin_runner_coldplug_prepare (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001414{
Richard Hughes12724852018-09-04 13:53:44 +01001415 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001416 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001417 g_autoptr(GError) error_local = NULL;
Richard Hughes46487c92017-01-07 21:26:34 +00001418
1419 /* not enabled */
1420 if (!priv->enabled)
1421 return TRUE;
1422
Richard Hughes639da472018-01-06 22:35:04 +00001423 /* no object loaded */
1424 if (priv->module == NULL)
1425 return TRUE;
1426
Richard Hughes46487c92017-01-07 21:26:34 +00001427 /* optional */
1428 g_module_symbol (priv->module, "fu_plugin_coldplug_prepare", (gpointer *) &func);
1429 if (func == NULL)
1430 return TRUE;
1431 g_debug ("performing coldplug_prepare() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001432 if (!func (self, &error_local)) {
1433 if (error_local == NULL) {
1434 g_critical ("unset error in plugin %s for coldplug_prepare()",
1435 priv->name);
1436 g_set_error_literal (&error_local,
1437 FWUPD_ERROR,
1438 FWUPD_ERROR_INTERNAL,
1439 "unspecified error");
1440 }
1441 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1442 "failed to coldplug_prepare using %s: ",
1443 priv->name);
Richard Hughes46487c92017-01-07 21:26:34 +00001444 return FALSE;
1445 }
1446 return TRUE;
1447}
1448
Mario Limonciello1a680f32019-11-25 19:44:53 -06001449/**
1450 * fu_plugin_runner_coldplug_cleanup:
1451 * @self: a #FuPlugin
1452 * @error: a #GError or NULL
1453 *
1454 * Runs the coldplug_cleanup routine for the plugin
1455 *
1456 * Returns: #TRUE for success, #FALSE for failure
1457 *
1458 * Since: 0.8.0
1459 **/
Richard Hughes46487c92017-01-07 21:26:34 +00001460gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001461fu_plugin_runner_coldplug_cleanup (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001462{
Richard Hughes12724852018-09-04 13:53:44 +01001463 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001464 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001465 g_autoptr(GError) error_local = NULL;
Richard Hughes46487c92017-01-07 21:26:34 +00001466
1467 /* not enabled */
1468 if (!priv->enabled)
1469 return TRUE;
1470
Richard Hughes639da472018-01-06 22:35:04 +00001471 /* no object loaded */
1472 if (priv->module == NULL)
1473 return TRUE;
1474
Richard Hughes46487c92017-01-07 21:26:34 +00001475 /* optional */
1476 g_module_symbol (priv->module, "fu_plugin_coldplug_cleanup", (gpointer *) &func);
1477 if (func == NULL)
1478 return TRUE;
1479 g_debug ("performing coldplug_cleanup() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001480 if (!func (self, &error_local)) {
1481 if (error_local == NULL) {
1482 g_critical ("unset error in plugin %s for coldplug_cleanup()",
1483 priv->name);
1484 g_set_error_literal (&error_local,
1485 FWUPD_ERROR,
1486 FWUPD_ERROR_INTERNAL,
1487 "unspecified error");
1488 }
1489 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1490 "failed to coldplug_cleanup using %s: ",
1491 priv->name);
Richard Hughes46487c92017-01-07 21:26:34 +00001492 return FALSE;
1493 }
1494 return TRUE;
1495}
1496
Mario Limonciello1a680f32019-11-25 19:44:53 -06001497/**
1498 * fu_plugin_runner_composite_prepare:
1499 * @self: a #FuPlugin
1500 * @devices: a #GPtrArray of devices
1501 * @error: a #GError or NULL
1502 *
1503 * Runs the composite_prepare routine for the plugin
1504 *
1505 * Returns: #TRUE for success, #FALSE for failure
1506 *
1507 * Since: 1.0.9
1508 **/
Richard Hughes46487c92017-01-07 21:26:34 +00001509gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001510fu_plugin_runner_composite_prepare (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001511{
Richard Hughes12724852018-09-04 13:53:44 +01001512 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001513 "fu_plugin_composite_prepare",
1514 error);
1515}
1516
Mario Limonciello1a680f32019-11-25 19:44:53 -06001517/**
1518 * fu_plugin_runner_composite_cleanup:
1519 * @self: a #FuPlugin
1520 * @devices: a #GPtrArray of devices
1521 * @error: a #GError or NULL
1522 *
1523 * Runs the composite_cleanup routine for the plugin
1524 *
1525 * Returns: #TRUE for success, #FALSE for failure
1526 *
1527 * Since: 1.0.9
1528 **/
Richard Hughesdbd8c762018-06-15 20:31:40 +01001529gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001530fu_plugin_runner_composite_cleanup (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001531{
Richard Hughes12724852018-09-04 13:53:44 +01001532 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001533 "fu_plugin_composite_cleanup",
1534 error);
1535}
1536
Mario Limonciello1a680f32019-11-25 19:44:53 -06001537/**
1538 * fu_plugin_runner_update_prepare:
1539 * @self: a #FuPlugin
1540 * @error: a #GError or NULL
1541 *
1542 * Runs the update_prepare routine for the plugin
1543 *
1544 * Returns: #TRUE for success, #FALSE for failure
1545 *
1546 * Since: 1.1.2
1547 **/
Richard Hughesdbd8c762018-06-15 20:31:40 +01001548gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001549fu_plugin_runner_update_prepare (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001550 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001551{
Richard Hughes12724852018-09-04 13:53:44 +01001552 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001553 "fu_plugin_update_prepare",
1554 error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001555}
1556
Mario Limonciello1a680f32019-11-25 19:44:53 -06001557/**
1558 * fu_plugin_runner_update_cleanup:
1559 * @self: a #FuPlugin
1560 * @error: a #GError or NULL
1561 *
1562 * Runs the update_cleanup routine for the plugin
1563 *
1564 * Returns: #TRUE for success, #FALSE for failure
1565 *
1566 * Since: 1.1.2
1567 **/
Richard Hughes7b8b2022016-12-12 16:15:03 +00001568gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001569fu_plugin_runner_update_cleanup (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001570 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001571{
Richard Hughes12724852018-09-04 13:53:44 +01001572 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001573 "fu_plugin_update_cleanup",
1574 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001575}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001576
Mario Limonciello1a680f32019-11-25 19:44:53 -06001577/**
1578 * fu_plugin_runner_update_attach:
1579 * @self: a #FuPlugin
1580 * @device: a #FuDevice
1581 * @error: a #GError or NULL
1582 *
1583 * Runs the update_attach routine for the plugin
1584 *
1585 * Returns: #TRUE for success, #FALSE for failure
1586 *
1587 * Since: 1.1.2
1588 **/
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001589gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001590fu_plugin_runner_update_attach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001591{
Richard Hughes12724852018-09-04 13:53:44 +01001592 return fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001593 "fu_plugin_update_attach",
1594 fu_plugin_device_attach,
1595 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001596}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001597
Mario Limonciello1a680f32019-11-25 19:44:53 -06001598/**
1599 * fu_plugin_runner_update_detach:
1600 * @self: a #FuPlugin
1601 * @device: A #FuDevice
1602 * @error: a #GError or NULL
1603 *
1604 * Runs the update_detach routine for the plugin
1605 *
1606 * Returns: #TRUE for success, #FALSE for failure
1607 *
1608 * Since: 1.1.2
1609 **/
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001610gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001611fu_plugin_runner_update_detach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001612{
Richard Hughes12724852018-09-04 13:53:44 +01001613 return fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001614 "fu_plugin_update_detach",
1615 fu_plugin_device_detach,
1616 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001617}
1618
Mario Limonciello1a680f32019-11-25 19:44:53 -06001619/**
1620 * fu_plugin_runner_update_reload:
1621 * @self: a #FuPlugin
1622 * @error: a #GError or NULL
1623 *
1624 * Runs reload routine for a device
1625 *
1626 * Returns: #TRUE for success, #FALSE for failure
1627 *
1628 * Since: 1.1.2
1629 **/
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001630gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001631fu_plugin_runner_update_reload (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001632{
Richard Hughes42f33df2019-10-05 20:52:33 +01001633 FuPluginPrivate *priv = GET_PRIVATE (self);
1634 g_autoptr(FuDeviceLocker) locker = NULL;
1635
1636 /* not enabled */
1637 if (!priv->enabled)
1638 return TRUE;
1639
1640 /* no object loaded */
1641 locker = fu_device_locker_new (device, error);
1642 if (locker == NULL)
1643 return FALSE;
1644 return fu_device_reload (device, error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001645}
1646
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001647/**
1648 * fu_plugin_add_udev_subsystem:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001649 * @self: a #FuPlugin
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001650 * @subsystem: a subsystem name, e.g. `pciport`
1651 *
1652 * Registers the udev subsystem to be watched by the daemon.
1653 *
1654 * Plugins can use this method only in fu_plugin_init()
Mario Limonciello1a680f32019-11-25 19:44:53 -06001655 *
1656 * Since: 1.1.2
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001657 **/
1658void
Richard Hughes12724852018-09-04 13:53:44 +01001659fu_plugin_add_udev_subsystem (FuPlugin *self, const gchar *subsystem)
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001660{
Richard Hughes12724852018-09-04 13:53:44 +01001661 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001662 for (guint i = 0; i < priv->udev_subsystems->len; i++) {
1663 const gchar *subsystem_tmp = g_ptr_array_index (priv->udev_subsystems, i);
1664 if (g_strcmp0 (subsystem_tmp, subsystem) == 0)
1665 return;
1666 }
1667 g_debug ("added udev subsystem watch of %s", subsystem);
1668 g_ptr_array_add (priv->udev_subsystems, g_strdup (subsystem));
1669}
1670
Richard Hughes989acf12019-10-05 20:16:47 +01001671/**
1672 * fu_plugin_set_device_gtype:
1673 * @self: a #FuPlugin
1674 * @device_gtype: a #GType `FU_TYPE_DEVICE`
1675 *
1676 * Sets the device #GType which is used when creating devices.
1677 *
1678 * If this method is used then fu_plugin_usb_device_added() is not called, and
1679 * instead the object is created in the daemon for the plugin.
1680 *
1681 * Plugins can use this method only in fu_plugin_init()
1682 *
1683 * Since: 1.3.3
1684 **/
1685void
1686fu_plugin_set_device_gtype (FuPlugin *self, GType device_gtype)
1687{
1688 FuPluginPrivate *priv = GET_PRIVATE (self);
1689 priv->device_gtype = device_gtype;
1690}
1691
Mario Limonciello1a680f32019-11-25 19:44:53 -06001692/**
1693 * fu_plugin_add_firmware_gtype:
1694 * @self: a #FuPlugin
1695 * @id: A string describing the type
1696 * @gtype: a #GType `FU_TYPE_DEVICE`
1697 *
1698 * Adds a firmware #GType which is used when creating devices.
1699 * *
1700 * Plugins can use this method only in fu_plugin_init()
1701 *
1702 * Since: 1.3.3
1703 **/
Richard Hughes95c98a92019-10-22 16:03:15 +01001704void
1705fu_plugin_add_firmware_gtype (FuPlugin *self, const gchar *id, GType gtype)
1706{
1707 g_signal_emit (self, signals[SIGNAL_ADD_FIRMWARE_GTYPE], 0, id, gtype);
1708}
1709
Richard Hughes989acf12019-10-05 20:16:47 +01001710static gboolean
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001711fu_plugin_check_supported_device (FuPlugin *self, FuDevice *device)
1712{
1713 GPtrArray *instance_ids = fu_device_get_instance_ids (device);
1714 for (guint i = 0; i < instance_ids->len; i++) {
1715 const gchar *instance_id = g_ptr_array_index (instance_ids, i);
1716 g_autofree gchar *guid = fwupd_guid_hash_string (instance_id);
1717 if (fu_plugin_check_supported (self, guid))
1718 return TRUE;
1719 }
1720 return FALSE;
1721}
1722
1723static gboolean
Richard Hughes989acf12019-10-05 20:16:47 +01001724fu_plugin_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error)
1725{
1726 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001727 GType device_gtype = fu_device_get_specialized_gtype (FU_DEVICE (device));
Richard Hughes989acf12019-10-05 20:16:47 +01001728 g_autoptr(FuDevice) dev = NULL;
1729 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001730
1731 /* fall back to plugin default */
1732 if (device_gtype == G_TYPE_INVALID)
1733 device_gtype = priv->device_gtype;
1734
1735 /* create new device and incorporate existing properties */
1736 dev = g_object_new (device_gtype, NULL);
1737 fu_device_incorporate (dev, FU_DEVICE (device));
1738
1739 /* there are a lot of different devices that match, but not all respond
1740 * well to opening -- so limit some ones with issued updates */
1741 if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_ONLY_SUPPORTED)) {
1742 if (!fu_device_probe (dev, error))
1743 return FALSE;
1744 fu_device_convert_instance_ids (dev);
1745 if (!fu_plugin_check_supported_device (self, dev)) {
1746 g_autofree gchar *guids = fu_device_get_guids_as_str (dev);
1747 g_debug ("%s has no updates, so ignoring device", guids);
1748 return TRUE;
1749 }
1750 }
1751
1752 /* open and add */
1753 locker = fu_device_locker_new (dev, error);
1754 if (locker == NULL)
1755 return FALSE;
1756 fu_plugin_device_add (self, dev);
1757 return TRUE;
1758}
1759
1760static gboolean
1761fu_plugin_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error)
1762{
1763 FuPluginPrivate *priv = GET_PRIVATE (self);
1764 GType device_gtype = fu_device_get_specialized_gtype (FU_DEVICE (device));
1765 g_autoptr(FuDevice) dev = NULL;
1766 g_autoptr(FuDeviceLocker) locker = NULL;
1767
1768 /* fall back to plugin default */
1769 if (device_gtype == G_TYPE_INVALID)
1770 device_gtype = priv->device_gtype;
1771
1772 /* create new device and incorporate existing properties */
1773 dev = g_object_new (device_gtype, NULL);
Richard Hughes989acf12019-10-05 20:16:47 +01001774 fu_device_incorporate (FU_DEVICE (dev), FU_DEVICE (device));
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001775
1776 /* there are a lot of different devices that match, but not all respond
1777 * well to opening -- so limit some ones with issued updates */
1778 if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_ONLY_SUPPORTED)) {
1779 if (!fu_device_probe (dev, error))
1780 return FALSE;
1781 fu_device_convert_instance_ids (dev);
1782 if (!fu_plugin_check_supported_device (self, dev)) {
1783 g_autofree gchar *guids = fu_device_get_guids_as_str (dev);
1784 g_debug ("%s has no updates, so ignoring device", guids);
1785 return TRUE;
1786 }
1787 }
1788
1789 /* open and add */
Richard Hughes989acf12019-10-05 20:16:47 +01001790 locker = fu_device_locker_new (dev, error);
1791 if (locker == NULL)
1792 return FALSE;
1793 fu_plugin_device_add (self, FU_DEVICE (dev));
1794 return TRUE;
1795}
1796
Mario Limonciello1a680f32019-11-25 19:44:53 -06001797/**
1798 * fu_plugin_runner_usb_device_added:
1799 * @self: a #FuPlugin
1800 * @device: a #FuUsbDevice
1801 * @error: a #GError or NULL
1802 *
1803 * Call the usb_device_added routine for the plugin
1804 *
1805 * Returns: #TRUE for success, #FALSE for failure
1806 *
1807 * Since: 1.0.2
1808 **/
Richard Hughes104f6512017-11-24 11:44:57 +00001809gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001810fu_plugin_runner_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error)
Richard Hughes104f6512017-11-24 11:44:57 +00001811{
Richard Hughes12724852018-09-04 13:53:44 +01001812 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes104f6512017-11-24 11:44:57 +00001813 FuPluginUsbDeviceAddedFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001814 g_autoptr(GError) error_local = NULL;
Richard Hughes104f6512017-11-24 11:44:57 +00001815
1816 /* not enabled */
1817 if (!priv->enabled)
1818 return TRUE;
Richard Hughes639da472018-01-06 22:35:04 +00001819
1820 /* no object loaded */
Richard Hughes104f6512017-11-24 11:44:57 +00001821 if (priv->module == NULL)
1822 return TRUE;
1823
1824 /* optional */
1825 g_module_symbol (priv->module, "fu_plugin_usb_device_added", (gpointer *) &func);
Richard Hughes989acf12019-10-05 20:16:47 +01001826 if (func == NULL) {
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001827 if (priv->device_gtype != G_TYPE_INVALID ||
1828 fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) {
Mario Limonciello0e500322019-10-17 18:41:04 -05001829 if (!fu_plugin_usb_device_added (self, device, error))
Mario Limoncielloa9be5362019-10-12 13:17:45 -05001830 return FALSE;
Richard Hughes989acf12019-10-05 20:16:47 +01001831 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001832 return TRUE;
Richard Hughes989acf12019-10-05 20:16:47 +01001833 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001834 g_debug ("performing usb_device_added() on %s", priv->name);
1835 if (!func (self, device, &error_local)) {
1836 if (error_local == NULL) {
1837 g_critical ("unset error in plugin %s for usb_device_added()",
1838 priv->name);
1839 g_set_error_literal (&error_local,
1840 FWUPD_ERROR,
1841 FWUPD_ERROR_INTERNAL,
1842 "unspecified error");
1843 }
1844 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1845 "failed to add device using on %s: ",
1846 priv->name);
1847 return FALSE;
Richard Hughes104f6512017-11-24 11:44:57 +00001848 }
1849 return TRUE;
1850}
1851
Mario Limonciello1a680f32019-11-25 19:44:53 -06001852/**
1853 * fu_plugin_runner_udev_device_added:
1854 * @self: a #FuPlugin
1855 * @device: a #FuUdevDevice
1856 * @error: a #GError or NULL
1857 *
1858 * Call the udev_device_added routine for the plugin
1859 *
1860 * Returns: #TRUE for success, #FALSE for failure
1861 *
1862 * Since: 1.0.2
1863 **/
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001864gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001865fu_plugin_runner_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error)
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001866{
Richard Hughes12724852018-09-04 13:53:44 +01001867 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001868 FuPluginUdevDeviceAddedFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001869 g_autoptr(GError) error_local = NULL;
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001870
1871 /* not enabled */
1872 if (!priv->enabled)
1873 return TRUE;
1874
1875 /* no object loaded */
1876 if (priv->module == NULL)
1877 return TRUE;
1878
1879 /* optional */
1880 g_module_symbol (priv->module, "fu_plugin_udev_device_added", (gpointer *) &func);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001881 if (func == NULL) {
1882 if (priv->device_gtype != G_TYPE_INVALID ||
1883 fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) {
Mario Limonciello0e500322019-10-17 18:41:04 -05001884 if (!fu_plugin_udev_device_added (self, device, error))
Mario Limoncielloa9be5362019-10-12 13:17:45 -05001885 return FALSE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001886 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001887 return TRUE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001888 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001889 g_debug ("performing udev_device_added() on %s", priv->name);
1890 if (!func (self, device, &error_local)) {
1891 if (error_local == NULL) {
1892 g_critical ("unset error in plugin %s for udev_device_added()",
1893 priv->name);
1894 g_set_error_literal (&error_local,
1895 FWUPD_ERROR,
1896 FWUPD_ERROR_INTERNAL,
1897 "unspecified error");
1898 }
1899 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1900 "failed to add device using on %s: ",
1901 priv->name);
1902 return FALSE;
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001903 }
1904 return TRUE;
1905}
1906
Mario Limonciello1a680f32019-11-25 19:44:53 -06001907/**
1908 * fu_plugin_runner_udev_device_changed:
1909 * @self: a #FuPlugin
1910 * @device: a #FuUdevDevice
1911 * @error: a #GError or NULL
1912 *
1913 * Call the udev_device_changed routine for the plugin
1914 *
1915 * Returns: #TRUE for success, #FALSE for failure
1916 *
1917 * Since: 1.0.2
1918 **/
Richard Hughes5e952ce2019-08-26 11:09:46 +01001919gboolean
1920fu_plugin_runner_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GError **error)
1921{
1922 FuPluginPrivate *priv = GET_PRIVATE (self);
1923 FuPluginUdevDeviceAddedFunc func = NULL;
1924 g_autoptr(GError) error_local = NULL;
1925
1926 /* not enabled */
1927 if (!priv->enabled)
1928 return TRUE;
1929
1930 /* no object loaded */
1931 if (priv->module == NULL)
1932 return TRUE;
1933
1934 /* optional */
1935 g_module_symbol (priv->module, "fu_plugin_udev_device_changed", (gpointer *) &func);
1936 if (func == NULL)
1937 return TRUE;
1938 g_debug ("performing udev_device_changed() on %s", priv->name);
1939 if (!func (self, device, &error_local)) {
1940 if (error_local == NULL) {
1941 g_critical ("unset error in plugin %s for udev_device_changed()",
1942 priv->name);
1943 g_set_error_literal (&error_local,
1944 FWUPD_ERROR,
1945 FWUPD_ERROR_INTERNAL,
1946 "unspecified error");
1947 }
1948 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1949 "failed to change device on %s: ",
1950 priv->name);
1951 return FALSE;
1952 }
1953 return TRUE;
1954}
1955
Mario Limonciello1a680f32019-11-25 19:44:53 -06001956/**
1957 * fu_plugin_runner_device_removed:
1958 * @self: a #FuPlugin
1959 * @device: a #FuDevice
1960 *
1961 * Call the device_removed routine for the plugin
1962 *
1963 * Since: 1.1.2
1964 **/
Richard Hughese1fd34d2017-08-24 14:19:51 +01001965void
Richard Hughes12724852018-09-04 13:53:44 +01001966fu_plugin_runner_device_removed (FuPlugin *self, FuDevice *device)
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001967{
1968 g_autoptr(GError) error_local= NULL;
1969
Richard Hughes12724852018-09-04 13:53:44 +01001970 if (!fu_plugin_runner_device_generic (self, device,
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001971 "fu_plugin_device_removed",
Richard Hughes4b303802019-10-04 13:22:51 +01001972 NULL,
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001973 &error_local))
1974 g_warning ("%s", error_local->message);
1975}
1976
Mario Limonciello1a680f32019-11-25 19:44:53 -06001977/**
1978 * fu_plugin_runner_device_register:
1979 * @self: a #FuPlugin
1980 * @device: a #FuDevice
1981 *
1982 * Call the device_registered routine for the plugin
1983 *
1984 * Since: 0.9.7
1985 **/
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001986void
Richard Hughes12724852018-09-04 13:53:44 +01001987fu_plugin_runner_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +01001988{
Richard Hughes12724852018-09-04 13:53:44 +01001989 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughese1fd34d2017-08-24 14:19:51 +01001990 FuPluginDeviceRegisterFunc func = NULL;
1991
1992 /* not enabled */
1993 if (!priv->enabled)
1994 return;
Richard Hughes34834102017-11-21 21:55:00 +00001995 if (priv->module == NULL)
1996 return;
Richard Hughese1fd34d2017-08-24 14:19:51 +01001997
Mario Limonciello4910b242018-06-22 15:04:21 -05001998 /* don't notify plugins on their own devices */
Richard Hughes12724852018-09-04 13:53:44 +01001999 if (g_strcmp0 (fu_device_get_plugin (device), fu_plugin_get_name (self)) == 0)
Mario Limonciello4910b242018-06-22 15:04:21 -05002000 return;
2001
Richard Hughese1fd34d2017-08-24 14:19:51 +01002002 /* optional */
2003 g_module_symbol (priv->module, "fu_plugin_device_registered", (gpointer *) &func);
2004 if (func != NULL) {
Richard Hughes1bf7ff92018-08-24 20:21:35 +01002005 g_debug ("performing fu_plugin_device_registered() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01002006 func (self, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +01002007 }
2008}
2009
Mario Limonciello1a680f32019-11-25 19:44:53 -06002010/**
2011 * fu_plugin_runner_schedule_update:
2012 * @self: a #FuPlugin
2013 * @device: a #FuDevice
2014 * @release: A #FwupdRelease
2015 * @blob_cab: A #GBytes
2016 * @flags: #FwupdInstallFlags
2017 * @error: A #GError or NULL
2018 *
2019 * Schedule an offline update with the plugin
2020 *
2021 * Returns: #TRUE for success, #FALSE for failure
2022 *
2023 * Since: 0.8.0
2024 **/
Richard Hughesc6c312f2019-02-01 16:37:14 +00002025gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002026fu_plugin_runner_schedule_update (FuPlugin *self,
Mario Limonciello1a680f32019-11-25 19:44:53 -06002027 FuDevice *device,
2028 FwupdRelease *release,
2029 GBytes *blob_cab,
2030 FwupdInstallFlags flags,
2031 GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00002032{
Richard Hughes0a906262019-05-16 13:38:47 +01002033 gchar tmpname[] = {"XXXXXX.cab"};
Richard Hughescff38bc2016-12-12 12:03:37 +00002034 g_autofree gchar *dirname = NULL;
2035 g_autofree gchar *filename = NULL;
Richard Hughes780ef3f2018-01-12 16:20:31 +00002036 g_autoptr(FuHistory) history = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002037 g_autoptr(GFile) file = NULL;
2038
2039 /* id already exists */
Richard Hughes780ef3f2018-01-12 16:20:31 +00002040 history = fu_history_new ();
Richard Hughes5cbb5cf2019-04-26 16:48:03 +01002041 if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) {
2042 g_autoptr(FuDevice) res_tmp = NULL;
2043 res_tmp = fu_history_get_device_by_id (history, fu_device_get_id (device), NULL);
2044 if (res_tmp != NULL &&
2045 fu_device_get_update_state (res_tmp) == FWUPD_UPDATE_STATE_PENDING) {
2046 g_set_error (error,
2047 FWUPD_ERROR,
2048 FWUPD_ERROR_ALREADY_PENDING,
2049 "%s is already scheduled to be updated",
2050 fu_device_get_id (device));
2051 return FALSE;
2052 }
Richard Hughescff38bc2016-12-12 12:03:37 +00002053 }
2054
2055 /* create directory */
Richard Hughes4be17d12018-05-30 20:36:29 +01002056 dirname = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG);
Richard Hughescff38bc2016-12-12 12:03:37 +00002057 file = g_file_new_for_path (dirname);
2058 if (!g_file_query_exists (file, NULL)) {
2059 if (!g_file_make_directory_with_parents (file, NULL, error))
2060 return FALSE;
2061 }
2062
2063 /* get a random filename */
2064 for (guint i = 0; i < 6; i++)
2065 tmpname[i] = (gchar) g_random_int_range ('A', 'Z');
2066 filename = g_build_filename (dirname, tmpname, NULL);
2067
2068 /* just copy to the temp file */
Richard Hughes23135eb2017-11-30 21:01:25 +00002069 fu_device_set_status (device, FWUPD_STATUS_SCHEDULING);
Richard Hughescff38bc2016-12-12 12:03:37 +00002070 if (!g_file_set_contents (filename,
2071 g_bytes_get_data (blob_cab, NULL),
2072 (gssize) g_bytes_get_size (blob_cab),
2073 error))
2074 return FALSE;
2075
2076 /* schedule for next boot */
2077 g_debug ("schedule %s to be installed to %s on next boot",
2078 filename, fu_device_get_id (device));
Richard Hughes994b4d92019-03-25 14:28:30 +00002079 fwupd_release_set_filename (release, filename);
Richard Hughescff38bc2016-12-12 12:03:37 +00002080
2081 /* add to database */
Richard Hughes809abea2019-03-23 11:06:18 +00002082 fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT);
Richard Hughes3e90a582018-01-06 22:38:09 +00002083 fu_device_set_update_state (device, FWUPD_UPDATE_STATE_PENDING);
Richard Hughes994b4d92019-03-25 14:28:30 +00002084 if (!fu_history_add_device (history, device, release, error))
Richard Hughescff38bc2016-12-12 12:03:37 +00002085 return FALSE;
2086
2087 /* next boot we run offline */
Richard Hughesdb69c812019-03-22 16:10:15 +00002088 fu_device_set_progress (device, 100);
Richard Hughescff38bc2016-12-12 12:03:37 +00002089 return fu_plugin_runner_offline_setup (error);
2090}
2091
Mario Limonciello1a680f32019-11-25 19:44:53 -06002092/**
2093 * fu_plugin_runner_verify:
2094 * @self: a #FuPlugin
2095 * @device: a #FuDevice
2096 * @flags: #FuPluginVerifyFlags
2097 * @error: A #GError or NULL
2098 *
2099 * Call into the plugin's verify routine
2100 *
2101 * Returns: #TRUE for success, #FALSE for failure
2102 *
2103 * Since: 0.8.0
2104 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002105gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002106fu_plugin_runner_verify (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +00002107 FuDevice *device,
2108 FuPluginVerifyFlags flags,
2109 GError **error)
2110{
Richard Hughes12724852018-09-04 13:53:44 +01002111 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00002112 FuPluginVerifyFunc func = NULL;
Richard Hughesababbb72017-06-15 20:18:36 +01002113 GPtrArray *checksums;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002114 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002115
2116 /* not enabled */
2117 if (!priv->enabled)
2118 return TRUE;
2119
Richard Hughes639da472018-01-06 22:35:04 +00002120 /* no object loaded */
2121 if (priv->module == NULL)
2122 return TRUE;
2123
Richard Hughescff38bc2016-12-12 12:03:37 +00002124 /* optional */
2125 g_module_symbol (priv->module, "fu_plugin_verify", (gpointer *) &func);
Richard Hughes7f677212019-10-05 16:19:40 +01002126 if (func == NULL) {
Richard Hughes7f677212019-10-05 16:19:40 +01002127 return fu_plugin_device_read_firmware (self, device, error);
2128 }
Richard Hughes1812fc72018-12-14 11:37:54 +00002129
2130 /* clear any existing verification checksums */
2131 checksums = fu_device_get_checksums (device);
2132 g_ptr_array_set_size (checksums, 0);
2133
Richard Hughesc9223be2019-03-18 08:46:42 +00002134 /* run additional detach */
2135 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01002136 "fu_plugin_update_detach",
Richard Hughes4b303802019-10-04 13:22:51 +01002137 fu_plugin_device_detach,
Richard Hughesc9223be2019-03-18 08:46:42 +00002138 error))
2139 return FALSE;
2140
Richard Hughes1812fc72018-12-14 11:37:54 +00002141 /* run vfunc */
Richard Hughescff38bc2016-12-12 12:03:37 +00002142 g_debug ("performing verify() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002143 if (!func (self, device, flags, &error_local)) {
Richard Hughesc9223be2019-03-18 08:46:42 +00002144 g_autoptr(GError) error_attach = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002145 if (error_local == NULL) {
2146 g_critical ("unset error in plugin %s for verify()",
2147 priv->name);
2148 g_set_error_literal (&error_local,
2149 FWUPD_ERROR,
2150 FWUPD_ERROR_INTERNAL,
2151 "unspecified error");
2152 }
2153 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2154 "failed to verify using %s: ",
2155 priv->name);
Richard Hughesc9223be2019-03-18 08:46:42 +00002156 /* make the device "work" again, but don't prefix the error */
2157 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01002158 "fu_plugin_update_attach",
Richard Hughes4b303802019-10-04 13:22:51 +01002159 fu_plugin_device_attach,
Richard Hughesc9223be2019-03-18 08:46:42 +00002160 &error_attach)) {
2161 g_warning ("failed to attach whilst aborting verify(): %s",
2162 error_attach->message);
2163 }
Richard Hughesd0905142016-03-13 09:46:49 +00002164 return FALSE;
2165 }
Richard Hughesc9223be2019-03-18 08:46:42 +00002166
2167 /* run optional attach */
2168 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01002169 "fu_plugin_update_attach",
Richard Hughes4b303802019-10-04 13:22:51 +01002170 fu_plugin_device_attach,
Richard Hughesc9223be2019-03-18 08:46:42 +00002171 error))
2172 return FALSE;
2173
2174 /* success */
Richard Hughesd0905142016-03-13 09:46:49 +00002175 return TRUE;
2176}
2177
Mario Limonciello1a680f32019-11-25 19:44:53 -06002178/**
2179 * fu_plugin_runner_activate:
2180 * @self: a #FuPlugin
2181 * @device: a #FuDevice
2182 * @error: A #GError or NULL
2183 *
2184 * Call into the plugin's activate routine
2185 *
2186 * Returns: #TRUE for success, #FALSE for failure
2187 *
2188 * Since: 1.2.6
2189 **/
Richard Hughesd0905142016-03-13 09:46:49 +00002190gboolean
Mario Limonciello96a0dd52019-02-25 13:50:03 -06002191fu_plugin_runner_activate (FuPlugin *self, FuDevice *device, GError **error)
2192{
2193 guint64 flags;
2194
2195 /* final check */
2196 flags = fu_device_get_flags (device);
2197 if ((flags & FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION) == 0) {
2198 g_set_error (error,
2199 FWUPD_ERROR,
2200 FWUPD_ERROR_NOT_SUPPORTED,
2201 "Device %s does not need activation",
2202 fu_device_get_id (device));
2203 return FALSE;
2204 }
2205
2206 /* run vfunc */
2207 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01002208 "fu_plugin_activate",
2209 fu_plugin_device_activate,
2210 error))
Mario Limonciello96a0dd52019-02-25 13:50:03 -06002211 return FALSE;
2212
2213 /* update with correct flags */
2214 fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION);
2215 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
2216 return TRUE;
2217}
2218
Mario Limonciello1a680f32019-11-25 19:44:53 -06002219/**
2220 * fu_plugin_runner_unlock:
2221 * @self: a #FuPlugin
2222 * @device: a #FuDevice
2223 * @error: A #GError or NULL
2224 *
2225 * Call into the plugin's unlock routine
2226 *
2227 * Returns: #TRUE for success, #FALSE for failure
2228 *
2229 * Since: 0.8.0
2230 **/
Mario Limonciello96a0dd52019-02-25 13:50:03 -06002231gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002232fu_plugin_runner_unlock (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00002233{
Richard Hughescff38bc2016-12-12 12:03:37 +00002234 guint64 flags;
Richard Hughescff38bc2016-12-12 12:03:37 +00002235
2236 /* final check */
2237 flags = fu_device_get_flags (device);
2238 if ((flags & FWUPD_DEVICE_FLAG_LOCKED) == 0) {
2239 g_set_error (error,
2240 FWUPD_ERROR,
2241 FWUPD_ERROR_NOT_SUPPORTED,
2242 "Device %s is not locked",
2243 fu_device_get_id (device));
2244 return FALSE;
2245 }
2246
Richard Hughes9c4b5312017-11-14 11:34:53 +00002247 /* run vfunc */
Richard Hughes12724852018-09-04 13:53:44 +01002248 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01002249 "fu_plugin_unlock",
2250 NULL,
2251 error))
Richard Hughes9c4b5312017-11-14 11:34:53 +00002252 return FALSE;
Richard Hughescff38bc2016-12-12 12:03:37 +00002253
2254 /* update with correct flags */
2255 flags = fu_device_get_flags (device);
2256 fu_device_set_flags (device, flags &= ~FWUPD_DEVICE_FLAG_LOCKED);
2257 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
2258 return TRUE;
2259}
2260
Mario Limonciello1a680f32019-11-25 19:44:53 -06002261/**
2262 * fu_plugin_runner_update:
2263 * @self: a #FuPlugin
2264 * @device: a #FuDevice
2265 * @blob_fw: A #GBytes
2266 * @flags: A #FwupdInstallFlags
2267 * @error: A #GError or NULL
2268 *
2269 * Call into the plugin's update routine
2270 *
2271 * Returns: #TRUE for success, #FALSE for failure
2272 *
2273 * Since: 0.8.0
2274 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002275gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002276fu_plugin_runner_update (FuPlugin *self,
Richard Hughesa785a1c2017-08-25 16:00:58 +01002277 FuDevice *device,
Richard Hughesa785a1c2017-08-25 16:00:58 +01002278 GBytes *blob_fw,
2279 FwupdInstallFlags flags,
2280 GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00002281{
Richard Hughes12724852018-09-04 13:53:44 +01002282 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesa785a1c2017-08-25 16:00:58 +01002283 FuPluginUpdateFunc update_func;
Richard Hughes780ef3f2018-01-12 16:20:31 +00002284 g_autoptr(FuHistory) history = NULL;
Richard Hughes68982c62017-09-13 15:40:14 +01002285 g_autoptr(FuDevice) device_pending = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002286 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002287
2288 /* not enabled */
Richard Hughes41c15482018-02-01 22:07:21 +00002289 if (!priv->enabled) {
2290 g_debug ("plugin not enabled, skipping");
Richard Hughesd0905142016-03-13 09:46:49 +00002291 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00002292 }
Richard Hughesd0905142016-03-13 09:46:49 +00002293
Richard Hughes639da472018-01-06 22:35:04 +00002294 /* no object loaded */
Richard Hughes41c15482018-02-01 22:07:21 +00002295 if (priv->module == NULL) {
2296 g_debug ("module not enabled, skipping");
Richard Hughes639da472018-01-06 22:35:04 +00002297 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00002298 }
Richard Hughes639da472018-01-06 22:35:04 +00002299
Richard Hughesd0905142016-03-13 09:46:49 +00002300 /* optional */
Richard Hughesa785a1c2017-08-25 16:00:58 +01002301 g_module_symbol (priv->module, "fu_plugin_update", (gpointer *) &update_func);
2302 if (update_func == NULL) {
Richard Hughes4b303802019-10-04 13:22:51 +01002303 g_debug ("running superclassed write_firmware() on %s", priv->name);
2304 return fu_plugin_device_write_firmware (self, device, blob_fw, flags, error);
Richard Hughesa785a1c2017-08-25 16:00:58 +01002305 }
Richard Hughesd0905142016-03-13 09:46:49 +00002306
Richard Hughescff38bc2016-12-12 12:03:37 +00002307 /* cancel the pending action */
2308 if (!fu_plugin_runner_offline_invalidate (error))
2309 return FALSE;
2310
2311 /* online */
Richard Hughes780ef3f2018-01-12 16:20:31 +00002312 history = fu_history_new ();
Richard Hughes0b9d9962018-01-12 16:31:28 +00002313 device_pending = fu_history_get_device_by_id (history, fu_device_get_id (device), NULL);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002314 if (!update_func (self, device, blob_fw, flags, &error_local)) {
2315 if (error_local == NULL) {
2316 g_critical ("unset error in plugin %s for update()",
2317 priv->name);
2318 g_set_error_literal (&error_local,
Richard Hughes3c8ada32018-10-12 10:08:58 +01002319 FWUPD_ERROR,
2320 FWUPD_ERROR_INTERNAL,
2321 "unspecified error");
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002322 return FALSE;
Richard Hughes3c8ada32018-10-12 10:08:58 +01002323 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002324 fu_device_set_update_error (device, error_local->message);
2325 g_propagate_error (error, g_steal_pointer (&error_local));
Richard Hughescff38bc2016-12-12 12:03:37 +00002326 return FALSE;
2327 }
2328
Richard Hughesf556d372017-06-15 19:49:18 +01002329 /* no longer valid */
Richard Hughesf8039642019-01-16 12:22:22 +00002330 if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT) &&
2331 !fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) {
Richard Hughes08435162018-12-12 10:34:16 +00002332 GPtrArray *checksums = fu_device_get_checksums (device);
2333 g_ptr_array_set_size (checksums, 0);
2334 }
Richard Hughesf556d372017-06-15 19:49:18 +01002335
Richard Hughescff38bc2016-12-12 12:03:37 +00002336 /* cleanup */
Richard Hughes68982c62017-09-13 15:40:14 +01002337 if (device_pending != NULL) {
Richard Hughescff38bc2016-12-12 12:03:37 +00002338 const gchar *tmp;
Richard Hughesbc3a4e12018-01-06 22:41:47 +00002339 FwupdRelease *release;
Richard Hughescff38bc2016-12-12 12:03:37 +00002340
Richard Hughes780ef3f2018-01-12 16:20:31 +00002341 /* update history database */
Richard Hughesc0cd0232018-01-31 15:02:00 +00002342 fu_device_set_update_state (device, FWUPD_UPDATE_STATE_SUCCESS);
Richard Hughes0bbef292019-11-01 12:15:15 +00002343 if (!fu_history_modify_device (history, device, error))
Richard Hughes0b9d9962018-01-12 16:31:28 +00002344 return FALSE;
Richard Hughescff38bc2016-12-12 12:03:37 +00002345
2346 /* delete cab file */
Richard Hughesbc3a4e12018-01-06 22:41:47 +00002347 release = fu_device_get_release_default (device_pending);
2348 tmp = fwupd_release_get_filename (release);
Richard Hughes668ee212019-11-22 09:17:46 +00002349 if (tmp != NULL && g_str_has_prefix (tmp, FWUPD_LIBEXECDIR)) {
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002350 g_autoptr(GError) error_delete = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002351 g_autoptr(GFile) file = NULL;
2352 file = g_file_new_for_path (tmp);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002353 if (!g_file_delete (file, NULL, &error_delete)) {
Richard Hughescff38bc2016-12-12 12:03:37 +00002354 g_set_error (error,
2355 FWUPD_ERROR,
2356 FWUPD_ERROR_INVALID_FILE,
2357 "Failed to delete %s: %s",
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002358 tmp, error_delete->message);
Richard Hughescff38bc2016-12-12 12:03:37 +00002359 return FALSE;
2360 }
2361 }
2362 }
Richard Hughesd0905142016-03-13 09:46:49 +00002363 return TRUE;
2364}
Richard Hughescff38bc2016-12-12 12:03:37 +00002365
Mario Limonciello1a680f32019-11-25 19:44:53 -06002366/**
2367 * fu_plugin_runner_clear_results:
2368 * @self: a #FuPlugin
2369 * @device: a #FuDevice
2370 * @error: A #GError or NULL
2371 *
2372 * Call into the plugin's clear results routine
2373 *
2374 * Returns: #TRUE for success, #FALSE for failure
2375 *
2376 * Since: 0.8.0
2377 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002378gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002379fu_plugin_runner_clear_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00002380{
Richard Hughes12724852018-09-04 13:53:44 +01002381 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00002382 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002383 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002384
2385 /* not enabled */
2386 if (!priv->enabled)
2387 return TRUE;
2388
Richard Hughes639da472018-01-06 22:35:04 +00002389 /* no object loaded */
2390 if (priv->module == NULL)
2391 return TRUE;
2392
Richard Hughes65e44ca2018-01-30 17:26:30 +00002393 /* optional */
Richard Hughescd644902019-11-01 12:35:17 +00002394 g_module_symbol (priv->module, "fu_plugin_clear_results", (gpointer *) &func);
Richard Hughes65e44ca2018-01-30 17:26:30 +00002395 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00002396 return TRUE;
Richard Hughes65e44ca2018-01-30 17:26:30 +00002397 g_debug ("performing clear_result() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002398 if (!func (self, device, &error_local)) {
2399 if (error_local == NULL) {
2400 g_critical ("unset error in plugin %s for clear_result()",
2401 priv->name);
2402 g_set_error_literal (&error_local,
2403 FWUPD_ERROR,
2404 FWUPD_ERROR_INTERNAL,
2405 "unspecified error");
2406 }
2407 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2408 "failed to clear_result using %s: ",
2409 priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00002410 return FALSE;
2411 }
Richard Hughes65e44ca2018-01-30 17:26:30 +00002412 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00002413}
2414
Mario Limonciello1a680f32019-11-25 19:44:53 -06002415/**
2416 * fu_plugin_runner_get_results:
2417 * @self: a #FuPlugin
2418 * @device: a #FuDevice
2419 * @error: A #GError or NULL
2420 *
2421 * Call into the plugin's get results routine
2422 *
2423 * Returns: #TRUE for success, #FALSE for failure
2424 *
2425 * Since: 0.8.0
2426 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002427gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002428fu_plugin_runner_get_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00002429{
Richard Hughes12724852018-09-04 13:53:44 +01002430 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00002431 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002432 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002433
2434 /* not enabled */
2435 if (!priv->enabled)
2436 return TRUE;
2437
Richard Hughes639da472018-01-06 22:35:04 +00002438 /* no object loaded */
2439 if (priv->module == NULL)
2440 return TRUE;
2441
Richard Hughes65e44ca2018-01-30 17:26:30 +00002442 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00002443 g_module_symbol (priv->module, "fu_plugin_get_results", (gpointer *) &func);
Richard Hughes65e44ca2018-01-30 17:26:30 +00002444 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00002445 return TRUE;
Richard Hughes65e44ca2018-01-30 17:26:30 +00002446 g_debug ("performing get_results() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002447 if (!func (self, device, &error_local)) {
2448 if (error_local == NULL) {
2449 g_critical ("unset error in plugin %s for get_results()",
2450 priv->name);
2451 g_set_error_literal (&error_local,
2452 FWUPD_ERROR,
2453 FWUPD_ERROR_INTERNAL,
2454 "unspecified error");
2455 }
2456 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2457 "failed to get_results using %s: ",
2458 priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00002459 return FALSE;
2460 }
Richard Hughescff38bc2016-12-12 12:03:37 +00002461 return TRUE;
2462}
2463
Richard Hughes08a37992017-09-12 12:57:43 +01002464/**
2465 * fu_plugin_get_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002466 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002467 *
2468 * Gets the plugin order, where higher numbers are run after lower
2469 * numbers.
2470 *
2471 * Returns: the integer value
Mario Limonciello1a680f32019-11-25 19:44:53 -06002472 *
2473 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002474 **/
2475guint
Richard Hughes12724852018-09-04 13:53:44 +01002476fu_plugin_get_order (FuPlugin *self)
Richard Hughes08a37992017-09-12 12:57:43 +01002477{
Richard Hughes12724852018-09-04 13:53:44 +01002478 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002479 return priv->order;
2480}
2481
2482/**
2483 * fu_plugin_set_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002484 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002485 * @order: a integer value
2486 *
2487 * Sets the plugin order, where higher numbers are run after lower
2488 * numbers.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002489 *
2490 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002491 **/
2492void
Richard Hughes12724852018-09-04 13:53:44 +01002493fu_plugin_set_order (FuPlugin *self, guint order)
Richard Hughes08a37992017-09-12 12:57:43 +01002494{
Richard Hughes12724852018-09-04 13:53:44 +01002495 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002496 priv->order = order;
2497}
2498
2499/**
Richard Hughes81c427c2018-08-06 15:20:17 +01002500 * fu_plugin_get_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002501 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01002502 *
2503 * Gets the plugin priority, where higher numbers are better.
2504 *
2505 * Returns: the integer value
Mario Limonciello1a680f32019-11-25 19:44:53 -06002506 *
2507 * Since: 1.1.1
Richard Hughes81c427c2018-08-06 15:20:17 +01002508 **/
2509guint
Richard Hughes12724852018-09-04 13:53:44 +01002510fu_plugin_get_priority (FuPlugin *self)
Richard Hughes81c427c2018-08-06 15:20:17 +01002511{
Richard Hughes12724852018-09-04 13:53:44 +01002512 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01002513 return priv->priority;
2514}
2515
2516/**
2517 * fu_plugin_set_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002518 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01002519 * @priority: a integer value
2520 *
2521 * Sets the plugin priority, where higher numbers are better.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002522 *
2523 * Since: 1.0.0
Richard Hughes81c427c2018-08-06 15:20:17 +01002524 **/
2525void
Richard Hughes12724852018-09-04 13:53:44 +01002526fu_plugin_set_priority (FuPlugin *self, guint priority)
Richard Hughes81c427c2018-08-06 15:20:17 +01002527{
Richard Hughes12724852018-09-04 13:53:44 +01002528 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01002529 priv->priority = priority;
2530}
2531
2532/**
Richard Hughes08a37992017-09-12 12:57:43 +01002533 * fu_plugin_add_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002534 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002535 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
Richard Hughes4eada342017-10-03 21:20:32 +01002536 * @name: a plugin name, e.g. `upower`
Richard Hughes08a37992017-09-12 12:57:43 +01002537 *
2538 * If the plugin name is found, the rule will be used to sort the plugin list,
2539 * for example the plugin specified by @name will be ordered after this plugin
2540 * when %FU_PLUGIN_RULE_RUN_AFTER is used.
2541 *
2542 * NOTE: The depsolver is iterative and may not solve overly-complicated rules;
2543 * If depsolving fails then fwupd will not start.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002544 *
2545 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002546 **/
2547void
Richard Hughes12724852018-09-04 13:53:44 +01002548fu_plugin_add_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes08a37992017-09-12 12:57:43 +01002549{
Richard Hughes12724852018-09-04 13:53:44 +01002550 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002551 g_ptr_array_add (priv->rules[rule], g_strdup (name));
Richard Hughes75b965d2018-11-15 13:51:21 +00002552 g_signal_emit (self, signals[SIGNAL_RULES_CHANGED], 0);
Richard Hughes08a37992017-09-12 12:57:43 +01002553}
2554
2555/**
2556 * fu_plugin_get_rules:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002557 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002558 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
2559 *
2560 * Gets the plugin IDs that should be run after this plugin.
2561 *
2562 * Returns: (element-type utf8) (transfer none): the list of plugin names, e.g. ['appstream']
Mario Limonciello1a680f32019-11-25 19:44:53 -06002563 *
2564 * Since: 1.0.0
Richard Hughes08a37992017-09-12 12:57:43 +01002565 **/
2566GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +01002567fu_plugin_get_rules (FuPlugin *self, FuPluginRule rule)
Richard Hughes08a37992017-09-12 12:57:43 +01002568{
Richard Hughes12724852018-09-04 13:53:44 +01002569 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002570 return priv->rules[rule];
2571}
2572
Richard Hughes80b79bb2018-01-11 21:11:06 +00002573/**
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002574 * fu_plugin_has_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002575 * @self: a #FuPlugin
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002576 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
2577 * @name: a plugin name, e.g. `upower`
2578 *
Richard Hughes87fb9ff2018-06-28 12:55:59 +01002579 * Gets the plugin IDs that should be run after this plugin.
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002580 *
2581 * Returns: %TRUE if the name exists for the specific rule
Mario Limonciello1a680f32019-11-25 19:44:53 -06002582 *
2583 * Since: 1.0.0
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002584 **/
2585gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002586fu_plugin_has_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002587{
Richard Hughes12724852018-09-04 13:53:44 +01002588 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002589 for (guint i = 0; i < priv->rules[rule]->len; i++) {
2590 const gchar *tmp = g_ptr_array_index (priv->rules[rule], i);
2591 if (g_strcmp0 (tmp, name) == 0)
2592 return TRUE;
2593 }
2594 return FALSE;
2595}
2596
2597/**
Richard Hughes80b79bb2018-01-11 21:11:06 +00002598 * fu_plugin_add_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002599 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00002600 * @key: a string, e.g. `FwupdateVersion`
2601 * @value: a string, e.g. `10`
2602 *
2603 * Sets any additional metadata to be included in the firmware report to aid
2604 * debugging problems.
2605 *
2606 * Any data included here will be sent to the metadata server after user
2607 * confirmation.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002608 *
2609 * Since: 1.0.4
Richard Hughes80b79bb2018-01-11 21:11:06 +00002610 **/
2611void
Richard Hughes12724852018-09-04 13:53:44 +01002612fu_plugin_add_report_metadata (FuPlugin *self, const gchar *key, const gchar *value)
Richard Hughes80b79bb2018-01-11 21:11:06 +00002613{
Richard Hughes12724852018-09-04 13:53:44 +01002614 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002615 g_hash_table_insert (priv->report_metadata, g_strdup (key), g_strdup (value));
2616}
2617
2618/**
2619 * fu_plugin_get_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002620 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00002621 *
2622 * Returns the list of additional metadata to be added when filing a report.
2623 *
2624 * Returns: (transfer none): the map of report metadata
Mario Limonciello1a680f32019-11-25 19:44:53 -06002625 *
2626 * Since: 1.0.4
Richard Hughes80b79bb2018-01-11 21:11:06 +00002627 **/
2628GHashTable *
Richard Hughes12724852018-09-04 13:53:44 +01002629fu_plugin_get_report_metadata (FuPlugin *self)
Richard Hughes80b79bb2018-01-11 21:11:06 +00002630{
Richard Hughes12724852018-09-04 13:53:44 +01002631 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002632 return priv->report_metadata;
2633}
2634
Mario Limonciello963dc422018-02-27 14:26:58 -06002635/**
2636 * fu_plugin_get_config_value:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002637 * @self: a #FuPlugin
Mario Limonciello963dc422018-02-27 14:26:58 -06002638 * @key: A settings key
2639 *
2640 * Return the value of a key if it's been configured
2641 *
2642 * Since: 1.0.6
2643 **/
2644gchar *
Richard Hughes12724852018-09-04 13:53:44 +01002645fu_plugin_get_config_value (FuPlugin *self, const gchar *key)
Mario Limonciello963dc422018-02-27 14:26:58 -06002646{
Richard Hughes4be17d12018-05-30 20:36:29 +01002647 g_autofree gchar *conf_dir = NULL;
Mario Limonciello963dc422018-02-27 14:26:58 -06002648 g_autofree gchar *conf_file = NULL;
2649 g_autofree gchar *conf_path = NULL;
2650 g_autoptr(GKeyFile) keyfile = NULL;
2651 const gchar *plugin_name;
2652
Richard Hughes4be17d12018-05-30 20:36:29 +01002653 conf_dir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR_PKG);
Richard Hughes12724852018-09-04 13:53:44 +01002654 plugin_name = fu_plugin_get_name (self);
Mario Limonciello963dc422018-02-27 14:26:58 -06002655 conf_file = g_strdup_printf ("%s.conf", plugin_name);
Richard Hughes4be17d12018-05-30 20:36:29 +01002656 conf_path = g_build_filename (conf_dir, conf_file, NULL);
Mario Limonciello963dc422018-02-27 14:26:58 -06002657 if (!g_file_test (conf_path, G_FILE_TEST_IS_REGULAR))
2658 return NULL;
2659 keyfile = g_key_file_new ();
2660 if (!g_key_file_load_from_file (keyfile, conf_path,
2661 G_KEY_FILE_NONE, NULL))
2662 return NULL;
2663 return g_key_file_get_string (keyfile, plugin_name, key, NULL);
2664}
2665
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002666/**
2667 * fu_plugin_name_compare:
2668 * @plugin1: first #FuPlugin to compare.
2669 * @plugin2: second #FuPlugin to compare.
2670 *
2671 * Compares two plugins by their names.
2672 *
2673 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002674 *
2675 * Since: 1.0.8
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002676 **/
2677gint
2678fu_plugin_name_compare (FuPlugin *plugin1, FuPlugin *plugin2)
2679{
2680 FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1);
2681 FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2);
2682 return g_strcmp0 (priv1->name, priv2->name);
2683}
2684
2685/**
2686 * fu_plugin_order_compare:
2687 * @plugin1: first #FuPlugin to compare.
2688 * @plugin2: second #FuPlugin to compare.
2689 *
2690 * Compares two plugins by their depsolved order.
2691 *
2692 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
Mario Limonciello1a680f32019-11-25 19:44:53 -06002693 *
2694 * Since: 1.0.8
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002695 **/
2696gint
2697fu_plugin_order_compare (FuPlugin *plugin1, FuPlugin *plugin2)
2698{
2699 FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1);
2700 FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2);
2701 if (priv1->order < priv2->order)
2702 return -1;
2703 if (priv1->order > priv2->order)
2704 return 1;
2705 return 0;
2706}
2707
Richard Hughescff38bc2016-12-12 12:03:37 +00002708static void
2709fu_plugin_class_init (FuPluginClass *klass)
2710{
2711 GObjectClass *object_class = G_OBJECT_CLASS (klass);
2712 object_class->finalize = fu_plugin_finalize;
2713 signals[SIGNAL_DEVICE_ADDED] =
2714 g_signal_new ("device-added",
2715 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2716 G_STRUCT_OFFSET (FuPluginClass, device_added),
2717 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2718 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
2719 signals[SIGNAL_DEVICE_REMOVED] =
2720 g_signal_new ("device-removed",
2721 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2722 G_STRUCT_OFFSET (FuPluginClass, device_removed),
2723 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2724 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughese1fd34d2017-08-24 14:19:51 +01002725 signals[SIGNAL_DEVICE_REGISTER] =
2726 g_signal_new ("device-register",
2727 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2728 G_STRUCT_OFFSET (FuPluginClass, device_register),
2729 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2730 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughes362d6d72017-01-07 21:42:14 +00002731 signals[SIGNAL_RECOLDPLUG] =
2732 g_signal_new ("recoldplug",
2733 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2734 G_STRUCT_OFFSET (FuPluginClass, recoldplug),
2735 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2736 G_TYPE_NONE, 0);
Richard Hughesb0829032017-01-10 09:27:08 +00002737 signals[SIGNAL_SET_COLDPLUG_DELAY] =
2738 g_signal_new ("set-coldplug-delay",
2739 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2740 G_STRUCT_OFFSET (FuPluginClass, set_coldplug_delay),
2741 NULL, NULL, g_cclosure_marshal_VOID__UINT,
2742 G_TYPE_NONE, 1, G_TYPE_UINT);
Richard Hughesaabdc372018-11-14 10:11:08 +00002743 signals[SIGNAL_CHECK_SUPPORTED] =
2744 g_signal_new ("check-supported",
2745 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2746 G_STRUCT_OFFSET (FuPluginClass, check_supported),
2747 NULL, NULL, g_cclosure_marshal_generic,
2748 G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
Richard Hughes75b965d2018-11-15 13:51:21 +00002749 signals[SIGNAL_RULES_CHANGED] =
2750 g_signal_new ("rules-changed",
2751 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2752 G_STRUCT_OFFSET (FuPluginClass, rules_changed),
2753 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2754 G_TYPE_NONE, 0);
Richard Hughes95c98a92019-10-22 16:03:15 +01002755 signals[SIGNAL_ADD_FIRMWARE_GTYPE] =
2756 g_signal_new ("add-firmware-gtype",
2757 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2758 G_STRUCT_OFFSET (FuPluginClass, add_firmware_gtype),
2759 NULL, NULL, g_cclosure_marshal_generic,
2760 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_GTYPE);
Richard Hughescff38bc2016-12-12 12:03:37 +00002761}
2762
2763static void
Richard Hughes12724852018-09-04 13:53:44 +01002764fu_plugin_init (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +00002765{
Richard Hughes12724852018-09-04 13:53:44 +01002766 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002767 priv->enabled = TRUE;
Richard Hughesb1065422019-08-15 16:44:34 +01002768 priv->udev_subsystems = g_ptr_array_new_with_free_func (g_free);
Richard Hughescff38bc2016-12-12 12:03:37 +00002769 priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal,
2770 g_free, (GDestroyNotify) g_object_unref);
Richard Hughes161e9b52019-06-12 14:22:45 +01002771 g_rw_lock_init (&priv->devices_mutex);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002772 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 +01002773 for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++)
2774 priv->rules[i] = g_ptr_array_new_with_free_func (g_free);
Richard Hughescff38bc2016-12-12 12:03:37 +00002775}
2776
2777static void
2778fu_plugin_finalize (GObject *object)
2779{
Richard Hughes12724852018-09-04 13:53:44 +01002780 FuPlugin *self = FU_PLUGIN (object);
2781 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002782 FuPluginInitFunc func = NULL;
2783
2784 /* optional */
2785 if (priv->module != NULL) {
2786 g_module_symbol (priv->module, "fu_plugin_destroy", (gpointer *) &func);
2787 if (func != NULL) {
2788 g_debug ("performing destroy() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01002789 func (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002790 }
2791 }
2792
Richard Hughes08a37992017-09-12 12:57:43 +01002793 for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++)
2794 g_ptr_array_unref (priv->rules[i]);
2795
Richard Hughescff38bc2016-12-12 12:03:37 +00002796 if (priv->usb_ctx != NULL)
2797 g_object_unref (priv->usb_ctx);
Richard Hughesb8f8db22017-04-25 15:56:00 +01002798 if (priv->hwids != NULL)
Richard Hughesd7704d42017-08-08 20:29:09 +01002799 g_object_unref (priv->hwids);
Richard Hughes9c028f02017-10-28 21:14:28 +01002800 if (priv->quirks != NULL)
2801 g_object_unref (priv->quirks);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01002802 if (priv->udev_subsystems != NULL)
2803 g_ptr_array_unref (priv->udev_subsystems);
Richard Hughes49e5e052017-09-03 12:15:41 +01002804 if (priv->smbios != NULL)
2805 g_object_unref (priv->smbios);
Richard Hughes275d3b42018-04-20 16:40:37 +01002806 if (priv->runtime_versions != NULL)
2807 g_hash_table_unref (priv->runtime_versions);
Richard Hughes34e0dab2018-04-20 16:43:00 +01002808 if (priv->compile_versions != NULL)
2809 g_hash_table_unref (priv->compile_versions);
Richard Hughescff38bc2016-12-12 12:03:37 +00002810 g_hash_table_unref (priv->devices);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002811 g_hash_table_unref (priv->report_metadata);
Richard Hughes161e9b52019-06-12 14:22:45 +01002812 g_rw_lock_clear (&priv->devices_mutex);
Richard Hughes84999302019-05-02 10:18:32 +01002813 g_free (priv->build_hash);
Richard Hughescff38bc2016-12-12 12:03:37 +00002814 g_free (priv->name);
2815 g_free (priv->data);
Mario Limonciello3f9a1c12018-06-06 14:06:40 -05002816 /* Must happen as the last step to avoid prematurely
2817 * freeing memory held by the plugin */
2818#ifndef RUNNING_ON_VALGRIND
2819 if (priv->module != NULL)
2820 g_module_close (priv->module);
2821#endif
Richard Hughescff38bc2016-12-12 12:03:37 +00002822
2823 G_OBJECT_CLASS (fu_plugin_parent_class)->finalize (object);
2824}
2825
Mario Limonciello1a680f32019-11-25 19:44:53 -06002826/**
2827 * fu_plugin_new:
2828 *
2829 * Creates a new #FuPlugin
2830 *
2831 * Since: 0.8.0
2832 **/
Richard Hughescff38bc2016-12-12 12:03:37 +00002833FuPlugin *
2834fu_plugin_new (void)
2835{
Richard Hughes12724852018-09-04 13:53:44 +01002836 return FU_PLUGIN (g_object_new (FU_TYPE_PLUGIN, NULL));
Richard Hughescff38bc2016-12-12 12:03:37 +00002837}