blob: 735d6e475de8102a686f21ce698267de60255747 [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>
Richard Hughescff38bc2016-12-12 12:03:37 +000016#include <gio/gunixinputstream.h>
Mario Limonciello6d0aa3d2017-02-28 08:22:27 -060017#ifdef HAVE_VALGRIND
Richard Hughes576c0122017-02-24 09:47:00 +000018#include <valgrind.h>
Mario Limonciello6d0aa3d2017-02-28 08:22:27 -060019#endif /* HAVE_VALGRIND */
Richard Hughesd0905142016-03-13 09:46:49 +000020
Richard Hughes9dde04f2017-09-13 12:07:15 +010021#include "fu-device-private.h"
Richard Hughescff38bc2016-12-12 12:03:37 +000022#include "fu-plugin-private.h"
Richard Hughesbc3a4e12018-01-06 22:41:47 +000023#include "fu-history.h"
Richard Hughes37d09432018-09-09 10:39:45 +010024#include "fu-mutex.h"
Richard Hughesd0905142016-03-13 09:46:49 +000025
Richard Hughes4eada342017-10-03 21:20:32 +010026/**
27 * SECTION:fu-plugin
28 * @short_description: a daemon plugin
29 *
30 * An object that represents a plugin run by the daemon.
31 *
32 * See also: #FuDevice
33 */
34
Richard Hughesb0829032017-01-10 09:27:08 +000035#define FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM 3000u /* ms */
36
Richard Hughescff38bc2016-12-12 12:03:37 +000037static void fu_plugin_finalize (GObject *object);
38
39typedef struct {
40 GModule *module;
41 GUsbContext *usb_ctx;
42 gboolean enabled;
Richard Hughes08a37992017-09-12 12:57:43 +010043 guint order;
Richard Hughes81c427c2018-08-06 15:20:17 +010044 guint priority;
Richard Hughes08a37992017-09-12 12:57:43 +010045 GPtrArray *rules[FU_PLUGIN_RULE_LAST];
Richard Hughescff38bc2016-12-12 12:03:37 +000046 gchar *name;
Richard Hughesf425d292019-01-18 17:57:39 +000047 gchar *build_hash;
Richard Hughesd7704d42017-08-08 20:29:09 +010048 FuHwids *hwids;
Richard Hughes9c028f02017-10-28 21:14:28 +010049 FuQuirks *quirks;
Richard Hughes0eb123b2018-04-19 12:00:04 +010050 GHashTable *runtime_versions;
Richard Hughes34e0dab2018-04-20 16:43:00 +010051 GHashTable *compile_versions;
Richard Hughes9d6e0e72018-08-24 20:20:17 +010052 GPtrArray *udev_subsystems;
Richard Hughes1354ea92017-09-19 15:58:31 +010053 FuSmbios *smbios;
Richard Hughes989acf12019-10-05 20:16:47 +010054 GType device_gtype;
Richard Hughescff38bc2016-12-12 12:03:37 +000055 GHashTable *devices; /* platform_id:GObject */
Richard Hughes161e9b52019-06-12 14:22:45 +010056 GRWLock devices_mutex;
Richard Hughes80b79bb2018-01-11 21:11:06 +000057 GHashTable *report_metadata; /* key:value */
Richard Hughescff38bc2016-12-12 12:03:37 +000058 FuPluginData *data;
59} FuPluginPrivate;
60
61enum {
62 SIGNAL_DEVICE_ADDED,
63 SIGNAL_DEVICE_REMOVED,
Richard Hughese1fd34d2017-08-24 14:19:51 +010064 SIGNAL_DEVICE_REGISTER,
Richard Hughes75b965d2018-11-15 13:51:21 +000065 SIGNAL_RULES_CHANGED,
Richard Hughes362d6d72017-01-07 21:42:14 +000066 SIGNAL_RECOLDPLUG,
Richard Hughesb0829032017-01-10 09:27:08 +000067 SIGNAL_SET_COLDPLUG_DELAY,
Richard Hughesaabdc372018-11-14 10:11:08 +000068 SIGNAL_CHECK_SUPPORTED,
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/**
110 * fu_plugin_get_name:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100111 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000112 *
113 * Gets the plugin name.
114 *
115 * Returns: a plugin name, or %NULL for unknown.
116 *
117 * Since: 0.8.0
118 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000119const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100120fu_plugin_get_name (FuPlugin *self)
Richard Hughesd0905142016-03-13 09:46:49 +0000121{
Richard Hughes12724852018-09-04 13:53:44 +0100122 FuPluginPrivate *priv = GET_PRIVATE (self);
123 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000124 return priv->name;
125}
Richard Hughesd0905142016-03-13 09:46:49 +0000126
Richard Hughes34834102017-11-21 21:55:00 +0000127void
Richard Hughes12724852018-09-04 13:53:44 +0100128fu_plugin_set_name (FuPlugin *self, const gchar *name)
Richard Hughes34834102017-11-21 21:55:00 +0000129{
Richard Hughes12724852018-09-04 13:53:44 +0100130 FuPluginPrivate *priv = GET_PRIVATE (self);
131 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughes34834102017-11-21 21:55:00 +0000132 g_return_if_fail (name != NULL);
133 g_free (priv->name);
134 priv->name = g_strdup (name);
135}
136
Richard Hughes57d18222017-01-10 16:02:59 +0000137/**
Richard Hughesf425d292019-01-18 17:57:39 +0000138 * fu_plugin_set_build_hash:
139 * @self: A #FuPlugin
140 * @build_hash: A checksum
141 *
142 * Sets the plugin build hash, typically a SHA256 checksum. All plugins must
143 * set the correct checksum to avoid the daemon being marked as tainted.
144 *
145 * Since: 1.2.4
146 **/
147void
148fu_plugin_set_build_hash (FuPlugin *self, const gchar *build_hash)
149{
150 FuPluginPrivate *priv = GET_PRIVATE (self);
151 g_return_if_fail (FU_IS_PLUGIN (self));
152 g_return_if_fail (build_hash != NULL);
153 g_free (priv->build_hash);
154 priv->build_hash = g_strdup (build_hash);
155}
156
157const gchar *
158fu_plugin_get_build_hash (FuPlugin *self)
159{
160 FuPluginPrivate *priv = GET_PRIVATE (self);
161 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
162 return priv->build_hash;
163}
164
165/**
Richard Hughes57d18222017-01-10 16:02:59 +0000166 * fu_plugin_cache_lookup:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100167 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000168 * @id: the key
169 *
170 * Finds an object in the per-plugin cache.
171 *
172 * Returns: (transfer none): a #GObject, or %NULL for unfound.
173 *
174 * Since: 0.8.0
175 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000176gpointer
Richard Hughes12724852018-09-04 13:53:44 +0100177fu_plugin_cache_lookup (FuPlugin *self, const gchar *id)
Richard Hughescff38bc2016-12-12 12:03:37 +0000178{
Richard Hughes12724852018-09-04 13:53:44 +0100179 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes161e9b52019-06-12 14:22:45 +0100180 g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100181 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughesccd78a92017-01-11 16:57:41 +0000182 g_return_val_if_fail (id != NULL, NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100183 g_return_val_if_fail (locker != NULL, NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000184 return g_hash_table_lookup (priv->devices, id);
185}
Richard Hughesd0905142016-03-13 09:46:49 +0000186
Richard Hughes57d18222017-01-10 16:02:59 +0000187/**
188 * fu_plugin_cache_add:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100189 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000190 * @id: the key
191 * @dev: a #GObject, typically a #FuDevice
192 *
193 * Adds an object to the per-plugin cache.
194 *
195 * Since: 0.8.0
196 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000197void
Richard Hughes12724852018-09-04 13:53:44 +0100198fu_plugin_cache_add (FuPlugin *self, const gchar *id, gpointer dev)
Richard Hughescff38bc2016-12-12 12:03:37 +0000199{
Richard Hughes12724852018-09-04 13:53:44 +0100200 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes161e9b52019-06-12 14:22:45 +0100201 g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_writer_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100202 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000203 g_return_if_fail (id != NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100204 g_return_if_fail (locker != NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000205 g_hash_table_insert (priv->devices, g_strdup (id), g_object_ref (dev));
206}
207
Richard Hughes57d18222017-01-10 16:02:59 +0000208/**
209 * fu_plugin_cache_remove:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100210 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000211 * @id: the key
212 *
213 * Removes an object from the per-plugin cache.
214 *
215 * Since: 0.8.0
216 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000217void
Richard Hughes12724852018-09-04 13:53:44 +0100218fu_plugin_cache_remove (FuPlugin *self, const gchar *id)
Richard Hughescff38bc2016-12-12 12:03:37 +0000219{
Richard Hughes12724852018-09-04 13:53:44 +0100220 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes161e9b52019-06-12 14:22:45 +0100221 g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_writer_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100222 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000223 g_return_if_fail (id != NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100224 g_return_if_fail (locker != NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000225 g_hash_table_remove (priv->devices, id);
226}
227
Richard Hughes57d18222017-01-10 16:02:59 +0000228/**
229 * fu_plugin_get_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100230 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000231 *
Richard Hughes4eada342017-10-03 21:20:32 +0100232 * Gets the per-plugin allocated private data. This will return %NULL unless
233 * fu_plugin_alloc_data() has been called by the plugin.
Richard Hughes57d18222017-01-10 16:02:59 +0000234 *
Richard Hughes4eada342017-10-03 21:20:32 +0100235 * Returns: (transfer none): a pointer to a structure, or %NULL for unset.
Richard Hughes57d18222017-01-10 16:02:59 +0000236 *
237 * Since: 0.8.0
238 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000239FuPluginData *
Richard Hughes12724852018-09-04 13:53:44 +0100240fu_plugin_get_data (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +0000241{
Richard Hughes12724852018-09-04 13:53:44 +0100242 FuPluginPrivate *priv = GET_PRIVATE (self);
243 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000244 return priv->data;
245}
246
Richard Hughes57d18222017-01-10 16:02:59 +0000247/**
248 * fu_plugin_alloc_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100249 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000250 * @data_sz: the size to allocate
251 *
252 * Allocates the per-plugin allocated private data.
253 *
254 * Returns: (transfer full): a pointer to a structure, or %NULL for unset.
255 *
256 * Since: 0.8.0
257 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000258FuPluginData *
Richard Hughes12724852018-09-04 13:53:44 +0100259fu_plugin_alloc_data (FuPlugin *self, gsize data_sz)
Richard Hughescff38bc2016-12-12 12:03:37 +0000260{
Richard Hughes12724852018-09-04 13:53:44 +0100261 FuPluginPrivate *priv = GET_PRIVATE (self);
262 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes44dee882017-01-11 08:31:10 +0000263 if (priv->data != NULL) {
264 g_critical ("fu_plugin_alloc_data() already used by plugin");
265 return priv->data;
266 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000267 priv->data = g_malloc0 (data_sz);
268 return priv->data;
Richard Hughesd0905142016-03-13 09:46:49 +0000269}
270
Richard Hughes57d18222017-01-10 16:02:59 +0000271/**
272 * fu_plugin_get_usb_context:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100273 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000274 *
275 * Gets the shared USB context that all plugins can use.
276 *
277 * Returns: (transfer none): a #GUsbContext.
278 *
279 * Since: 0.8.0
280 **/
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000281GUsbContext *
Richard Hughes12724852018-09-04 13:53:44 +0100282fu_plugin_get_usb_context (FuPlugin *self)
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000283{
Richard Hughes12724852018-09-04 13:53:44 +0100284 FuPluginPrivate *priv = GET_PRIVATE (self);
285 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000286 return priv->usb_ctx;
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000287}
288
289void
Richard Hughes12724852018-09-04 13:53:44 +0100290fu_plugin_set_usb_context (FuPlugin *self, GUsbContext *usb_ctx)
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000291{
Richard Hughes12724852018-09-04 13:53:44 +0100292 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +0000293 g_set_object (&priv->usb_ctx, usb_ctx);
294}
295
Richard Hughes57d18222017-01-10 16:02:59 +0000296/**
297 * fu_plugin_get_enabled:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100298 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000299 *
Richard Hughes4eada342017-10-03 21:20:32 +0100300 * Returns if the plugin is enabled. Plugins may self-disable using
301 * fu_plugin_set_enabled() or can be disabled by the daemon.
Richard Hughes57d18222017-01-10 16:02:59 +0000302 *
303 * Returns: %TRUE if the plugin is currently enabled.
304 *
305 * Since: 0.8.0
306 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000307gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100308fu_plugin_get_enabled (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +0000309{
Richard Hughes12724852018-09-04 13:53:44 +0100310 FuPluginPrivate *priv = GET_PRIVATE (self);
311 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
Richard Hughescff38bc2016-12-12 12:03:37 +0000312 return priv->enabled;
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000313}
314
Richard Hughes57d18222017-01-10 16:02:59 +0000315/**
316 * fu_plugin_set_enabled:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100317 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000318 * @enabled: the enabled value
319 *
320 * Enables or disables a plugin. Plugins can self-disable at any point.
321 *
322 * Since: 0.8.0
323 **/
Richard Hughesd0905142016-03-13 09:46:49 +0000324void
Richard Hughes12724852018-09-04 13:53:44 +0100325fu_plugin_set_enabled (FuPlugin *self, gboolean enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000326{
Richard Hughes12724852018-09-04 13:53:44 +0100327 FuPluginPrivate *priv = GET_PRIVATE (self);
328 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughescff38bc2016-12-12 12:03:37 +0000329 priv->enabled = enabled;
330}
331
Richard Hughes1e456bc2018-05-10 20:16:16 +0100332gchar *
333fu_plugin_guess_name_from_fn (const gchar *filename)
334{
335 const gchar *prefix = "libfu_plugin_";
336 gchar *name;
337 gchar *str = g_strstr_len (filename, -1, prefix);
338 if (str == NULL)
339 return NULL;
340 name = g_strdup (str + strlen (prefix));
341 g_strdelimit (name, ".", '\0');
342 return name;
343}
344
Richard Hughescff38bc2016-12-12 12:03:37 +0000345gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100346fu_plugin_open (FuPlugin *self, const gchar *filename, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +0000347{
Richard Hughes12724852018-09-04 13:53:44 +0100348 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +0000349 FuPluginInitFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000350
351 priv->module = g_module_open (filename, 0);
352 if (priv->module == NULL) {
353 g_set_error (error,
354 G_IO_ERROR,
355 G_IO_ERROR_FAILED,
356 "failed to open plugin: %s",
357 g_module_error ());
358 return FALSE;
359 }
360
361 /* set automatically */
Richard Hughes1e456bc2018-05-10 20:16:16 +0100362 if (priv->name == NULL)
363 priv->name = fu_plugin_guess_name_from_fn (filename);
Richard Hughesd0905142016-03-13 09:46:49 +0000364
365 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000366 g_module_symbol (priv->module, "fu_plugin_init", (gpointer *) &func);
367 if (func != NULL) {
368 g_debug ("performing init() on %s", filename);
Richard Hughes12724852018-09-04 13:53:44 +0100369 func (self);
Richard Hughesd0905142016-03-13 09:46:49 +0000370 }
371
Richard Hughescff38bc2016-12-12 12:03:37 +0000372 return TRUE;
373}
374
Richard Hughes57d18222017-01-10 16:02:59 +0000375/**
376 * fu_plugin_device_add:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100377 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000378 * @device: A #FuDevice
379 *
380 * Asks the daemon to add a device to the exported list. If this device ID
381 * has already been added by a different plugin then this request will be
382 * ignored.
383 *
384 * Plugins should use fu_plugin_device_add_delay() if they are not capable of
385 * actually flashing an image to the hardware so that higher-priority plugins
386 * can add the device themselves.
387 *
388 * Since: 0.8.0
389 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000390void
Richard Hughes12724852018-09-04 13:53:44 +0100391fu_plugin_device_add (FuPlugin *self, FuDevice *device)
Richard Hughescff38bc2016-12-12 12:03:37 +0000392{
Richard Hughes5e447292018-04-27 14:25:54 +0100393 GPtrArray *children;
Richard Hughesc125ec02018-09-05 19:35:17 +0100394 g_autoptr(GError) error = NULL;
Richard Hughes5e447292018-04-27 14:25:54 +0100395
Richard Hughes12724852018-09-04 13:53:44 +0100396 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000397 g_return_if_fail (FU_IS_DEVICE (device));
398
Richard Hughesc125ec02018-09-05 19:35:17 +0100399 /* ensure the device ID is set from the physical and logical IDs */
400 if (!fu_device_ensure_id (device, &error)) {
401 g_warning ("ignoring add: %s", error->message);
402 return;
403 }
404
Richard Hughescff38bc2016-12-12 12:03:37 +0000405 g_debug ("emit added from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100406 fu_plugin_get_name (self),
Richard Hughescff38bc2016-12-12 12:03:37 +0000407 fu_device_get_id (device));
408 fu_device_set_created (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
Richard Hughes12724852018-09-04 13:53:44 +0100409 fu_device_set_plugin (device, fu_plugin_get_name (self));
410 g_signal_emit (self, signals[SIGNAL_DEVICE_ADDED], 0, device);
Richard Hughes5e447292018-04-27 14:25:54 +0100411
Richard Hughes128c0162018-08-10 11:00:29 +0100412 /* add children if they have not already been added */
Richard Hughes5e447292018-04-27 14:25:54 +0100413 children = fu_device_get_children (device);
414 for (guint i = 0; i < children->len; i++) {
415 FuDevice *child = g_ptr_array_index (children, i);
Richard Hughes128c0162018-08-10 11:00:29 +0100416 if (fu_device_get_created (child) == 0)
Richard Hughes12724852018-09-04 13:53:44 +0100417 fu_plugin_device_add (self, child);
Richard Hughes5e447292018-04-27 14:25:54 +0100418 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000419}
420
Richard Hughese1fd34d2017-08-24 14:19:51 +0100421/**
422 * fu_plugin_device_register:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100423 * @self: A #FuPlugin
Richard Hughese1fd34d2017-08-24 14:19:51 +0100424 * @device: A #FuDevice
425 *
426 * Registers the device with other plugins so they can set metadata.
427 *
428 * Plugins do not have to call this manually as this is done automatically
429 * when using fu_plugin_device_add(). They may wish to use this manually
430 * if for intance the coldplug should be ignored based on the metadata
431 * set from other plugins.
432 *
433 * Since: 0.9.7
434 **/
435void
Richard Hughes12724852018-09-04 13:53:44 +0100436fu_plugin_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +0100437{
Richard Hughesc125ec02018-09-05 19:35:17 +0100438 g_autoptr(GError) error = NULL;
439
Richard Hughes12724852018-09-04 13:53:44 +0100440 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughese1fd34d2017-08-24 14:19:51 +0100441 g_return_if_fail (FU_IS_DEVICE (device));
442
Richard Hughesc125ec02018-09-05 19:35:17 +0100443 /* ensure the device ID is set from the physical and logical IDs */
444 if (!fu_device_ensure_id (device, &error)) {
445 g_warning ("ignoring registration: %s", error->message);
446 return;
447 }
448
Richard Hughese1fd34d2017-08-24 14:19:51 +0100449 g_debug ("emit device-register from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100450 fu_plugin_get_name (self),
Richard Hughese1fd34d2017-08-24 14:19:51 +0100451 fu_device_get_id (device));
Richard Hughes12724852018-09-04 13:53:44 +0100452 g_signal_emit (self, signals[SIGNAL_DEVICE_REGISTER], 0, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +0100453}
454
Richard Hughes57d18222017-01-10 16:02:59 +0000455/**
Richard Hughes4eada342017-10-03 21:20:32 +0100456 * fu_plugin_device_remove:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100457 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000458 * @device: A #FuDevice
459 *
460 * Asks the daemon to remove a device from the exported list.
461 *
462 * Since: 0.8.0
463 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000464void
Richard Hughes12724852018-09-04 13:53:44 +0100465fu_plugin_device_remove (FuPlugin *self, FuDevice *device)
Richard Hughescff38bc2016-12-12 12:03:37 +0000466{
Richard Hughes12724852018-09-04 13:53:44 +0100467 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000468 g_return_if_fail (FU_IS_DEVICE (device));
469
Richard Hughescff38bc2016-12-12 12:03:37 +0000470 g_debug ("emit removed from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100471 fu_plugin_get_name (self),
Richard Hughescff38bc2016-12-12 12:03:37 +0000472 fu_device_get_id (device));
Richard Hughes12724852018-09-04 13:53:44 +0100473 g_signal_emit (self, signals[SIGNAL_DEVICE_REMOVED], 0, device);
Richard Hughescff38bc2016-12-12 12:03:37 +0000474}
475
Richard Hughes57d18222017-01-10 16:02:59 +0000476/**
Richard Hughes2de8f132018-01-17 09:12:02 +0000477 * fu_plugin_request_recoldplug:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100478 * @self: A #FuPlugin
Richard Hughes362d6d72017-01-07 21:42:14 +0000479 *
480 * Ask all the plugins to coldplug all devices, which will include the prepare()
481 * and cleanup() phases. Duplicate devices added will be ignored.
482 *
483 * Since: 0.8.0
484 **/
485void
Richard Hughes12724852018-09-04 13:53:44 +0100486fu_plugin_request_recoldplug (FuPlugin *self)
Richard Hughes362d6d72017-01-07 21:42:14 +0000487{
Richard Hughes12724852018-09-04 13:53:44 +0100488 g_return_if_fail (FU_IS_PLUGIN (self));
489 g_signal_emit (self, signals[SIGNAL_RECOLDPLUG], 0);
Richard Hughes362d6d72017-01-07 21:42:14 +0000490}
491
Richard Hughesb0829032017-01-10 09:27:08 +0000492/**
Richard Hughesb8f8db22017-04-25 15:56:00 +0100493 * fu_plugin_check_hwid:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100494 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100495 * @hwid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
Richard Hughesb8f8db22017-04-25 15:56:00 +0100496 *
Richard Hughesd7704d42017-08-08 20:29:09 +0100497 * Checks to see if a specific GUID exists. All hardware IDs on a
Richard Hughesb8f8db22017-04-25 15:56:00 +0100498 * specific system can be shown using the `fwupdmgr hwids` command.
499 *
Richard Hughes4eada342017-10-03 21:20:32 +0100500 * Returns: %TRUE if the HwId is found on the system.
501 *
Richard Hughesb8f8db22017-04-25 15:56:00 +0100502 * Since: 0.9.1
503 **/
504gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100505fu_plugin_check_hwid (FuPlugin *self, const gchar *hwid)
Richard Hughesb8f8db22017-04-25 15:56:00 +0100506{
Richard Hughes12724852018-09-04 13:53:44 +0100507 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100508 if (priv->hwids == NULL)
509 return FALSE;
Richard Hughesd7704d42017-08-08 20:29:09 +0100510 return fu_hwids_has_guid (priv->hwids, hwid);
511}
512
513/**
Patrick Rudolpha60b5472019-10-16 10:43:03 +0200514 * fu_plugin_get_hwid_replace_value:
515 * @self: A #FuPlugin
516 * @keys: A key, e.g. `HardwareID-3` or %FU_HWIDS_KEY_PRODUCT_SKU
517 * @error: A #GError or %NULL
518 *
519 * Gets the replacement value for a specific key. All hardware IDs on a
520 * specific system can be shown using the `fwupdmgr hwids` command.
521 *
522 * Returns: (transfer full): a string, or %NULL for error.
523 *
524 * Since: 1.3.3
525 **/
526gchar *
527fu_plugin_get_hwid_replace_value (FuPlugin *self, const gchar *keys, GError **error)
528{
529 FuPluginPrivate *priv = GET_PRIVATE (self);
530 if (priv->hwids == NULL)
531 return NULL;
532
533 return fu_hwids_get_replace_values (priv->hwids, keys, error);
534}
535
536/**
Richard Hughes69a5f352018-08-08 11:58:15 +0100537 * fu_plugin_get_hwids:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100538 * @self: A #FuPlugin
Richard Hughes69a5f352018-08-08 11:58:15 +0100539 *
540 * Returns all the HWIDs defined in the system. All hardware IDs on a
541 * specific system can be shown using the `fwupdmgr hwids` command.
542 *
543 * Returns: (transfer none) (element-type utf-8): An array of GUIDs
544 *
545 * Since: 1.1.1
546 **/
547GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +0100548fu_plugin_get_hwids (FuPlugin *self)
Richard Hughes69a5f352018-08-08 11:58:15 +0100549{
Richard Hughes12724852018-09-04 13:53:44 +0100550 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes69a5f352018-08-08 11:58:15 +0100551 if (priv->hwids == NULL)
552 return NULL;
553 return fu_hwids_get_guids (priv->hwids);
554}
555
556/**
Richard Hughes19841802019-09-10 16:48:00 +0100557 * fu_plugin_has_custom_flag:
558 * @self: A #FuPlugin
559 * @flag: A custom text flag, specific to the plugin, e.g. `uefi-force-enable`
560 *
561 * Returns if a per-plugin HwId custom flag exists, typically added from a DMI quirk.
562 *
563 * Returns: %TRUE if the quirk entry exists
564 *
565 * Since: 1.3.1
566 **/
567gboolean
568fu_plugin_has_custom_flag (FuPlugin *self, const gchar *flag)
569{
570 FuPluginPrivate *priv = GET_PRIVATE (self);
571 GPtrArray *hwids = fu_plugin_get_hwids (self);
572
573 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
574 g_return_val_if_fail (flag != NULL, FALSE);
575
576 /* never set up, e.g. in tests */
577 if (hwids == NULL)
578 return FALSE;
579
580 /* search each hwid */
581 for (guint i = 0; i < hwids->len; i++) {
582 const gchar *hwid = g_ptr_array_index (hwids, i);
583 const gchar *value;
584 g_autofree gchar *key = g_strdup_printf ("HwId=%s", hwid);
585
586 /* does prefixed quirk exist */
587 value = fu_quirks_lookup_by_id (priv->quirks, key, FU_QUIRKS_FLAGS);
588 if (value != NULL) {
589 g_auto(GStrv) quirks = g_strsplit (value, ",", -1);
590 if (g_strv_contains ((const gchar * const *) quirks, flag))
591 return TRUE;
592 }
593 }
594 return FALSE;
595}
596
597/**
Richard Hughes1354ea92017-09-19 15:58:31 +0100598 * fu_plugin_check_supported:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100599 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100600 * @guid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
Richard Hughes1354ea92017-09-19 15:58:31 +0100601 *
602 * Checks to see if a specific device GUID is supported, i.e. available in the
603 * AppStream metadata.
604 *
Richard Hughes4eada342017-10-03 21:20:32 +0100605 * Returns: %TRUE if the device is supported.
606 *
Richard Hughes1354ea92017-09-19 15:58:31 +0100607 * Since: 1.0.0
608 **/
Richard Hughesd8a8d5e2019-10-08 13:05:02 +0100609static gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100610fu_plugin_check_supported (FuPlugin *self, const gchar *guid)
Richard Hughes1354ea92017-09-19 15:58:31 +0100611{
Richard Hughesaabdc372018-11-14 10:11:08 +0000612 gboolean retval = FALSE;
613 g_signal_emit (self, signals[SIGNAL_CHECK_SUPPORTED], 0, guid, &retval);
614 return retval;
Richard Hughes1354ea92017-09-19 15:58:31 +0100615}
616
617/**
Richard Hughesd7704d42017-08-08 20:29:09 +0100618 * fu_plugin_get_dmi_value:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100619 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100620 * @dmi_id: A DMI ID, e.g. `BiosVersion`
Richard Hughesd7704d42017-08-08 20:29:09 +0100621 *
622 * Gets a hardware DMI value.
623 *
Richard Hughes4eada342017-10-03 21:20:32 +0100624 * Returns: The string, or %NULL
625 *
Richard Hughesd7704d42017-08-08 20:29:09 +0100626 * Since: 0.9.7
627 **/
628const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100629fu_plugin_get_dmi_value (FuPlugin *self, const gchar *dmi_id)
Richard Hughesd7704d42017-08-08 20:29:09 +0100630{
Richard Hughes12724852018-09-04 13:53:44 +0100631 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd7704d42017-08-08 20:29:09 +0100632 if (priv->hwids == NULL)
Richard Hughes7ef96b82017-08-23 18:28:24 +0100633 return NULL;
Richard Hughesd7704d42017-08-08 20:29:09 +0100634 return fu_hwids_get_value (priv->hwids, dmi_id);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100635}
636
Richard Hughes49e5e052017-09-03 12:15:41 +0100637/**
638 * fu_plugin_get_smbios_string:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100639 * @self: A #FuPlugin
Richard Hughes49e5e052017-09-03 12:15:41 +0100640 * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
641 * @offset: A SMBIOS offset
642 *
643 * Gets a hardware SMBIOS string.
644 *
645 * The @type and @offset can be referenced from the DMTF SMBIOS specification:
646 * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.1.1.pdf
647 *
Richard Hughes4eada342017-10-03 21:20:32 +0100648 * Returns: A string, or %NULL
649 *
Richard Hughes49e5e052017-09-03 12:15:41 +0100650 * Since: 0.9.8
651 **/
652const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100653fu_plugin_get_smbios_string (FuPlugin *self, guint8 structure_type, guint8 offset)
Richard Hughes49e5e052017-09-03 12:15:41 +0100654{
Richard Hughes12724852018-09-04 13:53:44 +0100655 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100656 if (priv->smbios == NULL)
657 return NULL;
658 return fu_smbios_get_string (priv->smbios, structure_type, offset, NULL);
659}
660
661/**
662 * fu_plugin_get_smbios_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100663 * @self: A #FuPlugin
Richard Hughes49e5e052017-09-03 12:15:41 +0100664 * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
665 *
666 * Gets a hardware SMBIOS data.
667 *
Richard Hughesdfaca2d2019-08-01 08:08:03 +0100668 * Returns: (transfer full): A #GBytes, or %NULL
Richard Hughes4eada342017-10-03 21:20:32 +0100669 *
Richard Hughes49e5e052017-09-03 12:15:41 +0100670 * Since: 0.9.8
671 **/
672GBytes *
Richard Hughes12724852018-09-04 13:53:44 +0100673fu_plugin_get_smbios_data (FuPlugin *self, guint8 structure_type)
Richard Hughes49e5e052017-09-03 12:15:41 +0100674{
Richard Hughes12724852018-09-04 13:53:44 +0100675 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100676 if (priv->smbios == NULL)
677 return NULL;
678 return fu_smbios_get_data (priv->smbios, structure_type, NULL);
679}
680
Richard Hughesb8f8db22017-04-25 15:56:00 +0100681void
Richard Hughes12724852018-09-04 13:53:44 +0100682fu_plugin_set_hwids (FuPlugin *self, FuHwids *hwids)
Richard Hughesb8f8db22017-04-25 15:56:00 +0100683{
Richard Hughes12724852018-09-04 13:53:44 +0100684 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd7704d42017-08-08 20:29:09 +0100685 g_set_object (&priv->hwids, hwids);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100686}
687
Richard Hughes49e5e052017-09-03 12:15:41 +0100688void
Richard Hughes12724852018-09-04 13:53:44 +0100689fu_plugin_set_udev_subsystems (FuPlugin *self, GPtrArray *udev_subsystems)
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100690{
Richard Hughes12724852018-09-04 13:53:44 +0100691 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100692 if (priv->udev_subsystems != NULL)
693 g_ptr_array_unref (priv->udev_subsystems);
694 priv->udev_subsystems = g_ptr_array_ref (udev_subsystems);
695}
696
697void
Richard Hughes12724852018-09-04 13:53:44 +0100698fu_plugin_set_quirks (FuPlugin *self, FuQuirks *quirks)
Richard Hughes9c028f02017-10-28 21:14:28 +0100699{
Richard Hughes12724852018-09-04 13:53:44 +0100700 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9c028f02017-10-28 21:14:28 +0100701 g_set_object (&priv->quirks, quirks);
702}
703
704/**
705 * fu_plugin_get_quirks:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100706 * @self: A #FuPlugin
Richard Hughes9c028f02017-10-28 21:14:28 +0100707 *
708 * Returns the hardware database object. This can be used to discover device
709 * quirks or other device-specific settings.
710 *
711 * Returns: (transfer none): a #FuQuirks, or %NULL if not set
712 *
713 * Since: 1.0.1
714 **/
715FuQuirks *
Richard Hughes12724852018-09-04 13:53:44 +0100716fu_plugin_get_quirks (FuPlugin *self)
Richard Hughes9c028f02017-10-28 21:14:28 +0100717{
Richard Hughes12724852018-09-04 13:53:44 +0100718 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9c028f02017-10-28 21:14:28 +0100719 return priv->quirks;
720}
721
Richard Hughes0eb123b2018-04-19 12:00:04 +0100722void
Richard Hughes12724852018-09-04 13:53:44 +0100723fu_plugin_set_runtime_versions (FuPlugin *self, GHashTable *runtime_versions)
Richard Hughes0eb123b2018-04-19 12:00:04 +0100724{
Richard Hughes12724852018-09-04 13:53:44 +0100725 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0eb123b2018-04-19 12:00:04 +0100726 priv->runtime_versions = g_hash_table_ref (runtime_versions);
727}
728
729/**
730 * fu_plugin_add_runtime_version:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100731 * @self: A #FuPlugin
Richard Hughes0eb123b2018-04-19 12:00:04 +0100732 * @component_id: An AppStream component id, e.g. "org.gnome.Software"
733 * @version: A version string, e.g. "1.2.3"
734 *
Richard Hughesdce91202019-04-08 12:47:45 +0100735 * Sets a runtime version of a specific dependency.
Richard Hughes0eb123b2018-04-19 12:00:04 +0100736 *
737 * Since: 1.0.7
738 **/
739void
Richard Hughes12724852018-09-04 13:53:44 +0100740fu_plugin_add_runtime_version (FuPlugin *self,
Richard Hughes0eb123b2018-04-19 12:00:04 +0100741 const gchar *component_id,
742 const gchar *version)
743{
Richard Hughes12724852018-09-04 13:53:44 +0100744 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesb01b4862018-04-20 16:39:48 +0100745 if (priv->runtime_versions == NULL)
746 return;
Richard Hughes0eb123b2018-04-19 12:00:04 +0100747 g_hash_table_insert (priv->runtime_versions,
748 g_strdup (component_id),
749 g_strdup (version));
750}
751
Richard Hughes34e0dab2018-04-20 16:43:00 +0100752void
Richard Hughes12724852018-09-04 13:53:44 +0100753fu_plugin_set_compile_versions (FuPlugin *self, GHashTable *compile_versions)
Richard Hughes34e0dab2018-04-20 16:43:00 +0100754{
Richard Hughes12724852018-09-04 13:53:44 +0100755 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes34e0dab2018-04-20 16:43:00 +0100756 priv->compile_versions = g_hash_table_ref (compile_versions);
757}
758
759/**
760 * fu_plugin_add_compile_version:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100761 * @self: A #FuPlugin
Richard Hughes34e0dab2018-04-20 16:43:00 +0100762 * @component_id: An AppStream component id, e.g. "org.gnome.Software"
763 * @version: A version string, e.g. "1.2.3"
764 *
Richard Hughesdce91202019-04-08 12:47:45 +0100765 * Sets a compile-time version of a specific dependency.
Richard Hughes34e0dab2018-04-20 16:43:00 +0100766 *
767 * Since: 1.0.7
768 **/
769void
Richard Hughes12724852018-09-04 13:53:44 +0100770fu_plugin_add_compile_version (FuPlugin *self,
Richard Hughes34e0dab2018-04-20 16:43:00 +0100771 const gchar *component_id,
772 const gchar *version)
773{
Richard Hughes12724852018-09-04 13:53:44 +0100774 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes34e0dab2018-04-20 16:43:00 +0100775 if (priv->compile_versions == NULL)
776 return;
777 g_hash_table_insert (priv->compile_versions,
778 g_strdup (component_id),
779 g_strdup (version));
780}
781
Richard Hughes9c028f02017-10-28 21:14:28 +0100782/**
783 * fu_plugin_lookup_quirk_by_id:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100784 * @self: A #FuPlugin
Richard Hughes87fb9ff2018-06-28 12:55:59 +0100785 * @group: A string, e.g. "DfuFlags"
786 * @key: An ID to match the entry, e.g. "Summary"
Richard Hughes9c028f02017-10-28 21:14:28 +0100787 *
788 * Looks up an entry in the hardware database using a string value.
789 *
790 * Returns: (transfer none): values from the database, or %NULL if not found
791 *
792 * Since: 1.0.1
793 **/
794const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100795fu_plugin_lookup_quirk_by_id (FuPlugin *self, const gchar *group, const gchar *key)
Richard Hughes9c028f02017-10-28 21:14:28 +0100796{
Richard Hughes12724852018-09-04 13:53:44 +0100797 FuPluginPrivate *priv = GET_PRIVATE (self);
798 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes9c028f02017-10-28 21:14:28 +0100799
Richard Hughes9c028f02017-10-28 21:14:28 +0100800 /* exact ID */
Richard Hughes87fb9ff2018-06-28 12:55:59 +0100801 return fu_quirks_lookup_by_id (priv->quirks, group, key);
Richard Hughes9c028f02017-10-28 21:14:28 +0100802}
803
804/**
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100805 * fu_plugin_lookup_quirk_by_id_as_uint64:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100806 * @self: A #FuPlugin
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100807 * @group: A string, e.g. "DfuFlags"
808 * @key: An ID to match the entry, e.g. "Size"
809 *
810 * Looks up an entry in the hardware database using a string key, returning
811 * an integer value. Values are assumed base 10, unless prefixed with "0x"
812 * where they are parsed as base 16.
813 *
814 * Returns: (transfer none): value from the database, or 0 if not found
815 *
816 * Since: 1.1.2
817 **/
818guint64
Richard Hughes12724852018-09-04 13:53:44 +0100819fu_plugin_lookup_quirk_by_id_as_uint64 (FuPlugin *self, const gchar *group, const gchar *key)
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100820{
Richard Hughes12724852018-09-04 13:53:44 +0100821 return fu_common_strtoull (fu_plugin_lookup_quirk_by_id (self, group, key));
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100822}
823
Richard Hughes1354ea92017-09-19 15:58:31 +0100824void
Richard Hughes12724852018-09-04 13:53:44 +0100825fu_plugin_set_smbios (FuPlugin *self, FuSmbios *smbios)
Richard Hughes49e5e052017-09-03 12:15:41 +0100826{
Richard Hughes12724852018-09-04 13:53:44 +0100827 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100828 g_set_object (&priv->smbios, smbios);
829}
830
Richard Hughesb8f8db22017-04-25 15:56:00 +0100831/**
Richard Hughesb0829032017-01-10 09:27:08 +0000832 * fu_plugin_set_coldplug_delay:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100833 * @self: A #FuPlugin
Richard Hughesb0829032017-01-10 09:27:08 +0000834 * @duration: A delay in milliseconds
835 *
836 * Set the minimum time that should be waited inbetween the call to
837 * fu_plugin_coldplug_prepare() and fu_plugin_coldplug(). This is usually going
838 * to be the minimum hardware initialisation time from a datasheet.
839 *
840 * It is better to use this function rather than using a sleep() in the plugin
841 * itself as then only one delay is done in the daemon rather than waiting for
842 * each coldplug prepare in a serial way.
843 *
844 * Additionally, very long delays should be avoided as the daemon will be
845 * blocked from processing requests whilst the coldplug delay is being
846 * performed.
847 *
848 * Since: 0.8.0
849 **/
850void
Richard Hughes12724852018-09-04 13:53:44 +0100851fu_plugin_set_coldplug_delay (FuPlugin *self, guint duration)
Richard Hughesb0829032017-01-10 09:27:08 +0000852{
Richard Hughes12724852018-09-04 13:53:44 +0100853 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesb0829032017-01-10 09:27:08 +0000854 g_return_if_fail (duration > 0);
855
856 /* check sanity */
857 if (duration > FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM) {
858 g_warning ("duration of %ums is crazy, truncating to %ums",
859 duration,
860 FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM);
861 duration = FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM;
862 }
863
864 /* emit */
Richard Hughes12724852018-09-04 13:53:44 +0100865 g_signal_emit (self, signals[SIGNAL_SET_COLDPLUG_DELAY], 0, duration);
Richard Hughesb0829032017-01-10 09:27:08 +0000866}
867
Richard Hughes4b303802019-10-04 13:22:51 +0100868static gboolean
869fu_plugin_device_attach (FuPlugin *self, FuDevice *device, GError **error)
870{
871 g_autoptr(FuDeviceLocker) locker = NULL;
872 if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) {
873 g_debug ("already in runtime mode, skipping");
874 return TRUE;
875 }
876 locker = fu_device_locker_new (device, error);
877 if (locker == NULL)
878 return FALSE;
879 return fu_device_attach (device, error);
880}
881
882static gboolean
883fu_plugin_device_detach (FuPlugin *self, FuDevice *device, GError **error)
884{
885 g_autoptr(FuDeviceLocker) locker = NULL;
886 if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) {
887 g_debug ("already in bootloader mode, skipping");
888 return TRUE;
889 }
890 locker = fu_device_locker_new (device, error);
891 if (locker == NULL)
892 return FALSE;
893 return fu_device_detach (device, error);
894}
895
896static gboolean
Richard Hughes4b303802019-10-04 13:22:51 +0100897fu_plugin_device_activate (FuPlugin *self, FuDevice *device, GError **error)
898{
899 g_autoptr(FuDeviceLocker) locker = NULL;
900 locker = fu_device_locker_new (device, error);
901 if (locker == NULL)
902 return FALSE;
903 return fu_device_activate (device, error);
904}
905
906static gboolean
907fu_plugin_device_write_firmware (FuPlugin *self, FuDevice *device,
908 GBytes *fw, FwupdInstallFlags flags,
909 GError **error)
910{
911 g_autoptr(FuDeviceLocker) locker = NULL;
912 locker = fu_device_locker_new (device, error);
913 if (locker == NULL)
914 return FALSE;
915 return fu_device_write_firmware (device, fw, flags, error);
916}
917
Richard Hughes7f677212019-10-05 16:19:40 +0100918static gboolean
919fu_plugin_device_read_firmware (FuPlugin *self, FuDevice *device, GError **error)
920{
921 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughesf0eb0912019-10-10 11:37:22 +0100922 g_autoptr(FuFirmware) firmware = NULL;
Richard Hughes7f677212019-10-05 16:19:40 +0100923 g_autoptr(GBytes) fw = NULL;
924 GChecksumType checksum_types[] = {
925 G_CHECKSUM_SHA1,
926 G_CHECKSUM_SHA256,
927 0 };
928 locker = fu_device_locker_new (device, error);
929 if (locker == NULL)
930 return FALSE;
931 if (!fu_device_detach (device, error))
932 return FALSE;
Richard Hughesf0eb0912019-10-10 11:37:22 +0100933 firmware = fu_device_read_firmware (device, error);
934 if (firmware == NULL) {
935 g_autoptr(GError) error_local = NULL;
936 if (!fu_device_attach (device, &error_local))
937 g_debug ("ignoring attach failure: %s", error_local->message);
938 g_prefix_error (error, "failed to read firmware: ");
939 return FALSE;
940 }
941 fw = fu_firmware_write (firmware, error);
Richard Hughes7f677212019-10-05 16:19:40 +0100942 if (fw == NULL) {
943 g_autoptr(GError) error_local = NULL;
944 if (!fu_device_attach (device, &error_local))
Richard Hughesf0eb0912019-10-10 11:37:22 +0100945 g_debug ("ignoring attach failure: %s", error_local->message);
946 g_prefix_error (error, "failed to write firmware: ");
Richard Hughes7f677212019-10-05 16:19:40 +0100947 return FALSE;
948 }
949 for (guint i = 0; checksum_types[i] != 0; i++) {
950 g_autofree gchar *hash = NULL;
951 hash = g_compute_checksum_for_bytes (checksum_types[i], fw);
952 fu_device_add_checksum (device, hash);
953 }
954 return fu_device_attach (device, error);
955}
956
Richard Hughesd0905142016-03-13 09:46:49 +0000957gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100958fu_plugin_runner_startup (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +0000959{
Richard Hughes12724852018-09-04 13:53:44 +0100960 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000961 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +0000962 g_autoptr(GError) error_local = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +0000963
964 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +0000965 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000966 return TRUE;
967
Richard Hughes639da472018-01-06 22:35:04 +0000968 /* no object loaded */
969 if (priv->module == NULL)
970 return TRUE;
971
Richard Hughesd0905142016-03-13 09:46:49 +0000972 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000973 g_module_symbol (priv->module, "fu_plugin_startup", (gpointer *) &func);
974 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +0000975 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +0000976 g_debug ("performing startup() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +0000977 if (!func (self, &error_local)) {
978 if (error_local == NULL) {
979 g_critical ("unset error in plugin %s for startup()",
980 priv->name);
981 g_set_error_literal (&error_local,
982 FWUPD_ERROR,
983 FWUPD_ERROR_INTERNAL,
984 "unspecified error");
985 }
986 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
987 "failed to startup using %s: ",
988 priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +0000989 return FALSE;
990 }
991 return TRUE;
992}
993
994static gboolean
995fu_plugin_runner_offline_invalidate (GError **error)
996{
997 g_autoptr(GError) error_local = NULL;
998 g_autoptr(GFile) file1 = NULL;
999
1000 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1001
1002 file1 = g_file_new_for_path (FU_OFFLINE_TRIGGER_FILENAME);
1003 if (!g_file_query_exists (file1, NULL))
1004 return TRUE;
1005 if (!g_file_delete (file1, NULL, &error_local)) {
1006 g_set_error (error,
1007 FWUPD_ERROR,
1008 FWUPD_ERROR_INTERNAL,
1009 "Cannot delete %s: %s",
1010 FU_OFFLINE_TRIGGER_FILENAME,
1011 error_local->message);
1012 return FALSE;
1013 }
1014 return TRUE;
1015}
1016
1017static gboolean
1018fu_plugin_runner_offline_setup (GError **error)
1019{
1020 gint rc;
Richard Hughes484ee292019-03-22 16:10:50 +00001021 g_autofree gchar *filename = NULL;
Mario Limoncielloe1b4b202019-04-30 10:01:19 -05001022 g_autofree gchar *symlink_target = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG);
Richard Hughescff38bc2016-12-12 12:03:37 +00001023
1024 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1025
Richard Hughes484ee292019-03-22 16:10:50 +00001026 /* does already exist */
1027 filename = fu_common_realpath (FU_OFFLINE_TRIGGER_FILENAME, NULL);
1028 if (g_strcmp0 (filename, symlink_target) == 0) {
1029 g_debug ("%s already points to %s, skipping creation",
1030 FU_OFFLINE_TRIGGER_FILENAME, symlink_target);
1031 return TRUE;
1032 }
1033
Richard Hughescff38bc2016-12-12 12:03:37 +00001034 /* create symlink for the systemd-system-update-generator */
Richard Hughes484ee292019-03-22 16:10:50 +00001035 rc = symlink (symlink_target, FU_OFFLINE_TRIGGER_FILENAME);
Richard Hughescff38bc2016-12-12 12:03:37 +00001036 if (rc < 0) {
1037 g_set_error (error,
1038 FWUPD_ERROR,
1039 FWUPD_ERROR_INTERNAL,
1040 "Failed to create symlink %s to %s: %s",
1041 FU_OFFLINE_TRIGGER_FILENAME,
1042 "/var/lib", strerror (errno));
Richard Hughesd0905142016-03-13 09:46:49 +00001043 return FALSE;
1044 }
1045 return TRUE;
1046}
1047
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001048static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001049fu_plugin_runner_device_generic (FuPlugin *self, FuDevice *device,
Richard Hughes4b303802019-10-04 13:22:51 +01001050 const gchar *symbol_name,
1051 FuPluginDeviceFunc device_func,
1052 GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001053{
Richard Hughes12724852018-09-04 13:53:44 +01001054 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001055 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001056 g_autoptr(GError) error_local = NULL;
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001057
1058 /* not enabled */
1059 if (!priv->enabled)
1060 return TRUE;
1061
Richard Hughesd3d96cc2017-11-14 11:34:33 +00001062 /* no object loaded */
1063 if (priv->module == NULL)
1064 return TRUE;
1065
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001066 /* optional */
1067 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
Richard Hughes4b303802019-10-04 13:22:51 +01001068 if (func == NULL) {
1069 if (device_func != NULL) {
1070 g_debug ("running superclassed %s() on %s",
1071 symbol_name + 10, priv->name);
1072 return device_func (self, device, error);
1073 }
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001074 return TRUE;
Richard Hughes4b303802019-10-04 13:22:51 +01001075 }
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001076 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001077 if (!func (self, device, &error_local)) {
1078 if (error_local == NULL) {
1079 g_critical ("unset error in plugin %s for %s()",
1080 priv->name, symbol_name + 10);
1081 g_set_error_literal (&error_local,
1082 FWUPD_ERROR,
1083 FWUPD_ERROR_INTERNAL,
1084 "unspecified error");
1085 }
1086 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1087 "failed to %s using %s: ",
1088 symbol_name + 10, priv->name);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001089 return FALSE;
1090 }
1091 return TRUE;
1092}
1093
Richard Hughesdbd8c762018-06-15 20:31:40 +01001094static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001095fu_plugin_runner_flagged_device_generic (FuPlugin *self, FwupdInstallFlags flags,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001096 FuDevice *device,
1097 const gchar *symbol_name, GError **error)
1098{
Richard Hughes12724852018-09-04 13:53:44 +01001099 FuPluginPrivate *priv = GET_PRIVATE (self);
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001100 FuPluginFlaggedDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001101 g_autoptr(GError) error_local = NULL;
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001102
1103 /* not enabled */
1104 if (!priv->enabled)
1105 return TRUE;
1106
1107 /* no object loaded */
1108 if (priv->module == NULL)
1109 return TRUE;
1110
1111 /* optional */
1112 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1113 if (func == NULL)
1114 return TRUE;
1115 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001116 if (!func (self, flags, device, &error_local)) {
1117 if (error_local == NULL) {
1118 g_critical ("unset error in plugin %s for %s()",
1119 priv->name, symbol_name + 10);
1120 g_set_error_literal (&error_local,
1121 FWUPD_ERROR,
1122 FWUPD_ERROR_INTERNAL,
1123 "unspecified error");
1124 }
1125 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1126 "failed to %s using %s: ",
1127 symbol_name + 10, priv->name);
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001128 return FALSE;
1129 }
1130 return TRUE;
1131
1132}
1133
1134static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001135fu_plugin_runner_device_array_generic (FuPlugin *self, GPtrArray *devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001136 const gchar *symbol_name, GError **error)
1137{
Richard Hughes12724852018-09-04 13:53:44 +01001138 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesdbd8c762018-06-15 20:31:40 +01001139 FuPluginDeviceArrayFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001140 g_autoptr(GError) error_local = NULL;
Richard Hughesdbd8c762018-06-15 20:31:40 +01001141
1142 /* not enabled */
1143 if (!priv->enabled)
1144 return TRUE;
1145
1146 /* no object loaded */
1147 if (priv->module == NULL)
1148 return TRUE;
1149
1150 /* optional */
1151 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1152 if (func == NULL)
1153 return TRUE;
1154 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001155 if (!func (self, devices, &error_local)) {
1156 if (error_local == NULL) {
1157 g_critical ("unset error in plugin %s for %s()",
1158 priv->name, symbol_name + 10);
1159 g_set_error_literal (&error_local,
1160 FWUPD_ERROR,
1161 FWUPD_ERROR_INTERNAL,
1162 "unspecified error");
1163 }
1164 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1165 "failed to %s using %s: ",
1166 symbol_name + 10, priv->name);
Richard Hughesdbd8c762018-06-15 20:31:40 +01001167 return FALSE;
1168 }
1169 return TRUE;
1170}
1171
Richard Hughesd0905142016-03-13 09:46:49 +00001172gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001173fu_plugin_runner_coldplug (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00001174{
Richard Hughes12724852018-09-04 13:53:44 +01001175 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001176 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001177 g_autoptr(GError) error_local = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +00001178
1179 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +00001180 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +00001181 return TRUE;
1182
Richard Hughes639da472018-01-06 22:35:04 +00001183 /* no object loaded */
1184 if (priv->module == NULL)
1185 return TRUE;
1186
Richard Hughesd0905142016-03-13 09:46:49 +00001187 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00001188 g_module_symbol (priv->module, "fu_plugin_coldplug", (gpointer *) &func);
1189 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +00001190 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001191 g_debug ("performing coldplug() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001192 if (!func (self, &error_local)) {
1193 if (error_local == NULL) {
1194 g_critical ("unset error in plugin %s for coldplug()",
1195 priv->name);
1196 g_set_error_literal (&error_local,
1197 FWUPD_ERROR,
1198 FWUPD_ERROR_INTERNAL,
1199 "unspecified error");
1200 }
1201 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1202 "failed to coldplug using %s: ", priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00001203 return FALSE;
1204 }
1205 return TRUE;
1206}
1207
Richard Hughes7b8b2022016-12-12 16:15:03 +00001208gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001209fu_plugin_runner_recoldplug (FuPlugin *self, GError **error)
Richard Hughes2de8f132018-01-17 09:12:02 +00001210{
Richard Hughes12724852018-09-04 13:53:44 +01001211 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes2de8f132018-01-17 09:12:02 +00001212 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001213 g_autoptr(GError) error_local = NULL;
Richard Hughes2de8f132018-01-17 09:12:02 +00001214
1215 /* not enabled */
1216 if (!priv->enabled)
1217 return TRUE;
1218
1219 /* no object loaded */
1220 if (priv->module == NULL)
1221 return TRUE;
1222
1223 /* optional */
1224 g_module_symbol (priv->module, "fu_plugin_recoldplug", (gpointer *) &func);
1225 if (func == NULL)
1226 return TRUE;
1227 g_debug ("performing recoldplug() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001228 if (!func (self, &error_local)) {
1229 if (error_local == NULL) {
1230 g_critical ("unset error in plugin %s for recoldplug()",
1231 priv->name);
1232 g_set_error_literal (&error_local,
1233 FWUPD_ERROR,
1234 FWUPD_ERROR_INTERNAL,
1235 "unspecified error");
1236 }
1237 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1238 "failed to recoldplug using %s: ",
1239 priv->name);
Richard Hughes2de8f132018-01-17 09:12:02 +00001240 return FALSE;
1241 }
1242 return TRUE;
1243}
1244
1245gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001246fu_plugin_runner_coldplug_prepare (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001247{
Richard Hughes12724852018-09-04 13:53:44 +01001248 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001249 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001250 g_autoptr(GError) error_local = NULL;
Richard Hughes46487c92017-01-07 21:26:34 +00001251
1252 /* not enabled */
1253 if (!priv->enabled)
1254 return TRUE;
1255
Richard Hughes639da472018-01-06 22:35:04 +00001256 /* no object loaded */
1257 if (priv->module == NULL)
1258 return TRUE;
1259
Richard Hughes46487c92017-01-07 21:26:34 +00001260 /* optional */
1261 g_module_symbol (priv->module, "fu_plugin_coldplug_prepare", (gpointer *) &func);
1262 if (func == NULL)
1263 return TRUE;
1264 g_debug ("performing coldplug_prepare() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001265 if (!func (self, &error_local)) {
1266 if (error_local == NULL) {
1267 g_critical ("unset error in plugin %s for coldplug_prepare()",
1268 priv->name);
1269 g_set_error_literal (&error_local,
1270 FWUPD_ERROR,
1271 FWUPD_ERROR_INTERNAL,
1272 "unspecified error");
1273 }
1274 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1275 "failed to coldplug_prepare using %s: ",
1276 priv->name);
Richard Hughes46487c92017-01-07 21:26:34 +00001277 return FALSE;
1278 }
1279 return TRUE;
1280}
1281
1282gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001283fu_plugin_runner_coldplug_cleanup (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001284{
Richard Hughes12724852018-09-04 13:53:44 +01001285 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001286 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001287 g_autoptr(GError) error_local = NULL;
Richard Hughes46487c92017-01-07 21:26:34 +00001288
1289 /* not enabled */
1290 if (!priv->enabled)
1291 return TRUE;
1292
Richard Hughes639da472018-01-06 22:35:04 +00001293 /* no object loaded */
1294 if (priv->module == NULL)
1295 return TRUE;
1296
Richard Hughes46487c92017-01-07 21:26:34 +00001297 /* optional */
1298 g_module_symbol (priv->module, "fu_plugin_coldplug_cleanup", (gpointer *) &func);
1299 if (func == NULL)
1300 return TRUE;
1301 g_debug ("performing coldplug_cleanup() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001302 if (!func (self, &error_local)) {
1303 if (error_local == NULL) {
1304 g_critical ("unset error in plugin %s for coldplug_cleanup()",
1305 priv->name);
1306 g_set_error_literal (&error_local,
1307 FWUPD_ERROR,
1308 FWUPD_ERROR_INTERNAL,
1309 "unspecified error");
1310 }
1311 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1312 "failed to coldplug_cleanup using %s: ",
1313 priv->name);
Richard Hughes46487c92017-01-07 21:26:34 +00001314 return FALSE;
1315 }
1316 return TRUE;
1317}
1318
1319gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001320fu_plugin_runner_composite_prepare (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001321{
Richard Hughes12724852018-09-04 13:53:44 +01001322 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001323 "fu_plugin_composite_prepare",
1324 error);
1325}
1326
1327gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001328fu_plugin_runner_composite_cleanup (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001329{
Richard Hughes12724852018-09-04 13:53:44 +01001330 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001331 "fu_plugin_composite_cleanup",
1332 error);
1333}
1334
1335gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001336fu_plugin_runner_update_prepare (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001337 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001338{
Richard Hughes12724852018-09-04 13:53:44 +01001339 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001340 "fu_plugin_update_prepare",
1341 error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001342}
1343
1344gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001345fu_plugin_runner_update_cleanup (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001346 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001347{
Richard Hughes12724852018-09-04 13:53:44 +01001348 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001349 "fu_plugin_update_cleanup",
1350 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001351}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001352
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001353gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001354fu_plugin_runner_update_attach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001355{
Richard Hughes12724852018-09-04 13:53:44 +01001356 return fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001357 "fu_plugin_update_attach",
1358 fu_plugin_device_attach,
1359 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001360}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001361
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001362gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001363fu_plugin_runner_update_detach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001364{
Richard Hughes12724852018-09-04 13:53:44 +01001365 return fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001366 "fu_plugin_update_detach",
1367 fu_plugin_device_detach,
1368 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001369}
1370
1371gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001372fu_plugin_runner_update_reload (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001373{
Richard Hughes42f33df2019-10-05 20:52:33 +01001374 FuPluginPrivate *priv = GET_PRIVATE (self);
1375 g_autoptr(FuDeviceLocker) locker = NULL;
1376
1377 /* not enabled */
1378 if (!priv->enabled)
1379 return TRUE;
1380
1381 /* no object loaded */
1382 locker = fu_device_locker_new (device, error);
1383 if (locker == NULL)
1384 return FALSE;
1385 return fu_device_reload (device, error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001386}
1387
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001388/**
1389 * fu_plugin_add_udev_subsystem:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001390 * @self: a #FuPlugin
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001391 * @subsystem: a subsystem name, e.g. `pciport`
1392 *
1393 * Registers the udev subsystem to be watched by the daemon.
1394 *
1395 * Plugins can use this method only in fu_plugin_init()
1396 **/
1397void
Richard Hughes12724852018-09-04 13:53:44 +01001398fu_plugin_add_udev_subsystem (FuPlugin *self, const gchar *subsystem)
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001399{
Richard Hughes12724852018-09-04 13:53:44 +01001400 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001401 for (guint i = 0; i < priv->udev_subsystems->len; i++) {
1402 const gchar *subsystem_tmp = g_ptr_array_index (priv->udev_subsystems, i);
1403 if (g_strcmp0 (subsystem_tmp, subsystem) == 0)
1404 return;
1405 }
1406 g_debug ("added udev subsystem watch of %s", subsystem);
1407 g_ptr_array_add (priv->udev_subsystems, g_strdup (subsystem));
1408}
1409
Richard Hughes989acf12019-10-05 20:16:47 +01001410/**
1411 * fu_plugin_set_device_gtype:
1412 * @self: a #FuPlugin
1413 * @device_gtype: a #GType `FU_TYPE_DEVICE`
1414 *
1415 * Sets the device #GType which is used when creating devices.
1416 *
1417 * If this method is used then fu_plugin_usb_device_added() is not called, and
1418 * instead the object is created in the daemon for the plugin.
1419 *
1420 * Plugins can use this method only in fu_plugin_init()
1421 *
1422 * Since: 1.3.3
1423 **/
1424void
1425fu_plugin_set_device_gtype (FuPlugin *self, GType device_gtype)
1426{
1427 FuPluginPrivate *priv = GET_PRIVATE (self);
1428 priv->device_gtype = device_gtype;
1429}
1430
1431static gboolean
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001432fu_plugin_check_supported_device (FuPlugin *self, FuDevice *device)
1433{
1434 GPtrArray *instance_ids = fu_device_get_instance_ids (device);
1435 for (guint i = 0; i < instance_ids->len; i++) {
1436 const gchar *instance_id = g_ptr_array_index (instance_ids, i);
1437 g_autofree gchar *guid = fwupd_guid_hash_string (instance_id);
1438 if (fu_plugin_check_supported (self, guid))
1439 return TRUE;
1440 }
1441 return FALSE;
1442}
1443
1444static gboolean
Richard Hughes989acf12019-10-05 20:16:47 +01001445fu_plugin_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error)
1446{
1447 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001448 GType device_gtype = fu_device_get_specialized_gtype (FU_DEVICE (device));
Richard Hughes989acf12019-10-05 20:16:47 +01001449 g_autoptr(FuDevice) dev = NULL;
1450 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001451
1452 /* fall back to plugin default */
1453 if (device_gtype == G_TYPE_INVALID)
1454 device_gtype = priv->device_gtype;
1455
1456 /* create new device and incorporate existing properties */
1457 dev = g_object_new (device_gtype, NULL);
1458 fu_device_incorporate (dev, FU_DEVICE (device));
1459
1460 /* there are a lot of different devices that match, but not all respond
1461 * well to opening -- so limit some ones with issued updates */
1462 if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_ONLY_SUPPORTED)) {
1463 if (!fu_device_probe (dev, error))
1464 return FALSE;
1465 fu_device_convert_instance_ids (dev);
1466 if (!fu_plugin_check_supported_device (self, dev)) {
1467 g_autofree gchar *guids = fu_device_get_guids_as_str (dev);
1468 g_debug ("%s has no updates, so ignoring device", guids);
1469 return TRUE;
1470 }
1471 }
1472
1473 /* open and add */
1474 locker = fu_device_locker_new (dev, error);
1475 if (locker == NULL)
1476 return FALSE;
1477 fu_plugin_device_add (self, dev);
1478 return TRUE;
1479}
1480
1481static gboolean
1482fu_plugin_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error)
1483{
1484 FuPluginPrivate *priv = GET_PRIVATE (self);
1485 GType device_gtype = fu_device_get_specialized_gtype (FU_DEVICE (device));
1486 g_autoptr(FuDevice) dev = NULL;
1487 g_autoptr(FuDeviceLocker) locker = NULL;
1488
1489 /* fall back to plugin default */
1490 if (device_gtype == G_TYPE_INVALID)
1491 device_gtype = priv->device_gtype;
1492
1493 /* create new device and incorporate existing properties */
1494 dev = g_object_new (device_gtype, NULL);
Richard Hughes989acf12019-10-05 20:16:47 +01001495 fu_device_incorporate (FU_DEVICE (dev), FU_DEVICE (device));
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001496
1497 /* there are a lot of different devices that match, but not all respond
1498 * well to opening -- so limit some ones with issued updates */
1499 if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_ONLY_SUPPORTED)) {
1500 if (!fu_device_probe (dev, error))
1501 return FALSE;
1502 fu_device_convert_instance_ids (dev);
1503 if (!fu_plugin_check_supported_device (self, dev)) {
1504 g_autofree gchar *guids = fu_device_get_guids_as_str (dev);
1505 g_debug ("%s has no updates, so ignoring device", guids);
1506 return TRUE;
1507 }
1508 }
1509
1510 /* open and add */
Richard Hughes989acf12019-10-05 20:16:47 +01001511 locker = fu_device_locker_new (dev, error);
1512 if (locker == NULL)
1513 return FALSE;
1514 fu_plugin_device_add (self, FU_DEVICE (dev));
1515 return TRUE;
1516}
1517
Richard Hughes104f6512017-11-24 11:44:57 +00001518gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001519fu_plugin_runner_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error)
Richard Hughes104f6512017-11-24 11:44:57 +00001520{
Richard Hughes12724852018-09-04 13:53:44 +01001521 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes104f6512017-11-24 11:44:57 +00001522 FuPluginUsbDeviceAddedFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001523 g_autoptr(GError) error_local = NULL;
Richard Hughes104f6512017-11-24 11:44:57 +00001524
1525 /* not enabled */
1526 if (!priv->enabled)
1527 return TRUE;
Richard Hughes639da472018-01-06 22:35:04 +00001528
1529 /* no object loaded */
Richard Hughes104f6512017-11-24 11:44:57 +00001530 if (priv->module == NULL)
1531 return TRUE;
1532
1533 /* optional */
1534 g_module_symbol (priv->module, "fu_plugin_usb_device_added", (gpointer *) &func);
Richard Hughes989acf12019-10-05 20:16:47 +01001535 if (func == NULL) {
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001536 if (priv->device_gtype != G_TYPE_INVALID ||
1537 fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) {
Mario Limonciello0e500322019-10-17 18:41:04 -05001538 if (!fu_plugin_usb_device_added (self, device, error))
Mario Limoncielloa9be5362019-10-12 13:17:45 -05001539 return FALSE;
Richard Hughes989acf12019-10-05 20:16:47 +01001540 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001541 return TRUE;
Richard Hughes989acf12019-10-05 20:16:47 +01001542 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001543 g_debug ("performing usb_device_added() on %s", priv->name);
1544 if (!func (self, device, &error_local)) {
1545 if (error_local == NULL) {
1546 g_critical ("unset error in plugin %s for usb_device_added()",
1547 priv->name);
1548 g_set_error_literal (&error_local,
1549 FWUPD_ERROR,
1550 FWUPD_ERROR_INTERNAL,
1551 "unspecified error");
1552 }
1553 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1554 "failed to add device using on %s: ",
1555 priv->name);
1556 return FALSE;
Richard Hughes104f6512017-11-24 11:44:57 +00001557 }
1558 return TRUE;
1559}
1560
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001561gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001562fu_plugin_runner_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error)
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001563{
Richard Hughes12724852018-09-04 13:53:44 +01001564 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001565 FuPluginUdevDeviceAddedFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001566 g_autoptr(GError) error_local = NULL;
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001567
1568 /* not enabled */
1569 if (!priv->enabled)
1570 return TRUE;
1571
1572 /* no object loaded */
1573 if (priv->module == NULL)
1574 return TRUE;
1575
1576 /* optional */
1577 g_module_symbol (priv->module, "fu_plugin_udev_device_added", (gpointer *) &func);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001578 if (func == NULL) {
1579 if (priv->device_gtype != G_TYPE_INVALID ||
1580 fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) {
Mario Limonciello0e500322019-10-17 18:41:04 -05001581 if (!fu_plugin_udev_device_added (self, device, error))
Mario Limoncielloa9be5362019-10-12 13:17:45 -05001582 return FALSE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001583 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001584 return TRUE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001585 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001586 g_debug ("performing udev_device_added() on %s", priv->name);
1587 if (!func (self, device, &error_local)) {
1588 if (error_local == NULL) {
1589 g_critical ("unset error in plugin %s for udev_device_added()",
1590 priv->name);
1591 g_set_error_literal (&error_local,
1592 FWUPD_ERROR,
1593 FWUPD_ERROR_INTERNAL,
1594 "unspecified error");
1595 }
1596 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1597 "failed to add device using on %s: ",
1598 priv->name);
1599 return FALSE;
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001600 }
1601 return TRUE;
1602}
1603
Richard Hughes5e952ce2019-08-26 11:09:46 +01001604gboolean
1605fu_plugin_runner_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GError **error)
1606{
1607 FuPluginPrivate *priv = GET_PRIVATE (self);
1608 FuPluginUdevDeviceAddedFunc func = NULL;
1609 g_autoptr(GError) error_local = NULL;
1610
1611 /* not enabled */
1612 if (!priv->enabled)
1613 return TRUE;
1614
1615 /* no object loaded */
1616 if (priv->module == NULL)
1617 return TRUE;
1618
1619 /* optional */
1620 g_module_symbol (priv->module, "fu_plugin_udev_device_changed", (gpointer *) &func);
1621 if (func == NULL)
1622 return TRUE;
1623 g_debug ("performing udev_device_changed() on %s", priv->name);
1624 if (!func (self, device, &error_local)) {
1625 if (error_local == NULL) {
1626 g_critical ("unset error in plugin %s for udev_device_changed()",
1627 priv->name);
1628 g_set_error_literal (&error_local,
1629 FWUPD_ERROR,
1630 FWUPD_ERROR_INTERNAL,
1631 "unspecified error");
1632 }
1633 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1634 "failed to change device on %s: ",
1635 priv->name);
1636 return FALSE;
1637 }
1638 return TRUE;
1639}
1640
Richard Hughese1fd34d2017-08-24 14:19:51 +01001641void
Richard Hughes12724852018-09-04 13:53:44 +01001642fu_plugin_runner_device_removed (FuPlugin *self, FuDevice *device)
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001643{
1644 g_autoptr(GError) error_local= NULL;
1645
Richard Hughes12724852018-09-04 13:53:44 +01001646 if (!fu_plugin_runner_device_generic (self, device,
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001647 "fu_plugin_device_removed",
Richard Hughes4b303802019-10-04 13:22:51 +01001648 NULL,
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001649 &error_local))
1650 g_warning ("%s", error_local->message);
1651}
1652
1653void
Richard Hughes12724852018-09-04 13:53:44 +01001654fu_plugin_runner_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +01001655{
Richard Hughes12724852018-09-04 13:53:44 +01001656 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughese1fd34d2017-08-24 14:19:51 +01001657 FuPluginDeviceRegisterFunc func = NULL;
1658
1659 /* not enabled */
1660 if (!priv->enabled)
1661 return;
Richard Hughes34834102017-11-21 21:55:00 +00001662 if (priv->module == NULL)
1663 return;
Richard Hughese1fd34d2017-08-24 14:19:51 +01001664
Mario Limonciello4910b242018-06-22 15:04:21 -05001665 /* don't notify plugins on their own devices */
Richard Hughes12724852018-09-04 13:53:44 +01001666 if (g_strcmp0 (fu_device_get_plugin (device), fu_plugin_get_name (self)) == 0)
Mario Limonciello4910b242018-06-22 15:04:21 -05001667 return;
1668
Richard Hughese1fd34d2017-08-24 14:19:51 +01001669 /* optional */
1670 g_module_symbol (priv->module, "fu_plugin_device_registered", (gpointer *) &func);
1671 if (func != NULL) {
Richard Hughes1bf7ff92018-08-24 20:21:35 +01001672 g_debug ("performing fu_plugin_device_registered() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01001673 func (self, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +01001674 }
1675}
1676
Richard Hughesc6c312f2019-02-01 16:37:14 +00001677gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001678fu_plugin_runner_schedule_update (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +00001679 FuDevice *device,
Richard Hughes994b4d92019-03-25 14:28:30 +00001680 FwupdRelease *release,
Richard Hughescff38bc2016-12-12 12:03:37 +00001681 GBytes *blob_cab,
Richard Hughes5cbb5cf2019-04-26 16:48:03 +01001682 FwupdInstallFlags flags,
Richard Hughescff38bc2016-12-12 12:03:37 +00001683 GError **error)
1684{
Richard Hughes0a906262019-05-16 13:38:47 +01001685 gchar tmpname[] = {"XXXXXX.cab"};
Richard Hughescff38bc2016-12-12 12:03:37 +00001686 g_autofree gchar *dirname = NULL;
1687 g_autofree gchar *filename = NULL;
Richard Hughes780ef3f2018-01-12 16:20:31 +00001688 g_autoptr(FuHistory) history = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001689 g_autoptr(GFile) file = NULL;
1690
1691 /* id already exists */
Richard Hughes780ef3f2018-01-12 16:20:31 +00001692 history = fu_history_new ();
Richard Hughes5cbb5cf2019-04-26 16:48:03 +01001693 if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) {
1694 g_autoptr(FuDevice) res_tmp = NULL;
1695 res_tmp = fu_history_get_device_by_id (history, fu_device_get_id (device), NULL);
1696 if (res_tmp != NULL &&
1697 fu_device_get_update_state (res_tmp) == FWUPD_UPDATE_STATE_PENDING) {
1698 g_set_error (error,
1699 FWUPD_ERROR,
1700 FWUPD_ERROR_ALREADY_PENDING,
1701 "%s is already scheduled to be updated",
1702 fu_device_get_id (device));
1703 return FALSE;
1704 }
Richard Hughescff38bc2016-12-12 12:03:37 +00001705 }
1706
1707 /* create directory */
Richard Hughes4be17d12018-05-30 20:36:29 +01001708 dirname = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG);
Richard Hughescff38bc2016-12-12 12:03:37 +00001709 file = g_file_new_for_path (dirname);
1710 if (!g_file_query_exists (file, NULL)) {
1711 if (!g_file_make_directory_with_parents (file, NULL, error))
1712 return FALSE;
1713 }
1714
1715 /* get a random filename */
1716 for (guint i = 0; i < 6; i++)
1717 tmpname[i] = (gchar) g_random_int_range ('A', 'Z');
1718 filename = g_build_filename (dirname, tmpname, NULL);
1719
1720 /* just copy to the temp file */
Richard Hughes23135eb2017-11-30 21:01:25 +00001721 fu_device_set_status (device, FWUPD_STATUS_SCHEDULING);
Richard Hughescff38bc2016-12-12 12:03:37 +00001722 if (!g_file_set_contents (filename,
1723 g_bytes_get_data (blob_cab, NULL),
1724 (gssize) g_bytes_get_size (blob_cab),
1725 error))
1726 return FALSE;
1727
1728 /* schedule for next boot */
1729 g_debug ("schedule %s to be installed to %s on next boot",
1730 filename, fu_device_get_id (device));
Richard Hughes994b4d92019-03-25 14:28:30 +00001731 fwupd_release_set_filename (release, filename);
Richard Hughescff38bc2016-12-12 12:03:37 +00001732
1733 /* add to database */
Richard Hughes809abea2019-03-23 11:06:18 +00001734 fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT);
Richard Hughes3e90a582018-01-06 22:38:09 +00001735 fu_device_set_update_state (device, FWUPD_UPDATE_STATE_PENDING);
Richard Hughes994b4d92019-03-25 14:28:30 +00001736 if (!fu_history_add_device (history, device, release, error))
Richard Hughescff38bc2016-12-12 12:03:37 +00001737 return FALSE;
1738
1739 /* next boot we run offline */
Richard Hughesdb69c812019-03-22 16:10:15 +00001740 fu_device_set_progress (device, 100);
Richard Hughescff38bc2016-12-12 12:03:37 +00001741 return fu_plugin_runner_offline_setup (error);
1742}
1743
1744gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001745fu_plugin_runner_verify (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +00001746 FuDevice *device,
1747 FuPluginVerifyFlags flags,
1748 GError **error)
1749{
Richard Hughes12724852018-09-04 13:53:44 +01001750 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001751 FuPluginVerifyFunc func = NULL;
Richard Hughesababbb72017-06-15 20:18:36 +01001752 GPtrArray *checksums;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001753 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001754
1755 /* not enabled */
1756 if (!priv->enabled)
1757 return TRUE;
1758
Richard Hughes639da472018-01-06 22:35:04 +00001759 /* no object loaded */
1760 if (priv->module == NULL)
1761 return TRUE;
1762
Richard Hughescff38bc2016-12-12 12:03:37 +00001763 /* optional */
1764 g_module_symbol (priv->module, "fu_plugin_verify", (gpointer *) &func);
Richard Hughes7f677212019-10-05 16:19:40 +01001765 if (func == NULL) {
Richard Hughes7f677212019-10-05 16:19:40 +01001766 return fu_plugin_device_read_firmware (self, device, error);
1767 }
Richard Hughes1812fc72018-12-14 11:37:54 +00001768
1769 /* clear any existing verification checksums */
1770 checksums = fu_device_get_checksums (device);
1771 g_ptr_array_set_size (checksums, 0);
1772
Richard Hughesc9223be2019-03-18 08:46:42 +00001773 /* run additional detach */
1774 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01001775 "fu_plugin_update_detach",
Richard Hughes4b303802019-10-04 13:22:51 +01001776 fu_plugin_device_detach,
Richard Hughesc9223be2019-03-18 08:46:42 +00001777 error))
1778 return FALSE;
1779
Richard Hughes1812fc72018-12-14 11:37:54 +00001780 /* run vfunc */
Richard Hughescff38bc2016-12-12 12:03:37 +00001781 g_debug ("performing verify() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001782 if (!func (self, device, flags, &error_local)) {
Richard Hughesc9223be2019-03-18 08:46:42 +00001783 g_autoptr(GError) error_attach = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001784 if (error_local == NULL) {
1785 g_critical ("unset error in plugin %s for verify()",
1786 priv->name);
1787 g_set_error_literal (&error_local,
1788 FWUPD_ERROR,
1789 FWUPD_ERROR_INTERNAL,
1790 "unspecified error");
1791 }
1792 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1793 "failed to verify using %s: ",
1794 priv->name);
Richard Hughesc9223be2019-03-18 08:46:42 +00001795 /* make the device "work" again, but don't prefix the error */
1796 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01001797 "fu_plugin_update_attach",
Richard Hughes4b303802019-10-04 13:22:51 +01001798 fu_plugin_device_attach,
Richard Hughesc9223be2019-03-18 08:46:42 +00001799 &error_attach)) {
1800 g_warning ("failed to attach whilst aborting verify(): %s",
1801 error_attach->message);
1802 }
Richard Hughesd0905142016-03-13 09:46:49 +00001803 return FALSE;
1804 }
Richard Hughesc9223be2019-03-18 08:46:42 +00001805
1806 /* run optional attach */
1807 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01001808 "fu_plugin_update_attach",
Richard Hughes4b303802019-10-04 13:22:51 +01001809 fu_plugin_device_attach,
Richard Hughesc9223be2019-03-18 08:46:42 +00001810 error))
1811 return FALSE;
1812
1813 /* success */
Richard Hughesd0905142016-03-13 09:46:49 +00001814 return TRUE;
1815}
1816
Richard Hughesd0905142016-03-13 09:46:49 +00001817gboolean
Mario Limonciello96a0dd52019-02-25 13:50:03 -06001818fu_plugin_runner_activate (FuPlugin *self, FuDevice *device, GError **error)
1819{
1820 guint64 flags;
1821
1822 /* final check */
1823 flags = fu_device_get_flags (device);
1824 if ((flags & FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION) == 0) {
1825 g_set_error (error,
1826 FWUPD_ERROR,
1827 FWUPD_ERROR_NOT_SUPPORTED,
1828 "Device %s does not need activation",
1829 fu_device_get_id (device));
1830 return FALSE;
1831 }
1832
1833 /* run vfunc */
1834 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001835 "fu_plugin_activate",
1836 fu_plugin_device_activate,
1837 error))
Mario Limonciello96a0dd52019-02-25 13:50:03 -06001838 return FALSE;
1839
1840 /* update with correct flags */
1841 fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION);
1842 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
1843 return TRUE;
1844}
1845
1846gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001847fu_plugin_runner_unlock (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00001848{
Richard Hughescff38bc2016-12-12 12:03:37 +00001849 guint64 flags;
Richard Hughescff38bc2016-12-12 12:03:37 +00001850
1851 /* final check */
1852 flags = fu_device_get_flags (device);
1853 if ((flags & FWUPD_DEVICE_FLAG_LOCKED) == 0) {
1854 g_set_error (error,
1855 FWUPD_ERROR,
1856 FWUPD_ERROR_NOT_SUPPORTED,
1857 "Device %s is not locked",
1858 fu_device_get_id (device));
1859 return FALSE;
1860 }
1861
Richard Hughes9c4b5312017-11-14 11:34:53 +00001862 /* run vfunc */
Richard Hughes12724852018-09-04 13:53:44 +01001863 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001864 "fu_plugin_unlock",
1865 NULL,
1866 error))
Richard Hughes9c4b5312017-11-14 11:34:53 +00001867 return FALSE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001868
1869 /* update with correct flags */
1870 flags = fu_device_get_flags (device);
1871 fu_device_set_flags (device, flags &= ~FWUPD_DEVICE_FLAG_LOCKED);
1872 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
1873 return TRUE;
1874}
1875
1876gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001877fu_plugin_runner_update (FuPlugin *self,
Richard Hughesa785a1c2017-08-25 16:00:58 +01001878 FuDevice *device,
Richard Hughesa785a1c2017-08-25 16:00:58 +01001879 GBytes *blob_fw,
1880 FwupdInstallFlags flags,
1881 GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00001882{
Richard Hughes12724852018-09-04 13:53:44 +01001883 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesa785a1c2017-08-25 16:00:58 +01001884 FuPluginUpdateFunc update_func;
Richard Hughes780ef3f2018-01-12 16:20:31 +00001885 g_autoptr(FuHistory) history = NULL;
Richard Hughes68982c62017-09-13 15:40:14 +01001886 g_autoptr(FuDevice) device_pending = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001887 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001888
1889 /* not enabled */
Richard Hughes41c15482018-02-01 22:07:21 +00001890 if (!priv->enabled) {
1891 g_debug ("plugin not enabled, skipping");
Richard Hughesd0905142016-03-13 09:46:49 +00001892 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00001893 }
Richard Hughesd0905142016-03-13 09:46:49 +00001894
Richard Hughes639da472018-01-06 22:35:04 +00001895 /* no object loaded */
Richard Hughes41c15482018-02-01 22:07:21 +00001896 if (priv->module == NULL) {
1897 g_debug ("module not enabled, skipping");
Richard Hughes639da472018-01-06 22:35:04 +00001898 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00001899 }
Richard Hughes639da472018-01-06 22:35:04 +00001900
Richard Hughesd0905142016-03-13 09:46:49 +00001901 /* optional */
Richard Hughesa785a1c2017-08-25 16:00:58 +01001902 g_module_symbol (priv->module, "fu_plugin_update", (gpointer *) &update_func);
1903 if (update_func == NULL) {
Richard Hughes4b303802019-10-04 13:22:51 +01001904 g_debug ("running superclassed write_firmware() on %s", priv->name);
1905 return fu_plugin_device_write_firmware (self, device, blob_fw, flags, error);
Richard Hughesa785a1c2017-08-25 16:00:58 +01001906 }
Richard Hughesd0905142016-03-13 09:46:49 +00001907
Richard Hughescff38bc2016-12-12 12:03:37 +00001908 /* cancel the pending action */
1909 if (!fu_plugin_runner_offline_invalidate (error))
1910 return FALSE;
1911
1912 /* online */
Richard Hughes780ef3f2018-01-12 16:20:31 +00001913 history = fu_history_new ();
Richard Hughes0b9d9962018-01-12 16:31:28 +00001914 device_pending = fu_history_get_device_by_id (history, fu_device_get_id (device), NULL);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001915 if (!update_func (self, device, blob_fw, flags, &error_local)) {
1916 if (error_local == NULL) {
1917 g_critical ("unset error in plugin %s for update()",
1918 priv->name);
1919 g_set_error_literal (&error_local,
Richard Hughes3c8ada32018-10-12 10:08:58 +01001920 FWUPD_ERROR,
1921 FWUPD_ERROR_INTERNAL,
1922 "unspecified error");
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001923 return FALSE;
Richard Hughes3c8ada32018-10-12 10:08:58 +01001924 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001925 fu_device_set_update_error (device, error_local->message);
1926 g_propagate_error (error, g_steal_pointer (&error_local));
Richard Hughescff38bc2016-12-12 12:03:37 +00001927 return FALSE;
1928 }
1929
Richard Hughesf556d372017-06-15 19:49:18 +01001930 /* no longer valid */
Richard Hughesf8039642019-01-16 12:22:22 +00001931 if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT) &&
1932 !fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) {
Richard Hughes08435162018-12-12 10:34:16 +00001933 GPtrArray *checksums = fu_device_get_checksums (device);
1934 g_ptr_array_set_size (checksums, 0);
1935 }
Richard Hughesf556d372017-06-15 19:49:18 +01001936
Richard Hughescff38bc2016-12-12 12:03:37 +00001937 /* cleanup */
Richard Hughes68982c62017-09-13 15:40:14 +01001938 if (device_pending != NULL) {
Richard Hughescff38bc2016-12-12 12:03:37 +00001939 const gchar *tmp;
Richard Hughesbc3a4e12018-01-06 22:41:47 +00001940 FwupdRelease *release;
Richard Hughescff38bc2016-12-12 12:03:37 +00001941
Richard Hughes780ef3f2018-01-12 16:20:31 +00001942 /* update history database */
Richard Hughesc0cd0232018-01-31 15:02:00 +00001943 fu_device_set_update_state (device, FWUPD_UPDATE_STATE_SUCCESS);
1944 if (!fu_history_modify_device (history, device,
1945 FU_HISTORY_FLAGS_MATCH_NEW_VERSION,
1946 error))
Richard Hughes0b9d9962018-01-12 16:31:28 +00001947 return FALSE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001948
1949 /* delete cab file */
Richard Hughesbc3a4e12018-01-06 22:41:47 +00001950 release = fu_device_get_release_default (device_pending);
1951 tmp = fwupd_release_get_filename (release);
Richard Hughescff38bc2016-12-12 12:03:37 +00001952 if (tmp != NULL && g_str_has_prefix (tmp, LIBEXECDIR)) {
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001953 g_autoptr(GError) error_delete = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001954 g_autoptr(GFile) file = NULL;
1955 file = g_file_new_for_path (tmp);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001956 if (!g_file_delete (file, NULL, &error_delete)) {
Richard Hughescff38bc2016-12-12 12:03:37 +00001957 g_set_error (error,
1958 FWUPD_ERROR,
1959 FWUPD_ERROR_INVALID_FILE,
1960 "Failed to delete %s: %s",
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001961 tmp, error_delete->message);
Richard Hughescff38bc2016-12-12 12:03:37 +00001962 return FALSE;
1963 }
1964 }
1965 }
Richard Hughesd0905142016-03-13 09:46:49 +00001966 return TRUE;
1967}
Richard Hughescff38bc2016-12-12 12:03:37 +00001968
1969gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001970fu_plugin_runner_clear_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00001971{
Richard Hughes12724852018-09-04 13:53:44 +01001972 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001973 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001974 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001975
1976 /* not enabled */
1977 if (!priv->enabled)
1978 return TRUE;
1979
Richard Hughes639da472018-01-06 22:35:04 +00001980 /* no object loaded */
1981 if (priv->module == NULL)
1982 return TRUE;
1983
Richard Hughes65e44ca2018-01-30 17:26:30 +00001984 /* optional */
1985 g_module_symbol (priv->module, "fu_plugin_get_results", (gpointer *) &func);
1986 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00001987 return TRUE;
Richard Hughes65e44ca2018-01-30 17:26:30 +00001988 g_debug ("performing clear_result() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001989 if (!func (self, device, &error_local)) {
1990 if (error_local == NULL) {
1991 g_critical ("unset error in plugin %s for clear_result()",
1992 priv->name);
1993 g_set_error_literal (&error_local,
1994 FWUPD_ERROR,
1995 FWUPD_ERROR_INTERNAL,
1996 "unspecified error");
1997 }
1998 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1999 "failed to clear_result using %s: ",
2000 priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00002001 return FALSE;
2002 }
Richard Hughes65e44ca2018-01-30 17:26:30 +00002003 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00002004}
2005
2006gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002007fu_plugin_runner_get_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00002008{
Richard Hughes12724852018-09-04 13:53:44 +01002009 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00002010 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002011 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002012
2013 /* not enabled */
2014 if (!priv->enabled)
2015 return TRUE;
2016
Richard Hughes639da472018-01-06 22:35:04 +00002017 /* no object loaded */
2018 if (priv->module == NULL)
2019 return TRUE;
2020
Richard Hughes65e44ca2018-01-30 17:26:30 +00002021 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00002022 g_module_symbol (priv->module, "fu_plugin_get_results", (gpointer *) &func);
Richard Hughes65e44ca2018-01-30 17:26:30 +00002023 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00002024 return TRUE;
Richard Hughes65e44ca2018-01-30 17:26:30 +00002025 g_debug ("performing get_results() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002026 if (!func (self, device, &error_local)) {
2027 if (error_local == NULL) {
2028 g_critical ("unset error in plugin %s for get_results()",
2029 priv->name);
2030 g_set_error_literal (&error_local,
2031 FWUPD_ERROR,
2032 FWUPD_ERROR_INTERNAL,
2033 "unspecified error");
2034 }
2035 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2036 "failed to get_results using %s: ",
2037 priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00002038 return FALSE;
2039 }
Richard Hughescff38bc2016-12-12 12:03:37 +00002040 return TRUE;
2041}
2042
Richard Hughes08a37992017-09-12 12:57:43 +01002043/**
2044 * fu_plugin_get_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002045 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002046 *
2047 * Gets the plugin order, where higher numbers are run after lower
2048 * numbers.
2049 *
2050 * Returns: the integer value
2051 **/
2052guint
Richard Hughes12724852018-09-04 13:53:44 +01002053fu_plugin_get_order (FuPlugin *self)
Richard Hughes08a37992017-09-12 12:57:43 +01002054{
Richard Hughes12724852018-09-04 13:53:44 +01002055 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002056 return priv->order;
2057}
2058
2059/**
2060 * fu_plugin_set_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002061 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002062 * @order: a integer value
2063 *
2064 * Sets the plugin order, where higher numbers are run after lower
2065 * numbers.
2066 **/
2067void
Richard Hughes12724852018-09-04 13:53:44 +01002068fu_plugin_set_order (FuPlugin *self, guint order)
Richard Hughes08a37992017-09-12 12:57:43 +01002069{
Richard Hughes12724852018-09-04 13:53:44 +01002070 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002071 priv->order = order;
2072}
2073
2074/**
Richard Hughes81c427c2018-08-06 15:20:17 +01002075 * fu_plugin_get_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002076 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01002077 *
2078 * Gets the plugin priority, where higher numbers are better.
2079 *
2080 * Returns: the integer value
2081 **/
2082guint
Richard Hughes12724852018-09-04 13:53:44 +01002083fu_plugin_get_priority (FuPlugin *self)
Richard Hughes81c427c2018-08-06 15:20:17 +01002084{
Richard Hughes12724852018-09-04 13:53:44 +01002085 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01002086 return priv->priority;
2087}
2088
2089/**
2090 * fu_plugin_set_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002091 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01002092 * @priority: a integer value
2093 *
2094 * Sets the plugin priority, where higher numbers are better.
2095 **/
2096void
Richard Hughes12724852018-09-04 13:53:44 +01002097fu_plugin_set_priority (FuPlugin *self, guint priority)
Richard Hughes81c427c2018-08-06 15:20:17 +01002098{
Richard Hughes12724852018-09-04 13:53:44 +01002099 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01002100 priv->priority = priority;
2101}
2102
2103/**
Richard Hughes08a37992017-09-12 12:57:43 +01002104 * fu_plugin_add_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002105 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002106 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
Richard Hughes4eada342017-10-03 21:20:32 +01002107 * @name: a plugin name, e.g. `upower`
Richard Hughes08a37992017-09-12 12:57:43 +01002108 *
2109 * If the plugin name is found, the rule will be used to sort the plugin list,
2110 * for example the plugin specified by @name will be ordered after this plugin
2111 * when %FU_PLUGIN_RULE_RUN_AFTER is used.
2112 *
2113 * NOTE: The depsolver is iterative and may not solve overly-complicated rules;
2114 * If depsolving fails then fwupd will not start.
2115 **/
2116void
Richard Hughes12724852018-09-04 13:53:44 +01002117fu_plugin_add_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes08a37992017-09-12 12:57:43 +01002118{
Richard Hughes12724852018-09-04 13:53:44 +01002119 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002120 g_ptr_array_add (priv->rules[rule], g_strdup (name));
Richard Hughes75b965d2018-11-15 13:51:21 +00002121 g_signal_emit (self, signals[SIGNAL_RULES_CHANGED], 0);
Richard Hughes08a37992017-09-12 12:57:43 +01002122}
2123
2124/**
2125 * fu_plugin_get_rules:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002126 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002127 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
2128 *
2129 * Gets the plugin IDs that should be run after this plugin.
2130 *
2131 * Returns: (element-type utf8) (transfer none): the list of plugin names, e.g. ['appstream']
2132 **/
2133GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +01002134fu_plugin_get_rules (FuPlugin *self, FuPluginRule rule)
Richard Hughes08a37992017-09-12 12:57:43 +01002135{
Richard Hughes12724852018-09-04 13:53:44 +01002136 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002137 return priv->rules[rule];
2138}
2139
Richard Hughes80b79bb2018-01-11 21:11:06 +00002140/**
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002141 * fu_plugin_has_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002142 * @self: a #FuPlugin
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002143 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
2144 * @name: a plugin name, e.g. `upower`
2145 *
Richard Hughes87fb9ff2018-06-28 12:55:59 +01002146 * Gets the plugin IDs that should be run after this plugin.
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002147 *
2148 * Returns: %TRUE if the name exists for the specific rule
2149 **/
2150gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002151fu_plugin_has_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002152{
Richard Hughes12724852018-09-04 13:53:44 +01002153 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002154 for (guint i = 0; i < priv->rules[rule]->len; i++) {
2155 const gchar *tmp = g_ptr_array_index (priv->rules[rule], i);
2156 if (g_strcmp0 (tmp, name) == 0)
2157 return TRUE;
2158 }
2159 return FALSE;
2160}
2161
2162/**
Richard Hughes80b79bb2018-01-11 21:11:06 +00002163 * fu_plugin_add_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002164 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00002165 * @key: a string, e.g. `FwupdateVersion`
2166 * @value: a string, e.g. `10`
2167 *
2168 * Sets any additional metadata to be included in the firmware report to aid
2169 * debugging problems.
2170 *
2171 * Any data included here will be sent to the metadata server after user
2172 * confirmation.
2173 **/
2174void
Richard Hughes12724852018-09-04 13:53:44 +01002175fu_plugin_add_report_metadata (FuPlugin *self, const gchar *key, const gchar *value)
Richard Hughes80b79bb2018-01-11 21:11:06 +00002176{
Richard Hughes12724852018-09-04 13:53:44 +01002177 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002178 g_hash_table_insert (priv->report_metadata, g_strdup (key), g_strdup (value));
2179}
2180
2181/**
2182 * fu_plugin_get_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002183 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00002184 *
2185 * Returns the list of additional metadata to be added when filing a report.
2186 *
2187 * Returns: (transfer none): the map of report metadata
2188 **/
2189GHashTable *
Richard Hughes12724852018-09-04 13:53:44 +01002190fu_plugin_get_report_metadata (FuPlugin *self)
Richard Hughes80b79bb2018-01-11 21:11:06 +00002191{
Richard Hughes12724852018-09-04 13:53:44 +01002192 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002193 return priv->report_metadata;
2194}
2195
Mario Limonciello963dc422018-02-27 14:26:58 -06002196/**
2197 * fu_plugin_get_config_value:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002198 * @self: a #FuPlugin
Mario Limonciello963dc422018-02-27 14:26:58 -06002199 * @key: A settings key
2200 *
2201 * Return the value of a key if it's been configured
2202 *
2203 * Since: 1.0.6
2204 **/
2205gchar *
Richard Hughes12724852018-09-04 13:53:44 +01002206fu_plugin_get_config_value (FuPlugin *self, const gchar *key)
Mario Limonciello963dc422018-02-27 14:26:58 -06002207{
Richard Hughes4be17d12018-05-30 20:36:29 +01002208 g_autofree gchar *conf_dir = NULL;
Mario Limonciello963dc422018-02-27 14:26:58 -06002209 g_autofree gchar *conf_file = NULL;
2210 g_autofree gchar *conf_path = NULL;
2211 g_autoptr(GKeyFile) keyfile = NULL;
2212 const gchar *plugin_name;
2213
Richard Hughes4be17d12018-05-30 20:36:29 +01002214 conf_dir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR_PKG);
Richard Hughes12724852018-09-04 13:53:44 +01002215 plugin_name = fu_plugin_get_name (self);
Mario Limonciello963dc422018-02-27 14:26:58 -06002216 conf_file = g_strdup_printf ("%s.conf", plugin_name);
Richard Hughes4be17d12018-05-30 20:36:29 +01002217 conf_path = g_build_filename (conf_dir, conf_file, NULL);
Mario Limonciello963dc422018-02-27 14:26:58 -06002218 if (!g_file_test (conf_path, G_FILE_TEST_IS_REGULAR))
2219 return NULL;
2220 keyfile = g_key_file_new ();
2221 if (!g_key_file_load_from_file (keyfile, conf_path,
2222 G_KEY_FILE_NONE, NULL))
2223 return NULL;
2224 return g_key_file_get_string (keyfile, plugin_name, key, NULL);
2225}
2226
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002227/**
2228 * fu_plugin_name_compare:
2229 * @plugin1: first #FuPlugin to compare.
2230 * @plugin2: second #FuPlugin to compare.
2231 *
2232 * Compares two plugins by their names.
2233 *
2234 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
2235 **/
2236gint
2237fu_plugin_name_compare (FuPlugin *plugin1, FuPlugin *plugin2)
2238{
2239 FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1);
2240 FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2);
2241 return g_strcmp0 (priv1->name, priv2->name);
2242}
2243
2244/**
2245 * fu_plugin_order_compare:
2246 * @plugin1: first #FuPlugin to compare.
2247 * @plugin2: second #FuPlugin to compare.
2248 *
2249 * Compares two plugins by their depsolved order.
2250 *
2251 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
2252 **/
2253gint
2254fu_plugin_order_compare (FuPlugin *plugin1, FuPlugin *plugin2)
2255{
2256 FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1);
2257 FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2);
2258 if (priv1->order < priv2->order)
2259 return -1;
2260 if (priv1->order > priv2->order)
2261 return 1;
2262 return 0;
2263}
2264
Richard Hughescff38bc2016-12-12 12:03:37 +00002265static void
2266fu_plugin_class_init (FuPluginClass *klass)
2267{
2268 GObjectClass *object_class = G_OBJECT_CLASS (klass);
2269 object_class->finalize = fu_plugin_finalize;
2270 signals[SIGNAL_DEVICE_ADDED] =
2271 g_signal_new ("device-added",
2272 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2273 G_STRUCT_OFFSET (FuPluginClass, device_added),
2274 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2275 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
2276 signals[SIGNAL_DEVICE_REMOVED] =
2277 g_signal_new ("device-removed",
2278 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2279 G_STRUCT_OFFSET (FuPluginClass, device_removed),
2280 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2281 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughese1fd34d2017-08-24 14:19:51 +01002282 signals[SIGNAL_DEVICE_REGISTER] =
2283 g_signal_new ("device-register",
2284 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2285 G_STRUCT_OFFSET (FuPluginClass, device_register),
2286 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2287 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughes362d6d72017-01-07 21:42:14 +00002288 signals[SIGNAL_RECOLDPLUG] =
2289 g_signal_new ("recoldplug",
2290 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2291 G_STRUCT_OFFSET (FuPluginClass, recoldplug),
2292 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2293 G_TYPE_NONE, 0);
Richard Hughesb0829032017-01-10 09:27:08 +00002294 signals[SIGNAL_SET_COLDPLUG_DELAY] =
2295 g_signal_new ("set-coldplug-delay",
2296 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2297 G_STRUCT_OFFSET (FuPluginClass, set_coldplug_delay),
2298 NULL, NULL, g_cclosure_marshal_VOID__UINT,
2299 G_TYPE_NONE, 1, G_TYPE_UINT);
Richard Hughesaabdc372018-11-14 10:11:08 +00002300 signals[SIGNAL_CHECK_SUPPORTED] =
2301 g_signal_new ("check-supported",
2302 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2303 G_STRUCT_OFFSET (FuPluginClass, check_supported),
2304 NULL, NULL, g_cclosure_marshal_generic,
2305 G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
Richard Hughes75b965d2018-11-15 13:51:21 +00002306 signals[SIGNAL_RULES_CHANGED] =
2307 g_signal_new ("rules-changed",
2308 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2309 G_STRUCT_OFFSET (FuPluginClass, rules_changed),
2310 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2311 G_TYPE_NONE, 0);
Richard Hughescff38bc2016-12-12 12:03:37 +00002312}
2313
2314static void
Richard Hughes12724852018-09-04 13:53:44 +01002315fu_plugin_init (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +00002316{
Richard Hughes12724852018-09-04 13:53:44 +01002317 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002318 priv->enabled = TRUE;
Richard Hughesb1065422019-08-15 16:44:34 +01002319 priv->udev_subsystems = g_ptr_array_new_with_free_func (g_free);
Richard Hughescff38bc2016-12-12 12:03:37 +00002320 priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal,
2321 g_free, (GDestroyNotify) g_object_unref);
Richard Hughes161e9b52019-06-12 14:22:45 +01002322 g_rw_lock_init (&priv->devices_mutex);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002323 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 +01002324 for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++)
2325 priv->rules[i] = g_ptr_array_new_with_free_func (g_free);
Richard Hughescff38bc2016-12-12 12:03:37 +00002326}
2327
2328static void
2329fu_plugin_finalize (GObject *object)
2330{
Richard Hughes12724852018-09-04 13:53:44 +01002331 FuPlugin *self = FU_PLUGIN (object);
2332 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002333 FuPluginInitFunc func = NULL;
2334
2335 /* optional */
2336 if (priv->module != NULL) {
2337 g_module_symbol (priv->module, "fu_plugin_destroy", (gpointer *) &func);
2338 if (func != NULL) {
2339 g_debug ("performing destroy() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01002340 func (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002341 }
2342 }
2343
Richard Hughes08a37992017-09-12 12:57:43 +01002344 for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++)
2345 g_ptr_array_unref (priv->rules[i]);
2346
Richard Hughescff38bc2016-12-12 12:03:37 +00002347 if (priv->usb_ctx != NULL)
2348 g_object_unref (priv->usb_ctx);
Richard Hughesb8f8db22017-04-25 15:56:00 +01002349 if (priv->hwids != NULL)
Richard Hughesd7704d42017-08-08 20:29:09 +01002350 g_object_unref (priv->hwids);
Richard Hughes9c028f02017-10-28 21:14:28 +01002351 if (priv->quirks != NULL)
2352 g_object_unref (priv->quirks);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01002353 if (priv->udev_subsystems != NULL)
2354 g_ptr_array_unref (priv->udev_subsystems);
Richard Hughes49e5e052017-09-03 12:15:41 +01002355 if (priv->smbios != NULL)
2356 g_object_unref (priv->smbios);
Richard Hughes275d3b42018-04-20 16:40:37 +01002357 if (priv->runtime_versions != NULL)
2358 g_hash_table_unref (priv->runtime_versions);
Richard Hughes34e0dab2018-04-20 16:43:00 +01002359 if (priv->compile_versions != NULL)
2360 g_hash_table_unref (priv->compile_versions);
Richard Hughescff38bc2016-12-12 12:03:37 +00002361 g_hash_table_unref (priv->devices);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002362 g_hash_table_unref (priv->report_metadata);
Richard Hughes161e9b52019-06-12 14:22:45 +01002363 g_rw_lock_clear (&priv->devices_mutex);
Richard Hughes84999302019-05-02 10:18:32 +01002364 g_free (priv->build_hash);
Richard Hughescff38bc2016-12-12 12:03:37 +00002365 g_free (priv->name);
2366 g_free (priv->data);
Mario Limonciello3f9a1c12018-06-06 14:06:40 -05002367 /* Must happen as the last step to avoid prematurely
2368 * freeing memory held by the plugin */
2369#ifndef RUNNING_ON_VALGRIND
2370 if (priv->module != NULL)
2371 g_module_close (priv->module);
2372#endif
Richard Hughescff38bc2016-12-12 12:03:37 +00002373
2374 G_OBJECT_CLASS (fu_plugin_parent_class)->finalize (object);
2375}
2376
2377FuPlugin *
2378fu_plugin_new (void)
2379{
Richard Hughes12724852018-09-04 13:53:44 +01002380 return FU_PLUGIN (g_object_new (FU_TYPE_PLUGIN, NULL));
Richard Hughescff38bc2016-12-12 12:03:37 +00002381}