blob: 83bd8c4469f8f1e619d0406e7fc5b769ca731df1 [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 Hughesd7704d42017-08-08 20:29:09 +010047 FuHwids *hwids;
Richard Hughes9c028f02017-10-28 21:14:28 +010048 FuQuirks *quirks;
Richard Hughes0eb123b2018-04-19 12:00:04 +010049 GHashTable *runtime_versions;
Richard Hughes34e0dab2018-04-20 16:43:00 +010050 GHashTable *compile_versions;
Richard Hughes1354ea92017-09-19 15:58:31 +010051 GPtrArray *supported_guids;
Richard Hughes9d6e0e72018-08-24 20:20:17 +010052 GPtrArray *udev_subsystems;
Richard Hughes1354ea92017-09-19 15:58:31 +010053 FuSmbios *smbios;
Richard Hughescff38bc2016-12-12 12:03:37 +000054 GHashTable *devices; /* platform_id:GObject */
Richard Hughes37d09432018-09-09 10:39:45 +010055 FuMutex *devices_mutex;
Richard Hughes80b79bb2018-01-11 21:11:06 +000056 GHashTable *report_metadata; /* key:value */
Richard Hughescff38bc2016-12-12 12:03:37 +000057 FuPluginData *data;
58} FuPluginPrivate;
59
60enum {
61 SIGNAL_DEVICE_ADDED,
62 SIGNAL_DEVICE_REMOVED,
Richard Hughese1fd34d2017-08-24 14:19:51 +010063 SIGNAL_DEVICE_REGISTER,
Richard Hughes362d6d72017-01-07 21:42:14 +000064 SIGNAL_RECOLDPLUG,
Richard Hughesb0829032017-01-10 09:27:08 +000065 SIGNAL_SET_COLDPLUG_DELAY,
Richard Hughescff38bc2016-12-12 12:03:37 +000066 SIGNAL_LAST
67};
68
69static guint signals[SIGNAL_LAST] = { 0 };
70
71G_DEFINE_TYPE_WITH_PRIVATE (FuPlugin, fu_plugin, G_TYPE_OBJECT)
72#define GET_PRIVATE(o) (fu_plugin_get_instance_private (o))
73
74typedef const gchar *(*FuPluginGetNameFunc) (void);
Richard Hughes12724852018-09-04 13:53:44 +010075typedef void (*FuPluginInitFunc) (FuPlugin *self);
76typedef gboolean (*FuPluginStartupFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000077 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010078typedef void (*FuPluginDeviceRegisterFunc) (FuPlugin *self,
Richard Hughese1fd34d2017-08-24 14:19:51 +010079 FuDevice *device);
Richard Hughes12724852018-09-04 13:53:44 +010080typedef gboolean (*FuPluginDeviceFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000081 FuDevice *device,
82 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010083typedef gboolean (*FuPluginFlaggedDeviceFunc) (FuPlugin *self,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -050084 FwupdInstallFlags flags,
85 FuDevice *device,
86 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010087typedef gboolean (*FuPluginDeviceArrayFunc) (FuPlugin *self,
Richard Hughesdbd8c762018-06-15 20:31:40 +010088 GPtrArray *devices,
89 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010090typedef gboolean (*FuPluginVerifyFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000091 FuDevice *device,
92 FuPluginVerifyFlags flags,
93 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010094typedef gboolean (*FuPluginUpdateFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000095 FuDevice *device,
96 GBytes *blob_fw,
97 FwupdInstallFlags flags,
98 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010099typedef gboolean (*FuPluginUsbDeviceAddedFunc) (FuPlugin *self,
Richard Hughesff704412018-09-04 11:28:32 +0100100 FuUsbDevice *device,
Richard Hughes104f6512017-11-24 11:44:57 +0000101 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +0100102typedef gboolean (*FuPluginUdevDeviceAddedFunc) (FuPlugin *self,
Richard Hughesff704412018-09-04 11:28:32 +0100103 FuUdevDevice *device,
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100104 GError **error);
Richard Hughescff38bc2016-12-12 12:03:37 +0000105
Richard Hughes57d18222017-01-10 16:02:59 +0000106/**
107 * fu_plugin_get_name:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100108 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000109 *
110 * Gets the plugin name.
111 *
112 * Returns: a plugin name, or %NULL for unknown.
113 *
114 * Since: 0.8.0
115 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000116const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100117fu_plugin_get_name (FuPlugin *self)
Richard Hughesd0905142016-03-13 09:46:49 +0000118{
Richard Hughes12724852018-09-04 13:53:44 +0100119 FuPluginPrivate *priv = GET_PRIVATE (self);
120 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000121 return priv->name;
122}
Richard Hughesd0905142016-03-13 09:46:49 +0000123
Richard Hughes34834102017-11-21 21:55:00 +0000124void
Richard Hughes12724852018-09-04 13:53:44 +0100125fu_plugin_set_name (FuPlugin *self, const gchar *name)
Richard Hughes34834102017-11-21 21:55:00 +0000126{
Richard Hughes12724852018-09-04 13:53:44 +0100127 FuPluginPrivate *priv = GET_PRIVATE (self);
128 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughes34834102017-11-21 21:55:00 +0000129 g_return_if_fail (name != NULL);
130 g_free (priv->name);
131 priv->name = g_strdup (name);
132}
133
Richard Hughes57d18222017-01-10 16:02:59 +0000134/**
135 * fu_plugin_cache_lookup:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100136 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000137 * @id: the key
138 *
139 * Finds an object in the per-plugin cache.
140 *
141 * Returns: (transfer none): a #GObject, or %NULL for unfound.
142 *
143 * Since: 0.8.0
144 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000145gpointer
Richard Hughes12724852018-09-04 13:53:44 +0100146fu_plugin_cache_lookup (FuPlugin *self, const gchar *id)
Richard Hughescff38bc2016-12-12 12:03:37 +0000147{
Richard Hughes12724852018-09-04 13:53:44 +0100148 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes37d09432018-09-09 10:39:45 +0100149 g_autoptr(FuMutexLocker) locker = fu_mutex_read_locker_new (priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100150 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughesccd78a92017-01-11 16:57:41 +0000151 g_return_val_if_fail (id != NULL, NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100152 g_return_val_if_fail (locker != NULL, NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000153 return g_hash_table_lookup (priv->devices, id);
154}
Richard Hughesd0905142016-03-13 09:46:49 +0000155
Richard Hughes57d18222017-01-10 16:02:59 +0000156/**
157 * fu_plugin_cache_add:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100158 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000159 * @id: the key
160 * @dev: a #GObject, typically a #FuDevice
161 *
162 * Adds an object to the per-plugin cache.
163 *
164 * Since: 0.8.0
165 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000166void
Richard Hughes12724852018-09-04 13:53:44 +0100167fu_plugin_cache_add (FuPlugin *self, const gchar *id, gpointer dev)
Richard Hughescff38bc2016-12-12 12:03:37 +0000168{
Richard Hughes12724852018-09-04 13:53:44 +0100169 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes37d09432018-09-09 10:39:45 +0100170 g_autoptr(FuMutexLocker) locker = fu_mutex_write_locker_new (priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100171 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000172 g_return_if_fail (id != NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100173 g_return_if_fail (locker != NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000174 g_hash_table_insert (priv->devices, g_strdup (id), g_object_ref (dev));
175}
176
Richard Hughes57d18222017-01-10 16:02:59 +0000177/**
178 * fu_plugin_cache_remove:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100179 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000180 * @id: the key
181 *
182 * Removes an object from the per-plugin cache.
183 *
184 * Since: 0.8.0
185 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000186void
Richard Hughes12724852018-09-04 13:53:44 +0100187fu_plugin_cache_remove (FuPlugin *self, const gchar *id)
Richard Hughescff38bc2016-12-12 12:03:37 +0000188{
Richard Hughes12724852018-09-04 13:53:44 +0100189 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes37d09432018-09-09 10:39:45 +0100190 g_autoptr(FuMutexLocker) locker = fu_mutex_write_locker_new (priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100191 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000192 g_return_if_fail (id != NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100193 g_return_if_fail (locker != NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000194 g_hash_table_remove (priv->devices, id);
195}
196
Richard Hughes57d18222017-01-10 16:02:59 +0000197/**
198 * fu_plugin_get_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100199 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000200 *
Richard Hughes4eada342017-10-03 21:20:32 +0100201 * Gets the per-plugin allocated private data. This will return %NULL unless
202 * fu_plugin_alloc_data() has been called by the plugin.
Richard Hughes57d18222017-01-10 16:02:59 +0000203 *
Richard Hughes4eada342017-10-03 21:20:32 +0100204 * Returns: (transfer none): a pointer to a structure, or %NULL for unset.
Richard Hughes57d18222017-01-10 16:02:59 +0000205 *
206 * Since: 0.8.0
207 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000208FuPluginData *
Richard Hughes12724852018-09-04 13:53:44 +0100209fu_plugin_get_data (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +0000210{
Richard Hughes12724852018-09-04 13:53:44 +0100211 FuPluginPrivate *priv = GET_PRIVATE (self);
212 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000213 return priv->data;
214}
215
Richard Hughes57d18222017-01-10 16:02:59 +0000216/**
217 * fu_plugin_alloc_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100218 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000219 * @data_sz: the size to allocate
220 *
221 * Allocates the per-plugin allocated private data.
222 *
223 * Returns: (transfer full): a pointer to a structure, or %NULL for unset.
224 *
225 * Since: 0.8.0
226 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000227FuPluginData *
Richard Hughes12724852018-09-04 13:53:44 +0100228fu_plugin_alloc_data (FuPlugin *self, gsize data_sz)
Richard Hughescff38bc2016-12-12 12:03:37 +0000229{
Richard Hughes12724852018-09-04 13:53:44 +0100230 FuPluginPrivate *priv = GET_PRIVATE (self);
231 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes44dee882017-01-11 08:31:10 +0000232 if (priv->data != NULL) {
233 g_critical ("fu_plugin_alloc_data() already used by plugin");
234 return priv->data;
235 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000236 priv->data = g_malloc0 (data_sz);
237 return priv->data;
Richard Hughesd0905142016-03-13 09:46:49 +0000238}
239
Richard Hughes57d18222017-01-10 16:02:59 +0000240/**
241 * fu_plugin_get_usb_context:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100242 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000243 *
244 * Gets the shared USB context that all plugins can use.
245 *
246 * Returns: (transfer none): a #GUsbContext.
247 *
248 * Since: 0.8.0
249 **/
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000250GUsbContext *
Richard Hughes12724852018-09-04 13:53:44 +0100251fu_plugin_get_usb_context (FuPlugin *self)
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000252{
Richard Hughes12724852018-09-04 13:53:44 +0100253 FuPluginPrivate *priv = GET_PRIVATE (self);
254 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000255 return priv->usb_ctx;
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000256}
257
258void
Richard Hughes12724852018-09-04 13:53:44 +0100259fu_plugin_set_usb_context (FuPlugin *self, GUsbContext *usb_ctx)
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000260{
Richard Hughes12724852018-09-04 13:53:44 +0100261 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +0000262 g_set_object (&priv->usb_ctx, usb_ctx);
263}
264
Richard Hughes57d18222017-01-10 16:02:59 +0000265/**
266 * fu_plugin_get_enabled:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100267 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000268 *
Richard Hughes4eada342017-10-03 21:20:32 +0100269 * Returns if the plugin is enabled. Plugins may self-disable using
270 * fu_plugin_set_enabled() or can be disabled by the daemon.
Richard Hughes57d18222017-01-10 16:02:59 +0000271 *
272 * Returns: %TRUE if the plugin is currently enabled.
273 *
274 * Since: 0.8.0
275 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000276gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100277fu_plugin_get_enabled (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +0000278{
Richard Hughes12724852018-09-04 13:53:44 +0100279 FuPluginPrivate *priv = GET_PRIVATE (self);
280 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
Richard Hughescff38bc2016-12-12 12:03:37 +0000281 return priv->enabled;
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000282}
283
Richard Hughes57d18222017-01-10 16:02:59 +0000284/**
285 * fu_plugin_set_enabled:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100286 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000287 * @enabled: the enabled value
288 *
289 * Enables or disables a plugin. Plugins can self-disable at any point.
290 *
291 * Since: 0.8.0
292 **/
Richard Hughesd0905142016-03-13 09:46:49 +0000293void
Richard Hughes12724852018-09-04 13:53:44 +0100294fu_plugin_set_enabled (FuPlugin *self, gboolean enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000295{
Richard Hughes12724852018-09-04 13:53:44 +0100296 FuPluginPrivate *priv = GET_PRIVATE (self);
297 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughescff38bc2016-12-12 12:03:37 +0000298 priv->enabled = enabled;
299}
300
Richard Hughes1e456bc2018-05-10 20:16:16 +0100301gchar *
302fu_plugin_guess_name_from_fn (const gchar *filename)
303{
304 const gchar *prefix = "libfu_plugin_";
305 gchar *name;
306 gchar *str = g_strstr_len (filename, -1, prefix);
307 if (str == NULL)
308 return NULL;
309 name = g_strdup (str + strlen (prefix));
310 g_strdelimit (name, ".", '\0');
311 return name;
312}
313
Richard Hughescff38bc2016-12-12 12:03:37 +0000314gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100315fu_plugin_open (FuPlugin *self, const gchar *filename, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +0000316{
Richard Hughes12724852018-09-04 13:53:44 +0100317 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +0000318 FuPluginInitFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000319
320 priv->module = g_module_open (filename, 0);
321 if (priv->module == NULL) {
322 g_set_error (error,
323 G_IO_ERROR,
324 G_IO_ERROR_FAILED,
325 "failed to open plugin: %s",
326 g_module_error ());
327 return FALSE;
328 }
329
330 /* set automatically */
Richard Hughes1e456bc2018-05-10 20:16:16 +0100331 if (priv->name == NULL)
332 priv->name = fu_plugin_guess_name_from_fn (filename);
Richard Hughesd0905142016-03-13 09:46:49 +0000333
334 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000335 g_module_symbol (priv->module, "fu_plugin_init", (gpointer *) &func);
336 if (func != NULL) {
337 g_debug ("performing init() on %s", filename);
Richard Hughes12724852018-09-04 13:53:44 +0100338 func (self);
Richard Hughesd0905142016-03-13 09:46:49 +0000339 }
340
Richard Hughescff38bc2016-12-12 12:03:37 +0000341 return TRUE;
342}
343
Richard Hughes57d18222017-01-10 16:02:59 +0000344/**
345 * fu_plugin_device_add:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100346 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000347 * @device: A #FuDevice
348 *
349 * Asks the daemon to add a device to the exported list. If this device ID
350 * has already been added by a different plugin then this request will be
351 * ignored.
352 *
353 * Plugins should use fu_plugin_device_add_delay() if they are not capable of
354 * actually flashing an image to the hardware so that higher-priority plugins
355 * can add the device themselves.
356 *
357 * Since: 0.8.0
358 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000359void
Richard Hughes12724852018-09-04 13:53:44 +0100360fu_plugin_device_add (FuPlugin *self, FuDevice *device)
Richard Hughescff38bc2016-12-12 12:03:37 +0000361{
Richard Hughes5e447292018-04-27 14:25:54 +0100362 GPtrArray *children;
Richard Hughesc125ec02018-09-05 19:35:17 +0100363 g_autoptr(GError) error = NULL;
Richard Hughes5e447292018-04-27 14:25:54 +0100364
Richard Hughes12724852018-09-04 13:53:44 +0100365 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000366 g_return_if_fail (FU_IS_DEVICE (device));
367
Richard Hughesc125ec02018-09-05 19:35:17 +0100368 /* ensure the device ID is set from the physical and logical IDs */
369 if (!fu_device_ensure_id (device, &error)) {
370 g_warning ("ignoring add: %s", error->message);
371 return;
372 }
373
Richard Hughescff38bc2016-12-12 12:03:37 +0000374 g_debug ("emit added from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100375 fu_plugin_get_name (self),
Richard Hughescff38bc2016-12-12 12:03:37 +0000376 fu_device_get_id (device));
377 fu_device_set_created (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
Richard Hughes12724852018-09-04 13:53:44 +0100378 fu_device_set_plugin (device, fu_plugin_get_name (self));
379 g_signal_emit (self, signals[SIGNAL_DEVICE_ADDED], 0, device);
Richard Hughes5e447292018-04-27 14:25:54 +0100380
Richard Hughes128c0162018-08-10 11:00:29 +0100381 /* add children if they have not already been added */
Richard Hughes5e447292018-04-27 14:25:54 +0100382 children = fu_device_get_children (device);
383 for (guint i = 0; i < children->len; i++) {
384 FuDevice *child = g_ptr_array_index (children, i);
Richard Hughes128c0162018-08-10 11:00:29 +0100385 if (fu_device_get_created (child) == 0)
Richard Hughes12724852018-09-04 13:53:44 +0100386 fu_plugin_device_add (self, child);
Richard Hughes5e447292018-04-27 14:25:54 +0100387 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000388}
389
Richard Hughese1fd34d2017-08-24 14:19:51 +0100390/**
391 * fu_plugin_device_register:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100392 * @self: A #FuPlugin
Richard Hughese1fd34d2017-08-24 14:19:51 +0100393 * @device: A #FuDevice
394 *
395 * Registers the device with other plugins so they can set metadata.
396 *
397 * Plugins do not have to call this manually as this is done automatically
398 * when using fu_plugin_device_add(). They may wish to use this manually
399 * if for intance the coldplug should be ignored based on the metadata
400 * set from other plugins.
401 *
402 * Since: 0.9.7
403 **/
404void
Richard Hughes12724852018-09-04 13:53:44 +0100405fu_plugin_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +0100406{
Richard Hughesc125ec02018-09-05 19:35:17 +0100407 g_autoptr(GError) error = NULL;
408
Richard Hughes12724852018-09-04 13:53:44 +0100409 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughese1fd34d2017-08-24 14:19:51 +0100410 g_return_if_fail (FU_IS_DEVICE (device));
411
Richard Hughesc125ec02018-09-05 19:35:17 +0100412 /* ensure the device ID is set from the physical and logical IDs */
413 if (!fu_device_ensure_id (device, &error)) {
414 g_warning ("ignoring registration: %s", error->message);
415 return;
416 }
417
Richard Hughese1fd34d2017-08-24 14:19:51 +0100418 g_debug ("emit device-register from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100419 fu_plugin_get_name (self),
Richard Hughese1fd34d2017-08-24 14:19:51 +0100420 fu_device_get_id (device));
Richard Hughes12724852018-09-04 13:53:44 +0100421 g_signal_emit (self, signals[SIGNAL_DEVICE_REGISTER], 0, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +0100422}
423
Richard Hughes57d18222017-01-10 16:02:59 +0000424/**
Richard Hughes4eada342017-10-03 21:20:32 +0100425 * fu_plugin_device_remove:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100426 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000427 * @device: A #FuDevice
428 *
429 * Asks the daemon to remove a device from the exported list.
430 *
431 * Since: 0.8.0
432 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000433void
Richard Hughes12724852018-09-04 13:53:44 +0100434fu_plugin_device_remove (FuPlugin *self, FuDevice *device)
Richard Hughescff38bc2016-12-12 12:03:37 +0000435{
Richard Hughes12724852018-09-04 13:53:44 +0100436 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000437 g_return_if_fail (FU_IS_DEVICE (device));
438
Richard Hughescff38bc2016-12-12 12:03:37 +0000439 g_debug ("emit removed from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100440 fu_plugin_get_name (self),
Richard Hughescff38bc2016-12-12 12:03:37 +0000441 fu_device_get_id (device));
Richard Hughes12724852018-09-04 13:53:44 +0100442 g_signal_emit (self, signals[SIGNAL_DEVICE_REMOVED], 0, device);
Richard Hughescff38bc2016-12-12 12:03:37 +0000443}
444
Richard Hughes57d18222017-01-10 16:02:59 +0000445/**
Richard Hughes2de8f132018-01-17 09:12:02 +0000446 * fu_plugin_request_recoldplug:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100447 * @self: A #FuPlugin
Richard Hughes362d6d72017-01-07 21:42:14 +0000448 *
449 * Ask all the plugins to coldplug all devices, which will include the prepare()
450 * and cleanup() phases. Duplicate devices added will be ignored.
451 *
452 * Since: 0.8.0
453 **/
454void
Richard Hughes12724852018-09-04 13:53:44 +0100455fu_plugin_request_recoldplug (FuPlugin *self)
Richard Hughes362d6d72017-01-07 21:42:14 +0000456{
Richard Hughes12724852018-09-04 13:53:44 +0100457 g_return_if_fail (FU_IS_PLUGIN (self));
458 g_signal_emit (self, signals[SIGNAL_RECOLDPLUG], 0);
Richard Hughes362d6d72017-01-07 21:42:14 +0000459}
460
Richard Hughesb0829032017-01-10 09:27:08 +0000461/**
Richard Hughesb8f8db22017-04-25 15:56:00 +0100462 * fu_plugin_check_hwid:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100463 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100464 * @hwid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
Richard Hughesb8f8db22017-04-25 15:56:00 +0100465 *
Richard Hughesd7704d42017-08-08 20:29:09 +0100466 * Checks to see if a specific GUID exists. All hardware IDs on a
Richard Hughesb8f8db22017-04-25 15:56:00 +0100467 * specific system can be shown using the `fwupdmgr hwids` command.
468 *
Richard Hughes4eada342017-10-03 21:20:32 +0100469 * Returns: %TRUE if the HwId is found on the system.
470 *
Richard Hughesb8f8db22017-04-25 15:56:00 +0100471 * Since: 0.9.1
472 **/
473gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100474fu_plugin_check_hwid (FuPlugin *self, const gchar *hwid)
Richard Hughesb8f8db22017-04-25 15:56:00 +0100475{
Richard Hughes12724852018-09-04 13:53:44 +0100476 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100477 if (priv->hwids == NULL)
478 return FALSE;
Richard Hughesd7704d42017-08-08 20:29:09 +0100479 return fu_hwids_has_guid (priv->hwids, hwid);
480}
481
482/**
Richard Hughes69a5f352018-08-08 11:58:15 +0100483 * fu_plugin_get_hwids:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100484 * @self: A #FuPlugin
Richard Hughes69a5f352018-08-08 11:58:15 +0100485 *
486 * Returns all the HWIDs defined in the system. All hardware IDs on a
487 * specific system can be shown using the `fwupdmgr hwids` command.
488 *
489 * Returns: (transfer none) (element-type utf-8): An array of GUIDs
490 *
491 * Since: 1.1.1
492 **/
493GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +0100494fu_plugin_get_hwids (FuPlugin *self)
Richard Hughes69a5f352018-08-08 11:58:15 +0100495{
Richard Hughes12724852018-09-04 13:53:44 +0100496 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes69a5f352018-08-08 11:58:15 +0100497 if (priv->hwids == NULL)
498 return NULL;
499 return fu_hwids_get_guids (priv->hwids);
500}
501
502/**
Richard Hughes1354ea92017-09-19 15:58:31 +0100503 * fu_plugin_check_supported:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100504 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100505 * @guid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
Richard Hughes1354ea92017-09-19 15:58:31 +0100506 *
507 * Checks to see if a specific device GUID is supported, i.e. available in the
508 * AppStream metadata.
509 *
Richard Hughes4eada342017-10-03 21:20:32 +0100510 * Returns: %TRUE if the device is supported.
511 *
Richard Hughes1354ea92017-09-19 15:58:31 +0100512 * Since: 1.0.0
513 **/
514gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100515fu_plugin_check_supported (FuPlugin *self, const gchar *guid)
Richard Hughes1354ea92017-09-19 15:58:31 +0100516{
Richard Hughes12724852018-09-04 13:53:44 +0100517 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes1354ea92017-09-19 15:58:31 +0100518 if (priv->supported_guids == NULL)
519 return FALSE;
520 for (guint i = 0; i < priv->supported_guids->len; i++) {
521 const gchar *guid_tmp = g_ptr_array_index (priv->supported_guids, i);
522 if (g_strcmp0 (guid, guid_tmp) == 0)
523 return TRUE;
524 }
525 return FALSE;
526}
527
528/**
Richard Hughesd7704d42017-08-08 20:29:09 +0100529 * fu_plugin_get_dmi_value:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100530 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100531 * @dmi_id: A DMI ID, e.g. `BiosVersion`
Richard Hughesd7704d42017-08-08 20:29:09 +0100532 *
533 * Gets a hardware DMI value.
534 *
Richard Hughes4eada342017-10-03 21:20:32 +0100535 * Returns: The string, or %NULL
536 *
Richard Hughesd7704d42017-08-08 20:29:09 +0100537 * Since: 0.9.7
538 **/
539const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100540fu_plugin_get_dmi_value (FuPlugin *self, const gchar *dmi_id)
Richard Hughesd7704d42017-08-08 20:29:09 +0100541{
Richard Hughes12724852018-09-04 13:53:44 +0100542 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd7704d42017-08-08 20:29:09 +0100543 if (priv->hwids == NULL)
Richard Hughes7ef96b82017-08-23 18:28:24 +0100544 return NULL;
Richard Hughesd7704d42017-08-08 20:29:09 +0100545 return fu_hwids_get_value (priv->hwids, dmi_id);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100546}
547
Richard Hughes49e5e052017-09-03 12:15:41 +0100548/**
549 * fu_plugin_get_smbios_string:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100550 * @self: A #FuPlugin
Richard Hughes49e5e052017-09-03 12:15:41 +0100551 * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
552 * @offset: A SMBIOS offset
553 *
554 * Gets a hardware SMBIOS string.
555 *
556 * The @type and @offset can be referenced from the DMTF SMBIOS specification:
557 * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.1.1.pdf
558 *
Richard Hughes4eada342017-10-03 21:20:32 +0100559 * Returns: A string, or %NULL
560 *
Richard Hughes49e5e052017-09-03 12:15:41 +0100561 * Since: 0.9.8
562 **/
563const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100564fu_plugin_get_smbios_string (FuPlugin *self, guint8 structure_type, guint8 offset)
Richard Hughes49e5e052017-09-03 12:15:41 +0100565{
Richard Hughes12724852018-09-04 13:53:44 +0100566 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100567 if (priv->smbios == NULL)
568 return NULL;
569 return fu_smbios_get_string (priv->smbios, structure_type, offset, NULL);
570}
571
572/**
573 * fu_plugin_get_smbios_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100574 * @self: A #FuPlugin
Richard Hughes49e5e052017-09-03 12:15:41 +0100575 * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
576 *
577 * Gets a hardware SMBIOS data.
578 *
Richard Hughes4eada342017-10-03 21:20:32 +0100579 * Returns: (transfer none): A #GBytes, or %NULL
580 *
Richard Hughes49e5e052017-09-03 12:15:41 +0100581 * Since: 0.9.8
582 **/
583GBytes *
Richard Hughes12724852018-09-04 13:53:44 +0100584fu_plugin_get_smbios_data (FuPlugin *self, guint8 structure_type)
Richard Hughes49e5e052017-09-03 12:15:41 +0100585{
Richard Hughes12724852018-09-04 13:53:44 +0100586 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100587 if (priv->smbios == NULL)
588 return NULL;
589 return fu_smbios_get_data (priv->smbios, structure_type, NULL);
590}
591
Richard Hughesb8f8db22017-04-25 15:56:00 +0100592void
Richard Hughes12724852018-09-04 13:53:44 +0100593fu_plugin_set_hwids (FuPlugin *self, FuHwids *hwids)
Richard Hughesb8f8db22017-04-25 15:56:00 +0100594{
Richard Hughes12724852018-09-04 13:53:44 +0100595 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd7704d42017-08-08 20:29:09 +0100596 g_set_object (&priv->hwids, hwids);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100597}
598
Richard Hughes49e5e052017-09-03 12:15:41 +0100599void
Richard Hughes12724852018-09-04 13:53:44 +0100600fu_plugin_set_supported (FuPlugin *self, GPtrArray *supported_guids)
Richard Hughes1354ea92017-09-19 15:58:31 +0100601{
Richard Hughes12724852018-09-04 13:53:44 +0100602 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes1354ea92017-09-19 15:58:31 +0100603 if (priv->supported_guids != NULL)
604 g_ptr_array_unref (priv->supported_guids);
605 priv->supported_guids = g_ptr_array_ref (supported_guids);
606}
607
Richard Hughes9c028f02017-10-28 21:14:28 +0100608void
Richard Hughes12724852018-09-04 13:53:44 +0100609fu_plugin_set_udev_subsystems (FuPlugin *self, GPtrArray *udev_subsystems)
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100610{
Richard Hughes12724852018-09-04 13:53:44 +0100611 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100612 if (priv->udev_subsystems != NULL)
613 g_ptr_array_unref (priv->udev_subsystems);
614 priv->udev_subsystems = g_ptr_array_ref (udev_subsystems);
615}
616
617void
Richard Hughes12724852018-09-04 13:53:44 +0100618fu_plugin_set_quirks (FuPlugin *self, FuQuirks *quirks)
Richard Hughes9c028f02017-10-28 21:14:28 +0100619{
Richard Hughes12724852018-09-04 13:53:44 +0100620 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9c028f02017-10-28 21:14:28 +0100621 g_set_object (&priv->quirks, quirks);
622}
623
624/**
625 * fu_plugin_get_quirks:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100626 * @self: A #FuPlugin
Richard Hughes9c028f02017-10-28 21:14:28 +0100627 *
628 * Returns the hardware database object. This can be used to discover device
629 * quirks or other device-specific settings.
630 *
631 * Returns: (transfer none): a #FuQuirks, or %NULL if not set
632 *
633 * Since: 1.0.1
634 **/
635FuQuirks *
Richard Hughes12724852018-09-04 13:53:44 +0100636fu_plugin_get_quirks (FuPlugin *self)
Richard Hughes9c028f02017-10-28 21:14:28 +0100637{
Richard Hughes12724852018-09-04 13:53:44 +0100638 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9c028f02017-10-28 21:14:28 +0100639 return priv->quirks;
640}
641
Richard Hughes0eb123b2018-04-19 12:00:04 +0100642void
Richard Hughes12724852018-09-04 13:53:44 +0100643fu_plugin_set_runtime_versions (FuPlugin *self, GHashTable *runtime_versions)
Richard Hughes0eb123b2018-04-19 12:00:04 +0100644{
Richard Hughes12724852018-09-04 13:53:44 +0100645 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0eb123b2018-04-19 12:00:04 +0100646 priv->runtime_versions = g_hash_table_ref (runtime_versions);
647}
648
649/**
650 * fu_plugin_add_runtime_version:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100651 * @self: A #FuPlugin
Richard Hughes0eb123b2018-04-19 12:00:04 +0100652 * @component_id: An AppStream component id, e.g. "org.gnome.Software"
653 * @version: A version string, e.g. "1.2.3"
654 *
655 * Sets a runtime version of a specific dependancy.
656 *
657 * Since: 1.0.7
658 **/
659void
Richard Hughes12724852018-09-04 13:53:44 +0100660fu_plugin_add_runtime_version (FuPlugin *self,
Richard Hughes0eb123b2018-04-19 12:00:04 +0100661 const gchar *component_id,
662 const gchar *version)
663{
Richard Hughes12724852018-09-04 13:53:44 +0100664 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesb01b4862018-04-20 16:39:48 +0100665 if (priv->runtime_versions == NULL)
666 return;
Richard Hughes0eb123b2018-04-19 12:00:04 +0100667 g_hash_table_insert (priv->runtime_versions,
668 g_strdup (component_id),
669 g_strdup (version));
670}
671
Richard Hughes34e0dab2018-04-20 16:43:00 +0100672void
Richard Hughes12724852018-09-04 13:53:44 +0100673fu_plugin_set_compile_versions (FuPlugin *self, GHashTable *compile_versions)
Richard Hughes34e0dab2018-04-20 16:43:00 +0100674{
Richard Hughes12724852018-09-04 13:53:44 +0100675 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes34e0dab2018-04-20 16:43:00 +0100676 priv->compile_versions = g_hash_table_ref (compile_versions);
677}
678
679/**
680 * fu_plugin_add_compile_version:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100681 * @self: A #FuPlugin
Richard Hughes34e0dab2018-04-20 16:43:00 +0100682 * @component_id: An AppStream component id, e.g. "org.gnome.Software"
683 * @version: A version string, e.g. "1.2.3"
684 *
685 * Sets a compile-time version of a specific dependancy.
686 *
687 * Since: 1.0.7
688 **/
689void
Richard Hughes12724852018-09-04 13:53:44 +0100690fu_plugin_add_compile_version (FuPlugin *self,
Richard Hughes34e0dab2018-04-20 16:43:00 +0100691 const gchar *component_id,
692 const gchar *version)
693{
Richard Hughes12724852018-09-04 13:53:44 +0100694 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes34e0dab2018-04-20 16:43:00 +0100695 if (priv->compile_versions == NULL)
696 return;
697 g_hash_table_insert (priv->compile_versions,
698 g_strdup (component_id),
699 g_strdup (version));
700}
701
Richard Hughes9c028f02017-10-28 21:14:28 +0100702/**
703 * fu_plugin_lookup_quirk_by_id:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100704 * @self: A #FuPlugin
Richard Hughes87fb9ff2018-06-28 12:55:59 +0100705 * @group: A string, e.g. "DfuFlags"
706 * @key: An ID to match the entry, e.g. "Summary"
Richard Hughes9c028f02017-10-28 21:14:28 +0100707 *
708 * Looks up an entry in the hardware database using a string value.
709 *
710 * Returns: (transfer none): values from the database, or %NULL if not found
711 *
712 * Since: 1.0.1
713 **/
714const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100715fu_plugin_lookup_quirk_by_id (FuPlugin *self, const gchar *group, const gchar *key)
Richard Hughes9c028f02017-10-28 21:14:28 +0100716{
Richard Hughes12724852018-09-04 13:53:44 +0100717 FuPluginPrivate *priv = GET_PRIVATE (self);
718 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes9c028f02017-10-28 21:14:28 +0100719
Richard Hughes9c028f02017-10-28 21:14:28 +0100720 /* exact ID */
Richard Hughes87fb9ff2018-06-28 12:55:59 +0100721 return fu_quirks_lookup_by_id (priv->quirks, group, key);
Richard Hughes9c028f02017-10-28 21:14:28 +0100722}
723
724/**
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100725 * fu_plugin_lookup_quirk_by_id_as_uint64:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100726 * @self: A #FuPlugin
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100727 * @group: A string, e.g. "DfuFlags"
728 * @key: An ID to match the entry, e.g. "Size"
729 *
730 * Looks up an entry in the hardware database using a string key, returning
731 * an integer value. Values are assumed base 10, unless prefixed with "0x"
732 * where they are parsed as base 16.
733 *
734 * Returns: (transfer none): value from the database, or 0 if not found
735 *
736 * Since: 1.1.2
737 **/
738guint64
Richard Hughes12724852018-09-04 13:53:44 +0100739fu_plugin_lookup_quirk_by_id_as_uint64 (FuPlugin *self, const gchar *group, const gchar *key)
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100740{
Richard Hughes12724852018-09-04 13:53:44 +0100741 return fu_common_strtoull (fu_plugin_lookup_quirk_by_id (self, group, key));
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100742}
743
744/**
Richard Hughes1354ea92017-09-19 15:58:31 +0100745 * fu_plugin_get_supported:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100746 * @self: A #FuPlugin
Richard Hughes1354ea92017-09-19 15:58:31 +0100747 *
748 * Gets all the device GUIDs supported by the daemon.
749 *
Richard Hughes4eada342017-10-03 21:20:32 +0100750 * Returns: (element-type utf8) (transfer none): GUIDs
751 *
Richard Hughes1354ea92017-09-19 15:58:31 +0100752 * Since: 1.0.0
753 **/
754GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +0100755fu_plugin_get_supported (FuPlugin *self)
Richard Hughes1354ea92017-09-19 15:58:31 +0100756{
Richard Hughes12724852018-09-04 13:53:44 +0100757 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes1354ea92017-09-19 15:58:31 +0100758 return priv->supported_guids;
759}
760
761void
Richard Hughes12724852018-09-04 13:53:44 +0100762fu_plugin_set_smbios (FuPlugin *self, FuSmbios *smbios)
Richard Hughes49e5e052017-09-03 12:15:41 +0100763{
Richard Hughes12724852018-09-04 13:53:44 +0100764 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100765 g_set_object (&priv->smbios, smbios);
766}
767
Richard Hughesb8f8db22017-04-25 15:56:00 +0100768/**
Richard Hughesb0829032017-01-10 09:27:08 +0000769 * fu_plugin_set_coldplug_delay:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100770 * @self: A #FuPlugin
Richard Hughesb0829032017-01-10 09:27:08 +0000771 * @duration: A delay in milliseconds
772 *
773 * Set the minimum time that should be waited inbetween the call to
774 * fu_plugin_coldplug_prepare() and fu_plugin_coldplug(). This is usually going
775 * to be the minimum hardware initialisation time from a datasheet.
776 *
777 * It is better to use this function rather than using a sleep() in the plugin
778 * itself as then only one delay is done in the daemon rather than waiting for
779 * each coldplug prepare in a serial way.
780 *
781 * Additionally, very long delays should be avoided as the daemon will be
782 * blocked from processing requests whilst the coldplug delay is being
783 * performed.
784 *
785 * Since: 0.8.0
786 **/
787void
Richard Hughes12724852018-09-04 13:53:44 +0100788fu_plugin_set_coldplug_delay (FuPlugin *self, guint duration)
Richard Hughesb0829032017-01-10 09:27:08 +0000789{
Richard Hughes12724852018-09-04 13:53:44 +0100790 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesb0829032017-01-10 09:27:08 +0000791 g_return_if_fail (duration > 0);
792
793 /* check sanity */
794 if (duration > FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM) {
795 g_warning ("duration of %ums is crazy, truncating to %ums",
796 duration,
797 FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM);
798 duration = FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM;
799 }
800
801 /* emit */
Richard Hughes12724852018-09-04 13:53:44 +0100802 g_signal_emit (self, signals[SIGNAL_SET_COLDPLUG_DELAY], 0, duration);
Richard Hughesb0829032017-01-10 09:27:08 +0000803}
804
Richard Hughesd0905142016-03-13 09:46:49 +0000805gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100806fu_plugin_runner_startup (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +0000807{
Richard Hughes12724852018-09-04 13:53:44 +0100808 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000809 FuPluginStartupFunc func = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +0000810
811 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +0000812 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000813 return TRUE;
814
Richard Hughes639da472018-01-06 22:35:04 +0000815 /* no object loaded */
816 if (priv->module == NULL)
817 return TRUE;
818
Richard Hughesd0905142016-03-13 09:46:49 +0000819 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000820 g_module_symbol (priv->module, "fu_plugin_startup", (gpointer *) &func);
821 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +0000822 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +0000823 g_debug ("performing startup() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +0100824 if (!func (self, error)) {
Richard Hughescff38bc2016-12-12 12:03:37 +0000825 g_prefix_error (error, "failed to startup %s: ", priv->name);
826 return FALSE;
827 }
828 return TRUE;
829}
830
831static gboolean
832fu_plugin_runner_offline_invalidate (GError **error)
833{
834 g_autoptr(GError) error_local = NULL;
835 g_autoptr(GFile) file1 = NULL;
836
837 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
838
839 file1 = g_file_new_for_path (FU_OFFLINE_TRIGGER_FILENAME);
840 if (!g_file_query_exists (file1, NULL))
841 return TRUE;
842 if (!g_file_delete (file1, NULL, &error_local)) {
843 g_set_error (error,
844 FWUPD_ERROR,
845 FWUPD_ERROR_INTERNAL,
846 "Cannot delete %s: %s",
847 FU_OFFLINE_TRIGGER_FILENAME,
848 error_local->message);
849 return FALSE;
850 }
851 return TRUE;
852}
853
854static gboolean
855fu_plugin_runner_offline_setup (GError **error)
856{
857 gint rc;
858
859 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
860
861 /* create symlink for the systemd-system-update-generator */
862 rc = symlink ("/var/lib/fwupd", FU_OFFLINE_TRIGGER_FILENAME);
863 if (rc < 0) {
864 g_set_error (error,
865 FWUPD_ERROR,
866 FWUPD_ERROR_INTERNAL,
867 "Failed to create symlink %s to %s: %s",
868 FU_OFFLINE_TRIGGER_FILENAME,
869 "/var/lib", strerror (errno));
Richard Hughesd0905142016-03-13 09:46:49 +0000870 return FALSE;
871 }
872 return TRUE;
873}
874
Richard Hughes0d7fdb32017-11-11 20:23:14 +0000875static gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100876fu_plugin_runner_device_generic (FuPlugin *self, FuDevice *device,
Richard Hughes0d7fdb32017-11-11 20:23:14 +0000877 const gchar *symbol_name, GError **error)
878{
Richard Hughes12724852018-09-04 13:53:44 +0100879 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0d7fdb32017-11-11 20:23:14 +0000880 FuPluginDeviceFunc func = NULL;
881
882 /* not enabled */
883 if (!priv->enabled)
884 return TRUE;
885
Richard Hughesd3d96cc2017-11-14 11:34:33 +0000886 /* no object loaded */
887 if (priv->module == NULL)
888 return TRUE;
889
Richard Hughes0d7fdb32017-11-11 20:23:14 +0000890 /* optional */
891 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
892 if (func == NULL)
893 return TRUE;
894 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughes12724852018-09-04 13:53:44 +0100895 if (!func (self, device, error)) {
Richard Hughes83e54e42018-01-31 23:27:30 +0000896 g_prefix_error (error, "failed to run %s() on %s: ",
Richard Hughes0d7fdb32017-11-11 20:23:14 +0000897 symbol_name + 10,
Richard Hughes0d7fdb32017-11-11 20:23:14 +0000898 priv->name);
899 return FALSE;
900 }
901 return TRUE;
902}
903
Richard Hughesdbd8c762018-06-15 20:31:40 +0100904static gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100905fu_plugin_runner_flagged_device_generic (FuPlugin *self, FwupdInstallFlags flags,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -0500906 FuDevice *device,
907 const gchar *symbol_name, GError **error)
908{
Richard Hughes12724852018-09-04 13:53:44 +0100909 FuPluginPrivate *priv = GET_PRIVATE (self);
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -0500910 FuPluginFlaggedDeviceFunc func = NULL;
911
912 /* not enabled */
913 if (!priv->enabled)
914 return TRUE;
915
916 /* no object loaded */
917 if (priv->module == NULL)
918 return TRUE;
919
920 /* optional */
921 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
922 if (func == NULL)
923 return TRUE;
924 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughes12724852018-09-04 13:53:44 +0100925 if (!func (self, flags, device, error)) {
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -0500926 g_prefix_error (error, "failed to run %s() on %s: ",
927 symbol_name + 10,
928 priv->name);
929 return FALSE;
930 }
931 return TRUE;
932
933}
934
935static gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100936fu_plugin_runner_device_array_generic (FuPlugin *self, GPtrArray *devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +0100937 const gchar *symbol_name, GError **error)
938{
Richard Hughes12724852018-09-04 13:53:44 +0100939 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesdbd8c762018-06-15 20:31:40 +0100940 FuPluginDeviceArrayFunc func = NULL;
941
942 /* not enabled */
943 if (!priv->enabled)
944 return TRUE;
945
946 /* no object loaded */
947 if (priv->module == NULL)
948 return TRUE;
949
950 /* optional */
951 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
952 if (func == NULL)
953 return TRUE;
954 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughes12724852018-09-04 13:53:44 +0100955 if (!func (self, devices, error)) {
Richard Hughesdbd8c762018-06-15 20:31:40 +0100956 g_prefix_error (error, "failed to run %s() on %s: ",
957 symbol_name + 10,
958 priv->name);
959 return FALSE;
960 }
961 return TRUE;
962}
963
Richard Hughesd0905142016-03-13 09:46:49 +0000964gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100965fu_plugin_runner_coldplug (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +0000966{
Richard Hughes12724852018-09-04 13:53:44 +0100967 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000968 FuPluginStartupFunc func = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +0000969
970 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +0000971 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000972 return TRUE;
973
Richard Hughes639da472018-01-06 22:35:04 +0000974 /* no object loaded */
975 if (priv->module == NULL)
976 return TRUE;
977
Richard Hughesd0905142016-03-13 09:46:49 +0000978 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000979 g_module_symbol (priv->module, "fu_plugin_coldplug", (gpointer *) &func);
980 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +0000981 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +0000982 g_debug ("performing coldplug() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +0100983 if (!func (self, error)) {
Richard Hughescff38bc2016-12-12 12:03:37 +0000984 g_prefix_error (error, "failed to coldplug %s: ", priv->name);
985 return FALSE;
986 }
987 return TRUE;
988}
989
Richard Hughes7b8b2022016-12-12 16:15:03 +0000990gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100991fu_plugin_runner_recoldplug (FuPlugin *self, GError **error)
Richard Hughes2de8f132018-01-17 09:12:02 +0000992{
Richard Hughes12724852018-09-04 13:53:44 +0100993 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes2de8f132018-01-17 09:12:02 +0000994 FuPluginStartupFunc func = NULL;
995
996 /* not enabled */
997 if (!priv->enabled)
998 return TRUE;
999
1000 /* no object loaded */
1001 if (priv->module == NULL)
1002 return TRUE;
1003
1004 /* optional */
1005 g_module_symbol (priv->module, "fu_plugin_recoldplug", (gpointer *) &func);
1006 if (func == NULL)
1007 return TRUE;
1008 g_debug ("performing recoldplug() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01001009 if (!func (self, error)) {
Richard Hughes2de8f132018-01-17 09:12:02 +00001010 g_prefix_error (error, "failed to recoldplug %s: ", priv->name);
1011 return FALSE;
1012 }
1013 return TRUE;
1014}
1015
1016gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001017fu_plugin_runner_coldplug_prepare (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001018{
Richard Hughes12724852018-09-04 13:53:44 +01001019 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001020 FuPluginStartupFunc func = NULL;
1021
1022 /* not enabled */
1023 if (!priv->enabled)
1024 return TRUE;
1025
Richard Hughes639da472018-01-06 22:35:04 +00001026 /* no object loaded */
1027 if (priv->module == NULL)
1028 return TRUE;
1029
Richard Hughes46487c92017-01-07 21:26:34 +00001030 /* optional */
1031 g_module_symbol (priv->module, "fu_plugin_coldplug_prepare", (gpointer *) &func);
1032 if (func == NULL)
1033 return TRUE;
1034 g_debug ("performing coldplug_prepare() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01001035 if (!func (self, error)) {
Richard Hughes46487c92017-01-07 21:26:34 +00001036 g_prefix_error (error, "failed to prepare for coldplug %s: ", priv->name);
1037 return FALSE;
1038 }
1039 return TRUE;
1040}
1041
1042gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001043fu_plugin_runner_coldplug_cleanup (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001044{
Richard Hughes12724852018-09-04 13:53:44 +01001045 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001046 FuPluginStartupFunc func = NULL;
1047
1048 /* not enabled */
1049 if (!priv->enabled)
1050 return TRUE;
1051
Richard Hughes639da472018-01-06 22:35:04 +00001052 /* no object loaded */
1053 if (priv->module == NULL)
1054 return TRUE;
1055
Richard Hughes46487c92017-01-07 21:26:34 +00001056 /* optional */
1057 g_module_symbol (priv->module, "fu_plugin_coldplug_cleanup", (gpointer *) &func);
1058 if (func == NULL)
1059 return TRUE;
1060 g_debug ("performing coldplug_cleanup() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01001061 if (!func (self, error)) {
Richard Hughes46487c92017-01-07 21:26:34 +00001062 g_prefix_error (error, "failed to cleanup coldplug %s: ", priv->name);
1063 return FALSE;
1064 }
1065 return TRUE;
1066}
1067
1068gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001069fu_plugin_runner_composite_prepare (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001070{
Richard Hughes12724852018-09-04 13:53:44 +01001071 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001072 "fu_plugin_composite_prepare",
1073 error);
1074}
1075
1076gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001077fu_plugin_runner_composite_cleanup (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001078{
Richard Hughes12724852018-09-04 13:53:44 +01001079 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001080 "fu_plugin_composite_cleanup",
1081 error);
1082}
1083
1084gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001085fu_plugin_runner_update_prepare (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001086 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001087{
Richard Hughes12724852018-09-04 13:53:44 +01001088 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001089 "fu_plugin_update_prepare",
1090 error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001091}
1092
1093gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001094fu_plugin_runner_update_cleanup (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001095 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001096{
Richard Hughes12724852018-09-04 13:53:44 +01001097 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001098 "fu_plugin_update_cleanup",
1099 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001100}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001101
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001102gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001103fu_plugin_runner_update_attach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001104{
Richard Hughes12724852018-09-04 13:53:44 +01001105 return fu_plugin_runner_device_generic (self, device,
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001106 "fu_plugin_update_attach", error);
1107}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001108
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001109gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001110fu_plugin_runner_update_detach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001111{
Richard Hughes12724852018-09-04 13:53:44 +01001112 return fu_plugin_runner_device_generic (self, device,
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001113 "fu_plugin_update_detach", error);
1114}
1115
1116gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001117fu_plugin_runner_update_reload (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001118{
Richard Hughes12724852018-09-04 13:53:44 +01001119 return fu_plugin_runner_device_generic (self, device,
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001120 "fu_plugin_update_reload", error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001121}
1122
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001123/**
1124 * fu_plugin_add_udev_subsystem:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001125 * @self: a #FuPlugin
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001126 * @subsystem: a subsystem name, e.g. `pciport`
1127 *
1128 * Registers the udev subsystem to be watched by the daemon.
1129 *
1130 * Plugins can use this method only in fu_plugin_init()
1131 **/
1132void
Richard Hughes12724852018-09-04 13:53:44 +01001133fu_plugin_add_udev_subsystem (FuPlugin *self, const gchar *subsystem)
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001134{
Richard Hughes12724852018-09-04 13:53:44 +01001135 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001136 for (guint i = 0; i < priv->udev_subsystems->len; i++) {
1137 const gchar *subsystem_tmp = g_ptr_array_index (priv->udev_subsystems, i);
1138 if (g_strcmp0 (subsystem_tmp, subsystem) == 0)
1139 return;
1140 }
1141 g_debug ("added udev subsystem watch of %s", subsystem);
1142 g_ptr_array_add (priv->udev_subsystems, g_strdup (subsystem));
1143}
1144
Richard Hughes104f6512017-11-24 11:44:57 +00001145gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001146fu_plugin_runner_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error)
Richard Hughes104f6512017-11-24 11:44:57 +00001147{
Richard Hughes12724852018-09-04 13:53:44 +01001148 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes104f6512017-11-24 11:44:57 +00001149 FuPluginUsbDeviceAddedFunc func = NULL;
1150
1151 /* not enabled */
1152 if (!priv->enabled)
1153 return TRUE;
Richard Hughes639da472018-01-06 22:35:04 +00001154
1155 /* no object loaded */
Richard Hughes104f6512017-11-24 11:44:57 +00001156 if (priv->module == NULL)
1157 return TRUE;
1158
1159 /* optional */
1160 g_module_symbol (priv->module, "fu_plugin_usb_device_added", (gpointer *) &func);
1161 if (func != NULL) {
1162 g_debug ("performing usb_device_added() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01001163 return func (self, device, error);
Richard Hughes104f6512017-11-24 11:44:57 +00001164 }
1165 return TRUE;
1166}
1167
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001168gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001169fu_plugin_runner_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error)
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001170{
Richard Hughes12724852018-09-04 13:53:44 +01001171 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001172 FuPluginUdevDeviceAddedFunc func = NULL;
1173
1174 /* not enabled */
1175 if (!priv->enabled)
1176 return TRUE;
1177
1178 /* no object loaded */
1179 if (priv->module == NULL)
1180 return TRUE;
1181
1182 /* optional */
1183 g_module_symbol (priv->module, "fu_plugin_udev_device_added", (gpointer *) &func);
1184 if (func != NULL) {
1185 g_debug ("performing udev_device_added() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01001186 return func (self, device, error);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001187 }
1188 return TRUE;
1189}
1190
Richard Hughese1fd34d2017-08-24 14:19:51 +01001191void
Richard Hughes12724852018-09-04 13:53:44 +01001192fu_plugin_runner_device_removed (FuPlugin *self, FuDevice *device)
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001193{
1194 g_autoptr(GError) error_local= NULL;
1195
Richard Hughes12724852018-09-04 13:53:44 +01001196 if (!fu_plugin_runner_device_generic (self, device,
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001197 "fu_plugin_device_removed",
1198 &error_local))
1199 g_warning ("%s", error_local->message);
1200}
1201
1202void
Richard Hughes12724852018-09-04 13:53:44 +01001203fu_plugin_runner_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +01001204{
Richard Hughes12724852018-09-04 13:53:44 +01001205 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughese1fd34d2017-08-24 14:19:51 +01001206 FuPluginDeviceRegisterFunc func = NULL;
1207
1208 /* not enabled */
1209 if (!priv->enabled)
1210 return;
Richard Hughes34834102017-11-21 21:55:00 +00001211 if (priv->module == NULL)
1212 return;
Richard Hughese1fd34d2017-08-24 14:19:51 +01001213
Mario Limonciello4910b242018-06-22 15:04:21 -05001214 /* don't notify plugins on their own devices */
Richard Hughes12724852018-09-04 13:53:44 +01001215 if (g_strcmp0 (fu_device_get_plugin (device), fu_plugin_get_name (self)) == 0)
Mario Limonciello4910b242018-06-22 15:04:21 -05001216 return;
1217
Richard Hughese1fd34d2017-08-24 14:19:51 +01001218 /* optional */
1219 g_module_symbol (priv->module, "fu_plugin_device_registered", (gpointer *) &func);
1220 if (func != NULL) {
Richard Hughes1bf7ff92018-08-24 20:21:35 +01001221 g_debug ("performing fu_plugin_device_registered() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01001222 func (self, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +01001223 }
1224}
1225
Richard Hughescff38bc2016-12-12 12:03:37 +00001226static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001227fu_plugin_runner_schedule_update (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +00001228 FuDevice *device,
1229 GBytes *blob_cab,
1230 GError **error)
1231{
Richard Hughes38fb56c2018-02-01 22:07:52 +00001232 FwupdRelease *release;
Richard Hughescff38bc2016-12-12 12:03:37 +00001233 gchar tmpname[] = {"XXXXXX.cap"};
1234 g_autofree gchar *dirname = NULL;
1235 g_autofree gchar *filename = NULL;
Richard Hughes68982c62017-09-13 15:40:14 +01001236 g_autoptr(FuDevice) res_tmp = NULL;
Richard Hughes780ef3f2018-01-12 16:20:31 +00001237 g_autoptr(FuHistory) history = NULL;
Richard Hughes38fb56c2018-02-01 22:07:52 +00001238 g_autoptr(FwupdRelease) release_tmp = fwupd_release_new ();
Richard Hughescff38bc2016-12-12 12:03:37 +00001239 g_autoptr(GFile) file = NULL;
1240
1241 /* id already exists */
Richard Hughes780ef3f2018-01-12 16:20:31 +00001242 history = fu_history_new ();
Richard Hughes0b9d9962018-01-12 16:31:28 +00001243 res_tmp = fu_history_get_device_by_id (history, fu_device_get_id (device), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +00001244 if (res_tmp != NULL) {
1245 g_set_error (error,
1246 FWUPD_ERROR,
1247 FWUPD_ERROR_ALREADY_PENDING,
1248 "%s is already scheduled to be updated",
1249 fu_device_get_id (device));
1250 return FALSE;
1251 }
1252
1253 /* create directory */
Richard Hughes4be17d12018-05-30 20:36:29 +01001254 dirname = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG);
Richard Hughescff38bc2016-12-12 12:03:37 +00001255 file = g_file_new_for_path (dirname);
1256 if (!g_file_query_exists (file, NULL)) {
1257 if (!g_file_make_directory_with_parents (file, NULL, error))
1258 return FALSE;
1259 }
1260
1261 /* get a random filename */
1262 for (guint i = 0; i < 6; i++)
1263 tmpname[i] = (gchar) g_random_int_range ('A', 'Z');
1264 filename = g_build_filename (dirname, tmpname, NULL);
1265
1266 /* just copy to the temp file */
Richard Hughes23135eb2017-11-30 21:01:25 +00001267 fu_device_set_status (device, FWUPD_STATUS_SCHEDULING);
Richard Hughescff38bc2016-12-12 12:03:37 +00001268 if (!g_file_set_contents (filename,
1269 g_bytes_get_data (blob_cab, NULL),
1270 (gssize) g_bytes_get_size (blob_cab),
1271 error))
1272 return FALSE;
1273
1274 /* schedule for next boot */
1275 g_debug ("schedule %s to be installed to %s on next boot",
1276 filename, fu_device_get_id (device));
Richard Hughes38fb56c2018-02-01 22:07:52 +00001277 release = fu_device_get_release_default (device);
1278 fwupd_release_set_version (release_tmp, fwupd_release_get_version (release));
1279 fwupd_release_set_filename (release_tmp, filename);
Richard Hughescff38bc2016-12-12 12:03:37 +00001280
1281 /* add to database */
Richard Hughes3e90a582018-01-06 22:38:09 +00001282 fu_device_set_update_state (device, FWUPD_UPDATE_STATE_PENDING);
Richard Hughes38fb56c2018-02-01 22:07:52 +00001283 if (!fu_history_add_device (history, device, release_tmp, error))
Richard Hughescff38bc2016-12-12 12:03:37 +00001284 return FALSE;
1285
1286 /* next boot we run offline */
1287 return fu_plugin_runner_offline_setup (error);
1288}
1289
1290gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001291fu_plugin_runner_verify (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +00001292 FuDevice *device,
1293 FuPluginVerifyFlags flags,
1294 GError **error)
1295{
Richard Hughes12724852018-09-04 13:53:44 +01001296 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001297 FuPluginVerifyFunc func = NULL;
Richard Hughesababbb72017-06-15 20:18:36 +01001298 GPtrArray *checksums;
Richard Hughescff38bc2016-12-12 12:03:37 +00001299
1300 /* not enabled */
1301 if (!priv->enabled)
1302 return TRUE;
1303
Richard Hughes639da472018-01-06 22:35:04 +00001304 /* no object loaded */
1305 if (priv->module == NULL)
1306 return TRUE;
1307
Richard Hughesababbb72017-06-15 20:18:36 +01001308 /* clear any existing verification checksums */
1309 checksums = fu_device_get_checksums (device);
1310 g_ptr_array_set_size (checksums, 0);
1311
Richard Hughescff38bc2016-12-12 12:03:37 +00001312 /* optional */
1313 g_module_symbol (priv->module, "fu_plugin_verify", (gpointer *) &func);
1314 if (func == NULL)
1315 return TRUE;
1316 g_debug ("performing verify() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01001317 if (!func (self, device, flags, error)) {
Richard Hughescff38bc2016-12-12 12:03:37 +00001318 g_prefix_error (error, "failed to verify %s: ", priv->name);
Richard Hughesd0905142016-03-13 09:46:49 +00001319 return FALSE;
1320 }
1321 return TRUE;
1322}
1323
Richard Hughesd0905142016-03-13 09:46:49 +00001324gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001325fu_plugin_runner_unlock (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00001326{
Richard Hughescff38bc2016-12-12 12:03:37 +00001327 guint64 flags;
Richard Hughescff38bc2016-12-12 12:03:37 +00001328
1329 /* final check */
1330 flags = fu_device_get_flags (device);
1331 if ((flags & FWUPD_DEVICE_FLAG_LOCKED) == 0) {
1332 g_set_error (error,
1333 FWUPD_ERROR,
1334 FWUPD_ERROR_NOT_SUPPORTED,
1335 "Device %s is not locked",
1336 fu_device_get_id (device));
1337 return FALSE;
1338 }
1339
Richard Hughes9c4b5312017-11-14 11:34:53 +00001340 /* run vfunc */
Richard Hughes12724852018-09-04 13:53:44 +01001341 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes9c4b5312017-11-14 11:34:53 +00001342 "fu_plugin_unlock", error))
1343 return FALSE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001344
1345 /* update with correct flags */
1346 flags = fu_device_get_flags (device);
1347 fu_device_set_flags (device, flags &= ~FWUPD_DEVICE_FLAG_LOCKED);
1348 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
1349 return TRUE;
1350}
1351
1352gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001353fu_plugin_runner_update (FuPlugin *self,
Richard Hughesa785a1c2017-08-25 16:00:58 +01001354 FuDevice *device,
1355 GBytes *blob_cab,
1356 GBytes *blob_fw,
1357 FwupdInstallFlags flags,
1358 GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00001359{
Richard Hughes12724852018-09-04 13:53:44 +01001360 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesa785a1c2017-08-25 16:00:58 +01001361 FuPluginUpdateFunc update_func;
Richard Hughes780ef3f2018-01-12 16:20:31 +00001362 g_autoptr(FuHistory) history = NULL;
Richard Hughes68982c62017-09-13 15:40:14 +01001363 g_autoptr(FuDevice) device_pending = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001364 GError *error_update = NULL;
Richard Hughesf556d372017-06-15 19:49:18 +01001365 GPtrArray *checksums;
Richard Hughescff38bc2016-12-12 12:03:37 +00001366
1367 /* not enabled */
Richard Hughes41c15482018-02-01 22:07:21 +00001368 if (!priv->enabled) {
1369 g_debug ("plugin not enabled, skipping");
Richard Hughesd0905142016-03-13 09:46:49 +00001370 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00001371 }
Richard Hughesd0905142016-03-13 09:46:49 +00001372
Richard Hughes639da472018-01-06 22:35:04 +00001373 /* no object loaded */
Richard Hughes41c15482018-02-01 22:07:21 +00001374 if (priv->module == NULL) {
1375 g_debug ("module not enabled, skipping");
Richard Hughes639da472018-01-06 22:35:04 +00001376 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00001377 }
Richard Hughes639da472018-01-06 22:35:04 +00001378
Richard Hughesd0905142016-03-13 09:46:49 +00001379 /* optional */
Richard Hughesa785a1c2017-08-25 16:00:58 +01001380 g_module_symbol (priv->module, "fu_plugin_update", (gpointer *) &update_func);
1381 if (update_func == NULL) {
1382 g_set_error_literal (error,
1383 FWUPD_ERROR,
1384 FWUPD_ERROR_NOT_SUPPORTED,
1385 "No update possible");
1386 return FALSE;
1387 }
Richard Hughesd0905142016-03-13 09:46:49 +00001388
Richard Hughesa785a1c2017-08-25 16:00:58 +01001389 /* just schedule this for the next reboot */
Richard Hughescff38bc2016-12-12 12:03:37 +00001390 if (flags & FWUPD_INSTALL_FLAG_OFFLINE) {
Richard Hughes026cdd82018-05-18 10:23:19 +01001391 if (blob_cab == NULL) {
1392 g_set_error_literal (error,
1393 FWUPD_ERROR,
1394 FWUPD_ERROR_NOT_SUPPORTED,
1395 "No cabinet archive to schedule");
1396 return FALSE;
1397 }
Richard Hughes12724852018-09-04 13:53:44 +01001398 return fu_plugin_runner_schedule_update (self,
Richard Hughesa785a1c2017-08-25 16:00:58 +01001399 device,
1400 blob_cab,
1401 error);
Richard Hughescff38bc2016-12-12 12:03:37 +00001402 }
1403
1404 /* cancel the pending action */
1405 if (!fu_plugin_runner_offline_invalidate (error))
1406 return FALSE;
1407
1408 /* online */
Richard Hughes780ef3f2018-01-12 16:20:31 +00001409 history = fu_history_new ();
Richard Hughes0b9d9962018-01-12 16:31:28 +00001410 device_pending = fu_history_get_device_by_id (history, fu_device_get_id (device), NULL);
Richard Hughes12724852018-09-04 13:53:44 +01001411 if (!update_func (self, device, blob_fw, flags, &error_update)) {
Richard Hughesc0cd0232018-01-31 15:02:00 +00001412 fu_device_set_update_error (device, error_update->message);
Richard Hughescff38bc2016-12-12 12:03:37 +00001413 g_propagate_error (error, error_update);
1414 return FALSE;
1415 }
1416
Richard Hughesf556d372017-06-15 19:49:18 +01001417 /* no longer valid */
1418 checksums = fu_device_get_checksums (device);
1419 g_ptr_array_set_size (checksums, 0);
1420
Richard Hughescff38bc2016-12-12 12:03:37 +00001421 /* cleanup */
Richard Hughes68982c62017-09-13 15:40:14 +01001422 if (device_pending != NULL) {
Richard Hughescff38bc2016-12-12 12:03:37 +00001423 const gchar *tmp;
Richard Hughesbc3a4e12018-01-06 22:41:47 +00001424 FwupdRelease *release;
Richard Hughescff38bc2016-12-12 12:03:37 +00001425
Richard Hughes780ef3f2018-01-12 16:20:31 +00001426 /* update history database */
Richard Hughesc0cd0232018-01-31 15:02:00 +00001427 fu_device_set_update_state (device, FWUPD_UPDATE_STATE_SUCCESS);
1428 if (!fu_history_modify_device (history, device,
1429 FU_HISTORY_FLAGS_MATCH_NEW_VERSION,
1430 error))
Richard Hughes0b9d9962018-01-12 16:31:28 +00001431 return FALSE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001432
1433 /* delete cab file */
Richard Hughesbc3a4e12018-01-06 22:41:47 +00001434 release = fu_device_get_release_default (device_pending);
1435 tmp = fwupd_release_get_filename (release);
Richard Hughescff38bc2016-12-12 12:03:37 +00001436 if (tmp != NULL && g_str_has_prefix (tmp, LIBEXECDIR)) {
1437 g_autoptr(GError) error_local = NULL;
1438 g_autoptr(GFile) file = NULL;
1439 file = g_file_new_for_path (tmp);
1440 if (!g_file_delete (file, NULL, &error_local)) {
1441 g_set_error (error,
1442 FWUPD_ERROR,
1443 FWUPD_ERROR_INVALID_FILE,
1444 "Failed to delete %s: %s",
1445 tmp, error_local->message);
1446 return FALSE;
1447 }
1448 }
1449 }
Richard Hughesd0905142016-03-13 09:46:49 +00001450 return TRUE;
1451}
Richard Hughescff38bc2016-12-12 12:03:37 +00001452
1453gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001454fu_plugin_runner_clear_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00001455{
Richard Hughes12724852018-09-04 13:53:44 +01001456 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001457 FuPluginDeviceFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001458
1459 /* not enabled */
1460 if (!priv->enabled)
1461 return TRUE;
1462
Richard Hughes639da472018-01-06 22:35:04 +00001463 /* no object loaded */
1464 if (priv->module == NULL)
1465 return TRUE;
1466
Richard Hughes65e44ca2018-01-30 17:26:30 +00001467 /* optional */
1468 g_module_symbol (priv->module, "fu_plugin_get_results", (gpointer *) &func);
1469 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00001470 return TRUE;
Richard Hughes65e44ca2018-01-30 17:26:30 +00001471 g_debug ("performing clear_result() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01001472 if (!func (self, device, error)) {
Richard Hughes65e44ca2018-01-30 17:26:30 +00001473 g_prefix_error (error, "failed to clear_result %s: ", priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00001474 return FALSE;
1475 }
Richard Hughes65e44ca2018-01-30 17:26:30 +00001476 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001477}
1478
1479gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001480fu_plugin_runner_get_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00001481{
Richard Hughes12724852018-09-04 13:53:44 +01001482 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001483 FuPluginDeviceFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001484
1485 /* not enabled */
1486 if (!priv->enabled)
1487 return TRUE;
1488
Richard Hughes639da472018-01-06 22:35:04 +00001489 /* no object loaded */
1490 if (priv->module == NULL)
1491 return TRUE;
1492
Richard Hughes65e44ca2018-01-30 17:26:30 +00001493 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00001494 g_module_symbol (priv->module, "fu_plugin_get_results", (gpointer *) &func);
Richard Hughes65e44ca2018-01-30 17:26:30 +00001495 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00001496 return TRUE;
Richard Hughes65e44ca2018-01-30 17:26:30 +00001497 g_debug ("performing get_results() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01001498 if (!func (self, device, error)) {
Richard Hughes65e44ca2018-01-30 17:26:30 +00001499 g_prefix_error (error, "failed to get_results %s: ", priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00001500 return FALSE;
1501 }
Richard Hughescff38bc2016-12-12 12:03:37 +00001502 return TRUE;
1503}
1504
Richard Hughes08a37992017-09-12 12:57:43 +01001505/**
1506 * fu_plugin_get_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001507 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01001508 *
1509 * Gets the plugin order, where higher numbers are run after lower
1510 * numbers.
1511 *
1512 * Returns: the integer value
1513 **/
1514guint
Richard Hughes12724852018-09-04 13:53:44 +01001515fu_plugin_get_order (FuPlugin *self)
Richard Hughes08a37992017-09-12 12:57:43 +01001516{
Richard Hughes12724852018-09-04 13:53:44 +01001517 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01001518 return priv->order;
1519}
1520
1521/**
1522 * fu_plugin_set_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001523 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01001524 * @order: a integer value
1525 *
1526 * Sets the plugin order, where higher numbers are run after lower
1527 * numbers.
1528 **/
1529void
Richard Hughes12724852018-09-04 13:53:44 +01001530fu_plugin_set_order (FuPlugin *self, guint order)
Richard Hughes08a37992017-09-12 12:57:43 +01001531{
Richard Hughes12724852018-09-04 13:53:44 +01001532 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01001533 priv->order = order;
1534}
1535
1536/**
Richard Hughes81c427c2018-08-06 15:20:17 +01001537 * fu_plugin_get_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001538 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01001539 *
1540 * Gets the plugin priority, where higher numbers are better.
1541 *
1542 * Returns: the integer value
1543 **/
1544guint
Richard Hughes12724852018-09-04 13:53:44 +01001545fu_plugin_get_priority (FuPlugin *self)
Richard Hughes81c427c2018-08-06 15:20:17 +01001546{
Richard Hughes12724852018-09-04 13:53:44 +01001547 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01001548 return priv->priority;
1549}
1550
1551/**
1552 * fu_plugin_set_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001553 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01001554 * @priority: a integer value
1555 *
1556 * Sets the plugin priority, where higher numbers are better.
1557 **/
1558void
Richard Hughes12724852018-09-04 13:53:44 +01001559fu_plugin_set_priority (FuPlugin *self, guint priority)
Richard Hughes81c427c2018-08-06 15:20:17 +01001560{
Richard Hughes12724852018-09-04 13:53:44 +01001561 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01001562 priv->priority = priority;
1563}
1564
1565/**
Richard Hughes08a37992017-09-12 12:57:43 +01001566 * fu_plugin_add_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001567 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01001568 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
Richard Hughes4eada342017-10-03 21:20:32 +01001569 * @name: a plugin name, e.g. `upower`
Richard Hughes08a37992017-09-12 12:57:43 +01001570 *
1571 * If the plugin name is found, the rule will be used to sort the plugin list,
1572 * for example the plugin specified by @name will be ordered after this plugin
1573 * when %FU_PLUGIN_RULE_RUN_AFTER is used.
1574 *
1575 * NOTE: The depsolver is iterative and may not solve overly-complicated rules;
1576 * If depsolving fails then fwupd will not start.
1577 **/
1578void
Richard Hughes12724852018-09-04 13:53:44 +01001579fu_plugin_add_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes08a37992017-09-12 12:57:43 +01001580{
Richard Hughes12724852018-09-04 13:53:44 +01001581 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01001582 g_ptr_array_add (priv->rules[rule], g_strdup (name));
1583}
1584
1585/**
1586 * fu_plugin_get_rules:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001587 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01001588 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
1589 *
1590 * Gets the plugin IDs that should be run after this plugin.
1591 *
1592 * Returns: (element-type utf8) (transfer none): the list of plugin names, e.g. ['appstream']
1593 **/
1594GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +01001595fu_plugin_get_rules (FuPlugin *self, FuPluginRule rule)
Richard Hughes08a37992017-09-12 12:57:43 +01001596{
Richard Hughes12724852018-09-04 13:53:44 +01001597 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01001598 return priv->rules[rule];
1599}
1600
Richard Hughes80b79bb2018-01-11 21:11:06 +00001601/**
Richard Hughes5f3a56b2018-06-28 12:13:59 +01001602 * fu_plugin_has_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001603 * @self: a #FuPlugin
Richard Hughes5f3a56b2018-06-28 12:13:59 +01001604 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
1605 * @name: a plugin name, e.g. `upower`
1606 *
Richard Hughes87fb9ff2018-06-28 12:55:59 +01001607 * Gets the plugin IDs that should be run after this plugin.
Richard Hughes5f3a56b2018-06-28 12:13:59 +01001608 *
1609 * Returns: %TRUE if the name exists for the specific rule
1610 **/
1611gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001612fu_plugin_has_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes5f3a56b2018-06-28 12:13:59 +01001613{
Richard Hughes12724852018-09-04 13:53:44 +01001614 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes5f3a56b2018-06-28 12:13:59 +01001615 for (guint i = 0; i < priv->rules[rule]->len; i++) {
1616 const gchar *tmp = g_ptr_array_index (priv->rules[rule], i);
1617 if (g_strcmp0 (tmp, name) == 0)
1618 return TRUE;
1619 }
1620 return FALSE;
1621}
1622
1623/**
Richard Hughes80b79bb2018-01-11 21:11:06 +00001624 * fu_plugin_add_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001625 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00001626 * @key: a string, e.g. `FwupdateVersion`
1627 * @value: a string, e.g. `10`
1628 *
1629 * Sets any additional metadata to be included in the firmware report to aid
1630 * debugging problems.
1631 *
1632 * Any data included here will be sent to the metadata server after user
1633 * confirmation.
1634 **/
1635void
Richard Hughes12724852018-09-04 13:53:44 +01001636fu_plugin_add_report_metadata (FuPlugin *self, const gchar *key, const gchar *value)
Richard Hughes80b79bb2018-01-11 21:11:06 +00001637{
Richard Hughes12724852018-09-04 13:53:44 +01001638 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes80b79bb2018-01-11 21:11:06 +00001639 g_hash_table_insert (priv->report_metadata, g_strdup (key), g_strdup (value));
1640}
1641
1642/**
1643 * fu_plugin_get_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001644 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00001645 *
1646 * Returns the list of additional metadata to be added when filing a report.
1647 *
1648 * Returns: (transfer none): the map of report metadata
1649 **/
1650GHashTable *
Richard Hughes12724852018-09-04 13:53:44 +01001651fu_plugin_get_report_metadata (FuPlugin *self)
Richard Hughes80b79bb2018-01-11 21:11:06 +00001652{
Richard Hughes12724852018-09-04 13:53:44 +01001653 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes80b79bb2018-01-11 21:11:06 +00001654 return priv->report_metadata;
1655}
1656
Mario Limonciello963dc422018-02-27 14:26:58 -06001657/**
1658 * fu_plugin_get_config_value:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001659 * @self: a #FuPlugin
Mario Limonciello963dc422018-02-27 14:26:58 -06001660 * @key: A settings key
1661 *
1662 * Return the value of a key if it's been configured
1663 *
1664 * Since: 1.0.6
1665 **/
1666gchar *
Richard Hughes12724852018-09-04 13:53:44 +01001667fu_plugin_get_config_value (FuPlugin *self, const gchar *key)
Mario Limonciello963dc422018-02-27 14:26:58 -06001668{
Richard Hughes4be17d12018-05-30 20:36:29 +01001669 g_autofree gchar *conf_dir = NULL;
Mario Limonciello963dc422018-02-27 14:26:58 -06001670 g_autofree gchar *conf_file = NULL;
1671 g_autofree gchar *conf_path = NULL;
1672 g_autoptr(GKeyFile) keyfile = NULL;
1673 const gchar *plugin_name;
1674
Richard Hughes4be17d12018-05-30 20:36:29 +01001675 conf_dir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR_PKG);
Richard Hughes12724852018-09-04 13:53:44 +01001676 plugin_name = fu_plugin_get_name (self);
Mario Limonciello963dc422018-02-27 14:26:58 -06001677 conf_file = g_strdup_printf ("%s.conf", plugin_name);
Richard Hughes4be17d12018-05-30 20:36:29 +01001678 conf_path = g_build_filename (conf_dir, conf_file, NULL);
Mario Limonciello963dc422018-02-27 14:26:58 -06001679 if (!g_file_test (conf_path, G_FILE_TEST_IS_REGULAR))
1680 return NULL;
1681 keyfile = g_key_file_new ();
1682 if (!g_key_file_load_from_file (keyfile, conf_path,
1683 G_KEY_FILE_NONE, NULL))
1684 return NULL;
1685 return g_key_file_get_string (keyfile, plugin_name, key, NULL);
1686}
1687
Richard Hughes8c71a3f2018-05-22 19:19:52 +01001688/**
1689 * fu_plugin_name_compare:
1690 * @plugin1: first #FuPlugin to compare.
1691 * @plugin2: second #FuPlugin to compare.
1692 *
1693 * Compares two plugins by their names.
1694 *
1695 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
1696 **/
1697gint
1698fu_plugin_name_compare (FuPlugin *plugin1, FuPlugin *plugin2)
1699{
1700 FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1);
1701 FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2);
1702 return g_strcmp0 (priv1->name, priv2->name);
1703}
1704
1705/**
1706 * fu_plugin_order_compare:
1707 * @plugin1: first #FuPlugin to compare.
1708 * @plugin2: second #FuPlugin to compare.
1709 *
1710 * Compares two plugins by their depsolved order.
1711 *
1712 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
1713 **/
1714gint
1715fu_plugin_order_compare (FuPlugin *plugin1, FuPlugin *plugin2)
1716{
1717 FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1);
1718 FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2);
1719 if (priv1->order < priv2->order)
1720 return -1;
1721 if (priv1->order > priv2->order)
1722 return 1;
1723 return 0;
1724}
1725
Richard Hughescff38bc2016-12-12 12:03:37 +00001726static void
1727fu_plugin_class_init (FuPluginClass *klass)
1728{
1729 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1730 object_class->finalize = fu_plugin_finalize;
1731 signals[SIGNAL_DEVICE_ADDED] =
1732 g_signal_new ("device-added",
1733 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
1734 G_STRUCT_OFFSET (FuPluginClass, device_added),
1735 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
1736 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
1737 signals[SIGNAL_DEVICE_REMOVED] =
1738 g_signal_new ("device-removed",
1739 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
1740 G_STRUCT_OFFSET (FuPluginClass, device_removed),
1741 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
1742 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughese1fd34d2017-08-24 14:19:51 +01001743 signals[SIGNAL_DEVICE_REGISTER] =
1744 g_signal_new ("device-register",
1745 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
1746 G_STRUCT_OFFSET (FuPluginClass, device_register),
1747 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
1748 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughes362d6d72017-01-07 21:42:14 +00001749 signals[SIGNAL_RECOLDPLUG] =
1750 g_signal_new ("recoldplug",
1751 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
1752 G_STRUCT_OFFSET (FuPluginClass, recoldplug),
1753 NULL, NULL, g_cclosure_marshal_VOID__VOID,
1754 G_TYPE_NONE, 0);
Richard Hughesb0829032017-01-10 09:27:08 +00001755 signals[SIGNAL_SET_COLDPLUG_DELAY] =
1756 g_signal_new ("set-coldplug-delay",
1757 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
1758 G_STRUCT_OFFSET (FuPluginClass, set_coldplug_delay),
1759 NULL, NULL, g_cclosure_marshal_VOID__UINT,
1760 G_TYPE_NONE, 1, G_TYPE_UINT);
Richard Hughescff38bc2016-12-12 12:03:37 +00001761}
1762
1763static void
Richard Hughes12724852018-09-04 13:53:44 +01001764fu_plugin_init (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +00001765{
Richard Hughes12724852018-09-04 13:53:44 +01001766 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00001767 priv->enabled = TRUE;
1768 priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal,
1769 g_free, (GDestroyNotify) g_object_unref);
Richard Hughes37d09432018-09-09 10:39:45 +01001770 priv->devices_mutex = fu_mutex_new (G_OBJECT_TYPE_NAME(self), "devices");
Richard Hughes80b79bb2018-01-11 21:11:06 +00001771 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 +01001772 for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++)
1773 priv->rules[i] = g_ptr_array_new_with_free_func (g_free);
Richard Hughescff38bc2016-12-12 12:03:37 +00001774}
1775
1776static void
1777fu_plugin_finalize (GObject *object)
1778{
Richard Hughes12724852018-09-04 13:53:44 +01001779 FuPlugin *self = FU_PLUGIN (object);
1780 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00001781 FuPluginInitFunc func = NULL;
1782
1783 /* optional */
1784 if (priv->module != NULL) {
1785 g_module_symbol (priv->module, "fu_plugin_destroy", (gpointer *) &func);
1786 if (func != NULL) {
1787 g_debug ("performing destroy() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01001788 func (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00001789 }
1790 }
1791
Richard Hughes08a37992017-09-12 12:57:43 +01001792 for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++)
1793 g_ptr_array_unref (priv->rules[i]);
1794
Richard Hughescff38bc2016-12-12 12:03:37 +00001795 if (priv->usb_ctx != NULL)
1796 g_object_unref (priv->usb_ctx);
Richard Hughesb8f8db22017-04-25 15:56:00 +01001797 if (priv->hwids != NULL)
Richard Hughesd7704d42017-08-08 20:29:09 +01001798 g_object_unref (priv->hwids);
Richard Hughes9c028f02017-10-28 21:14:28 +01001799 if (priv->quirks != NULL)
1800 g_object_unref (priv->quirks);
Richard Hughes1354ea92017-09-19 15:58:31 +01001801 if (priv->supported_guids != NULL)
1802 g_ptr_array_unref (priv->supported_guids);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001803 if (priv->udev_subsystems != NULL)
1804 g_ptr_array_unref (priv->udev_subsystems);
Richard Hughes49e5e052017-09-03 12:15:41 +01001805 if (priv->smbios != NULL)
1806 g_object_unref (priv->smbios);
Richard Hughes275d3b42018-04-20 16:40:37 +01001807 if (priv->runtime_versions != NULL)
1808 g_hash_table_unref (priv->runtime_versions);
Richard Hughes34e0dab2018-04-20 16:43:00 +01001809 if (priv->compile_versions != NULL)
1810 g_hash_table_unref (priv->compile_versions);
Richard Hughescff38bc2016-12-12 12:03:37 +00001811 g_hash_table_unref (priv->devices);
Richard Hughes80b79bb2018-01-11 21:11:06 +00001812 g_hash_table_unref (priv->report_metadata);
Richard Hughes37d09432018-09-09 10:39:45 +01001813 g_object_unref (priv->devices_mutex);
Richard Hughescff38bc2016-12-12 12:03:37 +00001814 g_free (priv->name);
1815 g_free (priv->data);
Mario Limonciello3f9a1c12018-06-06 14:06:40 -05001816 /* Must happen as the last step to avoid prematurely
1817 * freeing memory held by the plugin */
1818#ifndef RUNNING_ON_VALGRIND
1819 if (priv->module != NULL)
1820 g_module_close (priv->module);
1821#endif
Richard Hughescff38bc2016-12-12 12:03:37 +00001822
1823 G_OBJECT_CLASS (fu_plugin_parent_class)->finalize (object);
1824}
1825
1826FuPlugin *
1827fu_plugin_new (void)
1828{
Richard Hughes12724852018-09-04 13:53:44 +01001829 return FU_PLUGIN (g_object_new (FU_TYPE_PLUGIN, NULL));
Richard Hughescff38bc2016-12-12 12:03:37 +00001830}