blob: 1fcb4c443a47aa5715b825f5978993e52eceb5eb [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
Richard Hughes34834102017-11-21 21:55:00 +0000144void
Richard Hughes12724852018-09-04 13:53:44 +0100145fu_plugin_set_name (FuPlugin *self, const gchar *name)
Richard Hughes34834102017-11-21 21:55:00 +0000146{
Richard Hughes12724852018-09-04 13:53:44 +0100147 FuPluginPrivate *priv = GET_PRIVATE (self);
148 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughes34834102017-11-21 21:55:00 +0000149 g_return_if_fail (name != NULL);
150 g_free (priv->name);
151 priv->name = g_strdup (name);
152}
153
Richard Hughes57d18222017-01-10 16:02:59 +0000154/**
Richard Hughesf425d292019-01-18 17:57:39 +0000155 * fu_plugin_set_build_hash:
156 * @self: A #FuPlugin
157 * @build_hash: A checksum
158 *
159 * Sets the plugin build hash, typically a SHA256 checksum. All plugins must
160 * set the correct checksum to avoid the daemon being marked as tainted.
161 *
162 * Since: 1.2.4
163 **/
164void
165fu_plugin_set_build_hash (FuPlugin *self, const gchar *build_hash)
166{
167 FuPluginPrivate *priv = GET_PRIVATE (self);
168 g_return_if_fail (FU_IS_PLUGIN (self));
169 g_return_if_fail (build_hash != NULL);
170 g_free (priv->build_hash);
171 priv->build_hash = g_strdup (build_hash);
172}
173
174const gchar *
175fu_plugin_get_build_hash (FuPlugin *self)
176{
177 FuPluginPrivate *priv = GET_PRIVATE (self);
178 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
179 return priv->build_hash;
180}
181
182/**
Richard Hughes57d18222017-01-10 16:02:59 +0000183 * fu_plugin_cache_lookup:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100184 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000185 * @id: the key
186 *
187 * Finds an object in the per-plugin cache.
188 *
189 * Returns: (transfer none): a #GObject, or %NULL for unfound.
190 *
191 * Since: 0.8.0
192 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000193gpointer
Richard Hughes12724852018-09-04 13:53:44 +0100194fu_plugin_cache_lookup (FuPlugin *self, const gchar *id)
Richard Hughescff38bc2016-12-12 12:03:37 +0000195{
Richard Hughes12724852018-09-04 13:53:44 +0100196 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes161e9b52019-06-12 14:22:45 +0100197 g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100198 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughesccd78a92017-01-11 16:57:41 +0000199 g_return_val_if_fail (id != NULL, NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100200 g_return_val_if_fail (locker != NULL, NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000201 return g_hash_table_lookup (priv->devices, id);
202}
Richard Hughesd0905142016-03-13 09:46:49 +0000203
Richard Hughes57d18222017-01-10 16:02:59 +0000204/**
205 * fu_plugin_cache_add:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100206 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000207 * @id: the key
208 * @dev: a #GObject, typically a #FuDevice
209 *
210 * Adds an object to the per-plugin cache.
211 *
212 * Since: 0.8.0
213 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000214void
Richard Hughes12724852018-09-04 13:53:44 +0100215fu_plugin_cache_add (FuPlugin *self, const gchar *id, gpointer dev)
Richard Hughescff38bc2016-12-12 12:03:37 +0000216{
Richard Hughes12724852018-09-04 13:53:44 +0100217 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0fe49142019-11-22 16:56:38 +0000218 g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100219 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000220 g_return_if_fail (id != NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100221 g_return_if_fail (locker != NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000222 g_hash_table_insert (priv->devices, g_strdup (id), g_object_ref (dev));
223}
224
Richard Hughes57d18222017-01-10 16:02:59 +0000225/**
226 * fu_plugin_cache_remove:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100227 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000228 * @id: the key
229 *
230 * Removes an object from the per-plugin cache.
231 *
232 * Since: 0.8.0
233 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000234void
Richard Hughes12724852018-09-04 13:53:44 +0100235fu_plugin_cache_remove (FuPlugin *self, const gchar *id)
Richard Hughescff38bc2016-12-12 12:03:37 +0000236{
Richard Hughes12724852018-09-04 13:53:44 +0100237 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0fe49142019-11-22 16:56:38 +0000238 g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100239 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000240 g_return_if_fail (id != NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100241 g_return_if_fail (locker != NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000242 g_hash_table_remove (priv->devices, id);
243}
244
Richard Hughes57d18222017-01-10 16:02:59 +0000245/**
246 * fu_plugin_get_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100247 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000248 *
Richard Hughes4eada342017-10-03 21:20:32 +0100249 * Gets the per-plugin allocated private data. This will return %NULL unless
250 * fu_plugin_alloc_data() has been called by the plugin.
Richard Hughes57d18222017-01-10 16:02:59 +0000251 *
Richard Hughes4eada342017-10-03 21:20:32 +0100252 * Returns: (transfer none): a pointer to a structure, or %NULL for unset.
Richard Hughes57d18222017-01-10 16:02:59 +0000253 *
254 * Since: 0.8.0
255 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000256FuPluginData *
Richard Hughes12724852018-09-04 13:53:44 +0100257fu_plugin_get_data (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +0000258{
Richard Hughes12724852018-09-04 13:53:44 +0100259 FuPluginPrivate *priv = GET_PRIVATE (self);
260 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000261 return priv->data;
262}
263
Richard Hughes57d18222017-01-10 16:02:59 +0000264/**
265 * fu_plugin_alloc_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100266 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000267 * @data_sz: the size to allocate
268 *
269 * Allocates the per-plugin allocated private data.
270 *
271 * Returns: (transfer full): a pointer to a structure, or %NULL for unset.
272 *
273 * Since: 0.8.0
274 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000275FuPluginData *
Richard Hughes12724852018-09-04 13:53:44 +0100276fu_plugin_alloc_data (FuPlugin *self, gsize data_sz)
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 Hughes44dee882017-01-11 08:31:10 +0000280 if (priv->data != NULL) {
281 g_critical ("fu_plugin_alloc_data() already used by plugin");
282 return priv->data;
283 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000284 priv->data = g_malloc0 (data_sz);
285 return priv->data;
Richard Hughesd0905142016-03-13 09:46:49 +0000286}
287
Richard Hughes57d18222017-01-10 16:02:59 +0000288/**
289 * fu_plugin_get_usb_context:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100290 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000291 *
292 * Gets the shared USB context that all plugins can use.
293 *
294 * Returns: (transfer none): a #GUsbContext.
295 *
296 * Since: 0.8.0
297 **/
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000298GUsbContext *
Richard Hughes12724852018-09-04 13:53:44 +0100299fu_plugin_get_usb_context (FuPlugin *self)
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000300{
Richard Hughes12724852018-09-04 13:53:44 +0100301 FuPluginPrivate *priv = GET_PRIVATE (self);
302 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000303 return priv->usb_ctx;
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000304}
305
306void
Richard Hughes12724852018-09-04 13:53:44 +0100307fu_plugin_set_usb_context (FuPlugin *self, GUsbContext *usb_ctx)
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000308{
Richard Hughes12724852018-09-04 13:53:44 +0100309 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +0000310 g_set_object (&priv->usb_ctx, usb_ctx);
311}
312
Richard Hughes57d18222017-01-10 16:02:59 +0000313/**
314 * fu_plugin_get_enabled:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100315 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000316 *
Richard Hughes4eada342017-10-03 21:20:32 +0100317 * Returns if the plugin is enabled. Plugins may self-disable using
318 * fu_plugin_set_enabled() or can be disabled by the daemon.
Richard Hughes57d18222017-01-10 16:02:59 +0000319 *
320 * Returns: %TRUE if the plugin is currently enabled.
321 *
322 * Since: 0.8.0
323 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000324gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100325fu_plugin_get_enabled (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +0000326{
Richard Hughes12724852018-09-04 13:53:44 +0100327 FuPluginPrivate *priv = GET_PRIVATE (self);
328 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
Richard Hughescff38bc2016-12-12 12:03:37 +0000329 return priv->enabled;
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000330}
331
Richard Hughes57d18222017-01-10 16:02:59 +0000332/**
333 * fu_plugin_set_enabled:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100334 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000335 * @enabled: the enabled value
336 *
337 * Enables or disables a plugin. Plugins can self-disable at any point.
338 *
339 * Since: 0.8.0
340 **/
Richard Hughesd0905142016-03-13 09:46:49 +0000341void
Richard Hughes12724852018-09-04 13:53:44 +0100342fu_plugin_set_enabled (FuPlugin *self, gboolean enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000343{
Richard Hughes12724852018-09-04 13:53:44 +0100344 FuPluginPrivate *priv = GET_PRIVATE (self);
345 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughescff38bc2016-12-12 12:03:37 +0000346 priv->enabled = enabled;
347}
348
Richard Hughes1e456bc2018-05-10 20:16:16 +0100349gchar *
350fu_plugin_guess_name_from_fn (const gchar *filename)
351{
352 const gchar *prefix = "libfu_plugin_";
353 gchar *name;
354 gchar *str = g_strstr_len (filename, -1, prefix);
355 if (str == NULL)
356 return NULL;
357 name = g_strdup (str + strlen (prefix));
358 g_strdelimit (name, ".", '\0');
359 return name;
360}
361
Richard Hughescff38bc2016-12-12 12:03:37 +0000362gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100363fu_plugin_open (FuPlugin *self, const gchar *filename, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +0000364{
Richard Hughes12724852018-09-04 13:53:44 +0100365 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +0000366 FuPluginInitFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000367
368 priv->module = g_module_open (filename, 0);
369 if (priv->module == NULL) {
370 g_set_error (error,
371 G_IO_ERROR,
372 G_IO_ERROR_FAILED,
Mario Limonciellof5605532019-11-04 07:49:50 -0600373 "failed to open plugin %s: %s",
374 filename, g_module_error ());
Richard Hughescff38bc2016-12-12 12:03:37 +0000375 return FALSE;
376 }
377
378 /* set automatically */
Richard Hughes1e456bc2018-05-10 20:16:16 +0100379 if (priv->name == NULL)
380 priv->name = fu_plugin_guess_name_from_fn (filename);
Richard Hughesd0905142016-03-13 09:46:49 +0000381
382 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000383 g_module_symbol (priv->module, "fu_plugin_init", (gpointer *) &func);
384 if (func != NULL) {
385 g_debug ("performing init() on %s", filename);
Richard Hughes12724852018-09-04 13:53:44 +0100386 func (self);
Richard Hughesd0905142016-03-13 09:46:49 +0000387 }
388
Richard Hughescff38bc2016-12-12 12:03:37 +0000389 return TRUE;
390}
391
Richard Hughes57d18222017-01-10 16:02:59 +0000392/**
393 * fu_plugin_device_add:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100394 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000395 * @device: A #FuDevice
396 *
397 * Asks the daemon to add a device to the exported list. If this device ID
398 * has already been added by a different plugin then this request will be
399 * ignored.
400 *
401 * Plugins should use fu_plugin_device_add_delay() if they are not capable of
402 * actually flashing an image to the hardware so that higher-priority plugins
403 * can add the device themselves.
404 *
405 * Since: 0.8.0
406 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000407void
Richard Hughes12724852018-09-04 13:53:44 +0100408fu_plugin_device_add (FuPlugin *self, FuDevice *device)
Richard Hughescff38bc2016-12-12 12:03:37 +0000409{
Richard Hughes5e447292018-04-27 14:25:54 +0100410 GPtrArray *children;
Richard Hughesc125ec02018-09-05 19:35:17 +0100411 g_autoptr(GError) error = NULL;
Richard Hughes5e447292018-04-27 14:25:54 +0100412
Richard Hughes12724852018-09-04 13:53:44 +0100413 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000414 g_return_if_fail (FU_IS_DEVICE (device));
415
Richard Hughesc125ec02018-09-05 19:35:17 +0100416 /* ensure the device ID is set from the physical and logical IDs */
417 if (!fu_device_ensure_id (device, &error)) {
418 g_warning ("ignoring add: %s", error->message);
419 return;
420 }
421
Richard Hughescff38bc2016-12-12 12:03:37 +0000422 g_debug ("emit added from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100423 fu_plugin_get_name (self),
Richard Hughescff38bc2016-12-12 12:03:37 +0000424 fu_device_get_id (device));
425 fu_device_set_created (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
Richard Hughes12724852018-09-04 13:53:44 +0100426 fu_device_set_plugin (device, fu_plugin_get_name (self));
427 g_signal_emit (self, signals[SIGNAL_DEVICE_ADDED], 0, device);
Richard Hughes5e447292018-04-27 14:25:54 +0100428
Richard Hughes128c0162018-08-10 11:00:29 +0100429 /* add children if they have not already been added */
Richard Hughes5e447292018-04-27 14:25:54 +0100430 children = fu_device_get_children (device);
431 for (guint i = 0; i < children->len; i++) {
432 FuDevice *child = g_ptr_array_index (children, i);
Richard Hughes128c0162018-08-10 11:00:29 +0100433 if (fu_device_get_created (child) == 0)
Richard Hughes12724852018-09-04 13:53:44 +0100434 fu_plugin_device_add (self, child);
Richard Hughes5e447292018-04-27 14:25:54 +0100435 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000436}
437
Richard Hughese1fd34d2017-08-24 14:19:51 +0100438/**
439 * fu_plugin_device_register:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100440 * @self: A #FuPlugin
Richard Hughese1fd34d2017-08-24 14:19:51 +0100441 * @device: A #FuDevice
442 *
443 * Registers the device with other plugins so they can set metadata.
444 *
445 * Plugins do not have to call this manually as this is done automatically
446 * when using fu_plugin_device_add(). They may wish to use this manually
447 * if for intance the coldplug should be ignored based on the metadata
448 * set from other plugins.
449 *
450 * Since: 0.9.7
451 **/
452void
Richard Hughes12724852018-09-04 13:53:44 +0100453fu_plugin_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +0100454{
Richard Hughesc125ec02018-09-05 19:35:17 +0100455 g_autoptr(GError) error = NULL;
456
Richard Hughes12724852018-09-04 13:53:44 +0100457 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughese1fd34d2017-08-24 14:19:51 +0100458 g_return_if_fail (FU_IS_DEVICE (device));
459
Richard Hughesc125ec02018-09-05 19:35:17 +0100460 /* ensure the device ID is set from the physical and logical IDs */
461 if (!fu_device_ensure_id (device, &error)) {
462 g_warning ("ignoring registration: %s", error->message);
463 return;
464 }
465
Richard Hughese1fd34d2017-08-24 14:19:51 +0100466 g_debug ("emit device-register from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100467 fu_plugin_get_name (self),
Richard Hughese1fd34d2017-08-24 14:19:51 +0100468 fu_device_get_id (device));
Richard Hughes12724852018-09-04 13:53:44 +0100469 g_signal_emit (self, signals[SIGNAL_DEVICE_REGISTER], 0, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +0100470}
471
Richard Hughes57d18222017-01-10 16:02:59 +0000472/**
Richard Hughes4eada342017-10-03 21:20:32 +0100473 * fu_plugin_device_remove:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100474 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000475 * @device: A #FuDevice
476 *
477 * Asks the daemon to remove a device from the exported list.
478 *
479 * Since: 0.8.0
480 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000481void
Richard Hughes12724852018-09-04 13:53:44 +0100482fu_plugin_device_remove (FuPlugin *self, FuDevice *device)
Richard Hughescff38bc2016-12-12 12:03:37 +0000483{
Richard Hughes12724852018-09-04 13:53:44 +0100484 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000485 g_return_if_fail (FU_IS_DEVICE (device));
486
Richard Hughescff38bc2016-12-12 12:03:37 +0000487 g_debug ("emit removed from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100488 fu_plugin_get_name (self),
Richard Hughescff38bc2016-12-12 12:03:37 +0000489 fu_device_get_id (device));
Richard Hughes12724852018-09-04 13:53:44 +0100490 g_signal_emit (self, signals[SIGNAL_DEVICE_REMOVED], 0, device);
Richard Hughescff38bc2016-12-12 12:03:37 +0000491}
492
Richard Hughes57d18222017-01-10 16:02:59 +0000493/**
Richard Hughes2de8f132018-01-17 09:12:02 +0000494 * fu_plugin_request_recoldplug:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100495 * @self: A #FuPlugin
Richard Hughes362d6d72017-01-07 21:42:14 +0000496 *
497 * Ask all the plugins to coldplug all devices, which will include the prepare()
498 * and cleanup() phases. Duplicate devices added will be ignored.
499 *
500 * Since: 0.8.0
501 **/
502void
Richard Hughes12724852018-09-04 13:53:44 +0100503fu_plugin_request_recoldplug (FuPlugin *self)
Richard Hughes362d6d72017-01-07 21:42:14 +0000504{
Richard Hughes12724852018-09-04 13:53:44 +0100505 g_return_if_fail (FU_IS_PLUGIN (self));
506 g_signal_emit (self, signals[SIGNAL_RECOLDPLUG], 0);
Richard Hughes362d6d72017-01-07 21:42:14 +0000507}
508
Richard Hughesb0829032017-01-10 09:27:08 +0000509/**
Richard Hughesb8f8db22017-04-25 15:56:00 +0100510 * fu_plugin_check_hwid:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100511 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100512 * @hwid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
Richard Hughesb8f8db22017-04-25 15:56:00 +0100513 *
Richard Hughesd7704d42017-08-08 20:29:09 +0100514 * Checks to see if a specific GUID exists. All hardware IDs on a
Richard Hughesb8f8db22017-04-25 15:56:00 +0100515 * specific system can be shown using the `fwupdmgr hwids` command.
516 *
Richard Hughes4eada342017-10-03 21:20:32 +0100517 * Returns: %TRUE if the HwId is found on the system.
518 *
Richard Hughesb8f8db22017-04-25 15:56:00 +0100519 * Since: 0.9.1
520 **/
521gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100522fu_plugin_check_hwid (FuPlugin *self, const gchar *hwid)
Richard Hughesb8f8db22017-04-25 15:56:00 +0100523{
Richard Hughes12724852018-09-04 13:53:44 +0100524 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100525 if (priv->hwids == NULL)
526 return FALSE;
Richard Hughesd7704d42017-08-08 20:29:09 +0100527 return fu_hwids_has_guid (priv->hwids, hwid);
528}
529
530/**
Patrick Rudolpha60b5472019-10-16 10:43:03 +0200531 * fu_plugin_get_hwid_replace_value:
532 * @self: A #FuPlugin
533 * @keys: A key, e.g. `HardwareID-3` or %FU_HWIDS_KEY_PRODUCT_SKU
534 * @error: A #GError or %NULL
535 *
536 * Gets the replacement value for a specific key. All hardware IDs on a
537 * specific system can be shown using the `fwupdmgr hwids` command.
538 *
539 * Returns: (transfer full): a string, or %NULL for error.
540 *
541 * Since: 1.3.3
542 **/
543gchar *
544fu_plugin_get_hwid_replace_value (FuPlugin *self, const gchar *keys, GError **error)
545{
546 FuPluginPrivate *priv = GET_PRIVATE (self);
547 if (priv->hwids == NULL)
548 return NULL;
549
550 return fu_hwids_get_replace_values (priv->hwids, keys, error);
551}
552
553/**
Richard Hughes69a5f352018-08-08 11:58:15 +0100554 * fu_plugin_get_hwids:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100555 * @self: A #FuPlugin
Richard Hughes69a5f352018-08-08 11:58:15 +0100556 *
557 * Returns all the HWIDs defined in the system. All hardware IDs on a
558 * specific system can be shown using the `fwupdmgr hwids` command.
559 *
560 * Returns: (transfer none) (element-type utf-8): An array of GUIDs
561 *
562 * Since: 1.1.1
563 **/
564GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +0100565fu_plugin_get_hwids (FuPlugin *self)
Richard Hughes69a5f352018-08-08 11:58:15 +0100566{
Richard Hughes12724852018-09-04 13:53:44 +0100567 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes69a5f352018-08-08 11:58:15 +0100568 if (priv->hwids == NULL)
569 return NULL;
570 return fu_hwids_get_guids (priv->hwids);
571}
572
573/**
Richard Hughes19841802019-09-10 16:48:00 +0100574 * fu_plugin_has_custom_flag:
575 * @self: A #FuPlugin
576 * @flag: A custom text flag, specific to the plugin, e.g. `uefi-force-enable`
577 *
578 * Returns if a per-plugin HwId custom flag exists, typically added from a DMI quirk.
579 *
580 * Returns: %TRUE if the quirk entry exists
581 *
582 * Since: 1.3.1
583 **/
584gboolean
585fu_plugin_has_custom_flag (FuPlugin *self, const gchar *flag)
586{
587 FuPluginPrivate *priv = GET_PRIVATE (self);
588 GPtrArray *hwids = fu_plugin_get_hwids (self);
589
590 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
591 g_return_val_if_fail (flag != NULL, FALSE);
592
593 /* never set up, e.g. in tests */
594 if (hwids == NULL)
595 return FALSE;
596
597 /* search each hwid */
598 for (guint i = 0; i < hwids->len; i++) {
599 const gchar *hwid = g_ptr_array_index (hwids, i);
600 const gchar *value;
601 g_autofree gchar *key = g_strdup_printf ("HwId=%s", hwid);
602
603 /* does prefixed quirk exist */
604 value = fu_quirks_lookup_by_id (priv->quirks, key, FU_QUIRKS_FLAGS);
605 if (value != NULL) {
606 g_auto(GStrv) quirks = g_strsplit (value, ",", -1);
607 if (g_strv_contains ((const gchar * const *) quirks, flag))
608 return TRUE;
609 }
610 }
611 return FALSE;
612}
613
614/**
Richard Hughes1354ea92017-09-19 15:58:31 +0100615 * fu_plugin_check_supported:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100616 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100617 * @guid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
Richard Hughes1354ea92017-09-19 15:58:31 +0100618 *
619 * Checks to see if a specific device GUID is supported, i.e. available in the
620 * AppStream metadata.
621 *
Richard Hughes4eada342017-10-03 21:20:32 +0100622 * Returns: %TRUE if the device is supported.
623 *
Richard Hughes1354ea92017-09-19 15:58:31 +0100624 * Since: 1.0.0
625 **/
Richard Hughesd8a8d5e2019-10-08 13:05:02 +0100626static gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100627fu_plugin_check_supported (FuPlugin *self, const gchar *guid)
Richard Hughes1354ea92017-09-19 15:58:31 +0100628{
Richard Hughesaabdc372018-11-14 10:11:08 +0000629 gboolean retval = FALSE;
630 g_signal_emit (self, signals[SIGNAL_CHECK_SUPPORTED], 0, guid, &retval);
631 return retval;
Richard Hughes1354ea92017-09-19 15:58:31 +0100632}
633
634/**
Richard Hughesd7704d42017-08-08 20:29:09 +0100635 * fu_plugin_get_dmi_value:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100636 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100637 * @dmi_id: A DMI ID, e.g. `BiosVersion`
Richard Hughesd7704d42017-08-08 20:29:09 +0100638 *
639 * Gets a hardware DMI value.
640 *
Richard Hughes4eada342017-10-03 21:20:32 +0100641 * Returns: The string, or %NULL
642 *
Richard Hughesd7704d42017-08-08 20:29:09 +0100643 * Since: 0.9.7
644 **/
645const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100646fu_plugin_get_dmi_value (FuPlugin *self, const gchar *dmi_id)
Richard Hughesd7704d42017-08-08 20:29:09 +0100647{
Richard Hughes12724852018-09-04 13:53:44 +0100648 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd7704d42017-08-08 20:29:09 +0100649 if (priv->hwids == NULL)
Richard Hughes7ef96b82017-08-23 18:28:24 +0100650 return NULL;
Richard Hughesd7704d42017-08-08 20:29:09 +0100651 return fu_hwids_get_value (priv->hwids, dmi_id);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100652}
653
Richard Hughes49e5e052017-09-03 12:15:41 +0100654/**
655 * fu_plugin_get_smbios_string:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100656 * @self: A #FuPlugin
Richard Hughes49e5e052017-09-03 12:15:41 +0100657 * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
658 * @offset: A SMBIOS offset
659 *
660 * Gets a hardware SMBIOS string.
661 *
662 * The @type and @offset can be referenced from the DMTF SMBIOS specification:
663 * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.1.1.pdf
664 *
Richard Hughes4eada342017-10-03 21:20:32 +0100665 * Returns: A string, or %NULL
666 *
Richard Hughes49e5e052017-09-03 12:15:41 +0100667 * Since: 0.9.8
668 **/
669const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100670fu_plugin_get_smbios_string (FuPlugin *self, guint8 structure_type, guint8 offset)
Richard Hughes49e5e052017-09-03 12:15:41 +0100671{
Richard Hughes12724852018-09-04 13:53:44 +0100672 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100673 if (priv->smbios == NULL)
674 return NULL;
675 return fu_smbios_get_string (priv->smbios, structure_type, offset, NULL);
676}
677
678/**
679 * fu_plugin_get_smbios_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100680 * @self: A #FuPlugin
Richard Hughes49e5e052017-09-03 12:15:41 +0100681 * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
682 *
683 * Gets a hardware SMBIOS data.
684 *
Richard Hughesdfaca2d2019-08-01 08:08:03 +0100685 * Returns: (transfer full): A #GBytes, or %NULL
Richard Hughes4eada342017-10-03 21:20:32 +0100686 *
Richard Hughes49e5e052017-09-03 12:15:41 +0100687 * Since: 0.9.8
688 **/
689GBytes *
Richard Hughes12724852018-09-04 13:53:44 +0100690fu_plugin_get_smbios_data (FuPlugin *self, guint8 structure_type)
Richard Hughes49e5e052017-09-03 12:15:41 +0100691{
Richard Hughes12724852018-09-04 13:53:44 +0100692 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100693 if (priv->smbios == NULL)
694 return NULL;
695 return fu_smbios_get_data (priv->smbios, structure_type, NULL);
696}
697
Richard Hughesb8f8db22017-04-25 15:56:00 +0100698void
Richard Hughes12724852018-09-04 13:53:44 +0100699fu_plugin_set_hwids (FuPlugin *self, FuHwids *hwids)
Richard Hughesb8f8db22017-04-25 15:56:00 +0100700{
Richard Hughes12724852018-09-04 13:53:44 +0100701 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd7704d42017-08-08 20:29:09 +0100702 g_set_object (&priv->hwids, hwids);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100703}
704
Richard Hughes49e5e052017-09-03 12:15:41 +0100705void
Richard Hughes12724852018-09-04 13:53:44 +0100706fu_plugin_set_udev_subsystems (FuPlugin *self, GPtrArray *udev_subsystems)
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100707{
Richard Hughes12724852018-09-04 13:53:44 +0100708 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100709 if (priv->udev_subsystems != NULL)
710 g_ptr_array_unref (priv->udev_subsystems);
711 priv->udev_subsystems = g_ptr_array_ref (udev_subsystems);
712}
713
714void
Richard Hughes12724852018-09-04 13:53:44 +0100715fu_plugin_set_quirks (FuPlugin *self, FuQuirks *quirks)
Richard Hughes9c028f02017-10-28 21:14:28 +0100716{
Richard Hughes12724852018-09-04 13:53:44 +0100717 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9c028f02017-10-28 21:14:28 +0100718 g_set_object (&priv->quirks, quirks);
719}
720
721/**
722 * fu_plugin_get_quirks:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100723 * @self: A #FuPlugin
Richard Hughes9c028f02017-10-28 21:14:28 +0100724 *
725 * Returns the hardware database object. This can be used to discover device
726 * quirks or other device-specific settings.
727 *
728 * Returns: (transfer none): a #FuQuirks, or %NULL if not set
729 *
730 * Since: 1.0.1
731 **/
732FuQuirks *
Richard Hughes12724852018-09-04 13:53:44 +0100733fu_plugin_get_quirks (FuPlugin *self)
Richard Hughes9c028f02017-10-28 21:14:28 +0100734{
Richard Hughes12724852018-09-04 13:53:44 +0100735 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9c028f02017-10-28 21:14:28 +0100736 return priv->quirks;
737}
738
Richard Hughes0eb123b2018-04-19 12:00:04 +0100739void
Richard Hughes12724852018-09-04 13:53:44 +0100740fu_plugin_set_runtime_versions (FuPlugin *self, GHashTable *runtime_versions)
Richard Hughes0eb123b2018-04-19 12:00:04 +0100741{
Richard Hughes12724852018-09-04 13:53:44 +0100742 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0eb123b2018-04-19 12:00:04 +0100743 priv->runtime_versions = g_hash_table_ref (runtime_versions);
744}
745
746/**
747 * fu_plugin_add_runtime_version:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100748 * @self: A #FuPlugin
Richard Hughes0eb123b2018-04-19 12:00:04 +0100749 * @component_id: An AppStream component id, e.g. "org.gnome.Software"
750 * @version: A version string, e.g. "1.2.3"
751 *
Richard Hughesdce91202019-04-08 12:47:45 +0100752 * Sets a runtime version of a specific dependency.
Richard Hughes0eb123b2018-04-19 12:00:04 +0100753 *
754 * Since: 1.0.7
755 **/
756void
Richard Hughes12724852018-09-04 13:53:44 +0100757fu_plugin_add_runtime_version (FuPlugin *self,
Richard Hughes0eb123b2018-04-19 12:00:04 +0100758 const gchar *component_id,
759 const gchar *version)
760{
Richard Hughes12724852018-09-04 13:53:44 +0100761 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesb01b4862018-04-20 16:39:48 +0100762 if (priv->runtime_versions == NULL)
763 return;
Richard Hughes0eb123b2018-04-19 12:00:04 +0100764 g_hash_table_insert (priv->runtime_versions,
765 g_strdup (component_id),
766 g_strdup (version));
767}
768
Richard Hughes34e0dab2018-04-20 16:43:00 +0100769void
Richard Hughes12724852018-09-04 13:53:44 +0100770fu_plugin_set_compile_versions (FuPlugin *self, GHashTable *compile_versions)
Richard Hughes34e0dab2018-04-20 16:43:00 +0100771{
Richard Hughes12724852018-09-04 13:53:44 +0100772 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes34e0dab2018-04-20 16:43:00 +0100773 priv->compile_versions = g_hash_table_ref (compile_versions);
774}
775
776/**
777 * fu_plugin_add_compile_version:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100778 * @self: A #FuPlugin
Richard Hughes34e0dab2018-04-20 16:43:00 +0100779 * @component_id: An AppStream component id, e.g. "org.gnome.Software"
780 * @version: A version string, e.g. "1.2.3"
781 *
Richard Hughesdce91202019-04-08 12:47:45 +0100782 * Sets a compile-time version of a specific dependency.
Richard Hughes34e0dab2018-04-20 16:43:00 +0100783 *
784 * Since: 1.0.7
785 **/
786void
Richard Hughes12724852018-09-04 13:53:44 +0100787fu_plugin_add_compile_version (FuPlugin *self,
Richard Hughes34e0dab2018-04-20 16:43:00 +0100788 const gchar *component_id,
789 const gchar *version)
790{
Richard Hughes12724852018-09-04 13:53:44 +0100791 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes34e0dab2018-04-20 16:43:00 +0100792 if (priv->compile_versions == NULL)
793 return;
794 g_hash_table_insert (priv->compile_versions,
795 g_strdup (component_id),
796 g_strdup (version));
797}
798
Richard Hughes9c028f02017-10-28 21:14:28 +0100799/**
800 * fu_plugin_lookup_quirk_by_id:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100801 * @self: A #FuPlugin
Richard Hughes87fb9ff2018-06-28 12:55:59 +0100802 * @group: A string, e.g. "DfuFlags"
803 * @key: An ID to match the entry, e.g. "Summary"
Richard Hughes9c028f02017-10-28 21:14:28 +0100804 *
805 * Looks up an entry in the hardware database using a string value.
806 *
807 * Returns: (transfer none): values from the database, or %NULL if not found
808 *
809 * Since: 1.0.1
810 **/
811const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100812fu_plugin_lookup_quirk_by_id (FuPlugin *self, const gchar *group, const gchar *key)
Richard Hughes9c028f02017-10-28 21:14:28 +0100813{
Richard Hughes12724852018-09-04 13:53:44 +0100814 FuPluginPrivate *priv = GET_PRIVATE (self);
815 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes9c028f02017-10-28 21:14:28 +0100816
Richard Hughes9c028f02017-10-28 21:14:28 +0100817 /* exact ID */
Richard Hughes87fb9ff2018-06-28 12:55:59 +0100818 return fu_quirks_lookup_by_id (priv->quirks, group, key);
Richard Hughes9c028f02017-10-28 21:14:28 +0100819}
820
821/**
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100822 * fu_plugin_lookup_quirk_by_id_as_uint64:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100823 * @self: A #FuPlugin
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100824 * @group: A string, e.g. "DfuFlags"
825 * @key: An ID to match the entry, e.g. "Size"
826 *
827 * Looks up an entry in the hardware database using a string key, returning
828 * an integer value. Values are assumed base 10, unless prefixed with "0x"
829 * where they are parsed as base 16.
830 *
831 * Returns: (transfer none): value from the database, or 0 if not found
832 *
833 * Since: 1.1.2
834 **/
835guint64
Richard Hughes12724852018-09-04 13:53:44 +0100836fu_plugin_lookup_quirk_by_id_as_uint64 (FuPlugin *self, const gchar *group, const gchar *key)
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100837{
Richard Hughes12724852018-09-04 13:53:44 +0100838 return fu_common_strtoull (fu_plugin_lookup_quirk_by_id (self, group, key));
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100839}
840
Richard Hughes1354ea92017-09-19 15:58:31 +0100841void
Richard Hughes12724852018-09-04 13:53:44 +0100842fu_plugin_set_smbios (FuPlugin *self, FuSmbios *smbios)
Richard Hughes49e5e052017-09-03 12:15:41 +0100843{
Richard Hughes12724852018-09-04 13:53:44 +0100844 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100845 g_set_object (&priv->smbios, smbios);
846}
847
Richard Hughesb8f8db22017-04-25 15:56:00 +0100848/**
Richard Hughesb0829032017-01-10 09:27:08 +0000849 * fu_plugin_set_coldplug_delay:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100850 * @self: A #FuPlugin
Richard Hughesb0829032017-01-10 09:27:08 +0000851 * @duration: A delay in milliseconds
852 *
853 * Set the minimum time that should be waited inbetween the call to
854 * fu_plugin_coldplug_prepare() and fu_plugin_coldplug(). This is usually going
855 * to be the minimum hardware initialisation time from a datasheet.
856 *
857 * It is better to use this function rather than using a sleep() in the plugin
858 * itself as then only one delay is done in the daemon rather than waiting for
859 * each coldplug prepare in a serial way.
860 *
861 * Additionally, very long delays should be avoided as the daemon will be
862 * blocked from processing requests whilst the coldplug delay is being
863 * performed.
864 *
865 * Since: 0.8.0
866 **/
867void
Richard Hughes12724852018-09-04 13:53:44 +0100868fu_plugin_set_coldplug_delay (FuPlugin *self, guint duration)
Richard Hughesb0829032017-01-10 09:27:08 +0000869{
Richard Hughes12724852018-09-04 13:53:44 +0100870 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesb0829032017-01-10 09:27:08 +0000871 g_return_if_fail (duration > 0);
872
873 /* check sanity */
874 if (duration > FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM) {
875 g_warning ("duration of %ums is crazy, truncating to %ums",
876 duration,
877 FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM);
878 duration = FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM;
879 }
880
881 /* emit */
Richard Hughes12724852018-09-04 13:53:44 +0100882 g_signal_emit (self, signals[SIGNAL_SET_COLDPLUG_DELAY], 0, duration);
Richard Hughesb0829032017-01-10 09:27:08 +0000883}
884
Richard Hughes4b303802019-10-04 13:22:51 +0100885static gboolean
886fu_plugin_device_attach (FuPlugin *self, FuDevice *device, GError **error)
887{
888 g_autoptr(FuDeviceLocker) locker = NULL;
889 if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) {
890 g_debug ("already in runtime mode, skipping");
891 return TRUE;
892 }
893 locker = fu_device_locker_new (device, error);
894 if (locker == NULL)
895 return FALSE;
896 return fu_device_attach (device, error);
897}
898
899static gboolean
900fu_plugin_device_detach (FuPlugin *self, FuDevice *device, GError **error)
901{
902 g_autoptr(FuDeviceLocker) locker = NULL;
903 if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) {
904 g_debug ("already in bootloader mode, skipping");
905 return TRUE;
906 }
907 locker = fu_device_locker_new (device, error);
908 if (locker == NULL)
909 return FALSE;
910 return fu_device_detach (device, error);
911}
912
913static gboolean
Richard Hughes4b303802019-10-04 13:22:51 +0100914fu_plugin_device_activate (FuPlugin *self, FuDevice *device, GError **error)
915{
916 g_autoptr(FuDeviceLocker) locker = NULL;
917 locker = fu_device_locker_new (device, error);
918 if (locker == NULL)
919 return FALSE;
920 return fu_device_activate (device, error);
921}
922
923static gboolean
924fu_plugin_device_write_firmware (FuPlugin *self, FuDevice *device,
925 GBytes *fw, FwupdInstallFlags flags,
926 GError **error)
927{
928 g_autoptr(FuDeviceLocker) locker = NULL;
929 locker = fu_device_locker_new (device, error);
930 if (locker == NULL)
931 return FALSE;
932 return fu_device_write_firmware (device, fw, flags, error);
933}
934
Richard Hughes7f677212019-10-05 16:19:40 +0100935static gboolean
936fu_plugin_device_read_firmware (FuPlugin *self, FuDevice *device, GError **error)
937{
938 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughesf0eb0912019-10-10 11:37:22 +0100939 g_autoptr(FuFirmware) firmware = NULL;
Richard Hughes7f677212019-10-05 16:19:40 +0100940 g_autoptr(GBytes) fw = NULL;
941 GChecksumType checksum_types[] = {
942 G_CHECKSUM_SHA1,
943 G_CHECKSUM_SHA256,
944 0 };
945 locker = fu_device_locker_new (device, error);
946 if (locker == NULL)
947 return FALSE;
948 if (!fu_device_detach (device, error))
949 return FALSE;
Richard Hughesf0eb0912019-10-10 11:37:22 +0100950 firmware = fu_device_read_firmware (device, error);
951 if (firmware == NULL) {
952 g_autoptr(GError) error_local = NULL;
953 if (!fu_device_attach (device, &error_local))
954 g_debug ("ignoring attach failure: %s", error_local->message);
955 g_prefix_error (error, "failed to read firmware: ");
956 return FALSE;
957 }
958 fw = fu_firmware_write (firmware, error);
Richard Hughes7f677212019-10-05 16:19:40 +0100959 if (fw == NULL) {
960 g_autoptr(GError) error_local = NULL;
961 if (!fu_device_attach (device, &error_local))
Richard Hughesf0eb0912019-10-10 11:37:22 +0100962 g_debug ("ignoring attach failure: %s", error_local->message);
963 g_prefix_error (error, "failed to write firmware: ");
Richard Hughes7f677212019-10-05 16:19:40 +0100964 return FALSE;
965 }
966 for (guint i = 0; checksum_types[i] != 0; i++) {
967 g_autofree gchar *hash = NULL;
968 hash = g_compute_checksum_for_bytes (checksum_types[i], fw);
969 fu_device_add_checksum (device, hash);
970 }
971 return fu_device_attach (device, error);
972}
973
Richard Hughesd0905142016-03-13 09:46:49 +0000974gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100975fu_plugin_runner_startup (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +0000976{
Richard Hughes12724852018-09-04 13:53:44 +0100977 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000978 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +0000979 g_autoptr(GError) error_local = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +0000980
981 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +0000982 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000983 return TRUE;
984
Richard Hughes639da472018-01-06 22:35:04 +0000985 /* no object loaded */
986 if (priv->module == NULL)
987 return TRUE;
988
Richard Hughesd0905142016-03-13 09:46:49 +0000989 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000990 g_module_symbol (priv->module, "fu_plugin_startup", (gpointer *) &func);
991 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +0000992 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +0000993 g_debug ("performing startup() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +0000994 if (!func (self, &error_local)) {
995 if (error_local == NULL) {
996 g_critical ("unset error in plugin %s for startup()",
997 priv->name);
998 g_set_error_literal (&error_local,
999 FWUPD_ERROR,
1000 FWUPD_ERROR_INTERNAL,
1001 "unspecified error");
1002 }
1003 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1004 "failed to startup using %s: ",
1005 priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00001006 return FALSE;
1007 }
1008 return TRUE;
1009}
1010
1011static gboolean
1012fu_plugin_runner_offline_invalidate (GError **error)
1013{
1014 g_autoptr(GError) error_local = NULL;
1015 g_autoptr(GFile) file1 = NULL;
1016
1017 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1018
1019 file1 = g_file_new_for_path (FU_OFFLINE_TRIGGER_FILENAME);
1020 if (!g_file_query_exists (file1, NULL))
1021 return TRUE;
1022 if (!g_file_delete (file1, NULL, &error_local)) {
1023 g_set_error (error,
1024 FWUPD_ERROR,
1025 FWUPD_ERROR_INTERNAL,
1026 "Cannot delete %s: %s",
1027 FU_OFFLINE_TRIGGER_FILENAME,
1028 error_local->message);
1029 return FALSE;
1030 }
1031 return TRUE;
1032}
1033
1034static gboolean
1035fu_plugin_runner_offline_setup (GError **error)
1036{
1037 gint rc;
Richard Hughes484ee292019-03-22 16:10:50 +00001038 g_autofree gchar *filename = NULL;
Mario Limoncielloe1b4b202019-04-30 10:01:19 -05001039 g_autofree gchar *symlink_target = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG);
Richard Hughescff38bc2016-12-12 12:03:37 +00001040
1041 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1042
Richard Hughes484ee292019-03-22 16:10:50 +00001043 /* does already exist */
1044 filename = fu_common_realpath (FU_OFFLINE_TRIGGER_FILENAME, NULL);
1045 if (g_strcmp0 (filename, symlink_target) == 0) {
1046 g_debug ("%s already points to %s, skipping creation",
1047 FU_OFFLINE_TRIGGER_FILENAME, symlink_target);
1048 return TRUE;
1049 }
1050
Richard Hughescff38bc2016-12-12 12:03:37 +00001051 /* create symlink for the systemd-system-update-generator */
Richard Hughes484ee292019-03-22 16:10:50 +00001052 rc = symlink (symlink_target, FU_OFFLINE_TRIGGER_FILENAME);
Richard Hughescff38bc2016-12-12 12:03:37 +00001053 if (rc < 0) {
1054 g_set_error (error,
1055 FWUPD_ERROR,
1056 FWUPD_ERROR_INTERNAL,
1057 "Failed to create symlink %s to %s: %s",
1058 FU_OFFLINE_TRIGGER_FILENAME,
1059 "/var/lib", strerror (errno));
Richard Hughesd0905142016-03-13 09:46:49 +00001060 return FALSE;
1061 }
1062 return TRUE;
1063}
1064
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001065static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001066fu_plugin_runner_device_generic (FuPlugin *self, FuDevice *device,
Richard Hughes4b303802019-10-04 13:22:51 +01001067 const gchar *symbol_name,
1068 FuPluginDeviceFunc device_func,
1069 GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001070{
Richard Hughes12724852018-09-04 13:53:44 +01001071 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001072 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001073 g_autoptr(GError) error_local = NULL;
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001074
1075 /* not enabled */
1076 if (!priv->enabled)
1077 return TRUE;
1078
Richard Hughesd3d96cc2017-11-14 11:34:33 +00001079 /* no object loaded */
1080 if (priv->module == NULL)
1081 return TRUE;
1082
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001083 /* optional */
1084 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
Richard Hughes4b303802019-10-04 13:22:51 +01001085 if (func == NULL) {
1086 if (device_func != NULL) {
1087 g_debug ("running superclassed %s() on %s",
1088 symbol_name + 10, priv->name);
1089 return device_func (self, device, error);
1090 }
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001091 return TRUE;
Richard Hughes4b303802019-10-04 13:22:51 +01001092 }
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001093 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001094 if (!func (self, device, &error_local)) {
1095 if (error_local == NULL) {
1096 g_critical ("unset error in plugin %s for %s()",
1097 priv->name, symbol_name + 10);
1098 g_set_error_literal (&error_local,
1099 FWUPD_ERROR,
1100 FWUPD_ERROR_INTERNAL,
1101 "unspecified error");
1102 }
1103 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1104 "failed to %s using %s: ",
1105 symbol_name + 10, priv->name);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001106 return FALSE;
1107 }
1108 return TRUE;
1109}
1110
Richard Hughesdbd8c762018-06-15 20:31:40 +01001111static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001112fu_plugin_runner_flagged_device_generic (FuPlugin *self, FwupdInstallFlags flags,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001113 FuDevice *device,
1114 const gchar *symbol_name, GError **error)
1115{
Richard Hughes12724852018-09-04 13:53:44 +01001116 FuPluginPrivate *priv = GET_PRIVATE (self);
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001117 FuPluginFlaggedDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001118 g_autoptr(GError) error_local = NULL;
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001119
1120 /* not enabled */
1121 if (!priv->enabled)
1122 return TRUE;
1123
1124 /* no object loaded */
1125 if (priv->module == NULL)
1126 return TRUE;
1127
1128 /* optional */
1129 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1130 if (func == NULL)
1131 return TRUE;
1132 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001133 if (!func (self, flags, device, &error_local)) {
1134 if (error_local == NULL) {
1135 g_critical ("unset error in plugin %s for %s()",
1136 priv->name, symbol_name + 10);
1137 g_set_error_literal (&error_local,
1138 FWUPD_ERROR,
1139 FWUPD_ERROR_INTERNAL,
1140 "unspecified error");
1141 }
1142 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1143 "failed to %s using %s: ",
1144 symbol_name + 10, priv->name);
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001145 return FALSE;
1146 }
1147 return TRUE;
1148
1149}
1150
1151static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001152fu_plugin_runner_device_array_generic (FuPlugin *self, GPtrArray *devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001153 const gchar *symbol_name, GError **error)
1154{
Richard Hughes12724852018-09-04 13:53:44 +01001155 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesdbd8c762018-06-15 20:31:40 +01001156 FuPluginDeviceArrayFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001157 g_autoptr(GError) error_local = NULL;
Richard Hughesdbd8c762018-06-15 20:31:40 +01001158
1159 /* not enabled */
1160 if (!priv->enabled)
1161 return TRUE;
1162
1163 /* no object loaded */
1164 if (priv->module == NULL)
1165 return TRUE;
1166
1167 /* optional */
1168 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1169 if (func == NULL)
1170 return TRUE;
1171 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001172 if (!func (self, devices, &error_local)) {
1173 if (error_local == NULL) {
1174 g_critical ("unset error in plugin %s for %s()",
1175 priv->name, symbol_name + 10);
1176 g_set_error_literal (&error_local,
1177 FWUPD_ERROR,
1178 FWUPD_ERROR_INTERNAL,
1179 "unspecified error");
1180 }
1181 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1182 "failed to %s using %s: ",
1183 symbol_name + 10, priv->name);
Richard Hughesdbd8c762018-06-15 20:31:40 +01001184 return FALSE;
1185 }
1186 return TRUE;
1187}
1188
Richard Hughesd0905142016-03-13 09:46:49 +00001189gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001190fu_plugin_runner_coldplug (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00001191{
Richard Hughes12724852018-09-04 13:53:44 +01001192 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001193 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001194 g_autoptr(GError) error_local = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +00001195
1196 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +00001197 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +00001198 return TRUE;
1199
Richard Hughes639da472018-01-06 22:35:04 +00001200 /* no object loaded */
1201 if (priv->module == NULL)
1202 return TRUE;
1203
Richard Hughesd0905142016-03-13 09:46:49 +00001204 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00001205 g_module_symbol (priv->module, "fu_plugin_coldplug", (gpointer *) &func);
1206 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +00001207 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001208 g_debug ("performing coldplug() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001209 if (!func (self, &error_local)) {
1210 if (error_local == NULL) {
1211 g_critical ("unset error in plugin %s for coldplug()",
1212 priv->name);
1213 g_set_error_literal (&error_local,
1214 FWUPD_ERROR,
1215 FWUPD_ERROR_INTERNAL,
1216 "unspecified error");
1217 }
1218 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1219 "failed to coldplug using %s: ", priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00001220 return FALSE;
1221 }
1222 return TRUE;
1223}
1224
Richard Hughes7b8b2022016-12-12 16:15:03 +00001225gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001226fu_plugin_runner_recoldplug (FuPlugin *self, GError **error)
Richard Hughes2de8f132018-01-17 09:12:02 +00001227{
Richard Hughes12724852018-09-04 13:53:44 +01001228 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes2de8f132018-01-17 09:12:02 +00001229 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001230 g_autoptr(GError) error_local = NULL;
Richard Hughes2de8f132018-01-17 09:12:02 +00001231
1232 /* not enabled */
1233 if (!priv->enabled)
1234 return TRUE;
1235
1236 /* no object loaded */
1237 if (priv->module == NULL)
1238 return TRUE;
1239
1240 /* optional */
1241 g_module_symbol (priv->module, "fu_plugin_recoldplug", (gpointer *) &func);
1242 if (func == NULL)
1243 return TRUE;
1244 g_debug ("performing recoldplug() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001245 if (!func (self, &error_local)) {
1246 if (error_local == NULL) {
1247 g_critical ("unset error in plugin %s for recoldplug()",
1248 priv->name);
1249 g_set_error_literal (&error_local,
1250 FWUPD_ERROR,
1251 FWUPD_ERROR_INTERNAL,
1252 "unspecified error");
1253 }
1254 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1255 "failed to recoldplug using %s: ",
1256 priv->name);
Richard Hughes2de8f132018-01-17 09:12:02 +00001257 return FALSE;
1258 }
1259 return TRUE;
1260}
1261
1262gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001263fu_plugin_runner_coldplug_prepare (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001264{
Richard Hughes12724852018-09-04 13:53:44 +01001265 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001266 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001267 g_autoptr(GError) error_local = NULL;
Richard Hughes46487c92017-01-07 21:26:34 +00001268
1269 /* not enabled */
1270 if (!priv->enabled)
1271 return TRUE;
1272
Richard Hughes639da472018-01-06 22:35:04 +00001273 /* no object loaded */
1274 if (priv->module == NULL)
1275 return TRUE;
1276
Richard Hughes46487c92017-01-07 21:26:34 +00001277 /* optional */
1278 g_module_symbol (priv->module, "fu_plugin_coldplug_prepare", (gpointer *) &func);
1279 if (func == NULL)
1280 return TRUE;
1281 g_debug ("performing coldplug_prepare() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001282 if (!func (self, &error_local)) {
1283 if (error_local == NULL) {
1284 g_critical ("unset error in plugin %s for coldplug_prepare()",
1285 priv->name);
1286 g_set_error_literal (&error_local,
1287 FWUPD_ERROR,
1288 FWUPD_ERROR_INTERNAL,
1289 "unspecified error");
1290 }
1291 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1292 "failed to coldplug_prepare using %s: ",
1293 priv->name);
Richard Hughes46487c92017-01-07 21:26:34 +00001294 return FALSE;
1295 }
1296 return TRUE;
1297}
1298
1299gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001300fu_plugin_runner_coldplug_cleanup (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001301{
Richard Hughes12724852018-09-04 13:53:44 +01001302 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001303 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001304 g_autoptr(GError) error_local = NULL;
Richard Hughes46487c92017-01-07 21:26:34 +00001305
1306 /* not enabled */
1307 if (!priv->enabled)
1308 return TRUE;
1309
Richard Hughes639da472018-01-06 22:35:04 +00001310 /* no object loaded */
1311 if (priv->module == NULL)
1312 return TRUE;
1313
Richard Hughes46487c92017-01-07 21:26:34 +00001314 /* optional */
1315 g_module_symbol (priv->module, "fu_plugin_coldplug_cleanup", (gpointer *) &func);
1316 if (func == NULL)
1317 return TRUE;
1318 g_debug ("performing coldplug_cleanup() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001319 if (!func (self, &error_local)) {
1320 if (error_local == NULL) {
1321 g_critical ("unset error in plugin %s for coldplug_cleanup()",
1322 priv->name);
1323 g_set_error_literal (&error_local,
1324 FWUPD_ERROR,
1325 FWUPD_ERROR_INTERNAL,
1326 "unspecified error");
1327 }
1328 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1329 "failed to coldplug_cleanup using %s: ",
1330 priv->name);
Richard Hughes46487c92017-01-07 21:26:34 +00001331 return FALSE;
1332 }
1333 return TRUE;
1334}
1335
1336gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001337fu_plugin_runner_composite_prepare (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001338{
Richard Hughes12724852018-09-04 13:53:44 +01001339 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001340 "fu_plugin_composite_prepare",
1341 error);
1342}
1343
1344gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001345fu_plugin_runner_composite_cleanup (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001346{
Richard Hughes12724852018-09-04 13:53:44 +01001347 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001348 "fu_plugin_composite_cleanup",
1349 error);
1350}
1351
1352gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001353fu_plugin_runner_update_prepare (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001354 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001355{
Richard Hughes12724852018-09-04 13:53:44 +01001356 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001357 "fu_plugin_update_prepare",
1358 error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001359}
1360
1361gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001362fu_plugin_runner_update_cleanup (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001363 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001364{
Richard Hughes12724852018-09-04 13:53:44 +01001365 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001366 "fu_plugin_update_cleanup",
1367 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001368}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001369
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001370gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001371fu_plugin_runner_update_attach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001372{
Richard Hughes12724852018-09-04 13:53:44 +01001373 return fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001374 "fu_plugin_update_attach",
1375 fu_plugin_device_attach,
1376 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001377}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001378
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001379gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001380fu_plugin_runner_update_detach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001381{
Richard Hughes12724852018-09-04 13:53:44 +01001382 return fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001383 "fu_plugin_update_detach",
1384 fu_plugin_device_detach,
1385 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001386}
1387
1388gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001389fu_plugin_runner_update_reload (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001390{
Richard Hughes42f33df2019-10-05 20:52:33 +01001391 FuPluginPrivate *priv = GET_PRIVATE (self);
1392 g_autoptr(FuDeviceLocker) locker = NULL;
1393
1394 /* not enabled */
1395 if (!priv->enabled)
1396 return TRUE;
1397
1398 /* no object loaded */
1399 locker = fu_device_locker_new (device, error);
1400 if (locker == NULL)
1401 return FALSE;
1402 return fu_device_reload (device, error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001403}
1404
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001405/**
1406 * fu_plugin_add_udev_subsystem:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001407 * @self: a #FuPlugin
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001408 * @subsystem: a subsystem name, e.g. `pciport`
1409 *
1410 * Registers the udev subsystem to be watched by the daemon.
1411 *
1412 * Plugins can use this method only in fu_plugin_init()
1413 **/
1414void
Richard Hughes12724852018-09-04 13:53:44 +01001415fu_plugin_add_udev_subsystem (FuPlugin *self, const gchar *subsystem)
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001416{
Richard Hughes12724852018-09-04 13:53:44 +01001417 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001418 for (guint i = 0; i < priv->udev_subsystems->len; i++) {
1419 const gchar *subsystem_tmp = g_ptr_array_index (priv->udev_subsystems, i);
1420 if (g_strcmp0 (subsystem_tmp, subsystem) == 0)
1421 return;
1422 }
1423 g_debug ("added udev subsystem watch of %s", subsystem);
1424 g_ptr_array_add (priv->udev_subsystems, g_strdup (subsystem));
1425}
1426
Richard Hughes989acf12019-10-05 20:16:47 +01001427/**
1428 * fu_plugin_set_device_gtype:
1429 * @self: a #FuPlugin
1430 * @device_gtype: a #GType `FU_TYPE_DEVICE`
1431 *
1432 * Sets the device #GType which is used when creating devices.
1433 *
1434 * If this method is used then fu_plugin_usb_device_added() is not called, and
1435 * instead the object is created in the daemon for the plugin.
1436 *
1437 * Plugins can use this method only in fu_plugin_init()
1438 *
1439 * Since: 1.3.3
1440 **/
1441void
1442fu_plugin_set_device_gtype (FuPlugin *self, GType device_gtype)
1443{
1444 FuPluginPrivate *priv = GET_PRIVATE (self);
1445 priv->device_gtype = device_gtype;
1446}
1447
Richard Hughes95c98a92019-10-22 16:03:15 +01001448void
1449fu_plugin_add_firmware_gtype (FuPlugin *self, const gchar *id, GType gtype)
1450{
1451 g_signal_emit (self, signals[SIGNAL_ADD_FIRMWARE_GTYPE], 0, id, gtype);
1452}
1453
Richard Hughes989acf12019-10-05 20:16:47 +01001454static gboolean
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001455fu_plugin_check_supported_device (FuPlugin *self, FuDevice *device)
1456{
1457 GPtrArray *instance_ids = fu_device_get_instance_ids (device);
1458 for (guint i = 0; i < instance_ids->len; i++) {
1459 const gchar *instance_id = g_ptr_array_index (instance_ids, i);
1460 g_autofree gchar *guid = fwupd_guid_hash_string (instance_id);
1461 if (fu_plugin_check_supported (self, guid))
1462 return TRUE;
1463 }
1464 return FALSE;
1465}
1466
1467static gboolean
Richard Hughes989acf12019-10-05 20:16:47 +01001468fu_plugin_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error)
1469{
1470 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001471 GType device_gtype = fu_device_get_specialized_gtype (FU_DEVICE (device));
Richard Hughes989acf12019-10-05 20:16:47 +01001472 g_autoptr(FuDevice) dev = NULL;
1473 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001474
1475 /* fall back to plugin default */
1476 if (device_gtype == G_TYPE_INVALID)
1477 device_gtype = priv->device_gtype;
1478
1479 /* create new device and incorporate existing properties */
1480 dev = g_object_new (device_gtype, NULL);
1481 fu_device_incorporate (dev, FU_DEVICE (device));
1482
1483 /* there are a lot of different devices that match, but not all respond
1484 * well to opening -- so limit some ones with issued updates */
1485 if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_ONLY_SUPPORTED)) {
1486 if (!fu_device_probe (dev, error))
1487 return FALSE;
1488 fu_device_convert_instance_ids (dev);
1489 if (!fu_plugin_check_supported_device (self, dev)) {
1490 g_autofree gchar *guids = fu_device_get_guids_as_str (dev);
1491 g_debug ("%s has no updates, so ignoring device", guids);
1492 return TRUE;
1493 }
1494 }
1495
1496 /* open and add */
1497 locker = fu_device_locker_new (dev, error);
1498 if (locker == NULL)
1499 return FALSE;
1500 fu_plugin_device_add (self, dev);
1501 return TRUE;
1502}
1503
1504static gboolean
1505fu_plugin_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error)
1506{
1507 FuPluginPrivate *priv = GET_PRIVATE (self);
1508 GType device_gtype = fu_device_get_specialized_gtype (FU_DEVICE (device));
1509 g_autoptr(FuDevice) dev = NULL;
1510 g_autoptr(FuDeviceLocker) locker = NULL;
1511
1512 /* fall back to plugin default */
1513 if (device_gtype == G_TYPE_INVALID)
1514 device_gtype = priv->device_gtype;
1515
1516 /* create new device and incorporate existing properties */
1517 dev = g_object_new (device_gtype, NULL);
Richard Hughes989acf12019-10-05 20:16:47 +01001518 fu_device_incorporate (FU_DEVICE (dev), FU_DEVICE (device));
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001519
1520 /* there are a lot of different devices that match, but not all respond
1521 * well to opening -- so limit some ones with issued updates */
1522 if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_ONLY_SUPPORTED)) {
1523 if (!fu_device_probe (dev, error))
1524 return FALSE;
1525 fu_device_convert_instance_ids (dev);
1526 if (!fu_plugin_check_supported_device (self, dev)) {
1527 g_autofree gchar *guids = fu_device_get_guids_as_str (dev);
1528 g_debug ("%s has no updates, so ignoring device", guids);
1529 return TRUE;
1530 }
1531 }
1532
1533 /* open and add */
Richard Hughes989acf12019-10-05 20:16:47 +01001534 locker = fu_device_locker_new (dev, error);
1535 if (locker == NULL)
1536 return FALSE;
1537 fu_plugin_device_add (self, FU_DEVICE (dev));
1538 return TRUE;
1539}
1540
Richard Hughes104f6512017-11-24 11:44:57 +00001541gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001542fu_plugin_runner_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error)
Richard Hughes104f6512017-11-24 11:44:57 +00001543{
Richard Hughes12724852018-09-04 13:53:44 +01001544 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes104f6512017-11-24 11:44:57 +00001545 FuPluginUsbDeviceAddedFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001546 g_autoptr(GError) error_local = NULL;
Richard Hughes104f6512017-11-24 11:44:57 +00001547
1548 /* not enabled */
1549 if (!priv->enabled)
1550 return TRUE;
Richard Hughes639da472018-01-06 22:35:04 +00001551
1552 /* no object loaded */
Richard Hughes104f6512017-11-24 11:44:57 +00001553 if (priv->module == NULL)
1554 return TRUE;
1555
1556 /* optional */
1557 g_module_symbol (priv->module, "fu_plugin_usb_device_added", (gpointer *) &func);
Richard Hughes989acf12019-10-05 20:16:47 +01001558 if (func == NULL) {
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001559 if (priv->device_gtype != G_TYPE_INVALID ||
1560 fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) {
Mario Limonciello0e500322019-10-17 18:41:04 -05001561 if (!fu_plugin_usb_device_added (self, device, error))
Mario Limoncielloa9be5362019-10-12 13:17:45 -05001562 return FALSE;
Richard Hughes989acf12019-10-05 20:16:47 +01001563 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001564 return TRUE;
Richard Hughes989acf12019-10-05 20:16:47 +01001565 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001566 g_debug ("performing usb_device_added() on %s", priv->name);
1567 if (!func (self, device, &error_local)) {
1568 if (error_local == NULL) {
1569 g_critical ("unset error in plugin %s for usb_device_added()",
1570 priv->name);
1571 g_set_error_literal (&error_local,
1572 FWUPD_ERROR,
1573 FWUPD_ERROR_INTERNAL,
1574 "unspecified error");
1575 }
1576 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1577 "failed to add device using on %s: ",
1578 priv->name);
1579 return FALSE;
Richard Hughes104f6512017-11-24 11:44:57 +00001580 }
1581 return TRUE;
1582}
1583
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001584gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001585fu_plugin_runner_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error)
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001586{
Richard Hughes12724852018-09-04 13:53:44 +01001587 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001588 FuPluginUdevDeviceAddedFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001589 g_autoptr(GError) error_local = NULL;
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001590
1591 /* not enabled */
1592 if (!priv->enabled)
1593 return TRUE;
1594
1595 /* no object loaded */
1596 if (priv->module == NULL)
1597 return TRUE;
1598
1599 /* optional */
1600 g_module_symbol (priv->module, "fu_plugin_udev_device_added", (gpointer *) &func);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001601 if (func == NULL) {
1602 if (priv->device_gtype != G_TYPE_INVALID ||
1603 fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) {
Mario Limonciello0e500322019-10-17 18:41:04 -05001604 if (!fu_plugin_udev_device_added (self, device, error))
Mario Limoncielloa9be5362019-10-12 13:17:45 -05001605 return FALSE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001606 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001607 return TRUE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001608 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001609 g_debug ("performing udev_device_added() on %s", priv->name);
1610 if (!func (self, device, &error_local)) {
1611 if (error_local == NULL) {
1612 g_critical ("unset error in plugin %s for udev_device_added()",
1613 priv->name);
1614 g_set_error_literal (&error_local,
1615 FWUPD_ERROR,
1616 FWUPD_ERROR_INTERNAL,
1617 "unspecified error");
1618 }
1619 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1620 "failed to add device using on %s: ",
1621 priv->name);
1622 return FALSE;
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001623 }
1624 return TRUE;
1625}
1626
Richard Hughes5e952ce2019-08-26 11:09:46 +01001627gboolean
1628fu_plugin_runner_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GError **error)
1629{
1630 FuPluginPrivate *priv = GET_PRIVATE (self);
1631 FuPluginUdevDeviceAddedFunc func = NULL;
1632 g_autoptr(GError) error_local = NULL;
1633
1634 /* not enabled */
1635 if (!priv->enabled)
1636 return TRUE;
1637
1638 /* no object loaded */
1639 if (priv->module == NULL)
1640 return TRUE;
1641
1642 /* optional */
1643 g_module_symbol (priv->module, "fu_plugin_udev_device_changed", (gpointer *) &func);
1644 if (func == NULL)
1645 return TRUE;
1646 g_debug ("performing udev_device_changed() on %s", priv->name);
1647 if (!func (self, device, &error_local)) {
1648 if (error_local == NULL) {
1649 g_critical ("unset error in plugin %s for udev_device_changed()",
1650 priv->name);
1651 g_set_error_literal (&error_local,
1652 FWUPD_ERROR,
1653 FWUPD_ERROR_INTERNAL,
1654 "unspecified error");
1655 }
1656 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1657 "failed to change device on %s: ",
1658 priv->name);
1659 return FALSE;
1660 }
1661 return TRUE;
1662}
1663
Richard Hughese1fd34d2017-08-24 14:19:51 +01001664void
Richard Hughes12724852018-09-04 13:53:44 +01001665fu_plugin_runner_device_removed (FuPlugin *self, FuDevice *device)
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001666{
1667 g_autoptr(GError) error_local= NULL;
1668
Richard Hughes12724852018-09-04 13:53:44 +01001669 if (!fu_plugin_runner_device_generic (self, device,
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001670 "fu_plugin_device_removed",
Richard Hughes4b303802019-10-04 13:22:51 +01001671 NULL,
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001672 &error_local))
1673 g_warning ("%s", error_local->message);
1674}
1675
1676void
Richard Hughes12724852018-09-04 13:53:44 +01001677fu_plugin_runner_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +01001678{
Richard Hughes12724852018-09-04 13:53:44 +01001679 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughese1fd34d2017-08-24 14:19:51 +01001680 FuPluginDeviceRegisterFunc func = NULL;
1681
1682 /* not enabled */
1683 if (!priv->enabled)
1684 return;
Richard Hughes34834102017-11-21 21:55:00 +00001685 if (priv->module == NULL)
1686 return;
Richard Hughese1fd34d2017-08-24 14:19:51 +01001687
Mario Limonciello4910b242018-06-22 15:04:21 -05001688 /* don't notify plugins on their own devices */
Richard Hughes12724852018-09-04 13:53:44 +01001689 if (g_strcmp0 (fu_device_get_plugin (device), fu_plugin_get_name (self)) == 0)
Mario Limonciello4910b242018-06-22 15:04:21 -05001690 return;
1691
Richard Hughese1fd34d2017-08-24 14:19:51 +01001692 /* optional */
1693 g_module_symbol (priv->module, "fu_plugin_device_registered", (gpointer *) &func);
1694 if (func != NULL) {
Richard Hughes1bf7ff92018-08-24 20:21:35 +01001695 g_debug ("performing fu_plugin_device_registered() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01001696 func (self, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +01001697 }
1698}
1699
Richard Hughesc6c312f2019-02-01 16:37:14 +00001700gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001701fu_plugin_runner_schedule_update (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +00001702 FuDevice *device,
Richard Hughes994b4d92019-03-25 14:28:30 +00001703 FwupdRelease *release,
Richard Hughescff38bc2016-12-12 12:03:37 +00001704 GBytes *blob_cab,
Richard Hughes5cbb5cf2019-04-26 16:48:03 +01001705 FwupdInstallFlags flags,
Richard Hughescff38bc2016-12-12 12:03:37 +00001706 GError **error)
1707{
Richard Hughes0a906262019-05-16 13:38:47 +01001708 gchar tmpname[] = {"XXXXXX.cab"};
Richard Hughescff38bc2016-12-12 12:03:37 +00001709 g_autofree gchar *dirname = NULL;
1710 g_autofree gchar *filename = NULL;
Richard Hughes780ef3f2018-01-12 16:20:31 +00001711 g_autoptr(FuHistory) history = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001712 g_autoptr(GFile) file = NULL;
1713
1714 /* id already exists */
Richard Hughes780ef3f2018-01-12 16:20:31 +00001715 history = fu_history_new ();
Richard Hughes5cbb5cf2019-04-26 16:48:03 +01001716 if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) {
1717 g_autoptr(FuDevice) res_tmp = NULL;
1718 res_tmp = fu_history_get_device_by_id (history, fu_device_get_id (device), NULL);
1719 if (res_tmp != NULL &&
1720 fu_device_get_update_state (res_tmp) == FWUPD_UPDATE_STATE_PENDING) {
1721 g_set_error (error,
1722 FWUPD_ERROR,
1723 FWUPD_ERROR_ALREADY_PENDING,
1724 "%s is already scheduled to be updated",
1725 fu_device_get_id (device));
1726 return FALSE;
1727 }
Richard Hughescff38bc2016-12-12 12:03:37 +00001728 }
1729
1730 /* create directory */
Richard Hughes4be17d12018-05-30 20:36:29 +01001731 dirname = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG);
Richard Hughescff38bc2016-12-12 12:03:37 +00001732 file = g_file_new_for_path (dirname);
1733 if (!g_file_query_exists (file, NULL)) {
1734 if (!g_file_make_directory_with_parents (file, NULL, error))
1735 return FALSE;
1736 }
1737
1738 /* get a random filename */
1739 for (guint i = 0; i < 6; i++)
1740 tmpname[i] = (gchar) g_random_int_range ('A', 'Z');
1741 filename = g_build_filename (dirname, tmpname, NULL);
1742
1743 /* just copy to the temp file */
Richard Hughes23135eb2017-11-30 21:01:25 +00001744 fu_device_set_status (device, FWUPD_STATUS_SCHEDULING);
Richard Hughescff38bc2016-12-12 12:03:37 +00001745 if (!g_file_set_contents (filename,
1746 g_bytes_get_data (blob_cab, NULL),
1747 (gssize) g_bytes_get_size (blob_cab),
1748 error))
1749 return FALSE;
1750
1751 /* schedule for next boot */
1752 g_debug ("schedule %s to be installed to %s on next boot",
1753 filename, fu_device_get_id (device));
Richard Hughes994b4d92019-03-25 14:28:30 +00001754 fwupd_release_set_filename (release, filename);
Richard Hughescff38bc2016-12-12 12:03:37 +00001755
1756 /* add to database */
Richard Hughes809abea2019-03-23 11:06:18 +00001757 fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT);
Richard Hughes3e90a582018-01-06 22:38:09 +00001758 fu_device_set_update_state (device, FWUPD_UPDATE_STATE_PENDING);
Richard Hughes994b4d92019-03-25 14:28:30 +00001759 if (!fu_history_add_device (history, device, release, error))
Richard Hughescff38bc2016-12-12 12:03:37 +00001760 return FALSE;
1761
1762 /* next boot we run offline */
Richard Hughesdb69c812019-03-22 16:10:15 +00001763 fu_device_set_progress (device, 100);
Richard Hughescff38bc2016-12-12 12:03:37 +00001764 return fu_plugin_runner_offline_setup (error);
1765}
1766
1767gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001768fu_plugin_runner_verify (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +00001769 FuDevice *device,
1770 FuPluginVerifyFlags flags,
1771 GError **error)
1772{
Richard Hughes12724852018-09-04 13:53:44 +01001773 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001774 FuPluginVerifyFunc func = NULL;
Richard Hughesababbb72017-06-15 20:18:36 +01001775 GPtrArray *checksums;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001776 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001777
1778 /* not enabled */
1779 if (!priv->enabled)
1780 return TRUE;
1781
Richard Hughes639da472018-01-06 22:35:04 +00001782 /* no object loaded */
1783 if (priv->module == NULL)
1784 return TRUE;
1785
Richard Hughescff38bc2016-12-12 12:03:37 +00001786 /* optional */
1787 g_module_symbol (priv->module, "fu_plugin_verify", (gpointer *) &func);
Richard Hughes7f677212019-10-05 16:19:40 +01001788 if (func == NULL) {
Richard Hughes7f677212019-10-05 16:19:40 +01001789 return fu_plugin_device_read_firmware (self, device, error);
1790 }
Richard Hughes1812fc72018-12-14 11:37:54 +00001791
1792 /* clear any existing verification checksums */
1793 checksums = fu_device_get_checksums (device);
1794 g_ptr_array_set_size (checksums, 0);
1795
Richard Hughesc9223be2019-03-18 08:46:42 +00001796 /* run additional detach */
1797 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01001798 "fu_plugin_update_detach",
Richard Hughes4b303802019-10-04 13:22:51 +01001799 fu_plugin_device_detach,
Richard Hughesc9223be2019-03-18 08:46:42 +00001800 error))
1801 return FALSE;
1802
Richard Hughes1812fc72018-12-14 11:37:54 +00001803 /* run vfunc */
Richard Hughescff38bc2016-12-12 12:03:37 +00001804 g_debug ("performing verify() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001805 if (!func (self, device, flags, &error_local)) {
Richard Hughesc9223be2019-03-18 08:46:42 +00001806 g_autoptr(GError) error_attach = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001807 if (error_local == NULL) {
1808 g_critical ("unset error in plugin %s for verify()",
1809 priv->name);
1810 g_set_error_literal (&error_local,
1811 FWUPD_ERROR,
1812 FWUPD_ERROR_INTERNAL,
1813 "unspecified error");
1814 }
1815 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1816 "failed to verify using %s: ",
1817 priv->name);
Richard Hughesc9223be2019-03-18 08:46:42 +00001818 /* make the device "work" again, but don't prefix the error */
1819 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01001820 "fu_plugin_update_attach",
Richard Hughes4b303802019-10-04 13:22:51 +01001821 fu_plugin_device_attach,
Richard Hughesc9223be2019-03-18 08:46:42 +00001822 &error_attach)) {
1823 g_warning ("failed to attach whilst aborting verify(): %s",
1824 error_attach->message);
1825 }
Richard Hughesd0905142016-03-13 09:46:49 +00001826 return FALSE;
1827 }
Richard Hughesc9223be2019-03-18 08:46:42 +00001828
1829 /* run optional attach */
1830 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01001831 "fu_plugin_update_attach",
Richard Hughes4b303802019-10-04 13:22:51 +01001832 fu_plugin_device_attach,
Richard Hughesc9223be2019-03-18 08:46:42 +00001833 error))
1834 return FALSE;
1835
1836 /* success */
Richard Hughesd0905142016-03-13 09:46:49 +00001837 return TRUE;
1838}
1839
Richard Hughesd0905142016-03-13 09:46:49 +00001840gboolean
Mario Limonciello96a0dd52019-02-25 13:50:03 -06001841fu_plugin_runner_activate (FuPlugin *self, FuDevice *device, GError **error)
1842{
1843 guint64 flags;
1844
1845 /* final check */
1846 flags = fu_device_get_flags (device);
1847 if ((flags & FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION) == 0) {
1848 g_set_error (error,
1849 FWUPD_ERROR,
1850 FWUPD_ERROR_NOT_SUPPORTED,
1851 "Device %s does not need activation",
1852 fu_device_get_id (device));
1853 return FALSE;
1854 }
1855
1856 /* run vfunc */
1857 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001858 "fu_plugin_activate",
1859 fu_plugin_device_activate,
1860 error))
Mario Limonciello96a0dd52019-02-25 13:50:03 -06001861 return FALSE;
1862
1863 /* update with correct flags */
1864 fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION);
1865 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
1866 return TRUE;
1867}
1868
1869gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001870fu_plugin_runner_unlock (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00001871{
Richard Hughescff38bc2016-12-12 12:03:37 +00001872 guint64 flags;
Richard Hughescff38bc2016-12-12 12:03:37 +00001873
1874 /* final check */
1875 flags = fu_device_get_flags (device);
1876 if ((flags & FWUPD_DEVICE_FLAG_LOCKED) == 0) {
1877 g_set_error (error,
1878 FWUPD_ERROR,
1879 FWUPD_ERROR_NOT_SUPPORTED,
1880 "Device %s is not locked",
1881 fu_device_get_id (device));
1882 return FALSE;
1883 }
1884
Richard Hughes9c4b5312017-11-14 11:34:53 +00001885 /* run vfunc */
Richard Hughes12724852018-09-04 13:53:44 +01001886 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001887 "fu_plugin_unlock",
1888 NULL,
1889 error))
Richard Hughes9c4b5312017-11-14 11:34:53 +00001890 return FALSE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001891
1892 /* update with correct flags */
1893 flags = fu_device_get_flags (device);
1894 fu_device_set_flags (device, flags &= ~FWUPD_DEVICE_FLAG_LOCKED);
1895 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
1896 return TRUE;
1897}
1898
1899gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001900fu_plugin_runner_update (FuPlugin *self,
Richard Hughesa785a1c2017-08-25 16:00:58 +01001901 FuDevice *device,
Richard Hughesa785a1c2017-08-25 16:00:58 +01001902 GBytes *blob_fw,
1903 FwupdInstallFlags flags,
1904 GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00001905{
Richard Hughes12724852018-09-04 13:53:44 +01001906 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesa785a1c2017-08-25 16:00:58 +01001907 FuPluginUpdateFunc update_func;
Richard Hughes780ef3f2018-01-12 16:20:31 +00001908 g_autoptr(FuHistory) history = NULL;
Richard Hughes68982c62017-09-13 15:40:14 +01001909 g_autoptr(FuDevice) device_pending = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001910 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001911
1912 /* not enabled */
Richard Hughes41c15482018-02-01 22:07:21 +00001913 if (!priv->enabled) {
1914 g_debug ("plugin not enabled, skipping");
Richard Hughesd0905142016-03-13 09:46:49 +00001915 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00001916 }
Richard Hughesd0905142016-03-13 09:46:49 +00001917
Richard Hughes639da472018-01-06 22:35:04 +00001918 /* no object loaded */
Richard Hughes41c15482018-02-01 22:07:21 +00001919 if (priv->module == NULL) {
1920 g_debug ("module not enabled, skipping");
Richard Hughes639da472018-01-06 22:35:04 +00001921 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00001922 }
Richard Hughes639da472018-01-06 22:35:04 +00001923
Richard Hughesd0905142016-03-13 09:46:49 +00001924 /* optional */
Richard Hughesa785a1c2017-08-25 16:00:58 +01001925 g_module_symbol (priv->module, "fu_plugin_update", (gpointer *) &update_func);
1926 if (update_func == NULL) {
Richard Hughes4b303802019-10-04 13:22:51 +01001927 g_debug ("running superclassed write_firmware() on %s", priv->name);
1928 return fu_plugin_device_write_firmware (self, device, blob_fw, flags, error);
Richard Hughesa785a1c2017-08-25 16:00:58 +01001929 }
Richard Hughesd0905142016-03-13 09:46:49 +00001930
Richard Hughescff38bc2016-12-12 12:03:37 +00001931 /* cancel the pending action */
1932 if (!fu_plugin_runner_offline_invalidate (error))
1933 return FALSE;
1934
1935 /* online */
Richard Hughes780ef3f2018-01-12 16:20:31 +00001936 history = fu_history_new ();
Richard Hughes0b9d9962018-01-12 16:31:28 +00001937 device_pending = fu_history_get_device_by_id (history, fu_device_get_id (device), NULL);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001938 if (!update_func (self, device, blob_fw, flags, &error_local)) {
1939 if (error_local == NULL) {
1940 g_critical ("unset error in plugin %s for update()",
1941 priv->name);
1942 g_set_error_literal (&error_local,
Richard Hughes3c8ada32018-10-12 10:08:58 +01001943 FWUPD_ERROR,
1944 FWUPD_ERROR_INTERNAL,
1945 "unspecified error");
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001946 return FALSE;
Richard Hughes3c8ada32018-10-12 10:08:58 +01001947 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001948 fu_device_set_update_error (device, error_local->message);
1949 g_propagate_error (error, g_steal_pointer (&error_local));
Richard Hughescff38bc2016-12-12 12:03:37 +00001950 return FALSE;
1951 }
1952
Richard Hughesf556d372017-06-15 19:49:18 +01001953 /* no longer valid */
Richard Hughesf8039642019-01-16 12:22:22 +00001954 if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT) &&
1955 !fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) {
Richard Hughes08435162018-12-12 10:34:16 +00001956 GPtrArray *checksums = fu_device_get_checksums (device);
1957 g_ptr_array_set_size (checksums, 0);
1958 }
Richard Hughesf556d372017-06-15 19:49:18 +01001959
Richard Hughescff38bc2016-12-12 12:03:37 +00001960 /* cleanup */
Richard Hughes68982c62017-09-13 15:40:14 +01001961 if (device_pending != NULL) {
Richard Hughescff38bc2016-12-12 12:03:37 +00001962 const gchar *tmp;
Richard Hughesbc3a4e12018-01-06 22:41:47 +00001963 FwupdRelease *release;
Richard Hughescff38bc2016-12-12 12:03:37 +00001964
Richard Hughes780ef3f2018-01-12 16:20:31 +00001965 /* update history database */
Richard Hughesc0cd0232018-01-31 15:02:00 +00001966 fu_device_set_update_state (device, FWUPD_UPDATE_STATE_SUCCESS);
Richard Hughes0bbef292019-11-01 12:15:15 +00001967 if (!fu_history_modify_device (history, device, error))
Richard Hughes0b9d9962018-01-12 16:31:28 +00001968 return FALSE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001969
1970 /* delete cab file */
Richard Hughesbc3a4e12018-01-06 22:41:47 +00001971 release = fu_device_get_release_default (device_pending);
1972 tmp = fwupd_release_get_filename (release);
Richard Hughescff38bc2016-12-12 12:03:37 +00001973 if (tmp != NULL && g_str_has_prefix (tmp, LIBEXECDIR)) {
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001974 g_autoptr(GError) error_delete = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001975 g_autoptr(GFile) file = NULL;
1976 file = g_file_new_for_path (tmp);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001977 if (!g_file_delete (file, NULL, &error_delete)) {
Richard Hughescff38bc2016-12-12 12:03:37 +00001978 g_set_error (error,
1979 FWUPD_ERROR,
1980 FWUPD_ERROR_INVALID_FILE,
1981 "Failed to delete %s: %s",
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001982 tmp, error_delete->message);
Richard Hughescff38bc2016-12-12 12:03:37 +00001983 return FALSE;
1984 }
1985 }
1986 }
Richard Hughesd0905142016-03-13 09:46:49 +00001987 return TRUE;
1988}
Richard Hughescff38bc2016-12-12 12:03:37 +00001989
1990gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001991fu_plugin_runner_clear_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00001992{
Richard Hughes12724852018-09-04 13:53:44 +01001993 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001994 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001995 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001996
1997 /* not enabled */
1998 if (!priv->enabled)
1999 return TRUE;
2000
Richard Hughes639da472018-01-06 22:35:04 +00002001 /* no object loaded */
2002 if (priv->module == NULL)
2003 return TRUE;
2004
Richard Hughes65e44ca2018-01-30 17:26:30 +00002005 /* optional */
Richard Hughescd644902019-11-01 12:35:17 +00002006 g_module_symbol (priv->module, "fu_plugin_clear_results", (gpointer *) &func);
Richard Hughes65e44ca2018-01-30 17:26:30 +00002007 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00002008 return TRUE;
Richard Hughes65e44ca2018-01-30 17:26:30 +00002009 g_debug ("performing clear_result() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002010 if (!func (self, device, &error_local)) {
2011 if (error_local == NULL) {
2012 g_critical ("unset error in plugin %s for clear_result()",
2013 priv->name);
2014 g_set_error_literal (&error_local,
2015 FWUPD_ERROR,
2016 FWUPD_ERROR_INTERNAL,
2017 "unspecified error");
2018 }
2019 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2020 "failed to clear_result using %s: ",
2021 priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00002022 return FALSE;
2023 }
Richard Hughes65e44ca2018-01-30 17:26:30 +00002024 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00002025}
2026
2027gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002028fu_plugin_runner_get_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00002029{
Richard Hughes12724852018-09-04 13:53:44 +01002030 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00002031 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002032 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002033
2034 /* not enabled */
2035 if (!priv->enabled)
2036 return TRUE;
2037
Richard Hughes639da472018-01-06 22:35:04 +00002038 /* no object loaded */
2039 if (priv->module == NULL)
2040 return TRUE;
2041
Richard Hughes65e44ca2018-01-30 17:26:30 +00002042 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00002043 g_module_symbol (priv->module, "fu_plugin_get_results", (gpointer *) &func);
Richard Hughes65e44ca2018-01-30 17:26:30 +00002044 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00002045 return TRUE;
Richard Hughes65e44ca2018-01-30 17:26:30 +00002046 g_debug ("performing get_results() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002047 if (!func (self, device, &error_local)) {
2048 if (error_local == NULL) {
2049 g_critical ("unset error in plugin %s for get_results()",
2050 priv->name);
2051 g_set_error_literal (&error_local,
2052 FWUPD_ERROR,
2053 FWUPD_ERROR_INTERNAL,
2054 "unspecified error");
2055 }
2056 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2057 "failed to get_results using %s: ",
2058 priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00002059 return FALSE;
2060 }
Richard Hughescff38bc2016-12-12 12:03:37 +00002061 return TRUE;
2062}
2063
Richard Hughes08a37992017-09-12 12:57:43 +01002064/**
2065 * fu_plugin_get_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002066 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002067 *
2068 * Gets the plugin order, where higher numbers are run after lower
2069 * numbers.
2070 *
2071 * Returns: the integer value
2072 **/
2073guint
Richard Hughes12724852018-09-04 13:53:44 +01002074fu_plugin_get_order (FuPlugin *self)
Richard Hughes08a37992017-09-12 12:57:43 +01002075{
Richard Hughes12724852018-09-04 13:53:44 +01002076 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002077 return priv->order;
2078}
2079
2080/**
2081 * fu_plugin_set_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002082 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002083 * @order: a integer value
2084 *
2085 * Sets the plugin order, where higher numbers are run after lower
2086 * numbers.
2087 **/
2088void
Richard Hughes12724852018-09-04 13:53:44 +01002089fu_plugin_set_order (FuPlugin *self, guint order)
Richard Hughes08a37992017-09-12 12:57:43 +01002090{
Richard Hughes12724852018-09-04 13:53:44 +01002091 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002092 priv->order = order;
2093}
2094
2095/**
Richard Hughes81c427c2018-08-06 15:20:17 +01002096 * fu_plugin_get_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002097 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01002098 *
2099 * Gets the plugin priority, where higher numbers are better.
2100 *
2101 * Returns: the integer value
2102 **/
2103guint
Richard Hughes12724852018-09-04 13:53:44 +01002104fu_plugin_get_priority (FuPlugin *self)
Richard Hughes81c427c2018-08-06 15:20:17 +01002105{
Richard Hughes12724852018-09-04 13:53:44 +01002106 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01002107 return priv->priority;
2108}
2109
2110/**
2111 * fu_plugin_set_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002112 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01002113 * @priority: a integer value
2114 *
2115 * Sets the plugin priority, where higher numbers are better.
2116 **/
2117void
Richard Hughes12724852018-09-04 13:53:44 +01002118fu_plugin_set_priority (FuPlugin *self, guint priority)
Richard Hughes81c427c2018-08-06 15:20:17 +01002119{
Richard Hughes12724852018-09-04 13:53:44 +01002120 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01002121 priv->priority = priority;
2122}
2123
2124/**
Richard Hughes08a37992017-09-12 12:57:43 +01002125 * fu_plugin_add_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002126 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002127 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
Richard Hughes4eada342017-10-03 21:20:32 +01002128 * @name: a plugin name, e.g. `upower`
Richard Hughes08a37992017-09-12 12:57:43 +01002129 *
2130 * If the plugin name is found, the rule will be used to sort the plugin list,
2131 * for example the plugin specified by @name will be ordered after this plugin
2132 * when %FU_PLUGIN_RULE_RUN_AFTER is used.
2133 *
2134 * NOTE: The depsolver is iterative and may not solve overly-complicated rules;
2135 * If depsolving fails then fwupd will not start.
2136 **/
2137void
Richard Hughes12724852018-09-04 13:53:44 +01002138fu_plugin_add_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes08a37992017-09-12 12:57:43 +01002139{
Richard Hughes12724852018-09-04 13:53:44 +01002140 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002141 g_ptr_array_add (priv->rules[rule], g_strdup (name));
Richard Hughes75b965d2018-11-15 13:51:21 +00002142 g_signal_emit (self, signals[SIGNAL_RULES_CHANGED], 0);
Richard Hughes08a37992017-09-12 12:57:43 +01002143}
2144
2145/**
2146 * fu_plugin_get_rules:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002147 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002148 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
2149 *
2150 * Gets the plugin IDs that should be run after this plugin.
2151 *
2152 * Returns: (element-type utf8) (transfer none): the list of plugin names, e.g. ['appstream']
2153 **/
2154GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +01002155fu_plugin_get_rules (FuPlugin *self, FuPluginRule rule)
Richard Hughes08a37992017-09-12 12:57:43 +01002156{
Richard Hughes12724852018-09-04 13:53:44 +01002157 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002158 return priv->rules[rule];
2159}
2160
Richard Hughes80b79bb2018-01-11 21:11:06 +00002161/**
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002162 * fu_plugin_has_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002163 * @self: a #FuPlugin
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002164 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
2165 * @name: a plugin name, e.g. `upower`
2166 *
Richard Hughes87fb9ff2018-06-28 12:55:59 +01002167 * Gets the plugin IDs that should be run after this plugin.
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002168 *
2169 * Returns: %TRUE if the name exists for the specific rule
2170 **/
2171gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002172fu_plugin_has_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002173{
Richard Hughes12724852018-09-04 13:53:44 +01002174 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002175 for (guint i = 0; i < priv->rules[rule]->len; i++) {
2176 const gchar *tmp = g_ptr_array_index (priv->rules[rule], i);
2177 if (g_strcmp0 (tmp, name) == 0)
2178 return TRUE;
2179 }
2180 return FALSE;
2181}
2182
2183/**
Richard Hughes80b79bb2018-01-11 21:11:06 +00002184 * fu_plugin_add_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002185 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00002186 * @key: a string, e.g. `FwupdateVersion`
2187 * @value: a string, e.g. `10`
2188 *
2189 * Sets any additional metadata to be included in the firmware report to aid
2190 * debugging problems.
2191 *
2192 * Any data included here will be sent to the metadata server after user
2193 * confirmation.
2194 **/
2195void
Richard Hughes12724852018-09-04 13:53:44 +01002196fu_plugin_add_report_metadata (FuPlugin *self, const gchar *key, const gchar *value)
Richard Hughes80b79bb2018-01-11 21:11:06 +00002197{
Richard Hughes12724852018-09-04 13:53:44 +01002198 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002199 g_hash_table_insert (priv->report_metadata, g_strdup (key), g_strdup (value));
2200}
2201
2202/**
2203 * fu_plugin_get_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002204 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00002205 *
2206 * Returns the list of additional metadata to be added when filing a report.
2207 *
2208 * Returns: (transfer none): the map of report metadata
2209 **/
2210GHashTable *
Richard Hughes12724852018-09-04 13:53:44 +01002211fu_plugin_get_report_metadata (FuPlugin *self)
Richard Hughes80b79bb2018-01-11 21:11:06 +00002212{
Richard Hughes12724852018-09-04 13:53:44 +01002213 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002214 return priv->report_metadata;
2215}
2216
Mario Limonciello963dc422018-02-27 14:26:58 -06002217/**
2218 * fu_plugin_get_config_value:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002219 * @self: a #FuPlugin
Mario Limonciello963dc422018-02-27 14:26:58 -06002220 * @key: A settings key
2221 *
2222 * Return the value of a key if it's been configured
2223 *
2224 * Since: 1.0.6
2225 **/
2226gchar *
Richard Hughes12724852018-09-04 13:53:44 +01002227fu_plugin_get_config_value (FuPlugin *self, const gchar *key)
Mario Limonciello963dc422018-02-27 14:26:58 -06002228{
Richard Hughes4be17d12018-05-30 20:36:29 +01002229 g_autofree gchar *conf_dir = NULL;
Mario Limonciello963dc422018-02-27 14:26:58 -06002230 g_autofree gchar *conf_file = NULL;
2231 g_autofree gchar *conf_path = NULL;
2232 g_autoptr(GKeyFile) keyfile = NULL;
2233 const gchar *plugin_name;
2234
Richard Hughes4be17d12018-05-30 20:36:29 +01002235 conf_dir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR_PKG);
Richard Hughes12724852018-09-04 13:53:44 +01002236 plugin_name = fu_plugin_get_name (self);
Mario Limonciello963dc422018-02-27 14:26:58 -06002237 conf_file = g_strdup_printf ("%s.conf", plugin_name);
Richard Hughes4be17d12018-05-30 20:36:29 +01002238 conf_path = g_build_filename (conf_dir, conf_file, NULL);
Mario Limonciello963dc422018-02-27 14:26:58 -06002239 if (!g_file_test (conf_path, G_FILE_TEST_IS_REGULAR))
2240 return NULL;
2241 keyfile = g_key_file_new ();
2242 if (!g_key_file_load_from_file (keyfile, conf_path,
2243 G_KEY_FILE_NONE, NULL))
2244 return NULL;
2245 return g_key_file_get_string (keyfile, plugin_name, key, NULL);
2246}
2247
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002248/**
2249 * fu_plugin_name_compare:
2250 * @plugin1: first #FuPlugin to compare.
2251 * @plugin2: second #FuPlugin to compare.
2252 *
2253 * Compares two plugins by their names.
2254 *
2255 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
2256 **/
2257gint
2258fu_plugin_name_compare (FuPlugin *plugin1, FuPlugin *plugin2)
2259{
2260 FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1);
2261 FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2);
2262 return g_strcmp0 (priv1->name, priv2->name);
2263}
2264
2265/**
2266 * fu_plugin_order_compare:
2267 * @plugin1: first #FuPlugin to compare.
2268 * @plugin2: second #FuPlugin to compare.
2269 *
2270 * Compares two plugins by their depsolved order.
2271 *
2272 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
2273 **/
2274gint
2275fu_plugin_order_compare (FuPlugin *plugin1, FuPlugin *plugin2)
2276{
2277 FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1);
2278 FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2);
2279 if (priv1->order < priv2->order)
2280 return -1;
2281 if (priv1->order > priv2->order)
2282 return 1;
2283 return 0;
2284}
2285
Richard Hughescff38bc2016-12-12 12:03:37 +00002286static void
2287fu_plugin_class_init (FuPluginClass *klass)
2288{
2289 GObjectClass *object_class = G_OBJECT_CLASS (klass);
2290 object_class->finalize = fu_plugin_finalize;
2291 signals[SIGNAL_DEVICE_ADDED] =
2292 g_signal_new ("device-added",
2293 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2294 G_STRUCT_OFFSET (FuPluginClass, device_added),
2295 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2296 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
2297 signals[SIGNAL_DEVICE_REMOVED] =
2298 g_signal_new ("device-removed",
2299 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2300 G_STRUCT_OFFSET (FuPluginClass, device_removed),
2301 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2302 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughese1fd34d2017-08-24 14:19:51 +01002303 signals[SIGNAL_DEVICE_REGISTER] =
2304 g_signal_new ("device-register",
2305 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2306 G_STRUCT_OFFSET (FuPluginClass, device_register),
2307 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2308 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughes362d6d72017-01-07 21:42:14 +00002309 signals[SIGNAL_RECOLDPLUG] =
2310 g_signal_new ("recoldplug",
2311 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2312 G_STRUCT_OFFSET (FuPluginClass, recoldplug),
2313 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2314 G_TYPE_NONE, 0);
Richard Hughesb0829032017-01-10 09:27:08 +00002315 signals[SIGNAL_SET_COLDPLUG_DELAY] =
2316 g_signal_new ("set-coldplug-delay",
2317 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2318 G_STRUCT_OFFSET (FuPluginClass, set_coldplug_delay),
2319 NULL, NULL, g_cclosure_marshal_VOID__UINT,
2320 G_TYPE_NONE, 1, G_TYPE_UINT);
Richard Hughesaabdc372018-11-14 10:11:08 +00002321 signals[SIGNAL_CHECK_SUPPORTED] =
2322 g_signal_new ("check-supported",
2323 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2324 G_STRUCT_OFFSET (FuPluginClass, check_supported),
2325 NULL, NULL, g_cclosure_marshal_generic,
2326 G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
Richard Hughes75b965d2018-11-15 13:51:21 +00002327 signals[SIGNAL_RULES_CHANGED] =
2328 g_signal_new ("rules-changed",
2329 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2330 G_STRUCT_OFFSET (FuPluginClass, rules_changed),
2331 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2332 G_TYPE_NONE, 0);
Richard Hughes95c98a92019-10-22 16:03:15 +01002333 signals[SIGNAL_ADD_FIRMWARE_GTYPE] =
2334 g_signal_new ("add-firmware-gtype",
2335 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2336 G_STRUCT_OFFSET (FuPluginClass, add_firmware_gtype),
2337 NULL, NULL, g_cclosure_marshal_generic,
2338 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_GTYPE);
Richard Hughescff38bc2016-12-12 12:03:37 +00002339}
2340
2341static void
Richard Hughes12724852018-09-04 13:53:44 +01002342fu_plugin_init (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +00002343{
Richard Hughes12724852018-09-04 13:53:44 +01002344 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002345 priv->enabled = TRUE;
Richard Hughesb1065422019-08-15 16:44:34 +01002346 priv->udev_subsystems = g_ptr_array_new_with_free_func (g_free);
Richard Hughescff38bc2016-12-12 12:03:37 +00002347 priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal,
2348 g_free, (GDestroyNotify) g_object_unref);
Richard Hughes161e9b52019-06-12 14:22:45 +01002349 g_rw_lock_init (&priv->devices_mutex);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002350 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 +01002351 for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++)
2352 priv->rules[i] = g_ptr_array_new_with_free_func (g_free);
Richard Hughescff38bc2016-12-12 12:03:37 +00002353}
2354
2355static void
2356fu_plugin_finalize (GObject *object)
2357{
Richard Hughes12724852018-09-04 13:53:44 +01002358 FuPlugin *self = FU_PLUGIN (object);
2359 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002360 FuPluginInitFunc func = NULL;
2361
2362 /* optional */
2363 if (priv->module != NULL) {
2364 g_module_symbol (priv->module, "fu_plugin_destroy", (gpointer *) &func);
2365 if (func != NULL) {
2366 g_debug ("performing destroy() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01002367 func (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002368 }
2369 }
2370
Richard Hughes08a37992017-09-12 12:57:43 +01002371 for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++)
2372 g_ptr_array_unref (priv->rules[i]);
2373
Richard Hughescff38bc2016-12-12 12:03:37 +00002374 if (priv->usb_ctx != NULL)
2375 g_object_unref (priv->usb_ctx);
Richard Hughesb8f8db22017-04-25 15:56:00 +01002376 if (priv->hwids != NULL)
Richard Hughesd7704d42017-08-08 20:29:09 +01002377 g_object_unref (priv->hwids);
Richard Hughes9c028f02017-10-28 21:14:28 +01002378 if (priv->quirks != NULL)
2379 g_object_unref (priv->quirks);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01002380 if (priv->udev_subsystems != NULL)
2381 g_ptr_array_unref (priv->udev_subsystems);
Richard Hughes49e5e052017-09-03 12:15:41 +01002382 if (priv->smbios != NULL)
2383 g_object_unref (priv->smbios);
Richard Hughes275d3b42018-04-20 16:40:37 +01002384 if (priv->runtime_versions != NULL)
2385 g_hash_table_unref (priv->runtime_versions);
Richard Hughes34e0dab2018-04-20 16:43:00 +01002386 if (priv->compile_versions != NULL)
2387 g_hash_table_unref (priv->compile_versions);
Richard Hughescff38bc2016-12-12 12:03:37 +00002388 g_hash_table_unref (priv->devices);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002389 g_hash_table_unref (priv->report_metadata);
Richard Hughes161e9b52019-06-12 14:22:45 +01002390 g_rw_lock_clear (&priv->devices_mutex);
Richard Hughes84999302019-05-02 10:18:32 +01002391 g_free (priv->build_hash);
Richard Hughescff38bc2016-12-12 12:03:37 +00002392 g_free (priv->name);
2393 g_free (priv->data);
Mario Limonciello3f9a1c12018-06-06 14:06:40 -05002394 /* Must happen as the last step to avoid prematurely
2395 * freeing memory held by the plugin */
2396#ifndef RUNNING_ON_VALGRIND
2397 if (priv->module != NULL)
2398 g_module_close (priv->module);
2399#endif
Richard Hughescff38bc2016-12-12 12:03:37 +00002400
2401 G_OBJECT_CLASS (fu_plugin_parent_class)->finalize (object);
2402}
2403
2404FuPlugin *
2405fu_plugin_new (void)
2406{
Richard Hughes12724852018-09-04 13:53:44 +01002407 return FU_PLUGIN (g_object_new (FU_TYPE_PLUGIN, NULL));
Richard Hughescff38bc2016-12-12 12:03:37 +00002408}