blob: 2dee097cf4ba7ca5c227f183a14b5c9416afa84d [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 Hughes95c98a92019-10-22 16:03:15 +010069 SIGNAL_ADD_FIRMWARE_GTYPE,
Richard Hughescff38bc2016-12-12 12:03:37 +000070 SIGNAL_LAST
71};
72
73static guint signals[SIGNAL_LAST] = { 0 };
74
75G_DEFINE_TYPE_WITH_PRIVATE (FuPlugin, fu_plugin, G_TYPE_OBJECT)
76#define GET_PRIVATE(o) (fu_plugin_get_instance_private (o))
77
78typedef const gchar *(*FuPluginGetNameFunc) (void);
Richard Hughes12724852018-09-04 13:53:44 +010079typedef void (*FuPluginInitFunc) (FuPlugin *self);
80typedef gboolean (*FuPluginStartupFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000081 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010082typedef void (*FuPluginDeviceRegisterFunc) (FuPlugin *self,
Richard Hughese1fd34d2017-08-24 14:19:51 +010083 FuDevice *device);
Richard Hughes12724852018-09-04 13:53:44 +010084typedef gboolean (*FuPluginDeviceFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000085 FuDevice *device,
86 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010087typedef gboolean (*FuPluginFlaggedDeviceFunc) (FuPlugin *self,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -050088 FwupdInstallFlags flags,
89 FuDevice *device,
90 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010091typedef gboolean (*FuPluginDeviceArrayFunc) (FuPlugin *self,
Richard Hughesdbd8c762018-06-15 20:31:40 +010092 GPtrArray *devices,
93 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010094typedef gboolean (*FuPluginVerifyFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000095 FuDevice *device,
96 FuPluginVerifyFlags flags,
97 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010098typedef gboolean (*FuPluginUpdateFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000099 FuDevice *device,
100 GBytes *blob_fw,
101 FwupdInstallFlags flags,
102 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +0100103typedef gboolean (*FuPluginUsbDeviceAddedFunc) (FuPlugin *self,
Richard Hughesff704412018-09-04 11:28:32 +0100104 FuUsbDevice *device,
Richard Hughes104f6512017-11-24 11:44:57 +0000105 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +0100106typedef gboolean (*FuPluginUdevDeviceAddedFunc) (FuPlugin *self,
Richard Hughesff704412018-09-04 11:28:32 +0100107 FuUdevDevice *device,
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100108 GError **error);
Richard Hughescff38bc2016-12-12 12:03:37 +0000109
Richard Hughes57d18222017-01-10 16:02:59 +0000110/**
111 * fu_plugin_get_name:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100112 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000113 *
114 * Gets the plugin name.
115 *
116 * Returns: a plugin name, or %NULL for unknown.
117 *
118 * Since: 0.8.0
119 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000120const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100121fu_plugin_get_name (FuPlugin *self)
Richard Hughesd0905142016-03-13 09:46:49 +0000122{
Richard Hughes12724852018-09-04 13:53:44 +0100123 FuPluginPrivate *priv = GET_PRIVATE (self);
124 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000125 return priv->name;
126}
Richard Hughesd0905142016-03-13 09:46:49 +0000127
Richard Hughes34834102017-11-21 21:55:00 +0000128void
Richard Hughes12724852018-09-04 13:53:44 +0100129fu_plugin_set_name (FuPlugin *self, const gchar *name)
Richard Hughes34834102017-11-21 21:55:00 +0000130{
Richard Hughes12724852018-09-04 13:53:44 +0100131 FuPluginPrivate *priv = GET_PRIVATE (self);
132 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughes34834102017-11-21 21:55:00 +0000133 g_return_if_fail (name != NULL);
134 g_free (priv->name);
135 priv->name = g_strdup (name);
136}
137
Richard Hughes57d18222017-01-10 16:02:59 +0000138/**
Richard Hughesf425d292019-01-18 17:57:39 +0000139 * fu_plugin_set_build_hash:
140 * @self: A #FuPlugin
141 * @build_hash: A checksum
142 *
143 * Sets the plugin build hash, typically a SHA256 checksum. All plugins must
144 * set the correct checksum to avoid the daemon being marked as tainted.
145 *
146 * Since: 1.2.4
147 **/
148void
149fu_plugin_set_build_hash (FuPlugin *self, const gchar *build_hash)
150{
151 FuPluginPrivate *priv = GET_PRIVATE (self);
152 g_return_if_fail (FU_IS_PLUGIN (self));
153 g_return_if_fail (build_hash != NULL);
154 g_free (priv->build_hash);
155 priv->build_hash = g_strdup (build_hash);
156}
157
158const gchar *
159fu_plugin_get_build_hash (FuPlugin *self)
160{
161 FuPluginPrivate *priv = GET_PRIVATE (self);
162 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
163 return priv->build_hash;
164}
165
166/**
Richard Hughes57d18222017-01-10 16:02:59 +0000167 * fu_plugin_cache_lookup:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100168 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000169 * @id: the key
170 *
171 * Finds an object in the per-plugin cache.
172 *
173 * Returns: (transfer none): a #GObject, or %NULL for unfound.
174 *
175 * Since: 0.8.0
176 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000177gpointer
Richard Hughes12724852018-09-04 13:53:44 +0100178fu_plugin_cache_lookup (FuPlugin *self, const gchar *id)
Richard Hughescff38bc2016-12-12 12:03:37 +0000179{
Richard Hughes12724852018-09-04 13:53:44 +0100180 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes161e9b52019-06-12 14:22:45 +0100181 g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100182 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughesccd78a92017-01-11 16:57:41 +0000183 g_return_val_if_fail (id != NULL, NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100184 g_return_val_if_fail (locker != NULL, NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000185 return g_hash_table_lookup (priv->devices, id);
186}
Richard Hughesd0905142016-03-13 09:46:49 +0000187
Richard Hughes57d18222017-01-10 16:02:59 +0000188/**
189 * fu_plugin_cache_add:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100190 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000191 * @id: the key
192 * @dev: a #GObject, typically a #FuDevice
193 *
194 * Adds an object to the per-plugin cache.
195 *
196 * Since: 0.8.0
197 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000198void
Richard Hughes12724852018-09-04 13:53:44 +0100199fu_plugin_cache_add (FuPlugin *self, const gchar *id, gpointer dev)
Richard Hughescff38bc2016-12-12 12:03:37 +0000200{
Richard Hughes12724852018-09-04 13:53:44 +0100201 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes161e9b52019-06-12 14:22:45 +0100202 g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_writer_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100203 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000204 g_return_if_fail (id != NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100205 g_return_if_fail (locker != NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000206 g_hash_table_insert (priv->devices, g_strdup (id), g_object_ref (dev));
207}
208
Richard Hughes57d18222017-01-10 16:02:59 +0000209/**
210 * fu_plugin_cache_remove:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100211 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000212 * @id: the key
213 *
214 * Removes an object from the per-plugin cache.
215 *
216 * Since: 0.8.0
217 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000218void
Richard Hughes12724852018-09-04 13:53:44 +0100219fu_plugin_cache_remove (FuPlugin *self, const gchar *id)
Richard Hughescff38bc2016-12-12 12:03:37 +0000220{
Richard Hughes12724852018-09-04 13:53:44 +0100221 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes161e9b52019-06-12 14:22:45 +0100222 g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_writer_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100223 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000224 g_return_if_fail (id != NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100225 g_return_if_fail (locker != NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000226 g_hash_table_remove (priv->devices, id);
227}
228
Richard Hughes57d18222017-01-10 16:02:59 +0000229/**
230 * fu_plugin_get_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100231 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000232 *
Richard Hughes4eada342017-10-03 21:20:32 +0100233 * Gets the per-plugin allocated private data. This will return %NULL unless
234 * fu_plugin_alloc_data() has been called by the plugin.
Richard Hughes57d18222017-01-10 16:02:59 +0000235 *
Richard Hughes4eada342017-10-03 21:20:32 +0100236 * Returns: (transfer none): a pointer to a structure, or %NULL for unset.
Richard Hughes57d18222017-01-10 16:02:59 +0000237 *
238 * Since: 0.8.0
239 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000240FuPluginData *
Richard Hughes12724852018-09-04 13:53:44 +0100241fu_plugin_get_data (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +0000242{
Richard Hughes12724852018-09-04 13:53:44 +0100243 FuPluginPrivate *priv = GET_PRIVATE (self);
244 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000245 return priv->data;
246}
247
Richard Hughes57d18222017-01-10 16:02:59 +0000248/**
249 * fu_plugin_alloc_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100250 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000251 * @data_sz: the size to allocate
252 *
253 * Allocates the per-plugin allocated private data.
254 *
255 * Returns: (transfer full): a pointer to a structure, or %NULL for unset.
256 *
257 * Since: 0.8.0
258 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000259FuPluginData *
Richard Hughes12724852018-09-04 13:53:44 +0100260fu_plugin_alloc_data (FuPlugin *self, gsize data_sz)
Richard Hughescff38bc2016-12-12 12:03:37 +0000261{
Richard Hughes12724852018-09-04 13:53:44 +0100262 FuPluginPrivate *priv = GET_PRIVATE (self);
263 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes44dee882017-01-11 08:31:10 +0000264 if (priv->data != NULL) {
265 g_critical ("fu_plugin_alloc_data() already used by plugin");
266 return priv->data;
267 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000268 priv->data = g_malloc0 (data_sz);
269 return priv->data;
Richard Hughesd0905142016-03-13 09:46:49 +0000270}
271
Richard Hughes57d18222017-01-10 16:02:59 +0000272/**
273 * fu_plugin_get_usb_context:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100274 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000275 *
276 * Gets the shared USB context that all plugins can use.
277 *
278 * Returns: (transfer none): a #GUsbContext.
279 *
280 * Since: 0.8.0
281 **/
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000282GUsbContext *
Richard Hughes12724852018-09-04 13:53:44 +0100283fu_plugin_get_usb_context (FuPlugin *self)
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000284{
Richard Hughes12724852018-09-04 13:53:44 +0100285 FuPluginPrivate *priv = GET_PRIVATE (self);
286 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000287 return priv->usb_ctx;
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000288}
289
290void
Richard Hughes12724852018-09-04 13:53:44 +0100291fu_plugin_set_usb_context (FuPlugin *self, GUsbContext *usb_ctx)
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000292{
Richard Hughes12724852018-09-04 13:53:44 +0100293 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +0000294 g_set_object (&priv->usb_ctx, usb_ctx);
295}
296
Richard Hughes57d18222017-01-10 16:02:59 +0000297/**
298 * fu_plugin_get_enabled:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100299 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000300 *
Richard Hughes4eada342017-10-03 21:20:32 +0100301 * Returns if the plugin is enabled. Plugins may self-disable using
302 * fu_plugin_set_enabled() or can be disabled by the daemon.
Richard Hughes57d18222017-01-10 16:02:59 +0000303 *
304 * Returns: %TRUE if the plugin is currently enabled.
305 *
306 * Since: 0.8.0
307 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000308gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100309fu_plugin_get_enabled (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +0000310{
Richard Hughes12724852018-09-04 13:53:44 +0100311 FuPluginPrivate *priv = GET_PRIVATE (self);
312 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
Richard Hughescff38bc2016-12-12 12:03:37 +0000313 return priv->enabled;
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000314}
315
Richard Hughes57d18222017-01-10 16:02:59 +0000316/**
317 * fu_plugin_set_enabled:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100318 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000319 * @enabled: the enabled value
320 *
321 * Enables or disables a plugin. Plugins can self-disable at any point.
322 *
323 * Since: 0.8.0
324 **/
Richard Hughesd0905142016-03-13 09:46:49 +0000325void
Richard Hughes12724852018-09-04 13:53:44 +0100326fu_plugin_set_enabled (FuPlugin *self, gboolean enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000327{
Richard Hughes12724852018-09-04 13:53:44 +0100328 FuPluginPrivate *priv = GET_PRIVATE (self);
329 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughescff38bc2016-12-12 12:03:37 +0000330 priv->enabled = enabled;
331}
332
Richard Hughes1e456bc2018-05-10 20:16:16 +0100333gchar *
334fu_plugin_guess_name_from_fn (const gchar *filename)
335{
336 const gchar *prefix = "libfu_plugin_";
337 gchar *name;
338 gchar *str = g_strstr_len (filename, -1, prefix);
339 if (str == NULL)
340 return NULL;
341 name = g_strdup (str + strlen (prefix));
342 g_strdelimit (name, ".", '\0');
343 return name;
344}
345
Richard Hughescff38bc2016-12-12 12:03:37 +0000346gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100347fu_plugin_open (FuPlugin *self, const gchar *filename, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +0000348{
Richard Hughes12724852018-09-04 13:53:44 +0100349 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +0000350 FuPluginInitFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000351
352 priv->module = g_module_open (filename, 0);
353 if (priv->module == NULL) {
354 g_set_error (error,
355 G_IO_ERROR,
356 G_IO_ERROR_FAILED,
357 "failed to open plugin: %s",
358 g_module_error ());
359 return FALSE;
360 }
361
362 /* set automatically */
Richard Hughes1e456bc2018-05-10 20:16:16 +0100363 if (priv->name == NULL)
364 priv->name = fu_plugin_guess_name_from_fn (filename);
Richard Hughesd0905142016-03-13 09:46:49 +0000365
366 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000367 g_module_symbol (priv->module, "fu_plugin_init", (gpointer *) &func);
368 if (func != NULL) {
369 g_debug ("performing init() on %s", filename);
Richard Hughes12724852018-09-04 13:53:44 +0100370 func (self);
Richard Hughesd0905142016-03-13 09:46:49 +0000371 }
372
Richard Hughescff38bc2016-12-12 12:03:37 +0000373 return TRUE;
374}
375
Richard Hughes57d18222017-01-10 16:02:59 +0000376/**
377 * fu_plugin_device_add:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100378 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000379 * @device: A #FuDevice
380 *
381 * Asks the daemon to add a device to the exported list. If this device ID
382 * has already been added by a different plugin then this request will be
383 * ignored.
384 *
385 * Plugins should use fu_plugin_device_add_delay() if they are not capable of
386 * actually flashing an image to the hardware so that higher-priority plugins
387 * can add the device themselves.
388 *
389 * Since: 0.8.0
390 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000391void
Richard Hughes12724852018-09-04 13:53:44 +0100392fu_plugin_device_add (FuPlugin *self, FuDevice *device)
Richard Hughescff38bc2016-12-12 12:03:37 +0000393{
Richard Hughes5e447292018-04-27 14:25:54 +0100394 GPtrArray *children;
Richard Hughesc125ec02018-09-05 19:35:17 +0100395 g_autoptr(GError) error = NULL;
Richard Hughes5e447292018-04-27 14:25:54 +0100396
Richard Hughes12724852018-09-04 13:53:44 +0100397 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000398 g_return_if_fail (FU_IS_DEVICE (device));
399
Richard Hughesc125ec02018-09-05 19:35:17 +0100400 /* ensure the device ID is set from the physical and logical IDs */
401 if (!fu_device_ensure_id (device, &error)) {
402 g_warning ("ignoring add: %s", error->message);
403 return;
404 }
405
Richard Hughescff38bc2016-12-12 12:03:37 +0000406 g_debug ("emit added from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100407 fu_plugin_get_name (self),
Richard Hughescff38bc2016-12-12 12:03:37 +0000408 fu_device_get_id (device));
409 fu_device_set_created (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
Richard Hughes12724852018-09-04 13:53:44 +0100410 fu_device_set_plugin (device, fu_plugin_get_name (self));
411 g_signal_emit (self, signals[SIGNAL_DEVICE_ADDED], 0, device);
Richard Hughes5e447292018-04-27 14:25:54 +0100412
Richard Hughes128c0162018-08-10 11:00:29 +0100413 /* add children if they have not already been added */
Richard Hughes5e447292018-04-27 14:25:54 +0100414 children = fu_device_get_children (device);
415 for (guint i = 0; i < children->len; i++) {
416 FuDevice *child = g_ptr_array_index (children, i);
Richard Hughes128c0162018-08-10 11:00:29 +0100417 if (fu_device_get_created (child) == 0)
Richard Hughes12724852018-09-04 13:53:44 +0100418 fu_plugin_device_add (self, child);
Richard Hughes5e447292018-04-27 14:25:54 +0100419 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000420}
421
Richard Hughese1fd34d2017-08-24 14:19:51 +0100422/**
423 * fu_plugin_device_register:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100424 * @self: A #FuPlugin
Richard Hughese1fd34d2017-08-24 14:19:51 +0100425 * @device: A #FuDevice
426 *
427 * Registers the device with other plugins so they can set metadata.
428 *
429 * Plugins do not have to call this manually as this is done automatically
430 * when using fu_plugin_device_add(). They may wish to use this manually
431 * if for intance the coldplug should be ignored based on the metadata
432 * set from other plugins.
433 *
434 * Since: 0.9.7
435 **/
436void
Richard Hughes12724852018-09-04 13:53:44 +0100437fu_plugin_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +0100438{
Richard Hughesc125ec02018-09-05 19:35:17 +0100439 g_autoptr(GError) error = NULL;
440
Richard Hughes12724852018-09-04 13:53:44 +0100441 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughese1fd34d2017-08-24 14:19:51 +0100442 g_return_if_fail (FU_IS_DEVICE (device));
443
Richard Hughesc125ec02018-09-05 19:35:17 +0100444 /* ensure the device ID is set from the physical and logical IDs */
445 if (!fu_device_ensure_id (device, &error)) {
446 g_warning ("ignoring registration: %s", error->message);
447 return;
448 }
449
Richard Hughese1fd34d2017-08-24 14:19:51 +0100450 g_debug ("emit device-register from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100451 fu_plugin_get_name (self),
Richard Hughese1fd34d2017-08-24 14:19:51 +0100452 fu_device_get_id (device));
Richard Hughes12724852018-09-04 13:53:44 +0100453 g_signal_emit (self, signals[SIGNAL_DEVICE_REGISTER], 0, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +0100454}
455
Richard Hughes57d18222017-01-10 16:02:59 +0000456/**
Richard Hughes4eada342017-10-03 21:20:32 +0100457 * fu_plugin_device_remove:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100458 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000459 * @device: A #FuDevice
460 *
461 * Asks the daemon to remove a device from the exported list.
462 *
463 * Since: 0.8.0
464 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000465void
Richard Hughes12724852018-09-04 13:53:44 +0100466fu_plugin_device_remove (FuPlugin *self, FuDevice *device)
Richard Hughescff38bc2016-12-12 12:03:37 +0000467{
Richard Hughes12724852018-09-04 13:53:44 +0100468 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000469 g_return_if_fail (FU_IS_DEVICE (device));
470
Richard Hughescff38bc2016-12-12 12:03:37 +0000471 g_debug ("emit removed from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100472 fu_plugin_get_name (self),
Richard Hughescff38bc2016-12-12 12:03:37 +0000473 fu_device_get_id (device));
Richard Hughes12724852018-09-04 13:53:44 +0100474 g_signal_emit (self, signals[SIGNAL_DEVICE_REMOVED], 0, device);
Richard Hughescff38bc2016-12-12 12:03:37 +0000475}
476
Richard Hughes57d18222017-01-10 16:02:59 +0000477/**
Richard Hughes2de8f132018-01-17 09:12:02 +0000478 * fu_plugin_request_recoldplug:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100479 * @self: A #FuPlugin
Richard Hughes362d6d72017-01-07 21:42:14 +0000480 *
481 * Ask all the plugins to coldplug all devices, which will include the prepare()
482 * and cleanup() phases. Duplicate devices added will be ignored.
483 *
484 * Since: 0.8.0
485 **/
486void
Richard Hughes12724852018-09-04 13:53:44 +0100487fu_plugin_request_recoldplug (FuPlugin *self)
Richard Hughes362d6d72017-01-07 21:42:14 +0000488{
Richard Hughes12724852018-09-04 13:53:44 +0100489 g_return_if_fail (FU_IS_PLUGIN (self));
490 g_signal_emit (self, signals[SIGNAL_RECOLDPLUG], 0);
Richard Hughes362d6d72017-01-07 21:42:14 +0000491}
492
Richard Hughesb0829032017-01-10 09:27:08 +0000493/**
Richard Hughesb8f8db22017-04-25 15:56:00 +0100494 * fu_plugin_check_hwid:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100495 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100496 * @hwid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
Richard Hughesb8f8db22017-04-25 15:56:00 +0100497 *
Richard Hughesd7704d42017-08-08 20:29:09 +0100498 * Checks to see if a specific GUID exists. All hardware IDs on a
Richard Hughesb8f8db22017-04-25 15:56:00 +0100499 * specific system can be shown using the `fwupdmgr hwids` command.
500 *
Richard Hughes4eada342017-10-03 21:20:32 +0100501 * Returns: %TRUE if the HwId is found on the system.
502 *
Richard Hughesb8f8db22017-04-25 15:56:00 +0100503 * Since: 0.9.1
504 **/
505gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100506fu_plugin_check_hwid (FuPlugin *self, const gchar *hwid)
Richard Hughesb8f8db22017-04-25 15:56:00 +0100507{
Richard Hughes12724852018-09-04 13:53:44 +0100508 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100509 if (priv->hwids == NULL)
510 return FALSE;
Richard Hughesd7704d42017-08-08 20:29:09 +0100511 return fu_hwids_has_guid (priv->hwids, hwid);
512}
513
514/**
Patrick Rudolpha60b5472019-10-16 10:43:03 +0200515 * fu_plugin_get_hwid_replace_value:
516 * @self: A #FuPlugin
517 * @keys: A key, e.g. `HardwareID-3` or %FU_HWIDS_KEY_PRODUCT_SKU
518 * @error: A #GError or %NULL
519 *
520 * Gets the replacement value for a specific key. All hardware IDs on a
521 * specific system can be shown using the `fwupdmgr hwids` command.
522 *
523 * Returns: (transfer full): a string, or %NULL for error.
524 *
525 * Since: 1.3.3
526 **/
527gchar *
528fu_plugin_get_hwid_replace_value (FuPlugin *self, const gchar *keys, GError **error)
529{
530 FuPluginPrivate *priv = GET_PRIVATE (self);
531 if (priv->hwids == NULL)
532 return NULL;
533
534 return fu_hwids_get_replace_values (priv->hwids, keys, error);
535}
536
537/**
Richard Hughes69a5f352018-08-08 11:58:15 +0100538 * fu_plugin_get_hwids:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100539 * @self: A #FuPlugin
Richard Hughes69a5f352018-08-08 11:58:15 +0100540 *
541 * Returns all the HWIDs defined in the system. All hardware IDs on a
542 * specific system can be shown using the `fwupdmgr hwids` command.
543 *
544 * Returns: (transfer none) (element-type utf-8): An array of GUIDs
545 *
546 * Since: 1.1.1
547 **/
548GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +0100549fu_plugin_get_hwids (FuPlugin *self)
Richard Hughes69a5f352018-08-08 11:58:15 +0100550{
Richard Hughes12724852018-09-04 13:53:44 +0100551 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes69a5f352018-08-08 11:58:15 +0100552 if (priv->hwids == NULL)
553 return NULL;
554 return fu_hwids_get_guids (priv->hwids);
555}
556
557/**
Richard Hughes19841802019-09-10 16:48:00 +0100558 * fu_plugin_has_custom_flag:
559 * @self: A #FuPlugin
560 * @flag: A custom text flag, specific to the plugin, e.g. `uefi-force-enable`
561 *
562 * Returns if a per-plugin HwId custom flag exists, typically added from a DMI quirk.
563 *
564 * Returns: %TRUE if the quirk entry exists
565 *
566 * Since: 1.3.1
567 **/
568gboolean
569fu_plugin_has_custom_flag (FuPlugin *self, const gchar *flag)
570{
571 FuPluginPrivate *priv = GET_PRIVATE (self);
572 GPtrArray *hwids = fu_plugin_get_hwids (self);
573
574 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
575 g_return_val_if_fail (flag != NULL, FALSE);
576
577 /* never set up, e.g. in tests */
578 if (hwids == NULL)
579 return FALSE;
580
581 /* search each hwid */
582 for (guint i = 0; i < hwids->len; i++) {
583 const gchar *hwid = g_ptr_array_index (hwids, i);
584 const gchar *value;
585 g_autofree gchar *key = g_strdup_printf ("HwId=%s", hwid);
586
587 /* does prefixed quirk exist */
588 value = fu_quirks_lookup_by_id (priv->quirks, key, FU_QUIRKS_FLAGS);
589 if (value != NULL) {
590 g_auto(GStrv) quirks = g_strsplit (value, ",", -1);
591 if (g_strv_contains ((const gchar * const *) quirks, flag))
592 return TRUE;
593 }
594 }
595 return FALSE;
596}
597
598/**
Richard Hughes1354ea92017-09-19 15:58:31 +0100599 * fu_plugin_check_supported:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100600 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100601 * @guid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
Richard Hughes1354ea92017-09-19 15:58:31 +0100602 *
603 * Checks to see if a specific device GUID is supported, i.e. available in the
604 * AppStream metadata.
605 *
Richard Hughes4eada342017-10-03 21:20:32 +0100606 * Returns: %TRUE if the device is supported.
607 *
Richard Hughes1354ea92017-09-19 15:58:31 +0100608 * Since: 1.0.0
609 **/
Richard Hughesd8a8d5e2019-10-08 13:05:02 +0100610static gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100611fu_plugin_check_supported (FuPlugin *self, const gchar *guid)
Richard Hughes1354ea92017-09-19 15:58:31 +0100612{
Richard Hughesaabdc372018-11-14 10:11:08 +0000613 gboolean retval = FALSE;
614 g_signal_emit (self, signals[SIGNAL_CHECK_SUPPORTED], 0, guid, &retval);
615 return retval;
Richard Hughes1354ea92017-09-19 15:58:31 +0100616}
617
618/**
Richard Hughesd7704d42017-08-08 20:29:09 +0100619 * fu_plugin_get_dmi_value:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100620 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100621 * @dmi_id: A DMI ID, e.g. `BiosVersion`
Richard Hughesd7704d42017-08-08 20:29:09 +0100622 *
623 * Gets a hardware DMI value.
624 *
Richard Hughes4eada342017-10-03 21:20:32 +0100625 * Returns: The string, or %NULL
626 *
Richard Hughesd7704d42017-08-08 20:29:09 +0100627 * Since: 0.9.7
628 **/
629const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100630fu_plugin_get_dmi_value (FuPlugin *self, const gchar *dmi_id)
Richard Hughesd7704d42017-08-08 20:29:09 +0100631{
Richard Hughes12724852018-09-04 13:53:44 +0100632 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd7704d42017-08-08 20:29:09 +0100633 if (priv->hwids == NULL)
Richard Hughes7ef96b82017-08-23 18:28:24 +0100634 return NULL;
Richard Hughesd7704d42017-08-08 20:29:09 +0100635 return fu_hwids_get_value (priv->hwids, dmi_id);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100636}
637
Richard Hughes49e5e052017-09-03 12:15:41 +0100638/**
639 * fu_plugin_get_smbios_string:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100640 * @self: A #FuPlugin
Richard Hughes49e5e052017-09-03 12:15:41 +0100641 * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
642 * @offset: A SMBIOS offset
643 *
644 * Gets a hardware SMBIOS string.
645 *
646 * The @type and @offset can be referenced from the DMTF SMBIOS specification:
647 * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.1.1.pdf
648 *
Richard Hughes4eada342017-10-03 21:20:32 +0100649 * Returns: A string, or %NULL
650 *
Richard Hughes49e5e052017-09-03 12:15:41 +0100651 * Since: 0.9.8
652 **/
653const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100654fu_plugin_get_smbios_string (FuPlugin *self, guint8 structure_type, guint8 offset)
Richard Hughes49e5e052017-09-03 12:15:41 +0100655{
Richard Hughes12724852018-09-04 13:53:44 +0100656 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100657 if (priv->smbios == NULL)
658 return NULL;
659 return fu_smbios_get_string (priv->smbios, structure_type, offset, NULL);
660}
661
662/**
663 * fu_plugin_get_smbios_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100664 * @self: A #FuPlugin
Richard Hughes49e5e052017-09-03 12:15:41 +0100665 * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
666 *
667 * Gets a hardware SMBIOS data.
668 *
Richard Hughesdfaca2d2019-08-01 08:08:03 +0100669 * Returns: (transfer full): A #GBytes, or %NULL
Richard Hughes4eada342017-10-03 21:20:32 +0100670 *
Richard Hughes49e5e052017-09-03 12:15:41 +0100671 * Since: 0.9.8
672 **/
673GBytes *
Richard Hughes12724852018-09-04 13:53:44 +0100674fu_plugin_get_smbios_data (FuPlugin *self, guint8 structure_type)
Richard Hughes49e5e052017-09-03 12:15:41 +0100675{
Richard Hughes12724852018-09-04 13:53:44 +0100676 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100677 if (priv->smbios == NULL)
678 return NULL;
679 return fu_smbios_get_data (priv->smbios, structure_type, NULL);
680}
681
Richard Hughesb8f8db22017-04-25 15:56:00 +0100682void
Richard Hughes12724852018-09-04 13:53:44 +0100683fu_plugin_set_hwids (FuPlugin *self, FuHwids *hwids)
Richard Hughesb8f8db22017-04-25 15:56:00 +0100684{
Richard Hughes12724852018-09-04 13:53:44 +0100685 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd7704d42017-08-08 20:29:09 +0100686 g_set_object (&priv->hwids, hwids);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100687}
688
Richard Hughes49e5e052017-09-03 12:15:41 +0100689void
Richard Hughes12724852018-09-04 13:53:44 +0100690fu_plugin_set_udev_subsystems (FuPlugin *self, GPtrArray *udev_subsystems)
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100691{
Richard Hughes12724852018-09-04 13:53:44 +0100692 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100693 if (priv->udev_subsystems != NULL)
694 g_ptr_array_unref (priv->udev_subsystems);
695 priv->udev_subsystems = g_ptr_array_ref (udev_subsystems);
696}
697
698void
Richard Hughes12724852018-09-04 13:53:44 +0100699fu_plugin_set_quirks (FuPlugin *self, FuQuirks *quirks)
Richard Hughes9c028f02017-10-28 21:14:28 +0100700{
Richard Hughes12724852018-09-04 13:53:44 +0100701 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9c028f02017-10-28 21:14:28 +0100702 g_set_object (&priv->quirks, quirks);
703}
704
705/**
706 * fu_plugin_get_quirks:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100707 * @self: A #FuPlugin
Richard Hughes9c028f02017-10-28 21:14:28 +0100708 *
709 * Returns the hardware database object. This can be used to discover device
710 * quirks or other device-specific settings.
711 *
712 * Returns: (transfer none): a #FuQuirks, or %NULL if not set
713 *
714 * Since: 1.0.1
715 **/
716FuQuirks *
Richard Hughes12724852018-09-04 13:53:44 +0100717fu_plugin_get_quirks (FuPlugin *self)
Richard Hughes9c028f02017-10-28 21:14:28 +0100718{
Richard Hughes12724852018-09-04 13:53:44 +0100719 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9c028f02017-10-28 21:14:28 +0100720 return priv->quirks;
721}
722
Richard Hughes0eb123b2018-04-19 12:00:04 +0100723void
Richard Hughes12724852018-09-04 13:53:44 +0100724fu_plugin_set_runtime_versions (FuPlugin *self, GHashTable *runtime_versions)
Richard Hughes0eb123b2018-04-19 12:00:04 +0100725{
Richard Hughes12724852018-09-04 13:53:44 +0100726 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0eb123b2018-04-19 12:00:04 +0100727 priv->runtime_versions = g_hash_table_ref (runtime_versions);
728}
729
730/**
731 * fu_plugin_add_runtime_version:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100732 * @self: A #FuPlugin
Richard Hughes0eb123b2018-04-19 12:00:04 +0100733 * @component_id: An AppStream component id, e.g. "org.gnome.Software"
734 * @version: A version string, e.g. "1.2.3"
735 *
Richard Hughesdce91202019-04-08 12:47:45 +0100736 * Sets a runtime version of a specific dependency.
Richard Hughes0eb123b2018-04-19 12:00:04 +0100737 *
738 * Since: 1.0.7
739 **/
740void
Richard Hughes12724852018-09-04 13:53:44 +0100741fu_plugin_add_runtime_version (FuPlugin *self,
Richard Hughes0eb123b2018-04-19 12:00:04 +0100742 const gchar *component_id,
743 const gchar *version)
744{
Richard Hughes12724852018-09-04 13:53:44 +0100745 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesb01b4862018-04-20 16:39:48 +0100746 if (priv->runtime_versions == NULL)
747 return;
Richard Hughes0eb123b2018-04-19 12:00:04 +0100748 g_hash_table_insert (priv->runtime_versions,
749 g_strdup (component_id),
750 g_strdup (version));
751}
752
Richard Hughes34e0dab2018-04-20 16:43:00 +0100753void
Richard Hughes12724852018-09-04 13:53:44 +0100754fu_plugin_set_compile_versions (FuPlugin *self, GHashTable *compile_versions)
Richard Hughes34e0dab2018-04-20 16:43:00 +0100755{
Richard Hughes12724852018-09-04 13:53:44 +0100756 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes34e0dab2018-04-20 16:43:00 +0100757 priv->compile_versions = g_hash_table_ref (compile_versions);
758}
759
760/**
761 * fu_plugin_add_compile_version:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100762 * @self: A #FuPlugin
Richard Hughes34e0dab2018-04-20 16:43:00 +0100763 * @component_id: An AppStream component id, e.g. "org.gnome.Software"
764 * @version: A version string, e.g. "1.2.3"
765 *
Richard Hughesdce91202019-04-08 12:47:45 +0100766 * Sets a compile-time version of a specific dependency.
Richard Hughes34e0dab2018-04-20 16:43:00 +0100767 *
768 * Since: 1.0.7
769 **/
770void
Richard Hughes12724852018-09-04 13:53:44 +0100771fu_plugin_add_compile_version (FuPlugin *self,
Richard Hughes34e0dab2018-04-20 16:43:00 +0100772 const gchar *component_id,
773 const gchar *version)
774{
Richard Hughes12724852018-09-04 13:53:44 +0100775 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes34e0dab2018-04-20 16:43:00 +0100776 if (priv->compile_versions == NULL)
777 return;
778 g_hash_table_insert (priv->compile_versions,
779 g_strdup (component_id),
780 g_strdup (version));
781}
782
Richard Hughes9c028f02017-10-28 21:14:28 +0100783/**
784 * fu_plugin_lookup_quirk_by_id:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100785 * @self: A #FuPlugin
Richard Hughes87fb9ff2018-06-28 12:55:59 +0100786 * @group: A string, e.g. "DfuFlags"
787 * @key: An ID to match the entry, e.g. "Summary"
Richard Hughes9c028f02017-10-28 21:14:28 +0100788 *
789 * Looks up an entry in the hardware database using a string value.
790 *
791 * Returns: (transfer none): values from the database, or %NULL if not found
792 *
793 * Since: 1.0.1
794 **/
795const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100796fu_plugin_lookup_quirk_by_id (FuPlugin *self, const gchar *group, const gchar *key)
Richard Hughes9c028f02017-10-28 21:14:28 +0100797{
Richard Hughes12724852018-09-04 13:53:44 +0100798 FuPluginPrivate *priv = GET_PRIVATE (self);
799 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes9c028f02017-10-28 21:14:28 +0100800
Richard Hughes9c028f02017-10-28 21:14:28 +0100801 /* exact ID */
Richard Hughes87fb9ff2018-06-28 12:55:59 +0100802 return fu_quirks_lookup_by_id (priv->quirks, group, key);
Richard Hughes9c028f02017-10-28 21:14:28 +0100803}
804
805/**
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100806 * fu_plugin_lookup_quirk_by_id_as_uint64:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100807 * @self: A #FuPlugin
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100808 * @group: A string, e.g. "DfuFlags"
809 * @key: An ID to match the entry, e.g. "Size"
810 *
811 * Looks up an entry in the hardware database using a string key, returning
812 * an integer value. Values are assumed base 10, unless prefixed with "0x"
813 * where they are parsed as base 16.
814 *
815 * Returns: (transfer none): value from the database, or 0 if not found
816 *
817 * Since: 1.1.2
818 **/
819guint64
Richard Hughes12724852018-09-04 13:53:44 +0100820fu_plugin_lookup_quirk_by_id_as_uint64 (FuPlugin *self, const gchar *group, const gchar *key)
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100821{
Richard Hughes12724852018-09-04 13:53:44 +0100822 return fu_common_strtoull (fu_plugin_lookup_quirk_by_id (self, group, key));
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100823}
824
Richard Hughes1354ea92017-09-19 15:58:31 +0100825void
Richard Hughes12724852018-09-04 13:53:44 +0100826fu_plugin_set_smbios (FuPlugin *self, FuSmbios *smbios)
Richard Hughes49e5e052017-09-03 12:15:41 +0100827{
Richard Hughes12724852018-09-04 13:53:44 +0100828 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100829 g_set_object (&priv->smbios, smbios);
830}
831
Richard Hughesb8f8db22017-04-25 15:56:00 +0100832/**
Richard Hughesb0829032017-01-10 09:27:08 +0000833 * fu_plugin_set_coldplug_delay:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100834 * @self: A #FuPlugin
Richard Hughesb0829032017-01-10 09:27:08 +0000835 * @duration: A delay in milliseconds
836 *
837 * Set the minimum time that should be waited inbetween the call to
838 * fu_plugin_coldplug_prepare() and fu_plugin_coldplug(). This is usually going
839 * to be the minimum hardware initialisation time from a datasheet.
840 *
841 * It is better to use this function rather than using a sleep() in the plugin
842 * itself as then only one delay is done in the daemon rather than waiting for
843 * each coldplug prepare in a serial way.
844 *
845 * Additionally, very long delays should be avoided as the daemon will be
846 * blocked from processing requests whilst the coldplug delay is being
847 * performed.
848 *
849 * Since: 0.8.0
850 **/
851void
Richard Hughes12724852018-09-04 13:53:44 +0100852fu_plugin_set_coldplug_delay (FuPlugin *self, guint duration)
Richard Hughesb0829032017-01-10 09:27:08 +0000853{
Richard Hughes12724852018-09-04 13:53:44 +0100854 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesb0829032017-01-10 09:27:08 +0000855 g_return_if_fail (duration > 0);
856
857 /* check sanity */
858 if (duration > FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM) {
859 g_warning ("duration of %ums is crazy, truncating to %ums",
860 duration,
861 FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM);
862 duration = FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM;
863 }
864
865 /* emit */
Richard Hughes12724852018-09-04 13:53:44 +0100866 g_signal_emit (self, signals[SIGNAL_SET_COLDPLUG_DELAY], 0, duration);
Richard Hughesb0829032017-01-10 09:27:08 +0000867}
868
Richard Hughes4b303802019-10-04 13:22:51 +0100869static gboolean
870fu_plugin_device_attach (FuPlugin *self, FuDevice *device, GError **error)
871{
872 g_autoptr(FuDeviceLocker) locker = NULL;
873 if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) {
874 g_debug ("already in runtime mode, skipping");
875 return TRUE;
876 }
877 locker = fu_device_locker_new (device, error);
878 if (locker == NULL)
879 return FALSE;
880 return fu_device_attach (device, error);
881}
882
883static gboolean
884fu_plugin_device_detach (FuPlugin *self, FuDevice *device, GError **error)
885{
886 g_autoptr(FuDeviceLocker) locker = NULL;
887 if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) {
888 g_debug ("already in bootloader mode, skipping");
889 return TRUE;
890 }
891 locker = fu_device_locker_new (device, error);
892 if (locker == NULL)
893 return FALSE;
894 return fu_device_detach (device, error);
895}
896
897static gboolean
Richard Hughes4b303802019-10-04 13:22:51 +0100898fu_plugin_device_activate (FuPlugin *self, FuDevice *device, GError **error)
899{
900 g_autoptr(FuDeviceLocker) locker = NULL;
901 locker = fu_device_locker_new (device, error);
902 if (locker == NULL)
903 return FALSE;
904 return fu_device_activate (device, error);
905}
906
907static gboolean
908fu_plugin_device_write_firmware (FuPlugin *self, FuDevice *device,
909 GBytes *fw, FwupdInstallFlags flags,
910 GError **error)
911{
912 g_autoptr(FuDeviceLocker) locker = NULL;
913 locker = fu_device_locker_new (device, error);
914 if (locker == NULL)
915 return FALSE;
916 return fu_device_write_firmware (device, fw, flags, error);
917}
918
Richard Hughes7f677212019-10-05 16:19:40 +0100919static gboolean
920fu_plugin_device_read_firmware (FuPlugin *self, FuDevice *device, GError **error)
921{
922 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughesf0eb0912019-10-10 11:37:22 +0100923 g_autoptr(FuFirmware) firmware = NULL;
Richard Hughes7f677212019-10-05 16:19:40 +0100924 g_autoptr(GBytes) fw = NULL;
925 GChecksumType checksum_types[] = {
926 G_CHECKSUM_SHA1,
927 G_CHECKSUM_SHA256,
928 0 };
929 locker = fu_device_locker_new (device, error);
930 if (locker == NULL)
931 return FALSE;
932 if (!fu_device_detach (device, error))
933 return FALSE;
Richard Hughesf0eb0912019-10-10 11:37:22 +0100934 firmware = fu_device_read_firmware (device, error);
935 if (firmware == NULL) {
936 g_autoptr(GError) error_local = NULL;
937 if (!fu_device_attach (device, &error_local))
938 g_debug ("ignoring attach failure: %s", error_local->message);
939 g_prefix_error (error, "failed to read firmware: ");
940 return FALSE;
941 }
942 fw = fu_firmware_write (firmware, error);
Richard Hughes7f677212019-10-05 16:19:40 +0100943 if (fw == NULL) {
944 g_autoptr(GError) error_local = NULL;
945 if (!fu_device_attach (device, &error_local))
Richard Hughesf0eb0912019-10-10 11:37:22 +0100946 g_debug ("ignoring attach failure: %s", error_local->message);
947 g_prefix_error (error, "failed to write firmware: ");
Richard Hughes7f677212019-10-05 16:19:40 +0100948 return FALSE;
949 }
950 for (guint i = 0; checksum_types[i] != 0; i++) {
951 g_autofree gchar *hash = NULL;
952 hash = g_compute_checksum_for_bytes (checksum_types[i], fw);
953 fu_device_add_checksum (device, hash);
954 }
955 return fu_device_attach (device, error);
956}
957
Richard Hughesd0905142016-03-13 09:46:49 +0000958gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100959fu_plugin_runner_startup (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +0000960{
Richard Hughes12724852018-09-04 13:53:44 +0100961 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000962 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +0000963 g_autoptr(GError) error_local = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +0000964
965 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +0000966 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000967 return TRUE;
968
Richard Hughes639da472018-01-06 22:35:04 +0000969 /* no object loaded */
970 if (priv->module == NULL)
971 return TRUE;
972
Richard Hughesd0905142016-03-13 09:46:49 +0000973 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000974 g_module_symbol (priv->module, "fu_plugin_startup", (gpointer *) &func);
975 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +0000976 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +0000977 g_debug ("performing startup() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +0000978 if (!func (self, &error_local)) {
979 if (error_local == NULL) {
980 g_critical ("unset error in plugin %s for startup()",
981 priv->name);
982 g_set_error_literal (&error_local,
983 FWUPD_ERROR,
984 FWUPD_ERROR_INTERNAL,
985 "unspecified error");
986 }
987 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
988 "failed to startup using %s: ",
989 priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +0000990 return FALSE;
991 }
992 return TRUE;
993}
994
995static gboolean
996fu_plugin_runner_offline_invalidate (GError **error)
997{
998 g_autoptr(GError) error_local = NULL;
999 g_autoptr(GFile) file1 = NULL;
1000
1001 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1002
1003 file1 = g_file_new_for_path (FU_OFFLINE_TRIGGER_FILENAME);
1004 if (!g_file_query_exists (file1, NULL))
1005 return TRUE;
1006 if (!g_file_delete (file1, NULL, &error_local)) {
1007 g_set_error (error,
1008 FWUPD_ERROR,
1009 FWUPD_ERROR_INTERNAL,
1010 "Cannot delete %s: %s",
1011 FU_OFFLINE_TRIGGER_FILENAME,
1012 error_local->message);
1013 return FALSE;
1014 }
1015 return TRUE;
1016}
1017
1018static gboolean
1019fu_plugin_runner_offline_setup (GError **error)
1020{
1021 gint rc;
Richard Hughes484ee292019-03-22 16:10:50 +00001022 g_autofree gchar *filename = NULL;
Mario Limoncielloe1b4b202019-04-30 10:01:19 -05001023 g_autofree gchar *symlink_target = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG);
Richard Hughescff38bc2016-12-12 12:03:37 +00001024
1025 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1026
Richard Hughes484ee292019-03-22 16:10:50 +00001027 /* does already exist */
1028 filename = fu_common_realpath (FU_OFFLINE_TRIGGER_FILENAME, NULL);
1029 if (g_strcmp0 (filename, symlink_target) == 0) {
1030 g_debug ("%s already points to %s, skipping creation",
1031 FU_OFFLINE_TRIGGER_FILENAME, symlink_target);
1032 return TRUE;
1033 }
1034
Richard Hughescff38bc2016-12-12 12:03:37 +00001035 /* create symlink for the systemd-system-update-generator */
Richard Hughes484ee292019-03-22 16:10:50 +00001036 rc = symlink (symlink_target, FU_OFFLINE_TRIGGER_FILENAME);
Richard Hughescff38bc2016-12-12 12:03:37 +00001037 if (rc < 0) {
1038 g_set_error (error,
1039 FWUPD_ERROR,
1040 FWUPD_ERROR_INTERNAL,
1041 "Failed to create symlink %s to %s: %s",
1042 FU_OFFLINE_TRIGGER_FILENAME,
1043 "/var/lib", strerror (errno));
Richard Hughesd0905142016-03-13 09:46:49 +00001044 return FALSE;
1045 }
1046 return TRUE;
1047}
1048
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001049static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001050fu_plugin_runner_device_generic (FuPlugin *self, FuDevice *device,
Richard Hughes4b303802019-10-04 13:22:51 +01001051 const gchar *symbol_name,
1052 FuPluginDeviceFunc device_func,
1053 GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001054{
Richard Hughes12724852018-09-04 13:53:44 +01001055 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001056 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001057 g_autoptr(GError) error_local = NULL;
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001058
1059 /* not enabled */
1060 if (!priv->enabled)
1061 return TRUE;
1062
Richard Hughesd3d96cc2017-11-14 11:34:33 +00001063 /* no object loaded */
1064 if (priv->module == NULL)
1065 return TRUE;
1066
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001067 /* optional */
1068 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
Richard Hughes4b303802019-10-04 13:22:51 +01001069 if (func == NULL) {
1070 if (device_func != NULL) {
1071 g_debug ("running superclassed %s() on %s",
1072 symbol_name + 10, priv->name);
1073 return device_func (self, device, error);
1074 }
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001075 return TRUE;
Richard Hughes4b303802019-10-04 13:22:51 +01001076 }
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001077 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001078 if (!func (self, device, &error_local)) {
1079 if (error_local == NULL) {
1080 g_critical ("unset error in plugin %s for %s()",
1081 priv->name, symbol_name + 10);
1082 g_set_error_literal (&error_local,
1083 FWUPD_ERROR,
1084 FWUPD_ERROR_INTERNAL,
1085 "unspecified error");
1086 }
1087 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1088 "failed to %s using %s: ",
1089 symbol_name + 10, priv->name);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001090 return FALSE;
1091 }
1092 return TRUE;
1093}
1094
Richard Hughesdbd8c762018-06-15 20:31:40 +01001095static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001096fu_plugin_runner_flagged_device_generic (FuPlugin *self, FwupdInstallFlags flags,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001097 FuDevice *device,
1098 const gchar *symbol_name, GError **error)
1099{
Richard Hughes12724852018-09-04 13:53:44 +01001100 FuPluginPrivate *priv = GET_PRIVATE (self);
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001101 FuPluginFlaggedDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001102 g_autoptr(GError) error_local = NULL;
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001103
1104 /* not enabled */
1105 if (!priv->enabled)
1106 return TRUE;
1107
1108 /* no object loaded */
1109 if (priv->module == NULL)
1110 return TRUE;
1111
1112 /* optional */
1113 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1114 if (func == NULL)
1115 return TRUE;
1116 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001117 if (!func (self, flags, device, &error_local)) {
1118 if (error_local == NULL) {
1119 g_critical ("unset error in plugin %s for %s()",
1120 priv->name, symbol_name + 10);
1121 g_set_error_literal (&error_local,
1122 FWUPD_ERROR,
1123 FWUPD_ERROR_INTERNAL,
1124 "unspecified error");
1125 }
1126 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1127 "failed to %s using %s: ",
1128 symbol_name + 10, priv->name);
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001129 return FALSE;
1130 }
1131 return TRUE;
1132
1133}
1134
1135static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001136fu_plugin_runner_device_array_generic (FuPlugin *self, GPtrArray *devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001137 const gchar *symbol_name, GError **error)
1138{
Richard Hughes12724852018-09-04 13:53:44 +01001139 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesdbd8c762018-06-15 20:31:40 +01001140 FuPluginDeviceArrayFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001141 g_autoptr(GError) error_local = NULL;
Richard Hughesdbd8c762018-06-15 20:31:40 +01001142
1143 /* not enabled */
1144 if (!priv->enabled)
1145 return TRUE;
1146
1147 /* no object loaded */
1148 if (priv->module == NULL)
1149 return TRUE;
1150
1151 /* optional */
1152 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1153 if (func == NULL)
1154 return TRUE;
1155 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001156 if (!func (self, devices, &error_local)) {
1157 if (error_local == NULL) {
1158 g_critical ("unset error in plugin %s for %s()",
1159 priv->name, symbol_name + 10);
1160 g_set_error_literal (&error_local,
1161 FWUPD_ERROR,
1162 FWUPD_ERROR_INTERNAL,
1163 "unspecified error");
1164 }
1165 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1166 "failed to %s using %s: ",
1167 symbol_name + 10, priv->name);
Richard Hughesdbd8c762018-06-15 20:31:40 +01001168 return FALSE;
1169 }
1170 return TRUE;
1171}
1172
Richard Hughesd0905142016-03-13 09:46:49 +00001173gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001174fu_plugin_runner_coldplug (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00001175{
Richard Hughes12724852018-09-04 13:53:44 +01001176 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001177 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001178 g_autoptr(GError) error_local = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +00001179
1180 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +00001181 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +00001182 return TRUE;
1183
Richard Hughes639da472018-01-06 22:35:04 +00001184 /* no object loaded */
1185 if (priv->module == NULL)
1186 return TRUE;
1187
Richard Hughesd0905142016-03-13 09:46:49 +00001188 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00001189 g_module_symbol (priv->module, "fu_plugin_coldplug", (gpointer *) &func);
1190 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +00001191 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001192 g_debug ("performing coldplug() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001193 if (!func (self, &error_local)) {
1194 if (error_local == NULL) {
1195 g_critical ("unset error in plugin %s for coldplug()",
1196 priv->name);
1197 g_set_error_literal (&error_local,
1198 FWUPD_ERROR,
1199 FWUPD_ERROR_INTERNAL,
1200 "unspecified error");
1201 }
1202 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1203 "failed to coldplug using %s: ", priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00001204 return FALSE;
1205 }
1206 return TRUE;
1207}
1208
Richard Hughes7b8b2022016-12-12 16:15:03 +00001209gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001210fu_plugin_runner_recoldplug (FuPlugin *self, GError **error)
Richard Hughes2de8f132018-01-17 09:12:02 +00001211{
Richard Hughes12724852018-09-04 13:53:44 +01001212 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes2de8f132018-01-17 09:12:02 +00001213 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001214 g_autoptr(GError) error_local = NULL;
Richard Hughes2de8f132018-01-17 09:12:02 +00001215
1216 /* not enabled */
1217 if (!priv->enabled)
1218 return TRUE;
1219
1220 /* no object loaded */
1221 if (priv->module == NULL)
1222 return TRUE;
1223
1224 /* optional */
1225 g_module_symbol (priv->module, "fu_plugin_recoldplug", (gpointer *) &func);
1226 if (func == NULL)
1227 return TRUE;
1228 g_debug ("performing recoldplug() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001229 if (!func (self, &error_local)) {
1230 if (error_local == NULL) {
1231 g_critical ("unset error in plugin %s for recoldplug()",
1232 priv->name);
1233 g_set_error_literal (&error_local,
1234 FWUPD_ERROR,
1235 FWUPD_ERROR_INTERNAL,
1236 "unspecified error");
1237 }
1238 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1239 "failed to recoldplug using %s: ",
1240 priv->name);
Richard Hughes2de8f132018-01-17 09:12:02 +00001241 return FALSE;
1242 }
1243 return TRUE;
1244}
1245
1246gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001247fu_plugin_runner_coldplug_prepare (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001248{
Richard Hughes12724852018-09-04 13:53:44 +01001249 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001250 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001251 g_autoptr(GError) error_local = NULL;
Richard Hughes46487c92017-01-07 21:26:34 +00001252
1253 /* not enabled */
1254 if (!priv->enabled)
1255 return TRUE;
1256
Richard Hughes639da472018-01-06 22:35:04 +00001257 /* no object loaded */
1258 if (priv->module == NULL)
1259 return TRUE;
1260
Richard Hughes46487c92017-01-07 21:26:34 +00001261 /* optional */
1262 g_module_symbol (priv->module, "fu_plugin_coldplug_prepare", (gpointer *) &func);
1263 if (func == NULL)
1264 return TRUE;
1265 g_debug ("performing coldplug_prepare() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001266 if (!func (self, &error_local)) {
1267 if (error_local == NULL) {
1268 g_critical ("unset error in plugin %s for coldplug_prepare()",
1269 priv->name);
1270 g_set_error_literal (&error_local,
1271 FWUPD_ERROR,
1272 FWUPD_ERROR_INTERNAL,
1273 "unspecified error");
1274 }
1275 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1276 "failed to coldplug_prepare using %s: ",
1277 priv->name);
Richard Hughes46487c92017-01-07 21:26:34 +00001278 return FALSE;
1279 }
1280 return TRUE;
1281}
1282
1283gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001284fu_plugin_runner_coldplug_cleanup (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001285{
Richard Hughes12724852018-09-04 13:53:44 +01001286 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001287 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001288 g_autoptr(GError) error_local = NULL;
Richard Hughes46487c92017-01-07 21:26:34 +00001289
1290 /* not enabled */
1291 if (!priv->enabled)
1292 return TRUE;
1293
Richard Hughes639da472018-01-06 22:35:04 +00001294 /* no object loaded */
1295 if (priv->module == NULL)
1296 return TRUE;
1297
Richard Hughes46487c92017-01-07 21:26:34 +00001298 /* optional */
1299 g_module_symbol (priv->module, "fu_plugin_coldplug_cleanup", (gpointer *) &func);
1300 if (func == NULL)
1301 return TRUE;
1302 g_debug ("performing coldplug_cleanup() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001303 if (!func (self, &error_local)) {
1304 if (error_local == NULL) {
1305 g_critical ("unset error in plugin %s for coldplug_cleanup()",
1306 priv->name);
1307 g_set_error_literal (&error_local,
1308 FWUPD_ERROR,
1309 FWUPD_ERROR_INTERNAL,
1310 "unspecified error");
1311 }
1312 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1313 "failed to coldplug_cleanup using %s: ",
1314 priv->name);
Richard Hughes46487c92017-01-07 21:26:34 +00001315 return FALSE;
1316 }
1317 return TRUE;
1318}
1319
1320gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001321fu_plugin_runner_composite_prepare (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001322{
Richard Hughes12724852018-09-04 13:53:44 +01001323 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001324 "fu_plugin_composite_prepare",
1325 error);
1326}
1327
1328gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001329fu_plugin_runner_composite_cleanup (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001330{
Richard Hughes12724852018-09-04 13:53:44 +01001331 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001332 "fu_plugin_composite_cleanup",
1333 error);
1334}
1335
1336gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001337fu_plugin_runner_update_prepare (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001338 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001339{
Richard Hughes12724852018-09-04 13:53:44 +01001340 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001341 "fu_plugin_update_prepare",
1342 error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001343}
1344
1345gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001346fu_plugin_runner_update_cleanup (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001347 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001348{
Richard Hughes12724852018-09-04 13:53:44 +01001349 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001350 "fu_plugin_update_cleanup",
1351 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001352}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001353
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001354gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001355fu_plugin_runner_update_attach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001356{
Richard Hughes12724852018-09-04 13:53:44 +01001357 return fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001358 "fu_plugin_update_attach",
1359 fu_plugin_device_attach,
1360 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001361}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001362
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001363gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001364fu_plugin_runner_update_detach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001365{
Richard Hughes12724852018-09-04 13:53:44 +01001366 return fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001367 "fu_plugin_update_detach",
1368 fu_plugin_device_detach,
1369 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001370}
1371
1372gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001373fu_plugin_runner_update_reload (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001374{
Richard Hughes42f33df2019-10-05 20:52:33 +01001375 FuPluginPrivate *priv = GET_PRIVATE (self);
1376 g_autoptr(FuDeviceLocker) locker = NULL;
1377
1378 /* not enabled */
1379 if (!priv->enabled)
1380 return TRUE;
1381
1382 /* no object loaded */
1383 locker = fu_device_locker_new (device, error);
1384 if (locker == NULL)
1385 return FALSE;
1386 return fu_device_reload (device, error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001387}
1388
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001389/**
1390 * fu_plugin_add_udev_subsystem:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001391 * @self: a #FuPlugin
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001392 * @subsystem: a subsystem name, e.g. `pciport`
1393 *
1394 * Registers the udev subsystem to be watched by the daemon.
1395 *
1396 * Plugins can use this method only in fu_plugin_init()
1397 **/
1398void
Richard Hughes12724852018-09-04 13:53:44 +01001399fu_plugin_add_udev_subsystem (FuPlugin *self, const gchar *subsystem)
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001400{
Richard Hughes12724852018-09-04 13:53:44 +01001401 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001402 for (guint i = 0; i < priv->udev_subsystems->len; i++) {
1403 const gchar *subsystem_tmp = g_ptr_array_index (priv->udev_subsystems, i);
1404 if (g_strcmp0 (subsystem_tmp, subsystem) == 0)
1405 return;
1406 }
1407 g_debug ("added udev subsystem watch of %s", subsystem);
1408 g_ptr_array_add (priv->udev_subsystems, g_strdup (subsystem));
1409}
1410
Richard Hughes989acf12019-10-05 20:16:47 +01001411/**
1412 * fu_plugin_set_device_gtype:
1413 * @self: a #FuPlugin
1414 * @device_gtype: a #GType `FU_TYPE_DEVICE`
1415 *
1416 * Sets the device #GType which is used when creating devices.
1417 *
1418 * If this method is used then fu_plugin_usb_device_added() is not called, and
1419 * instead the object is created in the daemon for the plugin.
1420 *
1421 * Plugins can use this method only in fu_plugin_init()
1422 *
1423 * Since: 1.3.3
1424 **/
1425void
1426fu_plugin_set_device_gtype (FuPlugin *self, GType device_gtype)
1427{
1428 FuPluginPrivate *priv = GET_PRIVATE (self);
1429 priv->device_gtype = device_gtype;
1430}
1431
Richard Hughes95c98a92019-10-22 16:03:15 +01001432void
1433fu_plugin_add_firmware_gtype (FuPlugin *self, const gchar *id, GType gtype)
1434{
1435 g_signal_emit (self, signals[SIGNAL_ADD_FIRMWARE_GTYPE], 0, id, gtype);
1436}
1437
Richard Hughes989acf12019-10-05 20:16:47 +01001438static gboolean
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001439fu_plugin_check_supported_device (FuPlugin *self, FuDevice *device)
1440{
1441 GPtrArray *instance_ids = fu_device_get_instance_ids (device);
1442 for (guint i = 0; i < instance_ids->len; i++) {
1443 const gchar *instance_id = g_ptr_array_index (instance_ids, i);
1444 g_autofree gchar *guid = fwupd_guid_hash_string (instance_id);
1445 if (fu_plugin_check_supported (self, guid))
1446 return TRUE;
1447 }
1448 return FALSE;
1449}
1450
1451static gboolean
Richard Hughes989acf12019-10-05 20:16:47 +01001452fu_plugin_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error)
1453{
1454 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001455 GType device_gtype = fu_device_get_specialized_gtype (FU_DEVICE (device));
Richard Hughes989acf12019-10-05 20:16:47 +01001456 g_autoptr(FuDevice) dev = NULL;
1457 g_autoptr(FuDeviceLocker) locker = NULL;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001458
1459 /* fall back to plugin default */
1460 if (device_gtype == G_TYPE_INVALID)
1461 device_gtype = priv->device_gtype;
1462
1463 /* create new device and incorporate existing properties */
1464 dev = g_object_new (device_gtype, NULL);
1465 fu_device_incorporate (dev, FU_DEVICE (device));
1466
1467 /* there are a lot of different devices that match, but not all respond
1468 * well to opening -- so limit some ones with issued updates */
1469 if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_ONLY_SUPPORTED)) {
1470 if (!fu_device_probe (dev, error))
1471 return FALSE;
1472 fu_device_convert_instance_ids (dev);
1473 if (!fu_plugin_check_supported_device (self, dev)) {
1474 g_autofree gchar *guids = fu_device_get_guids_as_str (dev);
1475 g_debug ("%s has no updates, so ignoring device", guids);
1476 return TRUE;
1477 }
1478 }
1479
1480 /* open and add */
1481 locker = fu_device_locker_new (dev, error);
1482 if (locker == NULL)
1483 return FALSE;
1484 fu_plugin_device_add (self, dev);
1485 return TRUE;
1486}
1487
1488static gboolean
1489fu_plugin_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error)
1490{
1491 FuPluginPrivate *priv = GET_PRIVATE (self);
1492 GType device_gtype = fu_device_get_specialized_gtype (FU_DEVICE (device));
1493 g_autoptr(FuDevice) dev = NULL;
1494 g_autoptr(FuDeviceLocker) locker = NULL;
1495
1496 /* fall back to plugin default */
1497 if (device_gtype == G_TYPE_INVALID)
1498 device_gtype = priv->device_gtype;
1499
1500 /* create new device and incorporate existing properties */
1501 dev = g_object_new (device_gtype, NULL);
Richard Hughes989acf12019-10-05 20:16:47 +01001502 fu_device_incorporate (FU_DEVICE (dev), FU_DEVICE (device));
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001503
1504 /* there are a lot of different devices that match, but not all respond
1505 * well to opening -- so limit some ones with issued updates */
1506 if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_ONLY_SUPPORTED)) {
1507 if (!fu_device_probe (dev, error))
1508 return FALSE;
1509 fu_device_convert_instance_ids (dev);
1510 if (!fu_plugin_check_supported_device (self, dev)) {
1511 g_autofree gchar *guids = fu_device_get_guids_as_str (dev);
1512 g_debug ("%s has no updates, so ignoring device", guids);
1513 return TRUE;
1514 }
1515 }
1516
1517 /* open and add */
Richard Hughes989acf12019-10-05 20:16:47 +01001518 locker = fu_device_locker_new (dev, error);
1519 if (locker == NULL)
1520 return FALSE;
1521 fu_plugin_device_add (self, FU_DEVICE (dev));
1522 return TRUE;
1523}
1524
Richard Hughes104f6512017-11-24 11:44:57 +00001525gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001526fu_plugin_runner_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error)
Richard Hughes104f6512017-11-24 11:44:57 +00001527{
Richard Hughes12724852018-09-04 13:53:44 +01001528 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes104f6512017-11-24 11:44:57 +00001529 FuPluginUsbDeviceAddedFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001530 g_autoptr(GError) error_local = NULL;
Richard Hughes104f6512017-11-24 11:44:57 +00001531
1532 /* not enabled */
1533 if (!priv->enabled)
1534 return TRUE;
Richard Hughes639da472018-01-06 22:35:04 +00001535
1536 /* no object loaded */
Richard Hughes104f6512017-11-24 11:44:57 +00001537 if (priv->module == NULL)
1538 return TRUE;
1539
1540 /* optional */
1541 g_module_symbol (priv->module, "fu_plugin_usb_device_added", (gpointer *) &func);
Richard Hughes989acf12019-10-05 20:16:47 +01001542 if (func == NULL) {
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001543 if (priv->device_gtype != G_TYPE_INVALID ||
1544 fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) {
Mario Limonciello0e500322019-10-17 18:41:04 -05001545 if (!fu_plugin_usb_device_added (self, device, error))
Mario Limoncielloa9be5362019-10-12 13:17:45 -05001546 return FALSE;
Richard Hughes989acf12019-10-05 20:16:47 +01001547 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001548 return TRUE;
Richard Hughes989acf12019-10-05 20:16:47 +01001549 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001550 g_debug ("performing usb_device_added() on %s", priv->name);
1551 if (!func (self, device, &error_local)) {
1552 if (error_local == NULL) {
1553 g_critical ("unset error in plugin %s for usb_device_added()",
1554 priv->name);
1555 g_set_error_literal (&error_local,
1556 FWUPD_ERROR,
1557 FWUPD_ERROR_INTERNAL,
1558 "unspecified error");
1559 }
1560 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1561 "failed to add device using on %s: ",
1562 priv->name);
1563 return FALSE;
Richard Hughes104f6512017-11-24 11:44:57 +00001564 }
1565 return TRUE;
1566}
1567
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001568gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001569fu_plugin_runner_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error)
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001570{
Richard Hughes12724852018-09-04 13:53:44 +01001571 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001572 FuPluginUdevDeviceAddedFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001573 g_autoptr(GError) error_local = NULL;
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001574
1575 /* not enabled */
1576 if (!priv->enabled)
1577 return TRUE;
1578
1579 /* no object loaded */
1580 if (priv->module == NULL)
1581 return TRUE;
1582
1583 /* optional */
1584 g_module_symbol (priv->module, "fu_plugin_udev_device_added", (gpointer *) &func);
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001585 if (func == NULL) {
1586 if (priv->device_gtype != G_TYPE_INVALID ||
1587 fu_device_get_specialized_gtype (FU_DEVICE (device)) != G_TYPE_INVALID) {
Mario Limonciello0e500322019-10-17 18:41:04 -05001588 if (!fu_plugin_udev_device_added (self, device, error))
Mario Limoncielloa9be5362019-10-12 13:17:45 -05001589 return FALSE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001590 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001591 return TRUE;
Richard Hughesd8a8d5e2019-10-08 13:05:02 +01001592 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001593 g_debug ("performing udev_device_added() on %s", priv->name);
1594 if (!func (self, device, &error_local)) {
1595 if (error_local == NULL) {
1596 g_critical ("unset error in plugin %s for udev_device_added()",
1597 priv->name);
1598 g_set_error_literal (&error_local,
1599 FWUPD_ERROR,
1600 FWUPD_ERROR_INTERNAL,
1601 "unspecified error");
1602 }
1603 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1604 "failed to add device using on %s: ",
1605 priv->name);
1606 return FALSE;
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001607 }
1608 return TRUE;
1609}
1610
Richard Hughes5e952ce2019-08-26 11:09:46 +01001611gboolean
1612fu_plugin_runner_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GError **error)
1613{
1614 FuPluginPrivate *priv = GET_PRIVATE (self);
1615 FuPluginUdevDeviceAddedFunc func = NULL;
1616 g_autoptr(GError) error_local = NULL;
1617
1618 /* not enabled */
1619 if (!priv->enabled)
1620 return TRUE;
1621
1622 /* no object loaded */
1623 if (priv->module == NULL)
1624 return TRUE;
1625
1626 /* optional */
1627 g_module_symbol (priv->module, "fu_plugin_udev_device_changed", (gpointer *) &func);
1628 if (func == NULL)
1629 return TRUE;
1630 g_debug ("performing udev_device_changed() on %s", priv->name);
1631 if (!func (self, device, &error_local)) {
1632 if (error_local == NULL) {
1633 g_critical ("unset error in plugin %s for udev_device_changed()",
1634 priv->name);
1635 g_set_error_literal (&error_local,
1636 FWUPD_ERROR,
1637 FWUPD_ERROR_INTERNAL,
1638 "unspecified error");
1639 }
1640 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1641 "failed to change device on %s: ",
1642 priv->name);
1643 return FALSE;
1644 }
1645 return TRUE;
1646}
1647
Richard Hughese1fd34d2017-08-24 14:19:51 +01001648void
Richard Hughes12724852018-09-04 13:53:44 +01001649fu_plugin_runner_device_removed (FuPlugin *self, FuDevice *device)
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001650{
1651 g_autoptr(GError) error_local= NULL;
1652
Richard Hughes12724852018-09-04 13:53:44 +01001653 if (!fu_plugin_runner_device_generic (self, device,
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001654 "fu_plugin_device_removed",
Richard Hughes4b303802019-10-04 13:22:51 +01001655 NULL,
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001656 &error_local))
1657 g_warning ("%s", error_local->message);
1658}
1659
1660void
Richard Hughes12724852018-09-04 13:53:44 +01001661fu_plugin_runner_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +01001662{
Richard Hughes12724852018-09-04 13:53:44 +01001663 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughese1fd34d2017-08-24 14:19:51 +01001664 FuPluginDeviceRegisterFunc func = NULL;
1665
1666 /* not enabled */
1667 if (!priv->enabled)
1668 return;
Richard Hughes34834102017-11-21 21:55:00 +00001669 if (priv->module == NULL)
1670 return;
Richard Hughese1fd34d2017-08-24 14:19:51 +01001671
Mario Limonciello4910b242018-06-22 15:04:21 -05001672 /* don't notify plugins on their own devices */
Richard Hughes12724852018-09-04 13:53:44 +01001673 if (g_strcmp0 (fu_device_get_plugin (device), fu_plugin_get_name (self)) == 0)
Mario Limonciello4910b242018-06-22 15:04:21 -05001674 return;
1675
Richard Hughese1fd34d2017-08-24 14:19:51 +01001676 /* optional */
1677 g_module_symbol (priv->module, "fu_plugin_device_registered", (gpointer *) &func);
1678 if (func != NULL) {
Richard Hughes1bf7ff92018-08-24 20:21:35 +01001679 g_debug ("performing fu_plugin_device_registered() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01001680 func (self, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +01001681 }
1682}
1683
Richard Hughesc6c312f2019-02-01 16:37:14 +00001684gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001685fu_plugin_runner_schedule_update (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +00001686 FuDevice *device,
Richard Hughes994b4d92019-03-25 14:28:30 +00001687 FwupdRelease *release,
Richard Hughescff38bc2016-12-12 12:03:37 +00001688 GBytes *blob_cab,
Richard Hughes5cbb5cf2019-04-26 16:48:03 +01001689 FwupdInstallFlags flags,
Richard Hughescff38bc2016-12-12 12:03:37 +00001690 GError **error)
1691{
Richard Hughes0a906262019-05-16 13:38:47 +01001692 gchar tmpname[] = {"XXXXXX.cab"};
Richard Hughescff38bc2016-12-12 12:03:37 +00001693 g_autofree gchar *dirname = NULL;
1694 g_autofree gchar *filename = NULL;
Richard Hughes780ef3f2018-01-12 16:20:31 +00001695 g_autoptr(FuHistory) history = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001696 g_autoptr(GFile) file = NULL;
1697
1698 /* id already exists */
Richard Hughes780ef3f2018-01-12 16:20:31 +00001699 history = fu_history_new ();
Richard Hughes5cbb5cf2019-04-26 16:48:03 +01001700 if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) {
1701 g_autoptr(FuDevice) res_tmp = NULL;
1702 res_tmp = fu_history_get_device_by_id (history, fu_device_get_id (device), NULL);
1703 if (res_tmp != NULL &&
1704 fu_device_get_update_state (res_tmp) == FWUPD_UPDATE_STATE_PENDING) {
1705 g_set_error (error,
1706 FWUPD_ERROR,
1707 FWUPD_ERROR_ALREADY_PENDING,
1708 "%s is already scheduled to be updated",
1709 fu_device_get_id (device));
1710 return FALSE;
1711 }
Richard Hughescff38bc2016-12-12 12:03:37 +00001712 }
1713
1714 /* create directory */
Richard Hughes4be17d12018-05-30 20:36:29 +01001715 dirname = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG);
Richard Hughescff38bc2016-12-12 12:03:37 +00001716 file = g_file_new_for_path (dirname);
1717 if (!g_file_query_exists (file, NULL)) {
1718 if (!g_file_make_directory_with_parents (file, NULL, error))
1719 return FALSE;
1720 }
1721
1722 /* get a random filename */
1723 for (guint i = 0; i < 6; i++)
1724 tmpname[i] = (gchar) g_random_int_range ('A', 'Z');
1725 filename = g_build_filename (dirname, tmpname, NULL);
1726
1727 /* just copy to the temp file */
Richard Hughes23135eb2017-11-30 21:01:25 +00001728 fu_device_set_status (device, FWUPD_STATUS_SCHEDULING);
Richard Hughescff38bc2016-12-12 12:03:37 +00001729 if (!g_file_set_contents (filename,
1730 g_bytes_get_data (blob_cab, NULL),
1731 (gssize) g_bytes_get_size (blob_cab),
1732 error))
1733 return FALSE;
1734
1735 /* schedule for next boot */
1736 g_debug ("schedule %s to be installed to %s on next boot",
1737 filename, fu_device_get_id (device));
Richard Hughes994b4d92019-03-25 14:28:30 +00001738 fwupd_release_set_filename (release, filename);
Richard Hughescff38bc2016-12-12 12:03:37 +00001739
1740 /* add to database */
Richard Hughes809abea2019-03-23 11:06:18 +00001741 fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT);
Richard Hughes3e90a582018-01-06 22:38:09 +00001742 fu_device_set_update_state (device, FWUPD_UPDATE_STATE_PENDING);
Richard Hughes994b4d92019-03-25 14:28:30 +00001743 if (!fu_history_add_device (history, device, release, error))
Richard Hughescff38bc2016-12-12 12:03:37 +00001744 return FALSE;
1745
1746 /* next boot we run offline */
Richard Hughesdb69c812019-03-22 16:10:15 +00001747 fu_device_set_progress (device, 100);
Richard Hughescff38bc2016-12-12 12:03:37 +00001748 return fu_plugin_runner_offline_setup (error);
1749}
1750
1751gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001752fu_plugin_runner_verify (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +00001753 FuDevice *device,
1754 FuPluginVerifyFlags flags,
1755 GError **error)
1756{
Richard Hughes12724852018-09-04 13:53:44 +01001757 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001758 FuPluginVerifyFunc func = NULL;
Richard Hughesababbb72017-06-15 20:18:36 +01001759 GPtrArray *checksums;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001760 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001761
1762 /* not enabled */
1763 if (!priv->enabled)
1764 return TRUE;
1765
Richard Hughes639da472018-01-06 22:35:04 +00001766 /* no object loaded */
1767 if (priv->module == NULL)
1768 return TRUE;
1769
Richard Hughescff38bc2016-12-12 12:03:37 +00001770 /* optional */
1771 g_module_symbol (priv->module, "fu_plugin_verify", (gpointer *) &func);
Richard Hughes7f677212019-10-05 16:19:40 +01001772 if (func == NULL) {
Richard Hughes7f677212019-10-05 16:19:40 +01001773 return fu_plugin_device_read_firmware (self, device, error);
1774 }
Richard Hughes1812fc72018-12-14 11:37:54 +00001775
1776 /* clear any existing verification checksums */
1777 checksums = fu_device_get_checksums (device);
1778 g_ptr_array_set_size (checksums, 0);
1779
Richard Hughesc9223be2019-03-18 08:46:42 +00001780 /* run additional detach */
1781 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01001782 "fu_plugin_update_detach",
Richard Hughes4b303802019-10-04 13:22:51 +01001783 fu_plugin_device_detach,
Richard Hughesc9223be2019-03-18 08:46:42 +00001784 error))
1785 return FALSE;
1786
Richard Hughes1812fc72018-12-14 11:37:54 +00001787 /* run vfunc */
Richard Hughescff38bc2016-12-12 12:03:37 +00001788 g_debug ("performing verify() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001789 if (!func (self, device, flags, &error_local)) {
Richard Hughesc9223be2019-03-18 08:46:42 +00001790 g_autoptr(GError) error_attach = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001791 if (error_local == NULL) {
1792 g_critical ("unset error in plugin %s for verify()",
1793 priv->name);
1794 g_set_error_literal (&error_local,
1795 FWUPD_ERROR,
1796 FWUPD_ERROR_INTERNAL,
1797 "unspecified error");
1798 }
1799 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1800 "failed to verify using %s: ",
1801 priv->name);
Richard Hughesc9223be2019-03-18 08:46:42 +00001802 /* make the device "work" again, but don't prefix the error */
1803 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01001804 "fu_plugin_update_attach",
Richard Hughes4b303802019-10-04 13:22:51 +01001805 fu_plugin_device_attach,
Richard Hughesc9223be2019-03-18 08:46:42 +00001806 &error_attach)) {
1807 g_warning ("failed to attach whilst aborting verify(): %s",
1808 error_attach->message);
1809 }
Richard Hughesd0905142016-03-13 09:46:49 +00001810 return FALSE;
1811 }
Richard Hughesc9223be2019-03-18 08:46:42 +00001812
1813 /* run optional attach */
1814 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01001815 "fu_plugin_update_attach",
Richard Hughes4b303802019-10-04 13:22:51 +01001816 fu_plugin_device_attach,
Richard Hughesc9223be2019-03-18 08:46:42 +00001817 error))
1818 return FALSE;
1819
1820 /* success */
Richard Hughesd0905142016-03-13 09:46:49 +00001821 return TRUE;
1822}
1823
Richard Hughesd0905142016-03-13 09:46:49 +00001824gboolean
Mario Limonciello96a0dd52019-02-25 13:50:03 -06001825fu_plugin_runner_activate (FuPlugin *self, FuDevice *device, GError **error)
1826{
1827 guint64 flags;
1828
1829 /* final check */
1830 flags = fu_device_get_flags (device);
1831 if ((flags & FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION) == 0) {
1832 g_set_error (error,
1833 FWUPD_ERROR,
1834 FWUPD_ERROR_NOT_SUPPORTED,
1835 "Device %s does not need activation",
1836 fu_device_get_id (device));
1837 return FALSE;
1838 }
1839
1840 /* run vfunc */
1841 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001842 "fu_plugin_activate",
1843 fu_plugin_device_activate,
1844 error))
Mario Limonciello96a0dd52019-02-25 13:50:03 -06001845 return FALSE;
1846
1847 /* update with correct flags */
1848 fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION);
1849 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
1850 return TRUE;
1851}
1852
1853gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001854fu_plugin_runner_unlock (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00001855{
Richard Hughescff38bc2016-12-12 12:03:37 +00001856 guint64 flags;
Richard Hughescff38bc2016-12-12 12:03:37 +00001857
1858 /* final check */
1859 flags = fu_device_get_flags (device);
1860 if ((flags & FWUPD_DEVICE_FLAG_LOCKED) == 0) {
1861 g_set_error (error,
1862 FWUPD_ERROR,
1863 FWUPD_ERROR_NOT_SUPPORTED,
1864 "Device %s is not locked",
1865 fu_device_get_id (device));
1866 return FALSE;
1867 }
1868
Richard Hughes9c4b5312017-11-14 11:34:53 +00001869 /* run vfunc */
Richard Hughes12724852018-09-04 13:53:44 +01001870 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001871 "fu_plugin_unlock",
1872 NULL,
1873 error))
Richard Hughes9c4b5312017-11-14 11:34:53 +00001874 return FALSE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001875
1876 /* update with correct flags */
1877 flags = fu_device_get_flags (device);
1878 fu_device_set_flags (device, flags &= ~FWUPD_DEVICE_FLAG_LOCKED);
1879 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
1880 return TRUE;
1881}
1882
1883gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001884fu_plugin_runner_update (FuPlugin *self,
Richard Hughesa785a1c2017-08-25 16:00:58 +01001885 FuDevice *device,
Richard Hughesa785a1c2017-08-25 16:00:58 +01001886 GBytes *blob_fw,
1887 FwupdInstallFlags flags,
1888 GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00001889{
Richard Hughes12724852018-09-04 13:53:44 +01001890 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesa785a1c2017-08-25 16:00:58 +01001891 FuPluginUpdateFunc update_func;
Richard Hughes780ef3f2018-01-12 16:20:31 +00001892 g_autoptr(FuHistory) history = NULL;
Richard Hughes68982c62017-09-13 15:40:14 +01001893 g_autoptr(FuDevice) device_pending = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001894 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001895
1896 /* not enabled */
Richard Hughes41c15482018-02-01 22:07:21 +00001897 if (!priv->enabled) {
1898 g_debug ("plugin not enabled, skipping");
Richard Hughesd0905142016-03-13 09:46:49 +00001899 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00001900 }
Richard Hughesd0905142016-03-13 09:46:49 +00001901
Richard Hughes639da472018-01-06 22:35:04 +00001902 /* no object loaded */
Richard Hughes41c15482018-02-01 22:07:21 +00001903 if (priv->module == NULL) {
1904 g_debug ("module not enabled, skipping");
Richard Hughes639da472018-01-06 22:35:04 +00001905 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00001906 }
Richard Hughes639da472018-01-06 22:35:04 +00001907
Richard Hughesd0905142016-03-13 09:46:49 +00001908 /* optional */
Richard Hughesa785a1c2017-08-25 16:00:58 +01001909 g_module_symbol (priv->module, "fu_plugin_update", (gpointer *) &update_func);
1910 if (update_func == NULL) {
Richard Hughes4b303802019-10-04 13:22:51 +01001911 g_debug ("running superclassed write_firmware() on %s", priv->name);
1912 return fu_plugin_device_write_firmware (self, device, blob_fw, flags, error);
Richard Hughesa785a1c2017-08-25 16:00:58 +01001913 }
Richard Hughesd0905142016-03-13 09:46:49 +00001914
Richard Hughescff38bc2016-12-12 12:03:37 +00001915 /* cancel the pending action */
1916 if (!fu_plugin_runner_offline_invalidate (error))
1917 return FALSE;
1918
1919 /* online */
Richard Hughes780ef3f2018-01-12 16:20:31 +00001920 history = fu_history_new ();
Richard Hughes0b9d9962018-01-12 16:31:28 +00001921 device_pending = fu_history_get_device_by_id (history, fu_device_get_id (device), NULL);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001922 if (!update_func (self, device, blob_fw, flags, &error_local)) {
1923 if (error_local == NULL) {
1924 g_critical ("unset error in plugin %s for update()",
1925 priv->name);
1926 g_set_error_literal (&error_local,
Richard Hughes3c8ada32018-10-12 10:08:58 +01001927 FWUPD_ERROR,
1928 FWUPD_ERROR_INTERNAL,
1929 "unspecified error");
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001930 return FALSE;
Richard Hughes3c8ada32018-10-12 10:08:58 +01001931 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001932 fu_device_set_update_error (device, error_local->message);
1933 g_propagate_error (error, g_steal_pointer (&error_local));
Richard Hughescff38bc2016-12-12 12:03:37 +00001934 return FALSE;
1935 }
1936
Richard Hughesf556d372017-06-15 19:49:18 +01001937 /* no longer valid */
Richard Hughesf8039642019-01-16 12:22:22 +00001938 if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT) &&
1939 !fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) {
Richard Hughes08435162018-12-12 10:34:16 +00001940 GPtrArray *checksums = fu_device_get_checksums (device);
1941 g_ptr_array_set_size (checksums, 0);
1942 }
Richard Hughesf556d372017-06-15 19:49:18 +01001943
Richard Hughescff38bc2016-12-12 12:03:37 +00001944 /* cleanup */
Richard Hughes68982c62017-09-13 15:40:14 +01001945 if (device_pending != NULL) {
Richard Hughescff38bc2016-12-12 12:03:37 +00001946 const gchar *tmp;
Richard Hughesbc3a4e12018-01-06 22:41:47 +00001947 FwupdRelease *release;
Richard Hughescff38bc2016-12-12 12:03:37 +00001948
Richard Hughes780ef3f2018-01-12 16:20:31 +00001949 /* update history database */
Richard Hughesc0cd0232018-01-31 15:02:00 +00001950 fu_device_set_update_state (device, FWUPD_UPDATE_STATE_SUCCESS);
Richard Hughes0bbef292019-11-01 12:15:15 +00001951 if (!fu_history_modify_device (history, device, error))
Richard Hughes0b9d9962018-01-12 16:31:28 +00001952 return FALSE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001953
1954 /* delete cab file */
Richard Hughesbc3a4e12018-01-06 22:41:47 +00001955 release = fu_device_get_release_default (device_pending);
1956 tmp = fwupd_release_get_filename (release);
Richard Hughescff38bc2016-12-12 12:03:37 +00001957 if (tmp != NULL && g_str_has_prefix (tmp, LIBEXECDIR)) {
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001958 g_autoptr(GError) error_delete = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001959 g_autoptr(GFile) file = NULL;
1960 file = g_file_new_for_path (tmp);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001961 if (!g_file_delete (file, NULL, &error_delete)) {
Richard Hughescff38bc2016-12-12 12:03:37 +00001962 g_set_error (error,
1963 FWUPD_ERROR,
1964 FWUPD_ERROR_INVALID_FILE,
1965 "Failed to delete %s: %s",
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001966 tmp, error_delete->message);
Richard Hughescff38bc2016-12-12 12:03:37 +00001967 return FALSE;
1968 }
1969 }
1970 }
Richard Hughesd0905142016-03-13 09:46:49 +00001971 return TRUE;
1972}
Richard Hughescff38bc2016-12-12 12:03:37 +00001973
1974gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001975fu_plugin_runner_clear_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00001976{
Richard Hughes12724852018-09-04 13:53:44 +01001977 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001978 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001979 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001980
1981 /* not enabled */
1982 if (!priv->enabled)
1983 return TRUE;
1984
Richard Hughes639da472018-01-06 22:35:04 +00001985 /* no object loaded */
1986 if (priv->module == NULL)
1987 return TRUE;
1988
Richard Hughes65e44ca2018-01-30 17:26:30 +00001989 /* optional */
1990 g_module_symbol (priv->module, "fu_plugin_get_results", (gpointer *) &func);
1991 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00001992 return TRUE;
Richard Hughes65e44ca2018-01-30 17:26:30 +00001993 g_debug ("performing clear_result() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001994 if (!func (self, device, &error_local)) {
1995 if (error_local == NULL) {
1996 g_critical ("unset error in plugin %s for clear_result()",
1997 priv->name);
1998 g_set_error_literal (&error_local,
1999 FWUPD_ERROR,
2000 FWUPD_ERROR_INTERNAL,
2001 "unspecified error");
2002 }
2003 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2004 "failed to clear_result using %s: ",
2005 priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00002006 return FALSE;
2007 }
Richard Hughes65e44ca2018-01-30 17:26:30 +00002008 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00002009}
2010
2011gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002012fu_plugin_runner_get_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00002013{
Richard Hughes12724852018-09-04 13:53:44 +01002014 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00002015 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002016 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00002017
2018 /* not enabled */
2019 if (!priv->enabled)
2020 return TRUE;
2021
Richard Hughes639da472018-01-06 22:35:04 +00002022 /* no object loaded */
2023 if (priv->module == NULL)
2024 return TRUE;
2025
Richard Hughes65e44ca2018-01-30 17:26:30 +00002026 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00002027 g_module_symbol (priv->module, "fu_plugin_get_results", (gpointer *) &func);
Richard Hughes65e44ca2018-01-30 17:26:30 +00002028 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00002029 return TRUE;
Richard Hughes65e44ca2018-01-30 17:26:30 +00002030 g_debug ("performing get_results() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00002031 if (!func (self, device, &error_local)) {
2032 if (error_local == NULL) {
2033 g_critical ("unset error in plugin %s for get_results()",
2034 priv->name);
2035 g_set_error_literal (&error_local,
2036 FWUPD_ERROR,
2037 FWUPD_ERROR_INTERNAL,
2038 "unspecified error");
2039 }
2040 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
2041 "failed to get_results using %s: ",
2042 priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00002043 return FALSE;
2044 }
Richard Hughescff38bc2016-12-12 12:03:37 +00002045 return TRUE;
2046}
2047
Richard Hughes08a37992017-09-12 12:57:43 +01002048/**
2049 * fu_plugin_get_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002050 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002051 *
2052 * Gets the plugin order, where higher numbers are run after lower
2053 * numbers.
2054 *
2055 * Returns: the integer value
2056 **/
2057guint
Richard Hughes12724852018-09-04 13:53:44 +01002058fu_plugin_get_order (FuPlugin *self)
Richard Hughes08a37992017-09-12 12:57:43 +01002059{
Richard Hughes12724852018-09-04 13:53:44 +01002060 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002061 return priv->order;
2062}
2063
2064/**
2065 * fu_plugin_set_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002066 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002067 * @order: a integer value
2068 *
2069 * Sets the plugin order, where higher numbers are run after lower
2070 * numbers.
2071 **/
2072void
Richard Hughes12724852018-09-04 13:53:44 +01002073fu_plugin_set_order (FuPlugin *self, guint order)
Richard Hughes08a37992017-09-12 12:57:43 +01002074{
Richard Hughes12724852018-09-04 13:53:44 +01002075 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002076 priv->order = order;
2077}
2078
2079/**
Richard Hughes81c427c2018-08-06 15:20:17 +01002080 * fu_plugin_get_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002081 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01002082 *
2083 * Gets the plugin priority, where higher numbers are better.
2084 *
2085 * Returns: the integer value
2086 **/
2087guint
Richard Hughes12724852018-09-04 13:53:44 +01002088fu_plugin_get_priority (FuPlugin *self)
Richard Hughes81c427c2018-08-06 15:20:17 +01002089{
Richard Hughes12724852018-09-04 13:53:44 +01002090 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01002091 return priv->priority;
2092}
2093
2094/**
2095 * fu_plugin_set_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002096 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01002097 * @priority: a integer value
2098 *
2099 * Sets the plugin priority, where higher numbers are better.
2100 **/
2101void
Richard Hughes12724852018-09-04 13:53:44 +01002102fu_plugin_set_priority (FuPlugin *self, guint priority)
Richard Hughes81c427c2018-08-06 15:20:17 +01002103{
Richard Hughes12724852018-09-04 13:53:44 +01002104 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01002105 priv->priority = priority;
2106}
2107
2108/**
Richard Hughes08a37992017-09-12 12:57:43 +01002109 * fu_plugin_add_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002110 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002111 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
Richard Hughes4eada342017-10-03 21:20:32 +01002112 * @name: a plugin name, e.g. `upower`
Richard Hughes08a37992017-09-12 12:57:43 +01002113 *
2114 * If the plugin name is found, the rule will be used to sort the plugin list,
2115 * for example the plugin specified by @name will be ordered after this plugin
2116 * when %FU_PLUGIN_RULE_RUN_AFTER is used.
2117 *
2118 * NOTE: The depsolver is iterative and may not solve overly-complicated rules;
2119 * If depsolving fails then fwupd will not start.
2120 **/
2121void
Richard Hughes12724852018-09-04 13:53:44 +01002122fu_plugin_add_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes08a37992017-09-12 12:57:43 +01002123{
Richard Hughes12724852018-09-04 13:53:44 +01002124 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002125 g_ptr_array_add (priv->rules[rule], g_strdup (name));
Richard Hughes75b965d2018-11-15 13:51:21 +00002126 g_signal_emit (self, signals[SIGNAL_RULES_CHANGED], 0);
Richard Hughes08a37992017-09-12 12:57:43 +01002127}
2128
2129/**
2130 * fu_plugin_get_rules:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002131 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002132 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
2133 *
2134 * Gets the plugin IDs that should be run after this plugin.
2135 *
2136 * Returns: (element-type utf8) (transfer none): the list of plugin names, e.g. ['appstream']
2137 **/
2138GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +01002139fu_plugin_get_rules (FuPlugin *self, FuPluginRule rule)
Richard Hughes08a37992017-09-12 12:57:43 +01002140{
Richard Hughes12724852018-09-04 13:53:44 +01002141 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002142 return priv->rules[rule];
2143}
2144
Richard Hughes80b79bb2018-01-11 21:11:06 +00002145/**
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002146 * fu_plugin_has_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002147 * @self: a #FuPlugin
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002148 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
2149 * @name: a plugin name, e.g. `upower`
2150 *
Richard Hughes87fb9ff2018-06-28 12:55:59 +01002151 * Gets the plugin IDs that should be run after this plugin.
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002152 *
2153 * Returns: %TRUE if the name exists for the specific rule
2154 **/
2155gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002156fu_plugin_has_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002157{
Richard Hughes12724852018-09-04 13:53:44 +01002158 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002159 for (guint i = 0; i < priv->rules[rule]->len; i++) {
2160 const gchar *tmp = g_ptr_array_index (priv->rules[rule], i);
2161 if (g_strcmp0 (tmp, name) == 0)
2162 return TRUE;
2163 }
2164 return FALSE;
2165}
2166
2167/**
Richard Hughes80b79bb2018-01-11 21:11:06 +00002168 * fu_plugin_add_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002169 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00002170 * @key: a string, e.g. `FwupdateVersion`
2171 * @value: a string, e.g. `10`
2172 *
2173 * Sets any additional metadata to be included in the firmware report to aid
2174 * debugging problems.
2175 *
2176 * Any data included here will be sent to the metadata server after user
2177 * confirmation.
2178 **/
2179void
Richard Hughes12724852018-09-04 13:53:44 +01002180fu_plugin_add_report_metadata (FuPlugin *self, const gchar *key, const gchar *value)
Richard Hughes80b79bb2018-01-11 21:11:06 +00002181{
Richard Hughes12724852018-09-04 13:53:44 +01002182 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002183 g_hash_table_insert (priv->report_metadata, g_strdup (key), g_strdup (value));
2184}
2185
2186/**
2187 * fu_plugin_get_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002188 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00002189 *
2190 * Returns the list of additional metadata to be added when filing a report.
2191 *
2192 * Returns: (transfer none): the map of report metadata
2193 **/
2194GHashTable *
Richard Hughes12724852018-09-04 13:53:44 +01002195fu_plugin_get_report_metadata (FuPlugin *self)
Richard Hughes80b79bb2018-01-11 21:11:06 +00002196{
Richard Hughes12724852018-09-04 13:53:44 +01002197 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002198 return priv->report_metadata;
2199}
2200
Mario Limonciello963dc422018-02-27 14:26:58 -06002201/**
2202 * fu_plugin_get_config_value:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002203 * @self: a #FuPlugin
Mario Limonciello963dc422018-02-27 14:26:58 -06002204 * @key: A settings key
2205 *
2206 * Return the value of a key if it's been configured
2207 *
2208 * Since: 1.0.6
2209 **/
2210gchar *
Richard Hughes12724852018-09-04 13:53:44 +01002211fu_plugin_get_config_value (FuPlugin *self, const gchar *key)
Mario Limonciello963dc422018-02-27 14:26:58 -06002212{
Richard Hughes4be17d12018-05-30 20:36:29 +01002213 g_autofree gchar *conf_dir = NULL;
Mario Limonciello963dc422018-02-27 14:26:58 -06002214 g_autofree gchar *conf_file = NULL;
2215 g_autofree gchar *conf_path = NULL;
2216 g_autoptr(GKeyFile) keyfile = NULL;
2217 const gchar *plugin_name;
2218
Richard Hughes4be17d12018-05-30 20:36:29 +01002219 conf_dir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR_PKG);
Richard Hughes12724852018-09-04 13:53:44 +01002220 plugin_name = fu_plugin_get_name (self);
Mario Limonciello963dc422018-02-27 14:26:58 -06002221 conf_file = g_strdup_printf ("%s.conf", plugin_name);
Richard Hughes4be17d12018-05-30 20:36:29 +01002222 conf_path = g_build_filename (conf_dir, conf_file, NULL);
Mario Limonciello963dc422018-02-27 14:26:58 -06002223 if (!g_file_test (conf_path, G_FILE_TEST_IS_REGULAR))
2224 return NULL;
2225 keyfile = g_key_file_new ();
2226 if (!g_key_file_load_from_file (keyfile, conf_path,
2227 G_KEY_FILE_NONE, NULL))
2228 return NULL;
2229 return g_key_file_get_string (keyfile, plugin_name, key, NULL);
2230}
2231
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002232/**
2233 * fu_plugin_name_compare:
2234 * @plugin1: first #FuPlugin to compare.
2235 * @plugin2: second #FuPlugin to compare.
2236 *
2237 * Compares two plugins by their names.
2238 *
2239 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
2240 **/
2241gint
2242fu_plugin_name_compare (FuPlugin *plugin1, FuPlugin *plugin2)
2243{
2244 FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1);
2245 FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2);
2246 return g_strcmp0 (priv1->name, priv2->name);
2247}
2248
2249/**
2250 * fu_plugin_order_compare:
2251 * @plugin1: first #FuPlugin to compare.
2252 * @plugin2: second #FuPlugin to compare.
2253 *
2254 * Compares two plugins by their depsolved order.
2255 *
2256 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
2257 **/
2258gint
2259fu_plugin_order_compare (FuPlugin *plugin1, FuPlugin *plugin2)
2260{
2261 FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1);
2262 FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2);
2263 if (priv1->order < priv2->order)
2264 return -1;
2265 if (priv1->order > priv2->order)
2266 return 1;
2267 return 0;
2268}
2269
Richard Hughescff38bc2016-12-12 12:03:37 +00002270static void
2271fu_plugin_class_init (FuPluginClass *klass)
2272{
2273 GObjectClass *object_class = G_OBJECT_CLASS (klass);
2274 object_class->finalize = fu_plugin_finalize;
2275 signals[SIGNAL_DEVICE_ADDED] =
2276 g_signal_new ("device-added",
2277 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2278 G_STRUCT_OFFSET (FuPluginClass, device_added),
2279 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2280 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
2281 signals[SIGNAL_DEVICE_REMOVED] =
2282 g_signal_new ("device-removed",
2283 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2284 G_STRUCT_OFFSET (FuPluginClass, device_removed),
2285 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2286 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughese1fd34d2017-08-24 14:19:51 +01002287 signals[SIGNAL_DEVICE_REGISTER] =
2288 g_signal_new ("device-register",
2289 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2290 G_STRUCT_OFFSET (FuPluginClass, device_register),
2291 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2292 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughes362d6d72017-01-07 21:42:14 +00002293 signals[SIGNAL_RECOLDPLUG] =
2294 g_signal_new ("recoldplug",
2295 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2296 G_STRUCT_OFFSET (FuPluginClass, recoldplug),
2297 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2298 G_TYPE_NONE, 0);
Richard Hughesb0829032017-01-10 09:27:08 +00002299 signals[SIGNAL_SET_COLDPLUG_DELAY] =
2300 g_signal_new ("set-coldplug-delay",
2301 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2302 G_STRUCT_OFFSET (FuPluginClass, set_coldplug_delay),
2303 NULL, NULL, g_cclosure_marshal_VOID__UINT,
2304 G_TYPE_NONE, 1, G_TYPE_UINT);
Richard Hughesaabdc372018-11-14 10:11:08 +00002305 signals[SIGNAL_CHECK_SUPPORTED] =
2306 g_signal_new ("check-supported",
2307 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2308 G_STRUCT_OFFSET (FuPluginClass, check_supported),
2309 NULL, NULL, g_cclosure_marshal_generic,
2310 G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
Richard Hughes75b965d2018-11-15 13:51:21 +00002311 signals[SIGNAL_RULES_CHANGED] =
2312 g_signal_new ("rules-changed",
2313 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2314 G_STRUCT_OFFSET (FuPluginClass, rules_changed),
2315 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2316 G_TYPE_NONE, 0);
Richard Hughes95c98a92019-10-22 16:03:15 +01002317 signals[SIGNAL_ADD_FIRMWARE_GTYPE] =
2318 g_signal_new ("add-firmware-gtype",
2319 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2320 G_STRUCT_OFFSET (FuPluginClass, add_firmware_gtype),
2321 NULL, NULL, g_cclosure_marshal_generic,
2322 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_GTYPE);
Richard Hughescff38bc2016-12-12 12:03:37 +00002323}
2324
2325static void
Richard Hughes12724852018-09-04 13:53:44 +01002326fu_plugin_init (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +00002327{
Richard Hughes12724852018-09-04 13:53:44 +01002328 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002329 priv->enabled = TRUE;
Richard Hughesb1065422019-08-15 16:44:34 +01002330 priv->udev_subsystems = g_ptr_array_new_with_free_func (g_free);
Richard Hughescff38bc2016-12-12 12:03:37 +00002331 priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal,
2332 g_free, (GDestroyNotify) g_object_unref);
Richard Hughes161e9b52019-06-12 14:22:45 +01002333 g_rw_lock_init (&priv->devices_mutex);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002334 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 +01002335 for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++)
2336 priv->rules[i] = g_ptr_array_new_with_free_func (g_free);
Richard Hughescff38bc2016-12-12 12:03:37 +00002337}
2338
2339static void
2340fu_plugin_finalize (GObject *object)
2341{
Richard Hughes12724852018-09-04 13:53:44 +01002342 FuPlugin *self = FU_PLUGIN (object);
2343 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002344 FuPluginInitFunc func = NULL;
2345
2346 /* optional */
2347 if (priv->module != NULL) {
2348 g_module_symbol (priv->module, "fu_plugin_destroy", (gpointer *) &func);
2349 if (func != NULL) {
2350 g_debug ("performing destroy() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01002351 func (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002352 }
2353 }
2354
Richard Hughes08a37992017-09-12 12:57:43 +01002355 for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++)
2356 g_ptr_array_unref (priv->rules[i]);
2357
Richard Hughescff38bc2016-12-12 12:03:37 +00002358 if (priv->usb_ctx != NULL)
2359 g_object_unref (priv->usb_ctx);
Richard Hughesb8f8db22017-04-25 15:56:00 +01002360 if (priv->hwids != NULL)
Richard Hughesd7704d42017-08-08 20:29:09 +01002361 g_object_unref (priv->hwids);
Richard Hughes9c028f02017-10-28 21:14:28 +01002362 if (priv->quirks != NULL)
2363 g_object_unref (priv->quirks);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01002364 if (priv->udev_subsystems != NULL)
2365 g_ptr_array_unref (priv->udev_subsystems);
Richard Hughes49e5e052017-09-03 12:15:41 +01002366 if (priv->smbios != NULL)
2367 g_object_unref (priv->smbios);
Richard Hughes275d3b42018-04-20 16:40:37 +01002368 if (priv->runtime_versions != NULL)
2369 g_hash_table_unref (priv->runtime_versions);
Richard Hughes34e0dab2018-04-20 16:43:00 +01002370 if (priv->compile_versions != NULL)
2371 g_hash_table_unref (priv->compile_versions);
Richard Hughescff38bc2016-12-12 12:03:37 +00002372 g_hash_table_unref (priv->devices);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002373 g_hash_table_unref (priv->report_metadata);
Richard Hughes161e9b52019-06-12 14:22:45 +01002374 g_rw_lock_clear (&priv->devices_mutex);
Richard Hughes84999302019-05-02 10:18:32 +01002375 g_free (priv->build_hash);
Richard Hughescff38bc2016-12-12 12:03:37 +00002376 g_free (priv->name);
2377 g_free (priv->data);
Mario Limonciello3f9a1c12018-06-06 14:06:40 -05002378 /* Must happen as the last step to avoid prematurely
2379 * freeing memory held by the plugin */
2380#ifndef RUNNING_ON_VALGRIND
2381 if (priv->module != NULL)
2382 g_module_close (priv->module);
2383#endif
Richard Hughescff38bc2016-12-12 12:03:37 +00002384
2385 G_OBJECT_CLASS (fu_plugin_parent_class)->finalize (object);
2386}
2387
2388FuPlugin *
2389fu_plugin_new (void)
2390{
Richard Hughes12724852018-09-04 13:53:44 +01002391 return FU_PLUGIN (g_object_new (FU_TYPE_PLUGIN, NULL));
Richard Hughescff38bc2016-12-12 12:03:37 +00002392}