blob: cff8cf735c65fa03e9760a8cf39ea98f4d4704f9 [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{
Richard Hughesafdba372019-11-23 12:57:35 +00001014 g_autofree gchar *trigger = fu_common_get_path (FU_PATH_KIND_OFFLINE_TRIGGER);
Richard Hughescff38bc2016-12-12 12:03:37 +00001015 g_autoptr(GError) error_local = NULL;
1016 g_autoptr(GFile) file1 = NULL;
1017
1018 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1019
Richard Hughesafdba372019-11-23 12:57:35 +00001020 file1 = g_file_new_for_path (trigger);
Richard Hughescff38bc2016-12-12 12:03:37 +00001021 if (!g_file_query_exists (file1, NULL))
1022 return TRUE;
1023 if (!g_file_delete (file1, NULL, &error_local)) {
1024 g_set_error (error,
1025 FWUPD_ERROR,
1026 FWUPD_ERROR_INTERNAL,
1027 "Cannot delete %s: %s",
Richard Hughesafdba372019-11-23 12:57:35 +00001028 trigger,
Richard Hughescff38bc2016-12-12 12:03:37 +00001029 error_local->message);
1030 return FALSE;
1031 }
1032 return TRUE;
1033}
1034
1035static gboolean
1036fu_plugin_runner_offline_setup (GError **error)
1037{
1038 gint rc;
Richard Hughes484ee292019-03-22 16:10:50 +00001039 g_autofree gchar *filename = NULL;
Mario Limoncielloe1b4b202019-04-30 10:01:19 -05001040 g_autofree gchar *symlink_target = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG);
Richard Hughesafdba372019-11-23 12:57:35 +00001041 g_autofree gchar *trigger = fu_common_get_path (FU_PATH_KIND_OFFLINE_TRIGGER);
Richard Hughescff38bc2016-12-12 12:03:37 +00001042
1043 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1044
Richard Hughes484ee292019-03-22 16:10:50 +00001045 /* does already exist */
Richard Hughesafdba372019-11-23 12:57:35 +00001046 filename = fu_common_realpath (trigger, NULL);
Richard Hughes484ee292019-03-22 16:10:50 +00001047 if (g_strcmp0 (filename, symlink_target) == 0) {
1048 g_debug ("%s already points to %s, skipping creation",
Richard Hughesafdba372019-11-23 12:57:35 +00001049 trigger, symlink_target);
Richard Hughes484ee292019-03-22 16:10:50 +00001050 return TRUE;
1051 }
1052
Richard Hughescff38bc2016-12-12 12:03:37 +00001053 /* create symlink for the systemd-system-update-generator */
Richard Hughesafdba372019-11-23 12:57:35 +00001054 rc = symlink (symlink_target, trigger);
Richard Hughescff38bc2016-12-12 12:03:37 +00001055 if (rc < 0) {
1056 g_set_error (error,
1057 FWUPD_ERROR,
1058 FWUPD_ERROR_INTERNAL,
1059 "Failed to create symlink %s to %s: %s",
Richard Hughesafdba372019-11-23 12:57:35 +00001060 trigger,
Richard Hughescff38bc2016-12-12 12:03:37 +00001061 "/var/lib", strerror (errno));
Richard Hughesd0905142016-03-13 09:46:49 +00001062 return FALSE;
1063 }
1064 return TRUE;
1065}
1066
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001067static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001068fu_plugin_runner_device_generic (FuPlugin *self, FuDevice *device,
Richard Hughes4b303802019-10-04 13:22:51 +01001069 const gchar *symbol_name,
1070 FuPluginDeviceFunc device_func,
1071 GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001072{
Richard Hughes12724852018-09-04 13:53:44 +01001073 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001074 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001075 g_autoptr(GError) error_local = NULL;
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001076
1077 /* not enabled */
1078 if (!priv->enabled)
1079 return TRUE;
1080
Richard Hughesd3d96cc2017-11-14 11:34:33 +00001081 /* no object loaded */
1082 if (priv->module == NULL)
1083 return TRUE;
1084
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001085 /* optional */
1086 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
Richard Hughes4b303802019-10-04 13:22:51 +01001087 if (func == NULL) {
1088 if (device_func != NULL) {
1089 g_debug ("running superclassed %s() on %s",
1090 symbol_name + 10, priv->name);
1091 return device_func (self, device, error);
1092 }
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001093 return TRUE;
Richard Hughes4b303802019-10-04 13:22:51 +01001094 }
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001095 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001096 if (!func (self, device, &error_local)) {
1097 if (error_local == NULL) {
1098 g_critical ("unset error in plugin %s for %s()",
1099 priv->name, symbol_name + 10);
1100 g_set_error_literal (&error_local,
1101 FWUPD_ERROR,
1102 FWUPD_ERROR_INTERNAL,
1103 "unspecified error");
1104 }
1105 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1106 "failed to %s using %s: ",
1107 symbol_name + 10, priv->name);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001108 return FALSE;
1109 }
1110 return TRUE;
1111}
1112
Richard Hughesdbd8c762018-06-15 20:31:40 +01001113static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001114fu_plugin_runner_flagged_device_generic (FuPlugin *self, FwupdInstallFlags flags,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001115 FuDevice *device,
1116 const gchar *symbol_name, GError **error)
1117{
Richard Hughes12724852018-09-04 13:53:44 +01001118 FuPluginPrivate *priv = GET_PRIVATE (self);
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001119 FuPluginFlaggedDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001120 g_autoptr(GError) error_local = NULL;
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001121
1122 /* not enabled */
1123 if (!priv->enabled)
1124 return TRUE;
1125
1126 /* no object loaded */
1127 if (priv->module == NULL)
1128 return TRUE;
1129
1130 /* optional */
1131 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1132 if (func == NULL)
1133 return TRUE;
1134 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001135 if (!func (self, flags, device, &error_local)) {
1136 if (error_local == NULL) {
1137 g_critical ("unset error in plugin %s for %s()",
1138 priv->name, symbol_name + 10);
1139 g_set_error_literal (&error_local,
1140 FWUPD_ERROR,
1141 FWUPD_ERROR_INTERNAL,
1142 "unspecified error");
1143 }
1144 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1145 "failed to %s using %s: ",
1146 symbol_name + 10, priv->name);
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001147 return FALSE;
1148 }
1149 return TRUE;
1150
1151}
1152
1153static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001154fu_plugin_runner_device_array_generic (FuPlugin *self, GPtrArray *devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001155 const gchar *symbol_name, GError **error)
1156{
Richard Hughes12724852018-09-04 13:53:44 +01001157 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesdbd8c762018-06-15 20:31:40 +01001158 FuPluginDeviceArrayFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001159 g_autoptr(GError) error_local = NULL;
Richard Hughesdbd8c762018-06-15 20:31:40 +01001160
1161 /* not enabled */
1162 if (!priv->enabled)
1163 return TRUE;
1164
1165 /* no object loaded */
1166 if (priv->module == NULL)
1167 return TRUE;
1168
1169 /* optional */
1170 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1171 if (func == NULL)
1172 return TRUE;
1173 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001174 if (!func (self, devices, &error_local)) {
1175 if (error_local == NULL) {
1176 g_critical ("unset error in plugin %s for %s()",
1177 priv->name, symbol_name + 10);
1178 g_set_error_literal (&error_local,
1179 FWUPD_ERROR,
1180 FWUPD_ERROR_INTERNAL,
1181 "unspecified error");
1182 }
1183 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1184 "failed to %s using %s: ",
1185 symbol_name + 10, priv->name);
Richard Hughesdbd8c762018-06-15 20:31:40 +01001186 return FALSE;
1187 }
1188 return TRUE;
1189}
1190
Richard Hughesd0905142016-03-13 09:46:49 +00001191gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001192fu_plugin_runner_coldplug (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00001193{
Richard Hughes12724852018-09-04 13:53:44 +01001194 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001195 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001196 g_autoptr(GError) error_local = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +00001197
1198 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +00001199 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +00001200 return TRUE;
1201
Richard Hughes639da472018-01-06 22:35:04 +00001202 /* no object loaded */
1203 if (priv->module == NULL)
1204 return TRUE;
1205
Richard Hughesd0905142016-03-13 09:46:49 +00001206 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00001207 g_module_symbol (priv->module, "fu_plugin_coldplug", (gpointer *) &func);
1208 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +00001209 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001210 g_debug ("performing coldplug() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001211 if (!func (self, &error_local)) {
1212 if (error_local == NULL) {
1213 g_critical ("unset error in plugin %s for coldplug()",
1214 priv->name);
1215 g_set_error_literal (&error_local,
1216 FWUPD_ERROR,
1217 FWUPD_ERROR_INTERNAL,
1218 "unspecified error");
1219 }
1220 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1221 "failed to coldplug using %s: ", priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00001222 return FALSE;
1223 }
1224 return TRUE;
1225}
1226
Richard Hughes7b8b2022016-12-12 16:15:03 +00001227gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001228fu_plugin_runner_recoldplug (FuPlugin *self, GError **error)
Richard Hughes2de8f132018-01-17 09:12:02 +00001229{
Richard Hughes12724852018-09-04 13:53:44 +01001230 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes2de8f132018-01-17 09:12:02 +00001231 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001232 g_autoptr(GError) error_local = NULL;
Richard Hughes2de8f132018-01-17 09:12:02 +00001233
1234 /* not enabled */
1235 if (!priv->enabled)
1236 return TRUE;
1237
1238 /* no object loaded */
1239 if (priv->module == NULL)
1240 return TRUE;
1241
1242 /* optional */
1243 g_module_symbol (priv->module, "fu_plugin_recoldplug", (gpointer *) &func);
1244 if (func == NULL)
1245 return TRUE;
1246 g_debug ("performing recoldplug() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001247 if (!func (self, &error_local)) {
1248 if (error_local == NULL) {
1249 g_critical ("unset error in plugin %s for recoldplug()",
1250 priv->name);
1251 g_set_error_literal (&error_local,
1252 FWUPD_ERROR,
1253 FWUPD_ERROR_INTERNAL,
1254 "unspecified error");
1255 }
1256 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1257 "failed to recoldplug using %s: ",
1258 priv->name);
Richard Hughes2de8f132018-01-17 09:12:02 +00001259 return FALSE;
1260 }
1261 return TRUE;
1262}
1263
1264gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001265fu_plugin_runner_coldplug_prepare (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001266{
Richard Hughes12724852018-09-04 13:53:44 +01001267 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001268 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001269 g_autoptr(GError) error_local = NULL;
Richard Hughes46487c92017-01-07 21:26:34 +00001270
1271 /* not enabled */
1272 if (!priv->enabled)
1273 return TRUE;
1274
Richard Hughes639da472018-01-06 22:35:04 +00001275 /* no object loaded */
1276 if (priv->module == NULL)
1277 return TRUE;
1278
Richard Hughes46487c92017-01-07 21:26:34 +00001279 /* optional */
1280 g_module_symbol (priv->module, "fu_plugin_coldplug_prepare", (gpointer *) &func);
1281 if (func == NULL)
1282 return TRUE;
1283 g_debug ("performing coldplug_prepare() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001284 if (!func (self, &error_local)) {
1285 if (error_local == NULL) {
1286 g_critical ("unset error in plugin %s for coldplug_prepare()",
1287 priv->name);
1288 g_set_error_literal (&error_local,
1289 FWUPD_ERROR,
1290 FWUPD_ERROR_INTERNAL,
1291 "unspecified error");
1292 }
1293 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1294 "failed to coldplug_prepare using %s: ",
1295 priv->name);
Richard Hughes46487c92017-01-07 21:26:34 +00001296 return FALSE;
1297 }
1298 return TRUE;
1299}
1300
1301gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001302fu_plugin_runner_coldplug_cleanup (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001303{
Richard Hughes12724852018-09-04 13:53:44 +01001304 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001305 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001306 g_autoptr(GError) error_local = NULL;
Richard Hughes46487c92017-01-07 21:26:34 +00001307
1308 /* not enabled */
1309 if (!priv->enabled)
1310 return TRUE;
1311
Richard Hughes639da472018-01-06 22:35:04 +00001312 /* no object loaded */
1313 if (priv->module == NULL)
1314 return TRUE;
1315
Richard Hughes46487c92017-01-07 21:26:34 +00001316 /* optional */
1317 g_module_symbol (priv->module, "fu_plugin_coldplug_cleanup", (gpointer *) &func);
1318 if (func == NULL)
1319 return TRUE;
1320 g_debug ("performing coldplug_cleanup() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001321 if (!func (self, &error_local)) {
1322 if (error_local == NULL) {
1323 g_critical ("unset error in plugin %s for coldplug_cleanup()",
1324 priv->name);
1325 g_set_error_literal (&error_local,
1326 FWUPD_ERROR,
1327 FWUPD_ERROR_INTERNAL,
1328 "unspecified error");
1329 }
1330 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1331 "failed to coldplug_cleanup using %s: ",
1332 priv->name);
Richard Hughes46487c92017-01-07 21:26:34 +00001333 return FALSE;
1334 }
1335 return TRUE;
1336}
1337
1338gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001339fu_plugin_runner_composite_prepare (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001340{
Richard Hughes12724852018-09-04 13:53:44 +01001341 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001342 "fu_plugin_composite_prepare",
1343 error);
1344}
1345
1346gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001347fu_plugin_runner_composite_cleanup (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001348{
Richard Hughes12724852018-09-04 13:53:44 +01001349 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001350 "fu_plugin_composite_cleanup",
1351 error);
1352}
1353
1354gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001355fu_plugin_runner_update_prepare (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001356 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001357{
Richard Hughes12724852018-09-04 13:53:44 +01001358 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001359 "fu_plugin_update_prepare",
1360 error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001361}
1362
1363gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001364fu_plugin_runner_update_cleanup (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001365 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001366{
Richard Hughes12724852018-09-04 13:53:44 +01001367 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001368 "fu_plugin_update_cleanup",
1369 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001370}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001371
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001372gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001373fu_plugin_runner_update_attach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001374{
Richard Hughes12724852018-09-04 13:53:44 +01001375 return fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001376 "fu_plugin_update_attach",
1377 fu_plugin_device_attach,
1378 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001379}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001380
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001381gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001382fu_plugin_runner_update_detach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001383{
Richard Hughes12724852018-09-04 13:53:44 +01001384 return fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001385 "fu_plugin_update_detach",
1386 fu_plugin_device_detach,
1387 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001388}
1389
1390gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001391fu_plugin_runner_update_reload (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001392{
Richard Hughes42f33df2019-10-05 20:52:33 +01001393 FuPluginPrivate *priv = GET_PRIVATE (self);
1394 g_autoptr(FuDeviceLocker) locker = NULL;
1395
1396 /* not enabled */
1397 if (!priv->enabled)
1398 return TRUE;
1399
1400 /* no object loaded */
1401 locker = fu_device_locker_new (device, error);
1402 if (locker == NULL)
1403 return FALSE;
1404 return fu_device_reload (device, error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001405}
1406
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001407/**
1408 * fu_plugin_add_udev_subsystem:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001409 * @self: a #FuPlugin
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001410 * @subsystem: a subsystem name, e.g. `pciport`
1411 *
1412 * Registers the udev subsystem to be watched by the daemon.
1413 *
1414 * Plugins can use this method only in fu_plugin_init()
1415 **/
1416void
Richard Hughes12724852018-09-04 13:53:44 +01001417fu_plugin_add_udev_subsystem (FuPlugin *self, const gchar *subsystem)
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001418{
Richard Hughes12724852018-09-04 13:53:44 +01001419 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001420 for (guint i = 0; i < priv->udev_subsystems->len; i++) {
1421 const gchar *subsystem_tmp = g_ptr_array_index (priv->udev_subsystems, i);
1422 if (g_strcmp0 (subsystem_tmp, subsystem) == 0)
1423 return;
1424 }
1425 g_debug ("added udev subsystem watch of %s", subsystem);
1426 g_ptr_array_add (priv->udev_subsystems, g_strdup (subsystem));
1427}
1428
Richard Hughes989acf12019-10-05 20:16:47 +01001429/**
1430 * fu_plugin_set_device_gtype:
1431 * @self: a #FuPlugin
1432 * @device_gtype: a #GType `FU_TYPE_DEVICE`
1433 *
1434 * Sets the device #GType which is used when creating devices.
1435 *
1436 * If this method is used then fu_plugin_usb_device_added() is not called, and
1437 * instead the object is created in the daemon for the plugin.
1438 *
1439 * Plugins can use this method only in fu_plugin_init()
1440 *
1441 * Since: 1.3.3
1442 **/
1443void
1444fu_plugin_set_device_gtype (FuPlugin *self, GType device_gtype)
1445{
1446 FuPluginPrivate *priv = GET_PRIVATE (self);
1447 priv->device_gtype = device_gtype;
1448}
1449
Richard Hughes95c98a92019-10-22 16:03:15 +01001450void
1451fu_plugin_add_firmware_gtype (FuPlugin *self, const gchar *id, GType gtype)
1452{
1453 g_signal_emit (self, signals[SIGNAL_ADD_FIRMWARE_GTYPE], 0, id, gtype);
1454}
1455
Richard Hughes989acf12019-10-05 20:16:47 +01001456static gboolean
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001457fu_plugin_check_supported_device (FuPlugin *self, FuDevice *device)
1458{
1459 GPtrArray *instance_ids = fu_device_get_instance_ids (device);
1460 for (guint i = 0; i < instance_ids->len; i++) {
1461 const gchar *instance_id = g_ptr_array_index (instance_ids, i);
1462 g_autofree gchar *guid = fwupd_guid_hash_string (instance_id);
1463 if (fu_plugin_check_supported (self, guid))
1464 return TRUE;
1465 }
1466 return FALSE;
1467}
1468
1469static gboolean
Richard Hughes989acf12019-10-05 20:16:47 +01001470fu_plugin_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error)
1471{
1472 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001473 GType device_gtype = fu_device_get_specialized_gtype (FU_DEVICE (device));
Richard Hughes989acf12019-10-05 20:16:47 +01001474 g_autoptr(FuDevice) dev = NULL;
1475 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001476
1477 /* fall back to plugin default */
1478 if (device_gtype == G_TYPE_INVALID)
1479 device_gtype = priv->device_gtype;
1480
1481 /* create new device and incorporate existing properties */
1482 dev = g_object_new (device_gtype, NULL);
1483 fu_device_incorporate (dev, FU_DEVICE (device));
1484
1485 /* there are a lot of different devices that match, but not all respond
1486 * well to opening -- so limit some ones with issued updates */
1487 if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_ONLY_SUPPORTED)) {
1488 if (!fu_device_probe (dev, error))
1489 return FALSE;
1490 fu_device_convert_instance_ids (dev);
1491 if (!fu_plugin_check_supported_device (self, dev)) {
1492 g_autofree gchar *guids = fu_device_get_guids_as_str (dev);
1493 g_debug ("%s has no updates, so ignoring device", guids);
1494 return TRUE;
1495 }
1496 }
1497
1498 /* open and add */
1499 locker = fu_device_locker_new (dev, error);
1500 if (locker == NULL)
1501 return FALSE;
1502 fu_plugin_device_add (self, dev);
1503 return TRUE;
1504}
1505
1506static gboolean
1507fu_plugin_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error)
1508{
1509 FuPluginPrivate *priv = GET_PRIVATE (self);
1510 GType device_gtype = fu_device_get_specialized_gtype (FU_DEVICE (device));
1511 g_autoptr(FuDevice) dev = NULL;
1512 g_autoptr(FuDeviceLocker) locker = NULL;
1513
1514 /* fall back to plugin default */
1515 if (device_gtype == G_TYPE_INVALID)
1516 device_gtype = priv->device_gtype;
1517
1518 /* create new device and incorporate existing properties */
1519 dev = g_object_new (device_gtype, NULL);
Richard Hughes989acf12019-10-05 20:16:47 +01001520 fu_device_incorporate (FU_DEVICE (dev), FU_DEVICE (device));
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001521
1522 /* there are a lot of different devices that match, but not all respond
1523 * well to opening -- so limit some ones with issued updates */
1524 if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_ONLY_SUPPORTED)) {
1525 if (!fu_device_probe (dev, error))
1526 return FALSE;
1527 fu_device_convert_instance_ids (dev);
1528 if (!fu_plugin_check_supported_device (self, dev)) {
1529 g_autofree gchar *guids = fu_device_get_guids_as_str (dev);
1530 g_debug ("%s has no updates, so ignoring device", guids);
1531 return TRUE;
1532 }
1533 }
1534
1535 /* open and add */
Richard Hughes989acf12019-10-05 20:16:47 +01001536 locker = fu_device_locker_new (dev, error);
1537 if (locker == NULL)
1538 return FALSE;
1539 fu_plugin_device_add (self, FU_DEVICE (dev));
1540 return TRUE;
1541}
1542
Richard Hughes104f6512017-11-24 11:44:57 +00001543gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001544fu_plugin_runner_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error)
Richard Hughes104f6512017-11-24 11:44:57 +00001545{
Richard Hughes12724852018-09-04 13:53:44 +01001546 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes104f6512017-11-24 11:44:57 +00001547 FuPluginUsbDeviceAddedFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001548 g_autoptr(GError) error_local = NULL;
Richard Hughes104f6512017-11-24 11:44:57 +00001549
1550 /* not enabled */
1551 if (!priv->enabled)
1552 return TRUE;
Richard Hughes639da472018-01-06 22:35:04 +00001553
1554 /* no object loaded */
Richard Hughes104f6512017-11-24 11:44:57 +00001555 if (priv->module == NULL)
1556 return TRUE;
1557
1558 /* optional */
1559 g_module_symbol (priv->module, "fu_plugin_usb_device_added", (gpointer *) &func);
Richard Hughes989acf12019-10-05 20:16:47 +01001560 if (func == NULL) {
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001561 if (priv->device_gtype != G_TYPE_INVALID ||
1562 fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) {
Mario Limonciello0e500322019-10-17 18:41:04 -05001563 if (!fu_plugin_usb_device_added (self, device, error))
Mario Limoncielloa9be5362019-10-12 13:17:45 -05001564 return FALSE;
Richard Hughes989acf12019-10-05 20:16:47 +01001565 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001566 return TRUE;
Richard Hughes989acf12019-10-05 20:16:47 +01001567 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001568 g_debug ("performing usb_device_added() on %s", priv->name);
1569 if (!func (self, device, &error_local)) {
1570 if (error_local == NULL) {
1571 g_critical ("unset error in plugin %s for usb_device_added()",
1572 priv->name);
1573 g_set_error_literal (&error_local,
1574 FWUPD_ERROR,
1575 FWUPD_ERROR_INTERNAL,
1576 "unspecified error");
1577 }
1578 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1579 "failed to add device using on %s: ",
1580 priv->name);
1581 return FALSE;
Richard Hughes104f6512017-11-24 11:44:57 +00001582 }
1583 return TRUE;
1584}
1585
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001586gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001587fu_plugin_runner_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error)
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001588{
Richard Hughes12724852018-09-04 13:53:44 +01001589 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001590 FuPluginUdevDeviceAddedFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001591 g_autoptr(GError) error_local = NULL;
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001592
1593 /* not enabled */
1594 if (!priv->enabled)
1595 return TRUE;
1596
1597 /* no object loaded */
1598 if (priv->module == NULL)
1599 return TRUE;
1600
1601 /* optional */
1602 g_module_symbol (priv->module, "fu_plugin_udev_device_added", (gpointer *) &func);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001603 if (func == NULL) {
1604 if (priv->device_gtype != G_TYPE_INVALID ||
1605 fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) {
Mario Limonciello0e500322019-10-17 18:41:04 -05001606 if (!fu_plugin_udev_device_added (self, device, error))
Mario Limoncielloa9be5362019-10-12 13:17:45 -05001607 return FALSE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001608 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001609 return TRUE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001610 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001611 g_debug ("performing udev_device_added() on %s", priv->name);
1612 if (!func (self, device, &error_local)) {
1613 if (error_local == NULL) {
1614 g_critical ("unset error in plugin %s for udev_device_added()",
1615 priv->name);
1616 g_set_error_literal (&error_local,
1617 FWUPD_ERROR,
1618 FWUPD_ERROR_INTERNAL,
1619 "unspecified error");
1620 }
1621 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1622 "failed to add device using on %s: ",
1623 priv->name);
1624 return FALSE;
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001625 }
1626 return TRUE;
1627}
1628
Richard Hughes5e952ce2019-08-26 11:09:46 +01001629gboolean
1630fu_plugin_runner_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GError **error)
1631{
1632 FuPluginPrivate *priv = GET_PRIVATE (self);
1633 FuPluginUdevDeviceAddedFunc func = NULL;
1634 g_autoptr(GError) error_local = NULL;
1635
1636 /* not enabled */
1637 if (!priv->enabled)
1638 return TRUE;
1639
1640 /* no object loaded */
1641 if (priv->module == NULL)
1642 return TRUE;
1643
1644 /* optional */
1645 g_module_symbol (priv->module, "fu_plugin_udev_device_changed", (gpointer *) &func);
1646 if (func == NULL)
1647 return TRUE;
1648 g_debug ("performing udev_device_changed() on %s", priv->name);
1649 if (!func (self, device, &error_local)) {
1650 if (error_local == NULL) {
1651 g_critical ("unset error in plugin %s for udev_device_changed()",
1652 priv->name);
1653 g_set_error_literal (&error_local,
1654 FWUPD_ERROR,
1655 FWUPD_ERROR_INTERNAL,
1656 "unspecified error");
1657 }
1658 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1659 "failed to change device on %s: ",
1660 priv->name);
1661 return FALSE;
1662 }
1663 return TRUE;
1664}
1665
Richard Hughese1fd34d2017-08-24 14:19:51 +01001666void
Richard Hughes12724852018-09-04 13:53:44 +01001667fu_plugin_runner_device_removed (FuPlugin *self, FuDevice *device)
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001668{
1669 g_autoptr(GError) error_local= NULL;
1670
Richard Hughes12724852018-09-04 13:53:44 +01001671 if (!fu_plugin_runner_device_generic (self, device,
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001672 "fu_plugin_device_removed",
Richard Hughes4b303802019-10-04 13:22:51 +01001673 NULL,
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001674 &error_local))
1675 g_warning ("%s", error_local->message);
1676}
1677
1678void
Richard Hughes12724852018-09-04 13:53:44 +01001679fu_plugin_runner_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +01001680{
Richard Hughes12724852018-09-04 13:53:44 +01001681 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughese1fd34d2017-08-24 14:19:51 +01001682 FuPluginDeviceRegisterFunc func = NULL;
1683
1684 /* not enabled */
1685 if (!priv->enabled)
1686 return;
Richard Hughes34834102017-11-21 21:55:00 +00001687 if (priv->module == NULL)
1688 return;
Richard Hughese1fd34d2017-08-24 14:19:51 +01001689
Mario Limonciello4910b242018-06-22 15:04:21 -05001690 /* don't notify plugins on their own devices */
Richard Hughes12724852018-09-04 13:53:44 +01001691 if (g_strcmp0 (fu_device_get_plugin (device), fu_plugin_get_name (self)) == 0)
Mario Limonciello4910b242018-06-22 15:04:21 -05001692 return;
1693
Richard Hughese1fd34d2017-08-24 14:19:51 +01001694 /* optional */
1695 g_module_symbol (priv->module, "fu_plugin_device_registered", (gpointer *) &func);
1696 if (func != NULL) {
Richard Hughes1bf7ff92018-08-24 20:21:35 +01001697 g_debug ("performing fu_plugin_device_registered() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01001698 func (self, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +01001699 }
1700}
1701
Richard Hughesc6c312f2019-02-01 16:37:14 +00001702gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001703fu_plugin_runner_schedule_update (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +00001704 FuDevice *device,
Richard Hughes994b4d92019-03-25 14:28:30 +00001705 FwupdRelease *release,
Richard Hughescff38bc2016-12-12 12:03:37 +00001706 GBytes *blob_cab,
Richard Hughes5cbb5cf2019-04-26 16:48:03 +01001707 FwupdInstallFlags flags,
Richard Hughescff38bc2016-12-12 12:03:37 +00001708 GError **error)
1709{
Richard Hughes0a906262019-05-16 13:38:47 +01001710 gchar tmpname[] = {"XXXXXX.cab"};
Richard Hughescff38bc2016-12-12 12:03:37 +00001711 g_autofree gchar *dirname = NULL;
1712 g_autofree gchar *filename = NULL;
Richard Hughes780ef3f2018-01-12 16:20:31 +00001713 g_autoptr(FuHistory) history = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001714 g_autoptr(GFile) file = NULL;
1715
1716 /* id already exists */
Richard Hughes780ef3f2018-01-12 16:20:31 +00001717 history = fu_history_new ();
Richard Hughes5cbb5cf2019-04-26 16:48:03 +01001718 if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) {
1719 g_autoptr(FuDevice) res_tmp = NULL;
1720 res_tmp = fu_history_get_device_by_id (history, fu_device_get_id (device), NULL);
1721 if (res_tmp != NULL &&
1722 fu_device_get_update_state (res_tmp) == FWUPD_UPDATE_STATE_PENDING) {
1723 g_set_error (error,
1724 FWUPD_ERROR,
1725 FWUPD_ERROR_ALREADY_PENDING,
1726 "%s is already scheduled to be updated",
1727 fu_device_get_id (device));
1728 return FALSE;
1729 }
Richard Hughescff38bc2016-12-12 12:03:37 +00001730 }
1731
1732 /* create directory */
Richard Hughes4be17d12018-05-30 20:36:29 +01001733 dirname = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG);
Richard Hughescff38bc2016-12-12 12:03:37 +00001734 file = g_file_new_for_path (dirname);
1735 if (!g_file_query_exists (file, NULL)) {
1736 if (!g_file_make_directory_with_parents (file, NULL, error))
1737 return FALSE;
1738 }
1739
1740 /* get a random filename */
1741 for (guint i = 0; i < 6; i++)
1742 tmpname[i] = (gchar) g_random_int_range ('A', 'Z');
1743 filename = g_build_filename (dirname, tmpname, NULL);
1744
1745 /* just copy to the temp file */
Richard Hughes23135eb2017-11-30 21:01:25 +00001746 fu_device_set_status (device, FWUPD_STATUS_SCHEDULING);
Richard Hughescff38bc2016-12-12 12:03:37 +00001747 if (!g_file_set_contents (filename,
1748 g_bytes_get_data (blob_cab, NULL),
1749 (gssize) g_bytes_get_size (blob_cab),
1750 error))
1751 return FALSE;
1752
1753 /* schedule for next boot */
1754 g_debug ("schedule %s to be installed to %s on next boot",
1755 filename, fu_device_get_id (device));
Richard Hughes994b4d92019-03-25 14:28:30 +00001756 fwupd_release_set_filename (release, filename);
Richard Hughescff38bc2016-12-12 12:03:37 +00001757
1758 /* add to database */
Richard Hughes809abea2019-03-23 11:06:18 +00001759 fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT);
Richard Hughes3e90a582018-01-06 22:38:09 +00001760 fu_device_set_update_state (device, FWUPD_UPDATE_STATE_PENDING);
Richard Hughes994b4d92019-03-25 14:28:30 +00001761 if (!fu_history_add_device (history, device, release, error))
Richard Hughescff38bc2016-12-12 12:03:37 +00001762 return FALSE;
1763
1764 /* next boot we run offline */
Richard Hughesdb69c812019-03-22 16:10:15 +00001765 fu_device_set_progress (device, 100);
Richard Hughescff38bc2016-12-12 12:03:37 +00001766 return fu_plugin_runner_offline_setup (error);
1767}
1768
1769gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001770fu_plugin_runner_verify (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +00001771 FuDevice *device,
1772 FuPluginVerifyFlags flags,
1773 GError **error)
1774{
Richard Hughes12724852018-09-04 13:53:44 +01001775 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001776 FuPluginVerifyFunc func = NULL;
Richard Hughesababbb72017-06-15 20:18:36 +01001777 GPtrArray *checksums;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001778 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001779
1780 /* not enabled */
1781 if (!priv->enabled)
1782 return TRUE;
1783
Richard Hughes639da472018-01-06 22:35:04 +00001784 /* no object loaded */
1785 if (priv->module == NULL)
1786 return TRUE;
1787
Richard Hughescff38bc2016-12-12 12:03:37 +00001788 /* optional */
1789 g_module_symbol (priv->module, "fu_plugin_verify", (gpointer *) &func);
Richard Hughes7f677212019-10-05 16:19:40 +01001790 if (func == NULL) {
Richard Hughes7f677212019-10-05 16:19:40 +01001791 return fu_plugin_device_read_firmware (self, device, error);
1792 }
Richard Hughes1812fc72018-12-14 11:37:54 +00001793
1794 /* clear any existing verification checksums */
1795 checksums = fu_device_get_checksums (device);
1796 g_ptr_array_set_size (checksums, 0);
1797
Richard Hughesc9223be2019-03-18 08:46:42 +00001798 /* run additional detach */
1799 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01001800 "fu_plugin_update_detach",
Richard Hughes4b303802019-10-04 13:22:51 +01001801 fu_plugin_device_detach,
Richard Hughesc9223be2019-03-18 08:46:42 +00001802 error))
1803 return FALSE;
1804
Richard Hughes1812fc72018-12-14 11:37:54 +00001805 /* run vfunc */
Richard Hughescff38bc2016-12-12 12:03:37 +00001806 g_debug ("performing verify() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001807 if (!func (self, device, flags, &error_local)) {
Richard Hughesc9223be2019-03-18 08:46:42 +00001808 g_autoptr(GError) error_attach = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001809 if (error_local == NULL) {
1810 g_critical ("unset error in plugin %s for verify()",
1811 priv->name);
1812 g_set_error_literal (&error_local,
1813 FWUPD_ERROR,
1814 FWUPD_ERROR_INTERNAL,
1815 "unspecified error");
1816 }
1817 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1818 "failed to verify using %s: ",
1819 priv->name);
Richard Hughesc9223be2019-03-18 08:46:42 +00001820 /* make the device "work" again, but don't prefix the error */
1821 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01001822 "fu_plugin_update_attach",
Richard Hughes4b303802019-10-04 13:22:51 +01001823 fu_plugin_device_attach,
Richard Hughesc9223be2019-03-18 08:46:42 +00001824 &error_attach)) {
1825 g_warning ("failed to attach whilst aborting verify(): %s",
1826 error_attach->message);
1827 }
Richard Hughesd0905142016-03-13 09:46:49 +00001828 return FALSE;
1829 }
Richard Hughesc9223be2019-03-18 08:46:42 +00001830
1831 /* run optional attach */
1832 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01001833 "fu_plugin_update_attach",
Richard Hughes4b303802019-10-04 13:22:51 +01001834 fu_plugin_device_attach,
Richard Hughesc9223be2019-03-18 08:46:42 +00001835 error))
1836 return FALSE;
1837
1838 /* success */
Richard Hughesd0905142016-03-13 09:46:49 +00001839 return TRUE;
1840}
1841
Richard Hughesd0905142016-03-13 09:46:49 +00001842gboolean
Mario Limonciello96a0dd52019-02-25 13:50:03 -06001843fu_plugin_runner_activate (FuPlugin *self, FuDevice *device, GError **error)
1844{
1845 guint64 flags;
1846
1847 /* final check */
1848 flags = fu_device_get_flags (device);
1849 if ((flags & FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION) == 0) {
1850 g_set_error (error,
1851 FWUPD_ERROR,
1852 FWUPD_ERROR_NOT_SUPPORTED,
1853 "Device %s does not need activation",
1854 fu_device_get_id (device));
1855 return FALSE;
1856 }
1857
1858 /* run vfunc */
1859 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001860 "fu_plugin_activate",
1861 fu_plugin_device_activate,
1862 error))
Mario Limonciello96a0dd52019-02-25 13:50:03 -06001863 return FALSE;
1864
1865 /* update with correct flags */
1866 fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION);
1867 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
1868 return TRUE;
1869}
1870
1871gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001872fu_plugin_runner_unlock (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00001873{
Richard Hughescff38bc2016-12-12 12:03:37 +00001874 guint64 flags;
Richard Hughescff38bc2016-12-12 12:03:37 +00001875
1876 /* final check */
1877 flags = fu_device_get_flags (device);
1878 if ((flags & FWUPD_DEVICE_FLAG_LOCKED) == 0) {
1879 g_set_error (error,
1880 FWUPD_ERROR,
1881 FWUPD_ERROR_NOT_SUPPORTED,
1882 "Device %s is not locked",
1883 fu_device_get_id (device));
1884 return FALSE;
1885 }
1886
Richard Hughes9c4b5312017-11-14 11:34:53 +00001887 /* run vfunc */
Richard Hughes12724852018-09-04 13:53:44 +01001888 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001889 "fu_plugin_unlock",
1890 NULL,
1891 error))
Richard Hughes9c4b5312017-11-14 11:34:53 +00001892 return FALSE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001893
1894 /* update with correct flags */
1895 flags = fu_device_get_flags (device);
1896 fu_device_set_flags (device, flags &= ~FWUPD_DEVICE_FLAG_LOCKED);
1897 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
1898 return TRUE;
1899}
1900
1901gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001902fu_plugin_runner_update (FuPlugin *self,
Richard Hughesa785a1c2017-08-25 16:00:58 +01001903 FuDevice *device,
Richard Hughesa785a1c2017-08-25 16:00:58 +01001904 GBytes *blob_fw,
1905 FwupdInstallFlags flags,
1906 GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00001907{
Richard Hughes12724852018-09-04 13:53:44 +01001908 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesa785a1c2017-08-25 16:00:58 +01001909 FuPluginUpdateFunc update_func;
Richard Hughes780ef3f2018-01-12 16:20:31 +00001910 g_autoptr(FuHistory) history = NULL;
Richard Hughes68982c62017-09-13 15:40:14 +01001911 g_autoptr(FuDevice) device_pending = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001912 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001913
1914 /* not enabled */
Richard Hughes41c15482018-02-01 22:07:21 +00001915 if (!priv->enabled) {
1916 g_debug ("plugin not enabled, skipping");
Richard Hughesd0905142016-03-13 09:46:49 +00001917 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00001918 }
Richard Hughesd0905142016-03-13 09:46:49 +00001919
Richard Hughes639da472018-01-06 22:35:04 +00001920 /* no object loaded */
Richard Hughes41c15482018-02-01 22:07:21 +00001921 if (priv->module == NULL) {
1922 g_debug ("module not enabled, skipping");
Richard Hughes639da472018-01-06 22:35:04 +00001923 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00001924 }
Richard Hughes639da472018-01-06 22:35:04 +00001925
Richard Hughesd0905142016-03-13 09:46:49 +00001926 /* optional */
Richard Hughesa785a1c2017-08-25 16:00:58 +01001927 g_module_symbol (priv->module, "fu_plugin_update", (gpointer *) &update_func);
1928 if (update_func == NULL) {
Richard Hughes4b303802019-10-04 13:22:51 +01001929 g_debug ("running superclassed write_firmware() on %s", priv->name);
1930 return fu_plugin_device_write_firmware (self, device, blob_fw, flags, error);
Richard Hughesa785a1c2017-08-25 16:00:58 +01001931 }
Richard Hughesd0905142016-03-13 09:46:49 +00001932
Richard Hughescff38bc2016-12-12 12:03:37 +00001933 /* cancel the pending action */
1934 if (!fu_plugin_runner_offline_invalidate (error))
1935 return FALSE;
1936
1937 /* online */
Richard Hughes780ef3f2018-01-12 16:20:31 +00001938 history = fu_history_new ();
Richard Hughes0b9d9962018-01-12 16:31:28 +00001939 device_pending = fu_history_get_device_by_id (history, fu_device_get_id (device), NULL);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001940 if (!update_func (self, device, blob_fw, flags, &error_local)) {
1941 if (error_local == NULL) {
1942 g_critical ("unset error in plugin %s for update()",
1943 priv->name);
1944 g_set_error_literal (&error_local,
Richard Hughes3c8ada32018-10-12 10:08:58 +01001945 FWUPD_ERROR,
1946 FWUPD_ERROR_INTERNAL,
1947 "unspecified error");
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001948 return FALSE;
Richard Hughes3c8ada32018-10-12 10:08:58 +01001949 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001950 fu_device_set_update_error (device, error_local->message);
1951 g_propagate_error (error, g_steal_pointer (&error_local));
Richard Hughescff38bc2016-12-12 12:03:37 +00001952 return FALSE;
1953 }
1954
Richard Hughesf556d372017-06-15 19:49:18 +01001955 /* no longer valid */
Richard Hughesf8039642019-01-16 12:22:22 +00001956 if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT) &&
1957 !fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) {
Richard Hughes08435162018-12-12 10:34:16 +00001958 GPtrArray *checksums = fu_device_get_checksums (device);
1959 g_ptr_array_set_size (checksums, 0);
1960 }
Richard Hughesf556d372017-06-15 19:49:18 +01001961
Richard Hughescff38bc2016-12-12 12:03:37 +00001962 /* cleanup */
Richard Hughes68982c62017-09-13 15:40:14 +01001963 if (device_pending != NULL) {
Richard Hughescff38bc2016-12-12 12:03:37 +00001964 const gchar *tmp;
Richard Hughesbc3a4e12018-01-06 22:41:47 +00001965 FwupdRelease *release;
Richard Hughescff38bc2016-12-12 12:03:37 +00001966
Richard Hughes780ef3f2018-01-12 16:20:31 +00001967 /* update history database */
Richard Hughesc0cd0232018-01-31 15:02:00 +00001968 fu_device_set_update_state (device, FWUPD_UPDATE_STATE_SUCCESS);
Richard Hughes0bbef292019-11-01 12:15:15 +00001969 if (!fu_history_modify_device (history, device, error))
Richard Hughes0b9d9962018-01-12 16:31:28 +00001970 return FALSE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001971
1972 /* delete cab file */
Richard Hughesbc3a4e12018-01-06 22:41:47 +00001973 release = fu_device_get_release_default (device_pending);
1974 tmp = fwupd_release_get_filename (release);
Richard Hughes668ee212019-11-22 09:17:46 +00001975 if (tmp != NULL && g_str_has_prefix (tmp, FWUPD_LIBEXECDIR)) {
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001976 g_autoptr(GError) error_delete = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001977 g_autoptr(GFile) file = NULL;
1978 file = g_file_new_for_path (tmp);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001979 if (!g_file_delete (file, NULL, &error_delete)) {
Richard Hughescff38bc2016-12-12 12:03:37 +00001980 g_set_error (error,
1981 FWUPD_ERROR,
1982 FWUPD_ERROR_INVALID_FILE,
1983 "Failed to delete %s: %s",
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001984 tmp, error_delete->message);
Richard Hughescff38bc2016-12-12 12:03:37 +00001985 return FALSE;
1986 }
1987 }
1988 }
Richard Hughesd0905142016-03-13 09:46:49 +00001989 return TRUE;
1990}
Richard Hughescff38bc2016-12-12 12:03:37 +00001991
1992gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001993fu_plugin_runner_clear_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00001994{
Richard Hughes12724852018-09-04 13:53:44 +01001995 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001996 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001997 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001998
1999 /* not enabled */
2000 if (!priv->enabled)
2001 return TRUE;
2002
Richard Hughes639da472018-01-06 22:35:04 +00002003 /* no object loaded */
2004 if (priv->module == NULL)
2005 return TRUE;
2006
Richard Hughes65e44ca2018-01-30 17:26:30 +00002007 /* optional */
Richard Hughescd644902019-11-01 12:35:17 +00002008 g_module_symbol (priv->module, "fu_plugin_clear_results", (gpointer *) &func);
Richard Hughes65e44ca2018-01-30 17:26:30 +00002009 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00002010 return TRUE;
Richard Hughes65e44ca2018-01-30 17:26:30 +00002011 g_debug ("performing clear_result() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002012 if (!func (self, device, &error_local)) {
2013 if (error_local == NULL) {
2014 g_critical ("unset error in plugin %s for clear_result()",
2015 priv->name);
2016 g_set_error_literal (&error_local,
2017 FWUPD_ERROR,
2018 FWUPD_ERROR_INTERNAL,
2019 "unspecified error");
2020 }
2021 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2022 "failed to clear_result using %s: ",
2023 priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00002024 return FALSE;
2025 }
Richard Hughes65e44ca2018-01-30 17:26:30 +00002026 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00002027}
2028
2029gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002030fu_plugin_runner_get_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00002031{
Richard Hughes12724852018-09-04 13:53:44 +01002032 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00002033 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002034 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002035
2036 /* not enabled */
2037 if (!priv->enabled)
2038 return TRUE;
2039
Richard Hughes639da472018-01-06 22:35:04 +00002040 /* no object loaded */
2041 if (priv->module == NULL)
2042 return TRUE;
2043
Richard Hughes65e44ca2018-01-30 17:26:30 +00002044 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00002045 g_module_symbol (priv->module, "fu_plugin_get_results", (gpointer *) &func);
Richard Hughes65e44ca2018-01-30 17:26:30 +00002046 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00002047 return TRUE;
Richard Hughes65e44ca2018-01-30 17:26:30 +00002048 g_debug ("performing get_results() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002049 if (!func (self, device, &error_local)) {
2050 if (error_local == NULL) {
2051 g_critical ("unset error in plugin %s for get_results()",
2052 priv->name);
2053 g_set_error_literal (&error_local,
2054 FWUPD_ERROR,
2055 FWUPD_ERROR_INTERNAL,
2056 "unspecified error");
2057 }
2058 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2059 "failed to get_results using %s: ",
2060 priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00002061 return FALSE;
2062 }
Richard Hughescff38bc2016-12-12 12:03:37 +00002063 return TRUE;
2064}
2065
Richard Hughes08a37992017-09-12 12:57:43 +01002066/**
2067 * fu_plugin_get_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002068 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002069 *
2070 * Gets the plugin order, where higher numbers are run after lower
2071 * numbers.
2072 *
2073 * Returns: the integer value
2074 **/
2075guint
Richard Hughes12724852018-09-04 13:53:44 +01002076fu_plugin_get_order (FuPlugin *self)
Richard Hughes08a37992017-09-12 12:57:43 +01002077{
Richard Hughes12724852018-09-04 13:53:44 +01002078 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002079 return priv->order;
2080}
2081
2082/**
2083 * fu_plugin_set_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002084 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002085 * @order: a integer value
2086 *
2087 * Sets the plugin order, where higher numbers are run after lower
2088 * numbers.
2089 **/
2090void
Richard Hughes12724852018-09-04 13:53:44 +01002091fu_plugin_set_order (FuPlugin *self, guint order)
Richard Hughes08a37992017-09-12 12:57:43 +01002092{
Richard Hughes12724852018-09-04 13:53:44 +01002093 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002094 priv->order = order;
2095}
2096
2097/**
Richard Hughes81c427c2018-08-06 15:20:17 +01002098 * fu_plugin_get_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002099 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01002100 *
2101 * Gets the plugin priority, where higher numbers are better.
2102 *
2103 * Returns: the integer value
2104 **/
2105guint
Richard Hughes12724852018-09-04 13:53:44 +01002106fu_plugin_get_priority (FuPlugin *self)
Richard Hughes81c427c2018-08-06 15:20:17 +01002107{
Richard Hughes12724852018-09-04 13:53:44 +01002108 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01002109 return priv->priority;
2110}
2111
2112/**
2113 * fu_plugin_set_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002114 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01002115 * @priority: a integer value
2116 *
2117 * Sets the plugin priority, where higher numbers are better.
2118 **/
2119void
Richard Hughes12724852018-09-04 13:53:44 +01002120fu_plugin_set_priority (FuPlugin *self, guint priority)
Richard Hughes81c427c2018-08-06 15:20:17 +01002121{
Richard Hughes12724852018-09-04 13:53:44 +01002122 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01002123 priv->priority = priority;
2124}
2125
2126/**
Richard Hughes08a37992017-09-12 12:57:43 +01002127 * fu_plugin_add_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002128 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002129 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
Richard Hughes4eada342017-10-03 21:20:32 +01002130 * @name: a plugin name, e.g. `upower`
Richard Hughes08a37992017-09-12 12:57:43 +01002131 *
2132 * If the plugin name is found, the rule will be used to sort the plugin list,
2133 * for example the plugin specified by @name will be ordered after this plugin
2134 * when %FU_PLUGIN_RULE_RUN_AFTER is used.
2135 *
2136 * NOTE: The depsolver is iterative and may not solve overly-complicated rules;
2137 * If depsolving fails then fwupd will not start.
2138 **/
2139void
Richard Hughes12724852018-09-04 13:53:44 +01002140fu_plugin_add_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes08a37992017-09-12 12:57:43 +01002141{
Richard Hughes12724852018-09-04 13:53:44 +01002142 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002143 g_ptr_array_add (priv->rules[rule], g_strdup (name));
Richard Hughes75b965d2018-11-15 13:51:21 +00002144 g_signal_emit (self, signals[SIGNAL_RULES_CHANGED], 0);
Richard Hughes08a37992017-09-12 12:57:43 +01002145}
2146
2147/**
2148 * fu_plugin_get_rules:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002149 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002150 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
2151 *
2152 * Gets the plugin IDs that should be run after this plugin.
2153 *
2154 * Returns: (element-type utf8) (transfer none): the list of plugin names, e.g. ['appstream']
2155 **/
2156GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +01002157fu_plugin_get_rules (FuPlugin *self, FuPluginRule rule)
Richard Hughes08a37992017-09-12 12:57:43 +01002158{
Richard Hughes12724852018-09-04 13:53:44 +01002159 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002160 return priv->rules[rule];
2161}
2162
Richard Hughes80b79bb2018-01-11 21:11:06 +00002163/**
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002164 * fu_plugin_has_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002165 * @self: a #FuPlugin
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002166 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
2167 * @name: a plugin name, e.g. `upower`
2168 *
Richard Hughes87fb9ff2018-06-28 12:55:59 +01002169 * Gets the plugin IDs that should be run after this plugin.
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002170 *
2171 * Returns: %TRUE if the name exists for the specific rule
2172 **/
2173gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002174fu_plugin_has_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002175{
Richard Hughes12724852018-09-04 13:53:44 +01002176 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002177 for (guint i = 0; i < priv->rules[rule]->len; i++) {
2178 const gchar *tmp = g_ptr_array_index (priv->rules[rule], i);
2179 if (g_strcmp0 (tmp, name) == 0)
2180 return TRUE;
2181 }
2182 return FALSE;
2183}
2184
2185/**
Richard Hughes80b79bb2018-01-11 21:11:06 +00002186 * fu_plugin_add_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002187 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00002188 * @key: a string, e.g. `FwupdateVersion`
2189 * @value: a string, e.g. `10`
2190 *
2191 * Sets any additional metadata to be included in the firmware report to aid
2192 * debugging problems.
2193 *
2194 * Any data included here will be sent to the metadata server after user
2195 * confirmation.
2196 **/
2197void
Richard Hughes12724852018-09-04 13:53:44 +01002198fu_plugin_add_report_metadata (FuPlugin *self, const gchar *key, const gchar *value)
Richard Hughes80b79bb2018-01-11 21:11:06 +00002199{
Richard Hughes12724852018-09-04 13:53:44 +01002200 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002201 g_hash_table_insert (priv->report_metadata, g_strdup (key), g_strdup (value));
2202}
2203
2204/**
2205 * fu_plugin_get_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002206 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00002207 *
2208 * Returns the list of additional metadata to be added when filing a report.
2209 *
2210 * Returns: (transfer none): the map of report metadata
2211 **/
2212GHashTable *
Richard Hughes12724852018-09-04 13:53:44 +01002213fu_plugin_get_report_metadata (FuPlugin *self)
Richard Hughes80b79bb2018-01-11 21:11:06 +00002214{
Richard Hughes12724852018-09-04 13:53:44 +01002215 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002216 return priv->report_metadata;
2217}
2218
Mario Limonciello963dc422018-02-27 14:26:58 -06002219/**
2220 * fu_plugin_get_config_value:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002221 * @self: a #FuPlugin
Mario Limonciello963dc422018-02-27 14:26:58 -06002222 * @key: A settings key
2223 *
2224 * Return the value of a key if it's been configured
2225 *
2226 * Since: 1.0.6
2227 **/
2228gchar *
Richard Hughes12724852018-09-04 13:53:44 +01002229fu_plugin_get_config_value (FuPlugin *self, const gchar *key)
Mario Limonciello963dc422018-02-27 14:26:58 -06002230{
Richard Hughes4be17d12018-05-30 20:36:29 +01002231 g_autofree gchar *conf_dir = NULL;
Mario Limonciello963dc422018-02-27 14:26:58 -06002232 g_autofree gchar *conf_file = NULL;
2233 g_autofree gchar *conf_path = NULL;
2234 g_autoptr(GKeyFile) keyfile = NULL;
2235 const gchar *plugin_name;
2236
Richard Hughes4be17d12018-05-30 20:36:29 +01002237 conf_dir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR_PKG);
Richard Hughes12724852018-09-04 13:53:44 +01002238 plugin_name = fu_plugin_get_name (self);
Mario Limonciello963dc422018-02-27 14:26:58 -06002239 conf_file = g_strdup_printf ("%s.conf", plugin_name);
Richard Hughes4be17d12018-05-30 20:36:29 +01002240 conf_path = g_build_filename (conf_dir, conf_file, NULL);
Mario Limonciello963dc422018-02-27 14:26:58 -06002241 if (!g_file_test (conf_path, G_FILE_TEST_IS_REGULAR))
2242 return NULL;
2243 keyfile = g_key_file_new ();
2244 if (!g_key_file_load_from_file (keyfile, conf_path,
2245 G_KEY_FILE_NONE, NULL))
2246 return NULL;
2247 return g_key_file_get_string (keyfile, plugin_name, key, NULL);
2248}
2249
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002250/**
2251 * fu_plugin_name_compare:
2252 * @plugin1: first #FuPlugin to compare.
2253 * @plugin2: second #FuPlugin to compare.
2254 *
2255 * Compares two plugins by their names.
2256 *
2257 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
2258 **/
2259gint
2260fu_plugin_name_compare (FuPlugin *plugin1, FuPlugin *plugin2)
2261{
2262 FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1);
2263 FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2);
2264 return g_strcmp0 (priv1->name, priv2->name);
2265}
2266
2267/**
2268 * fu_plugin_order_compare:
2269 * @plugin1: first #FuPlugin to compare.
2270 * @plugin2: second #FuPlugin to compare.
2271 *
2272 * Compares two plugins by their depsolved order.
2273 *
2274 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
2275 **/
2276gint
2277fu_plugin_order_compare (FuPlugin *plugin1, FuPlugin *plugin2)
2278{
2279 FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1);
2280 FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2);
2281 if (priv1->order < priv2->order)
2282 return -1;
2283 if (priv1->order > priv2->order)
2284 return 1;
2285 return 0;
2286}
2287
Richard Hughescff38bc2016-12-12 12:03:37 +00002288static void
2289fu_plugin_class_init (FuPluginClass *klass)
2290{
2291 GObjectClass *object_class = G_OBJECT_CLASS (klass);
2292 object_class->finalize = fu_plugin_finalize;
2293 signals[SIGNAL_DEVICE_ADDED] =
2294 g_signal_new ("device-added",
2295 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2296 G_STRUCT_OFFSET (FuPluginClass, device_added),
2297 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2298 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
2299 signals[SIGNAL_DEVICE_REMOVED] =
2300 g_signal_new ("device-removed",
2301 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2302 G_STRUCT_OFFSET (FuPluginClass, device_removed),
2303 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2304 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughese1fd34d2017-08-24 14:19:51 +01002305 signals[SIGNAL_DEVICE_REGISTER] =
2306 g_signal_new ("device-register",
2307 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2308 G_STRUCT_OFFSET (FuPluginClass, device_register),
2309 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2310 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughes362d6d72017-01-07 21:42:14 +00002311 signals[SIGNAL_RECOLDPLUG] =
2312 g_signal_new ("recoldplug",
2313 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2314 G_STRUCT_OFFSET (FuPluginClass, recoldplug),
2315 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2316 G_TYPE_NONE, 0);
Richard Hughesb0829032017-01-10 09:27:08 +00002317 signals[SIGNAL_SET_COLDPLUG_DELAY] =
2318 g_signal_new ("set-coldplug-delay",
2319 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2320 G_STRUCT_OFFSET (FuPluginClass, set_coldplug_delay),
2321 NULL, NULL, g_cclosure_marshal_VOID__UINT,
2322 G_TYPE_NONE, 1, G_TYPE_UINT);
Richard Hughesaabdc372018-11-14 10:11:08 +00002323 signals[SIGNAL_CHECK_SUPPORTED] =
2324 g_signal_new ("check-supported",
2325 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2326 G_STRUCT_OFFSET (FuPluginClass, check_supported),
2327 NULL, NULL, g_cclosure_marshal_generic,
2328 G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
Richard Hughes75b965d2018-11-15 13:51:21 +00002329 signals[SIGNAL_RULES_CHANGED] =
2330 g_signal_new ("rules-changed",
2331 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2332 G_STRUCT_OFFSET (FuPluginClass, rules_changed),
2333 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2334 G_TYPE_NONE, 0);
Richard Hughes95c98a92019-10-22 16:03:15 +01002335 signals[SIGNAL_ADD_FIRMWARE_GTYPE] =
2336 g_signal_new ("add-firmware-gtype",
2337 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2338 G_STRUCT_OFFSET (FuPluginClass, add_firmware_gtype),
2339 NULL, NULL, g_cclosure_marshal_generic,
2340 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_GTYPE);
Richard Hughescff38bc2016-12-12 12:03:37 +00002341}
2342
2343static void
Richard Hughes12724852018-09-04 13:53:44 +01002344fu_plugin_init (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +00002345{
Richard Hughes12724852018-09-04 13:53:44 +01002346 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002347 priv->enabled = TRUE;
Richard Hughesb1065422019-08-15 16:44:34 +01002348 priv->udev_subsystems = g_ptr_array_new_with_free_func (g_free);
Richard Hughescff38bc2016-12-12 12:03:37 +00002349 priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal,
2350 g_free, (GDestroyNotify) g_object_unref);
Richard Hughes161e9b52019-06-12 14:22:45 +01002351 g_rw_lock_init (&priv->devices_mutex);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002352 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 +01002353 for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++)
2354 priv->rules[i] = g_ptr_array_new_with_free_func (g_free);
Richard Hughescff38bc2016-12-12 12:03:37 +00002355}
2356
2357static void
2358fu_plugin_finalize (GObject *object)
2359{
Richard Hughes12724852018-09-04 13:53:44 +01002360 FuPlugin *self = FU_PLUGIN (object);
2361 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002362 FuPluginInitFunc func = NULL;
2363
2364 /* optional */
2365 if (priv->module != NULL) {
2366 g_module_symbol (priv->module, "fu_plugin_destroy", (gpointer *) &func);
2367 if (func != NULL) {
2368 g_debug ("performing destroy() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01002369 func (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002370 }
2371 }
2372
Richard Hughes08a37992017-09-12 12:57:43 +01002373 for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++)
2374 g_ptr_array_unref (priv->rules[i]);
2375
Richard Hughescff38bc2016-12-12 12:03:37 +00002376 if (priv->usb_ctx != NULL)
2377 g_object_unref (priv->usb_ctx);
Richard Hughesb8f8db22017-04-25 15:56:00 +01002378 if (priv->hwids != NULL)
Richard Hughesd7704d42017-08-08 20:29:09 +01002379 g_object_unref (priv->hwids);
Richard Hughes9c028f02017-10-28 21:14:28 +01002380 if (priv->quirks != NULL)
2381 g_object_unref (priv->quirks);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01002382 if (priv->udev_subsystems != NULL)
2383 g_ptr_array_unref (priv->udev_subsystems);
Richard Hughes49e5e052017-09-03 12:15:41 +01002384 if (priv->smbios != NULL)
2385 g_object_unref (priv->smbios);
Richard Hughes275d3b42018-04-20 16:40:37 +01002386 if (priv->runtime_versions != NULL)
2387 g_hash_table_unref (priv->runtime_versions);
Richard Hughes34e0dab2018-04-20 16:43:00 +01002388 if (priv->compile_versions != NULL)
2389 g_hash_table_unref (priv->compile_versions);
Richard Hughescff38bc2016-12-12 12:03:37 +00002390 g_hash_table_unref (priv->devices);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002391 g_hash_table_unref (priv->report_metadata);
Richard Hughes161e9b52019-06-12 14:22:45 +01002392 g_rw_lock_clear (&priv->devices_mutex);
Richard Hughes84999302019-05-02 10:18:32 +01002393 g_free (priv->build_hash);
Richard Hughescff38bc2016-12-12 12:03:37 +00002394 g_free (priv->name);
2395 g_free (priv->data);
Mario Limonciello3f9a1c12018-06-06 14:06:40 -05002396 /* Must happen as the last step to avoid prematurely
2397 * freeing memory held by the plugin */
2398#ifndef RUNNING_ON_VALGRIND
2399 if (priv->module != NULL)
2400 g_module_close (priv->module);
2401#endif
Richard Hughescff38bc2016-12-12 12:03:37 +00002402
2403 G_OBJECT_CLASS (fu_plugin_parent_class)->finalize (object);
2404}
2405
2406FuPlugin *
2407fu_plugin_new (void)
2408{
Richard Hughes12724852018-09-04 13:53:44 +01002409 return FU_PLUGIN (g_object_new (FU_TYPE_PLUGIN, NULL));
Richard Hughescff38bc2016-12-12 12:03:37 +00002410}