blob: a364b0e3c4f5dbc3d1368b7b304ee34c5889c531 [file] [log] [blame]
Richard Hughes02c90d82018-08-09 12:13:03 +01001/*
Richard Hughes2de8f132018-01-17 09:12:02 +00002 * Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
Richard Hughesd0905142016-03-13 09:46:49 +00003 *
Mario Limonciello51308e62018-05-28 20:05:46 -05004 * SPDX-License-Identifier: LGPL-2.1+
Richard Hughesd0905142016-03-13 09:46:49 +00005 */
6
Richard Hughesb08e7bc2018-09-11 10:51:13 +01007#define G_LOG_DOMAIN "FuPlugin"
8
Richard Hughesd0905142016-03-13 09:46:49 +00009#include "config.h"
10
Richard Hughescff38bc2016-12-12 12:03:37 +000011#include <fwupd.h>
12#include <gmodule.h>
Richard Hughescff38bc2016-12-12 12:03:37 +000013#include <errno.h>
14#include <string.h>
Richard Hughes68f12dd2018-08-09 14:43:31 +010015#include <unistd.h>
Richard Hughescff38bc2016-12-12 12:03:37 +000016#include <gio/gunixinputstream.h>
Mario Limonciello6d0aa3d2017-02-28 08:22:27 -060017#ifdef HAVE_VALGRIND
Richard Hughes576c0122017-02-24 09:47:00 +000018#include <valgrind.h>
Mario Limonciello6d0aa3d2017-02-28 08:22:27 -060019#endif /* HAVE_VALGRIND */
Richard Hughesd0905142016-03-13 09:46:49 +000020
Richard Hughes9dde04f2017-09-13 12:07:15 +010021#include "fu-device-private.h"
Richard Hughescff38bc2016-12-12 12:03:37 +000022#include "fu-plugin-private.h"
Richard Hughesbc3a4e12018-01-06 22:41:47 +000023#include "fu-history.h"
Richard Hughes37d09432018-09-09 10:39:45 +010024#include "fu-mutex.h"
Richard Hughesd0905142016-03-13 09:46:49 +000025
Richard Hughes4eada342017-10-03 21:20:32 +010026/**
27 * SECTION:fu-plugin
28 * @short_description: a daemon plugin
29 *
30 * An object that represents a plugin run by the daemon.
31 *
32 * See also: #FuDevice
33 */
34
Richard Hughesb0829032017-01-10 09:27:08 +000035#define FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM 3000u /* ms */
36
Richard Hughescff38bc2016-12-12 12:03:37 +000037static void fu_plugin_finalize (GObject *object);
38
39typedef struct {
40 GModule *module;
41 GUsbContext *usb_ctx;
42 gboolean enabled;
Richard Hughes08a37992017-09-12 12:57:43 +010043 guint order;
Richard Hughes81c427c2018-08-06 15:20:17 +010044 guint priority;
Richard Hughes08a37992017-09-12 12:57:43 +010045 GPtrArray *rules[FU_PLUGIN_RULE_LAST];
Richard Hughescff38bc2016-12-12 12:03:37 +000046 gchar *name;
Richard Hughesf425d292019-01-18 17:57:39 +000047 gchar *build_hash;
Richard Hughesd7704d42017-08-08 20:29:09 +010048 FuHwids *hwids;
Richard Hughes9c028f02017-10-28 21:14:28 +010049 FuQuirks *quirks;
Richard Hughes0eb123b2018-04-19 12:00:04 +010050 GHashTable *runtime_versions;
Richard Hughes34e0dab2018-04-20 16:43:00 +010051 GHashTable *compile_versions;
Richard Hughes9d6e0e72018-08-24 20:20:17 +010052 GPtrArray *udev_subsystems;
Richard Hughes1354ea92017-09-19 15:58:31 +010053 FuSmbios *smbios;
Richard Hughes989acf12019-10-05 20:16:47 +010054 GType device_gtype;
Richard Hughescff38bc2016-12-12 12:03:37 +000055 GHashTable *devices; /* platform_id:GObject */
Richard Hughes161e9b52019-06-12 14:22:45 +010056 GRWLock devices_mutex;
Richard Hughes80b79bb2018-01-11 21:11:06 +000057 GHashTable *report_metadata; /* key:value */
Richard Hughescff38bc2016-12-12 12:03:37 +000058 FuPluginData *data;
59} FuPluginPrivate;
60
61enum {
62 SIGNAL_DEVICE_ADDED,
63 SIGNAL_DEVICE_REMOVED,
Richard Hughese1fd34d2017-08-24 14:19:51 +010064 SIGNAL_DEVICE_REGISTER,
Richard Hughes75b965d2018-11-15 13:51:21 +000065 SIGNAL_RULES_CHANGED,
Richard Hughes362d6d72017-01-07 21:42:14 +000066 SIGNAL_RECOLDPLUG,
Richard Hughesb0829032017-01-10 09:27:08 +000067 SIGNAL_SET_COLDPLUG_DELAY,
Richard Hughesaabdc372018-11-14 10:11:08 +000068 SIGNAL_CHECK_SUPPORTED,
Richard Hughescff38bc2016-12-12 12:03:37 +000069 SIGNAL_LAST
70};
71
72static guint signals[SIGNAL_LAST] = { 0 };
73
74G_DEFINE_TYPE_WITH_PRIVATE (FuPlugin, fu_plugin, G_TYPE_OBJECT)
75#define GET_PRIVATE(o) (fu_plugin_get_instance_private (o))
76
77typedef const gchar *(*FuPluginGetNameFunc) (void);
Richard Hughes12724852018-09-04 13:53:44 +010078typedef void (*FuPluginInitFunc) (FuPlugin *self);
79typedef gboolean (*FuPluginStartupFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000080 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010081typedef void (*FuPluginDeviceRegisterFunc) (FuPlugin *self,
Richard Hughese1fd34d2017-08-24 14:19:51 +010082 FuDevice *device);
Richard Hughes12724852018-09-04 13:53:44 +010083typedef gboolean (*FuPluginDeviceFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000084 FuDevice *device,
85 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010086typedef gboolean (*FuPluginFlaggedDeviceFunc) (FuPlugin *self,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -050087 FwupdInstallFlags flags,
88 FuDevice *device,
89 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010090typedef gboolean (*FuPluginDeviceArrayFunc) (FuPlugin *self,
Richard Hughesdbd8c762018-06-15 20:31:40 +010091 GPtrArray *devices,
92 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010093typedef gboolean (*FuPluginVerifyFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000094 FuDevice *device,
95 FuPluginVerifyFlags flags,
96 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +010097typedef gboolean (*FuPluginUpdateFunc) (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +000098 FuDevice *device,
99 GBytes *blob_fw,
100 FwupdInstallFlags flags,
101 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +0100102typedef gboolean (*FuPluginUsbDeviceAddedFunc) (FuPlugin *self,
Richard Hughesff704412018-09-04 11:28:32 +0100103 FuUsbDevice *device,
Richard Hughes104f6512017-11-24 11:44:57 +0000104 GError **error);
Richard Hughes12724852018-09-04 13:53:44 +0100105typedef gboolean (*FuPluginUdevDeviceAddedFunc) (FuPlugin *self,
Richard Hughesff704412018-09-04 11:28:32 +0100106 FuUdevDevice *device,
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100107 GError **error);
Richard Hughescff38bc2016-12-12 12:03:37 +0000108
Richard Hughes57d18222017-01-10 16:02:59 +0000109/**
110 * fu_plugin_get_name:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100111 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000112 *
113 * Gets the plugin name.
114 *
115 * Returns: a plugin name, or %NULL for unknown.
116 *
117 * Since: 0.8.0
118 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000119const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100120fu_plugin_get_name (FuPlugin *self)
Richard Hughesd0905142016-03-13 09:46:49 +0000121{
Richard Hughes12724852018-09-04 13:53:44 +0100122 FuPluginPrivate *priv = GET_PRIVATE (self);
123 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000124 return priv->name;
125}
Richard Hughesd0905142016-03-13 09:46:49 +0000126
Richard Hughes34834102017-11-21 21:55:00 +0000127void
Richard Hughes12724852018-09-04 13:53:44 +0100128fu_plugin_set_name (FuPlugin *self, const gchar *name)
Richard Hughes34834102017-11-21 21:55:00 +0000129{
Richard Hughes12724852018-09-04 13:53:44 +0100130 FuPluginPrivate *priv = GET_PRIVATE (self);
131 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughes34834102017-11-21 21:55:00 +0000132 g_return_if_fail (name != NULL);
133 g_free (priv->name);
134 priv->name = g_strdup (name);
135}
136
Richard Hughes57d18222017-01-10 16:02:59 +0000137/**
Richard Hughesf425d292019-01-18 17:57:39 +0000138 * fu_plugin_set_build_hash:
139 * @self: A #FuPlugin
140 * @build_hash: A checksum
141 *
142 * Sets the plugin build hash, typically a SHA256 checksum. All plugins must
143 * set the correct checksum to avoid the daemon being marked as tainted.
144 *
145 * Since: 1.2.4
146 **/
147void
148fu_plugin_set_build_hash (FuPlugin *self, const gchar *build_hash)
149{
150 FuPluginPrivate *priv = GET_PRIVATE (self);
151 g_return_if_fail (FU_IS_PLUGIN (self));
152 g_return_if_fail (build_hash != NULL);
153 g_free (priv->build_hash);
154 priv->build_hash = g_strdup (build_hash);
155}
156
157const gchar *
158fu_plugin_get_build_hash (FuPlugin *self)
159{
160 FuPluginPrivate *priv = GET_PRIVATE (self);
161 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
162 return priv->build_hash;
163}
164
165/**
Richard Hughes57d18222017-01-10 16:02:59 +0000166 * fu_plugin_cache_lookup:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100167 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000168 * @id: the key
169 *
170 * Finds an object in the per-plugin cache.
171 *
172 * Returns: (transfer none): a #GObject, or %NULL for unfound.
173 *
174 * Since: 0.8.0
175 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000176gpointer
Richard Hughes12724852018-09-04 13:53:44 +0100177fu_plugin_cache_lookup (FuPlugin *self, const gchar *id)
Richard Hughescff38bc2016-12-12 12:03:37 +0000178{
Richard Hughes12724852018-09-04 13:53:44 +0100179 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes161e9b52019-06-12 14:22:45 +0100180 g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100181 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughesccd78a92017-01-11 16:57:41 +0000182 g_return_val_if_fail (id != NULL, NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100183 g_return_val_if_fail (locker != NULL, NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000184 return g_hash_table_lookup (priv->devices, id);
185}
Richard Hughesd0905142016-03-13 09:46:49 +0000186
Richard Hughes57d18222017-01-10 16:02:59 +0000187/**
188 * fu_plugin_cache_add:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100189 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000190 * @id: the key
191 * @dev: a #GObject, typically a #FuDevice
192 *
193 * Adds an object to the per-plugin cache.
194 *
195 * Since: 0.8.0
196 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000197void
Richard Hughes12724852018-09-04 13:53:44 +0100198fu_plugin_cache_add (FuPlugin *self, const gchar *id, gpointer dev)
Richard Hughescff38bc2016-12-12 12:03:37 +0000199{
Richard Hughes12724852018-09-04 13:53:44 +0100200 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes161e9b52019-06-12 14:22:45 +0100201 g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_writer_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100202 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000203 g_return_if_fail (id != NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100204 g_return_if_fail (locker != NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000205 g_hash_table_insert (priv->devices, g_strdup (id), g_object_ref (dev));
206}
207
Richard Hughes57d18222017-01-10 16:02:59 +0000208/**
209 * fu_plugin_cache_remove:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100210 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000211 * @id: the key
212 *
213 * Removes an object from the per-plugin cache.
214 *
215 * Since: 0.8.0
216 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000217void
Richard Hughes12724852018-09-04 13:53:44 +0100218fu_plugin_cache_remove (FuPlugin *self, const gchar *id)
Richard Hughescff38bc2016-12-12 12:03:37 +0000219{
Richard Hughes12724852018-09-04 13:53:44 +0100220 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes161e9b52019-06-12 14:22:45 +0100221 g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_writer_locker_new (&priv->devices_mutex);
Richard Hughes12724852018-09-04 13:53:44 +0100222 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000223 g_return_if_fail (id != NULL);
Richard Hughes37d09432018-09-09 10:39:45 +0100224 g_return_if_fail (locker != NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000225 g_hash_table_remove (priv->devices, id);
226}
227
Richard Hughes57d18222017-01-10 16:02:59 +0000228/**
229 * fu_plugin_get_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100230 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000231 *
Richard Hughes4eada342017-10-03 21:20:32 +0100232 * Gets the per-plugin allocated private data. This will return %NULL unless
233 * fu_plugin_alloc_data() has been called by the plugin.
Richard Hughes57d18222017-01-10 16:02:59 +0000234 *
Richard Hughes4eada342017-10-03 21:20:32 +0100235 * Returns: (transfer none): a pointer to a structure, or %NULL for unset.
Richard Hughes57d18222017-01-10 16:02:59 +0000236 *
237 * Since: 0.8.0
238 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000239FuPluginData *
Richard Hughes12724852018-09-04 13:53:44 +0100240fu_plugin_get_data (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +0000241{
Richard Hughes12724852018-09-04 13:53:44 +0100242 FuPluginPrivate *priv = GET_PRIVATE (self);
243 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000244 return priv->data;
245}
246
Richard Hughes57d18222017-01-10 16:02:59 +0000247/**
248 * fu_plugin_alloc_data:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100249 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000250 * @data_sz: the size to allocate
251 *
252 * Allocates the per-plugin allocated private data.
253 *
254 * Returns: (transfer full): a pointer to a structure, or %NULL for unset.
255 *
256 * Since: 0.8.0
257 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000258FuPluginData *
Richard Hughes12724852018-09-04 13:53:44 +0100259fu_plugin_alloc_data (FuPlugin *self, gsize data_sz)
Richard Hughescff38bc2016-12-12 12:03:37 +0000260{
Richard Hughes12724852018-09-04 13:53:44 +0100261 FuPluginPrivate *priv = GET_PRIVATE (self);
262 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes44dee882017-01-11 08:31:10 +0000263 if (priv->data != NULL) {
264 g_critical ("fu_plugin_alloc_data() already used by plugin");
265 return priv->data;
266 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000267 priv->data = g_malloc0 (data_sz);
268 return priv->data;
Richard Hughesd0905142016-03-13 09:46:49 +0000269}
270
Richard Hughes57d18222017-01-10 16:02:59 +0000271/**
272 * fu_plugin_get_usb_context:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100273 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000274 *
275 * Gets the shared USB context that all plugins can use.
276 *
277 * Returns: (transfer none): a #GUsbContext.
278 *
279 * Since: 0.8.0
280 **/
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000281GUsbContext *
Richard Hughes12724852018-09-04 13:53:44 +0100282fu_plugin_get_usb_context (FuPlugin *self)
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000283{
Richard Hughes12724852018-09-04 13:53:44 +0100284 FuPluginPrivate *priv = GET_PRIVATE (self);
285 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughescff38bc2016-12-12 12:03:37 +0000286 return priv->usb_ctx;
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000287}
288
289void
Richard Hughes12724852018-09-04 13:53:44 +0100290fu_plugin_set_usb_context (FuPlugin *self, GUsbContext *usb_ctx)
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000291{
Richard Hughes12724852018-09-04 13:53:44 +0100292 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +0000293 g_set_object (&priv->usb_ctx, usb_ctx);
294}
295
Richard Hughes57d18222017-01-10 16:02:59 +0000296/**
297 * fu_plugin_get_enabled:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100298 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000299 *
Richard Hughes4eada342017-10-03 21:20:32 +0100300 * Returns if the plugin is enabled. Plugins may self-disable using
301 * fu_plugin_set_enabled() or can be disabled by the daemon.
Richard Hughes57d18222017-01-10 16:02:59 +0000302 *
303 * Returns: %TRUE if the plugin is currently enabled.
304 *
305 * Since: 0.8.0
306 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000307gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100308fu_plugin_get_enabled (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +0000309{
Richard Hughes12724852018-09-04 13:53:44 +0100310 FuPluginPrivate *priv = GET_PRIVATE (self);
311 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
Richard Hughescff38bc2016-12-12 12:03:37 +0000312 return priv->enabled;
Richard Hughesbc93e4a2016-12-08 17:29:51 +0000313}
314
Richard Hughes57d18222017-01-10 16:02:59 +0000315/**
316 * fu_plugin_set_enabled:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100317 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000318 * @enabled: the enabled value
319 *
320 * Enables or disables a plugin. Plugins can self-disable at any point.
321 *
322 * Since: 0.8.0
323 **/
Richard Hughesd0905142016-03-13 09:46:49 +0000324void
Richard Hughes12724852018-09-04 13:53:44 +0100325fu_plugin_set_enabled (FuPlugin *self, gboolean enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000326{
Richard Hughes12724852018-09-04 13:53:44 +0100327 FuPluginPrivate *priv = GET_PRIVATE (self);
328 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughescff38bc2016-12-12 12:03:37 +0000329 priv->enabled = enabled;
330}
331
Richard Hughes1e456bc2018-05-10 20:16:16 +0100332gchar *
333fu_plugin_guess_name_from_fn (const gchar *filename)
334{
335 const gchar *prefix = "libfu_plugin_";
336 gchar *name;
337 gchar *str = g_strstr_len (filename, -1, prefix);
338 if (str == NULL)
339 return NULL;
340 name = g_strdup (str + strlen (prefix));
341 g_strdelimit (name, ".", '\0');
342 return name;
343}
344
Richard Hughescff38bc2016-12-12 12:03:37 +0000345gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100346fu_plugin_open (FuPlugin *self, const gchar *filename, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +0000347{
Richard Hughes12724852018-09-04 13:53:44 +0100348 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +0000349 FuPluginInitFunc func = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +0000350
351 priv->module = g_module_open (filename, 0);
352 if (priv->module == NULL) {
353 g_set_error (error,
354 G_IO_ERROR,
355 G_IO_ERROR_FAILED,
356 "failed to open plugin: %s",
357 g_module_error ());
358 return FALSE;
359 }
360
361 /* set automatically */
Richard Hughes1e456bc2018-05-10 20:16:16 +0100362 if (priv->name == NULL)
363 priv->name = fu_plugin_guess_name_from_fn (filename);
Richard Hughesd0905142016-03-13 09:46:49 +0000364
365 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000366 g_module_symbol (priv->module, "fu_plugin_init", (gpointer *) &func);
367 if (func != NULL) {
368 g_debug ("performing init() on %s", filename);
Richard Hughes12724852018-09-04 13:53:44 +0100369 func (self);
Richard Hughesd0905142016-03-13 09:46:49 +0000370 }
371
Richard Hughescff38bc2016-12-12 12:03:37 +0000372 return TRUE;
373}
374
Richard Hughes57d18222017-01-10 16:02:59 +0000375/**
376 * fu_plugin_device_add:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100377 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000378 * @device: A #FuDevice
379 *
380 * Asks the daemon to add a device to the exported list. If this device ID
381 * has already been added by a different plugin then this request will be
382 * ignored.
383 *
384 * Plugins should use fu_plugin_device_add_delay() if they are not capable of
385 * actually flashing an image to the hardware so that higher-priority plugins
386 * can add the device themselves.
387 *
388 * Since: 0.8.0
389 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000390void
Richard Hughes12724852018-09-04 13:53:44 +0100391fu_plugin_device_add (FuPlugin *self, FuDevice *device)
Richard Hughescff38bc2016-12-12 12:03:37 +0000392{
Richard Hughes5e447292018-04-27 14:25:54 +0100393 GPtrArray *children;
Richard Hughesc125ec02018-09-05 19:35:17 +0100394 g_autoptr(GError) error = NULL;
Richard Hughes5e447292018-04-27 14:25:54 +0100395
Richard Hughes12724852018-09-04 13:53:44 +0100396 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000397 g_return_if_fail (FU_IS_DEVICE (device));
398
Richard Hughesc125ec02018-09-05 19:35:17 +0100399 /* ensure the device ID is set from the physical and logical IDs */
400 if (!fu_device_ensure_id (device, &error)) {
401 g_warning ("ignoring add: %s", error->message);
402 return;
403 }
404
Richard Hughescff38bc2016-12-12 12:03:37 +0000405 g_debug ("emit added from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100406 fu_plugin_get_name (self),
Richard Hughescff38bc2016-12-12 12:03:37 +0000407 fu_device_get_id (device));
408 fu_device_set_created (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
Richard Hughes12724852018-09-04 13:53:44 +0100409 fu_device_set_plugin (device, fu_plugin_get_name (self));
410 g_signal_emit (self, signals[SIGNAL_DEVICE_ADDED], 0, device);
Richard Hughes5e447292018-04-27 14:25:54 +0100411
Richard Hughes128c0162018-08-10 11:00:29 +0100412 /* add children if they have not already been added */
Richard Hughes5e447292018-04-27 14:25:54 +0100413 children = fu_device_get_children (device);
414 for (guint i = 0; i < children->len; i++) {
415 FuDevice *child = g_ptr_array_index (children, i);
Richard Hughes128c0162018-08-10 11:00:29 +0100416 if (fu_device_get_created (child) == 0)
Richard Hughes12724852018-09-04 13:53:44 +0100417 fu_plugin_device_add (self, child);
Richard Hughes5e447292018-04-27 14:25:54 +0100418 }
Richard Hughescff38bc2016-12-12 12:03:37 +0000419}
420
Richard Hughese1fd34d2017-08-24 14:19:51 +0100421/**
422 * fu_plugin_device_register:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100423 * @self: A #FuPlugin
Richard Hughese1fd34d2017-08-24 14:19:51 +0100424 * @device: A #FuDevice
425 *
426 * Registers the device with other plugins so they can set metadata.
427 *
428 * Plugins do not have to call this manually as this is done automatically
429 * when using fu_plugin_device_add(). They may wish to use this manually
430 * if for intance the coldplug should be ignored based on the metadata
431 * set from other plugins.
432 *
433 * Since: 0.9.7
434 **/
435void
Richard Hughes12724852018-09-04 13:53:44 +0100436fu_plugin_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +0100437{
Richard Hughesc125ec02018-09-05 19:35:17 +0100438 g_autoptr(GError) error = NULL;
439
Richard Hughes12724852018-09-04 13:53:44 +0100440 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughese1fd34d2017-08-24 14:19:51 +0100441 g_return_if_fail (FU_IS_DEVICE (device));
442
Richard Hughesc125ec02018-09-05 19:35:17 +0100443 /* ensure the device ID is set from the physical and logical IDs */
444 if (!fu_device_ensure_id (device, &error)) {
445 g_warning ("ignoring registration: %s", error->message);
446 return;
447 }
448
Richard Hughese1fd34d2017-08-24 14:19:51 +0100449 g_debug ("emit device-register from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100450 fu_plugin_get_name (self),
Richard Hughese1fd34d2017-08-24 14:19:51 +0100451 fu_device_get_id (device));
Richard Hughes12724852018-09-04 13:53:44 +0100452 g_signal_emit (self, signals[SIGNAL_DEVICE_REGISTER], 0, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +0100453}
454
Richard Hughes57d18222017-01-10 16:02:59 +0000455/**
Richard Hughes4eada342017-10-03 21:20:32 +0100456 * fu_plugin_device_remove:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100457 * @self: A #FuPlugin
Richard Hughes57d18222017-01-10 16:02:59 +0000458 * @device: A #FuDevice
459 *
460 * Asks the daemon to remove a device from the exported list.
461 *
462 * Since: 0.8.0
463 **/
Richard Hughescff38bc2016-12-12 12:03:37 +0000464void
Richard Hughes12724852018-09-04 13:53:44 +0100465fu_plugin_device_remove (FuPlugin *self, FuDevice *device)
Richard Hughescff38bc2016-12-12 12:03:37 +0000466{
Richard Hughes12724852018-09-04 13:53:44 +0100467 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesccd78a92017-01-11 16:57:41 +0000468 g_return_if_fail (FU_IS_DEVICE (device));
469
Richard Hughescff38bc2016-12-12 12:03:37 +0000470 g_debug ("emit removed from %s: %s",
Richard Hughes12724852018-09-04 13:53:44 +0100471 fu_plugin_get_name (self),
Richard Hughescff38bc2016-12-12 12:03:37 +0000472 fu_device_get_id (device));
Richard Hughes12724852018-09-04 13:53:44 +0100473 g_signal_emit (self, signals[SIGNAL_DEVICE_REMOVED], 0, device);
Richard Hughescff38bc2016-12-12 12:03:37 +0000474}
475
Richard Hughes57d18222017-01-10 16:02:59 +0000476/**
Richard Hughes2de8f132018-01-17 09:12:02 +0000477 * fu_plugin_request_recoldplug:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100478 * @self: A #FuPlugin
Richard Hughes362d6d72017-01-07 21:42:14 +0000479 *
480 * Ask all the plugins to coldplug all devices, which will include the prepare()
481 * and cleanup() phases. Duplicate devices added will be ignored.
482 *
483 * Since: 0.8.0
484 **/
485void
Richard Hughes12724852018-09-04 13:53:44 +0100486fu_plugin_request_recoldplug (FuPlugin *self)
Richard Hughes362d6d72017-01-07 21:42:14 +0000487{
Richard Hughes12724852018-09-04 13:53:44 +0100488 g_return_if_fail (FU_IS_PLUGIN (self));
489 g_signal_emit (self, signals[SIGNAL_RECOLDPLUG], 0);
Richard Hughes362d6d72017-01-07 21:42:14 +0000490}
491
Richard Hughesb0829032017-01-10 09:27:08 +0000492/**
Richard Hughesb8f8db22017-04-25 15:56:00 +0100493 * fu_plugin_check_hwid:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100494 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100495 * @hwid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
Richard Hughesb8f8db22017-04-25 15:56:00 +0100496 *
Richard Hughesd7704d42017-08-08 20:29:09 +0100497 * Checks to see if a specific GUID exists. All hardware IDs on a
Richard Hughesb8f8db22017-04-25 15:56:00 +0100498 * specific system can be shown using the `fwupdmgr hwids` command.
499 *
Richard Hughes4eada342017-10-03 21:20:32 +0100500 * Returns: %TRUE if the HwId is found on the system.
501 *
Richard Hughesb8f8db22017-04-25 15:56:00 +0100502 * Since: 0.9.1
503 **/
504gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100505fu_plugin_check_hwid (FuPlugin *self, const gchar *hwid)
Richard Hughesb8f8db22017-04-25 15:56:00 +0100506{
Richard Hughes12724852018-09-04 13:53:44 +0100507 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100508 if (priv->hwids == NULL)
509 return FALSE;
Richard Hughesd7704d42017-08-08 20:29:09 +0100510 return fu_hwids_has_guid (priv->hwids, hwid);
511}
512
513/**
Richard Hughes69a5f352018-08-08 11:58:15 +0100514 * fu_plugin_get_hwids:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100515 * @self: A #FuPlugin
Richard Hughes69a5f352018-08-08 11:58:15 +0100516 *
517 * Returns all the HWIDs defined in the system. All hardware IDs on a
518 * specific system can be shown using the `fwupdmgr hwids` command.
519 *
520 * Returns: (transfer none) (element-type utf-8): An array of GUIDs
521 *
522 * Since: 1.1.1
523 **/
524GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +0100525fu_plugin_get_hwids (FuPlugin *self)
Richard Hughes69a5f352018-08-08 11:58:15 +0100526{
Richard Hughes12724852018-09-04 13:53:44 +0100527 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes69a5f352018-08-08 11:58:15 +0100528 if (priv->hwids == NULL)
529 return NULL;
530 return fu_hwids_get_guids (priv->hwids);
531}
532
533/**
Richard Hughes19841802019-09-10 16:48:00 +0100534 * fu_plugin_has_custom_flag:
535 * @self: A #FuPlugin
536 * @flag: A custom text flag, specific to the plugin, e.g. `uefi-force-enable`
537 *
538 * Returns if a per-plugin HwId custom flag exists, typically added from a DMI quirk.
539 *
540 * Returns: %TRUE if the quirk entry exists
541 *
542 * Since: 1.3.1
543 **/
544gboolean
545fu_plugin_has_custom_flag (FuPlugin *self, const gchar *flag)
546{
547 FuPluginPrivate *priv = GET_PRIVATE (self);
548 GPtrArray *hwids = fu_plugin_get_hwids (self);
549
550 g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
551 g_return_val_if_fail (flag != NULL, FALSE);
552
553 /* never set up, e.g. in tests */
554 if (hwids == NULL)
555 return FALSE;
556
557 /* search each hwid */
558 for (guint i = 0; i < hwids->len; i++) {
559 const gchar *hwid = g_ptr_array_index (hwids, i);
560 const gchar *value;
561 g_autofree gchar *key = g_strdup_printf ("HwId=%s", hwid);
562
563 /* does prefixed quirk exist */
564 value = fu_quirks_lookup_by_id (priv->quirks, key, FU_QUIRKS_FLAGS);
565 if (value != NULL) {
566 g_auto(GStrv) quirks = g_strsplit (value, ",", -1);
567 if (g_strv_contains ((const gchar * const *) quirks, flag))
568 return TRUE;
569 }
570 }
571 return FALSE;
572}
573
574/**
Richard Hughes1354ea92017-09-19 15:58:31 +0100575 * fu_plugin_check_supported:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100576 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100577 * @guid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
Richard Hughes1354ea92017-09-19 15:58:31 +0100578 *
579 * Checks to see if a specific device GUID is supported, i.e. available in the
580 * AppStream metadata.
581 *
Richard Hughes4eada342017-10-03 21:20:32 +0100582 * Returns: %TRUE if the device is supported.
583 *
Richard Hughes1354ea92017-09-19 15:58:31 +0100584 * Since: 1.0.0
585 **/
586gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100587fu_plugin_check_supported (FuPlugin *self, const gchar *guid)
Richard Hughes1354ea92017-09-19 15:58:31 +0100588{
Richard Hughesaabdc372018-11-14 10:11:08 +0000589 gboolean retval = FALSE;
590 g_signal_emit (self, signals[SIGNAL_CHECK_SUPPORTED], 0, guid, &retval);
591 return retval;
Richard Hughes1354ea92017-09-19 15:58:31 +0100592}
593
594/**
Richard Hughesd7704d42017-08-08 20:29:09 +0100595 * fu_plugin_get_dmi_value:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100596 * @self: A #FuPlugin
Richard Hughes4eada342017-10-03 21:20:32 +0100597 * @dmi_id: A DMI ID, e.g. `BiosVersion`
Richard Hughesd7704d42017-08-08 20:29:09 +0100598 *
599 * Gets a hardware DMI value.
600 *
Richard Hughes4eada342017-10-03 21:20:32 +0100601 * Returns: The string, or %NULL
602 *
Richard Hughesd7704d42017-08-08 20:29:09 +0100603 * Since: 0.9.7
604 **/
605const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100606fu_plugin_get_dmi_value (FuPlugin *self, const gchar *dmi_id)
Richard Hughesd7704d42017-08-08 20:29:09 +0100607{
Richard Hughes12724852018-09-04 13:53:44 +0100608 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd7704d42017-08-08 20:29:09 +0100609 if (priv->hwids == NULL)
Richard Hughes7ef96b82017-08-23 18:28:24 +0100610 return NULL;
Richard Hughesd7704d42017-08-08 20:29:09 +0100611 return fu_hwids_get_value (priv->hwids, dmi_id);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100612}
613
Richard Hughes49e5e052017-09-03 12:15:41 +0100614/**
615 * fu_plugin_get_smbios_string:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100616 * @self: A #FuPlugin
Richard Hughes49e5e052017-09-03 12:15:41 +0100617 * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
618 * @offset: A SMBIOS offset
619 *
620 * Gets a hardware SMBIOS string.
621 *
622 * The @type and @offset can be referenced from the DMTF SMBIOS specification:
623 * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.1.1.pdf
624 *
Richard Hughes4eada342017-10-03 21:20:32 +0100625 * Returns: A string, or %NULL
626 *
Richard Hughes49e5e052017-09-03 12:15:41 +0100627 * Since: 0.9.8
628 **/
629const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100630fu_plugin_get_smbios_string (FuPlugin *self, guint8 structure_type, guint8 offset)
Richard Hughes49e5e052017-09-03 12:15:41 +0100631{
Richard Hughes12724852018-09-04 13:53:44 +0100632 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100633 if (priv->smbios == NULL)
634 return NULL;
635 return fu_smbios_get_string (priv->smbios, structure_type, offset, NULL);
636}
637
638/**
639 * fu_plugin_get_smbios_data:
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 *
643 * Gets a hardware SMBIOS data.
644 *
Richard Hughesdfaca2d2019-08-01 08:08:03 +0100645 * Returns: (transfer full): A #GBytes, or %NULL
Richard Hughes4eada342017-10-03 21:20:32 +0100646 *
Richard Hughes49e5e052017-09-03 12:15:41 +0100647 * Since: 0.9.8
648 **/
649GBytes *
Richard Hughes12724852018-09-04 13:53:44 +0100650fu_plugin_get_smbios_data (FuPlugin *self, guint8 structure_type)
Richard Hughes49e5e052017-09-03 12:15:41 +0100651{
Richard Hughes12724852018-09-04 13:53:44 +0100652 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100653 if (priv->smbios == NULL)
654 return NULL;
655 return fu_smbios_get_data (priv->smbios, structure_type, NULL);
656}
657
Richard Hughesb8f8db22017-04-25 15:56:00 +0100658void
Richard Hughes12724852018-09-04 13:53:44 +0100659fu_plugin_set_hwids (FuPlugin *self, FuHwids *hwids)
Richard Hughesb8f8db22017-04-25 15:56:00 +0100660{
Richard Hughes12724852018-09-04 13:53:44 +0100661 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesd7704d42017-08-08 20:29:09 +0100662 g_set_object (&priv->hwids, hwids);
Richard Hughesb8f8db22017-04-25 15:56:00 +0100663}
664
Richard Hughes49e5e052017-09-03 12:15:41 +0100665void
Richard Hughes12724852018-09-04 13:53:44 +0100666fu_plugin_set_udev_subsystems (FuPlugin *self, GPtrArray *udev_subsystems)
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100667{
Richard Hughes12724852018-09-04 13:53:44 +0100668 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +0100669 if (priv->udev_subsystems != NULL)
670 g_ptr_array_unref (priv->udev_subsystems);
671 priv->udev_subsystems = g_ptr_array_ref (udev_subsystems);
672}
673
674void
Richard Hughes12724852018-09-04 13:53:44 +0100675fu_plugin_set_quirks (FuPlugin *self, FuQuirks *quirks)
Richard Hughes9c028f02017-10-28 21:14:28 +0100676{
Richard Hughes12724852018-09-04 13:53:44 +0100677 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9c028f02017-10-28 21:14:28 +0100678 g_set_object (&priv->quirks, quirks);
679}
680
681/**
682 * fu_plugin_get_quirks:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100683 * @self: A #FuPlugin
Richard Hughes9c028f02017-10-28 21:14:28 +0100684 *
685 * Returns the hardware database object. This can be used to discover device
686 * quirks or other device-specific settings.
687 *
688 * Returns: (transfer none): a #FuQuirks, or %NULL if not set
689 *
690 * Since: 1.0.1
691 **/
692FuQuirks *
Richard Hughes12724852018-09-04 13:53:44 +0100693fu_plugin_get_quirks (FuPlugin *self)
Richard Hughes9c028f02017-10-28 21:14:28 +0100694{
Richard Hughes12724852018-09-04 13:53:44 +0100695 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9c028f02017-10-28 21:14:28 +0100696 return priv->quirks;
697}
698
Richard Hughes0eb123b2018-04-19 12:00:04 +0100699void
Richard Hughes12724852018-09-04 13:53:44 +0100700fu_plugin_set_runtime_versions (FuPlugin *self, GHashTable *runtime_versions)
Richard Hughes0eb123b2018-04-19 12:00:04 +0100701{
Richard Hughes12724852018-09-04 13:53:44 +0100702 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0eb123b2018-04-19 12:00:04 +0100703 priv->runtime_versions = g_hash_table_ref (runtime_versions);
704}
705
706/**
707 * fu_plugin_add_runtime_version:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100708 * @self: A #FuPlugin
Richard Hughes0eb123b2018-04-19 12:00:04 +0100709 * @component_id: An AppStream component id, e.g. "org.gnome.Software"
710 * @version: A version string, e.g. "1.2.3"
711 *
Richard Hughesdce91202019-04-08 12:47:45 +0100712 * Sets a runtime version of a specific dependency.
Richard Hughes0eb123b2018-04-19 12:00:04 +0100713 *
714 * Since: 1.0.7
715 **/
716void
Richard Hughes12724852018-09-04 13:53:44 +0100717fu_plugin_add_runtime_version (FuPlugin *self,
Richard Hughes0eb123b2018-04-19 12:00:04 +0100718 const gchar *component_id,
719 const gchar *version)
720{
Richard Hughes12724852018-09-04 13:53:44 +0100721 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesb01b4862018-04-20 16:39:48 +0100722 if (priv->runtime_versions == NULL)
723 return;
Richard Hughes0eb123b2018-04-19 12:00:04 +0100724 g_hash_table_insert (priv->runtime_versions,
725 g_strdup (component_id),
726 g_strdup (version));
727}
728
Richard Hughes34e0dab2018-04-20 16:43:00 +0100729void
Richard Hughes12724852018-09-04 13:53:44 +0100730fu_plugin_set_compile_versions (FuPlugin *self, GHashTable *compile_versions)
Richard Hughes34e0dab2018-04-20 16:43:00 +0100731{
Richard Hughes12724852018-09-04 13:53:44 +0100732 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes34e0dab2018-04-20 16:43:00 +0100733 priv->compile_versions = g_hash_table_ref (compile_versions);
734}
735
736/**
737 * fu_plugin_add_compile_version:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100738 * @self: A #FuPlugin
Richard Hughes34e0dab2018-04-20 16:43:00 +0100739 * @component_id: An AppStream component id, e.g. "org.gnome.Software"
740 * @version: A version string, e.g. "1.2.3"
741 *
Richard Hughesdce91202019-04-08 12:47:45 +0100742 * Sets a compile-time version of a specific dependency.
Richard Hughes34e0dab2018-04-20 16:43:00 +0100743 *
744 * Since: 1.0.7
745 **/
746void
Richard Hughes12724852018-09-04 13:53:44 +0100747fu_plugin_add_compile_version (FuPlugin *self,
Richard Hughes34e0dab2018-04-20 16:43:00 +0100748 const gchar *component_id,
749 const gchar *version)
750{
Richard Hughes12724852018-09-04 13:53:44 +0100751 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes34e0dab2018-04-20 16:43:00 +0100752 if (priv->compile_versions == NULL)
753 return;
754 g_hash_table_insert (priv->compile_versions,
755 g_strdup (component_id),
756 g_strdup (version));
757}
758
Richard Hughes9c028f02017-10-28 21:14:28 +0100759/**
760 * fu_plugin_lookup_quirk_by_id:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100761 * @self: A #FuPlugin
Richard Hughes87fb9ff2018-06-28 12:55:59 +0100762 * @group: A string, e.g. "DfuFlags"
763 * @key: An ID to match the entry, e.g. "Summary"
Richard Hughes9c028f02017-10-28 21:14:28 +0100764 *
765 * Looks up an entry in the hardware database using a string value.
766 *
767 * Returns: (transfer none): values from the database, or %NULL if not found
768 *
769 * Since: 1.0.1
770 **/
771const gchar *
Richard Hughes12724852018-09-04 13:53:44 +0100772fu_plugin_lookup_quirk_by_id (FuPlugin *self, const gchar *group, const gchar *key)
Richard Hughes9c028f02017-10-28 21:14:28 +0100773{
Richard Hughes12724852018-09-04 13:53:44 +0100774 FuPluginPrivate *priv = GET_PRIVATE (self);
775 g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
Richard Hughes9c028f02017-10-28 21:14:28 +0100776
Richard Hughes9c028f02017-10-28 21:14:28 +0100777 /* exact ID */
Richard Hughes87fb9ff2018-06-28 12:55:59 +0100778 return fu_quirks_lookup_by_id (priv->quirks, group, key);
Richard Hughes9c028f02017-10-28 21:14:28 +0100779}
780
781/**
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100782 * fu_plugin_lookup_quirk_by_id_as_uint64:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100783 * @self: A #FuPlugin
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100784 * @group: A string, e.g. "DfuFlags"
785 * @key: An ID to match the entry, e.g. "Size"
786 *
787 * Looks up an entry in the hardware database using a string key, returning
788 * an integer value. Values are assumed base 10, unless prefixed with "0x"
789 * where they are parsed as base 16.
790 *
791 * Returns: (transfer none): value from the database, or 0 if not found
792 *
793 * Since: 1.1.2
794 **/
795guint64
Richard Hughes12724852018-09-04 13:53:44 +0100796fu_plugin_lookup_quirk_by_id_as_uint64 (FuPlugin *self, const gchar *group, const gchar *key)
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100797{
Richard Hughes12724852018-09-04 13:53:44 +0100798 return fu_common_strtoull (fu_plugin_lookup_quirk_by_id (self, group, key));
Richard Hughes8fe7cdd2018-08-23 10:02:44 +0100799}
800
Richard Hughes1354ea92017-09-19 15:58:31 +0100801void
Richard Hughes12724852018-09-04 13:53:44 +0100802fu_plugin_set_smbios (FuPlugin *self, FuSmbios *smbios)
Richard Hughes49e5e052017-09-03 12:15:41 +0100803{
Richard Hughes12724852018-09-04 13:53:44 +0100804 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes49e5e052017-09-03 12:15:41 +0100805 g_set_object (&priv->smbios, smbios);
806}
807
Richard Hughesb8f8db22017-04-25 15:56:00 +0100808/**
Richard Hughesb0829032017-01-10 09:27:08 +0000809 * fu_plugin_set_coldplug_delay:
Richard Hughes2c0635a2018-09-04 14:52:46 +0100810 * @self: A #FuPlugin
Richard Hughesb0829032017-01-10 09:27:08 +0000811 * @duration: A delay in milliseconds
812 *
813 * Set the minimum time that should be waited inbetween the call to
814 * fu_plugin_coldplug_prepare() and fu_plugin_coldplug(). This is usually going
815 * to be the minimum hardware initialisation time from a datasheet.
816 *
817 * It is better to use this function rather than using a sleep() in the plugin
818 * itself as then only one delay is done in the daemon rather than waiting for
819 * each coldplug prepare in a serial way.
820 *
821 * Additionally, very long delays should be avoided as the daemon will be
822 * blocked from processing requests whilst the coldplug delay is being
823 * performed.
824 *
825 * Since: 0.8.0
826 **/
827void
Richard Hughes12724852018-09-04 13:53:44 +0100828fu_plugin_set_coldplug_delay (FuPlugin *self, guint duration)
Richard Hughesb0829032017-01-10 09:27:08 +0000829{
Richard Hughes12724852018-09-04 13:53:44 +0100830 g_return_if_fail (FU_IS_PLUGIN (self));
Richard Hughesb0829032017-01-10 09:27:08 +0000831 g_return_if_fail (duration > 0);
832
833 /* check sanity */
834 if (duration > FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM) {
835 g_warning ("duration of %ums is crazy, truncating to %ums",
836 duration,
837 FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM);
838 duration = FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM;
839 }
840
841 /* emit */
Richard Hughes12724852018-09-04 13:53:44 +0100842 g_signal_emit (self, signals[SIGNAL_SET_COLDPLUG_DELAY], 0, duration);
Richard Hughesb0829032017-01-10 09:27:08 +0000843}
844
Richard Hughes4b303802019-10-04 13:22:51 +0100845static gboolean
846fu_plugin_device_attach (FuPlugin *self, FuDevice *device, GError **error)
847{
848 g_autoptr(FuDeviceLocker) locker = NULL;
849 if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) {
850 g_debug ("already in runtime mode, skipping");
851 return TRUE;
852 }
853 locker = fu_device_locker_new (device, error);
854 if (locker == NULL)
855 return FALSE;
856 return fu_device_attach (device, error);
857}
858
859static gboolean
860fu_plugin_device_detach (FuPlugin *self, FuDevice *device, GError **error)
861{
862 g_autoptr(FuDeviceLocker) locker = NULL;
863 if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) {
864 g_debug ("already in bootloader mode, skipping");
865 return TRUE;
866 }
867 locker = fu_device_locker_new (device, error);
868 if (locker == NULL)
869 return FALSE;
870 return fu_device_detach (device, error);
871}
872
873static gboolean
Richard Hughes4b303802019-10-04 13:22:51 +0100874fu_plugin_device_activate (FuPlugin *self, FuDevice *device, GError **error)
875{
876 g_autoptr(FuDeviceLocker) locker = NULL;
877 locker = fu_device_locker_new (device, error);
878 if (locker == NULL)
879 return FALSE;
880 return fu_device_activate (device, error);
881}
882
883static gboolean
884fu_plugin_device_write_firmware (FuPlugin *self, FuDevice *device,
885 GBytes *fw, FwupdInstallFlags flags,
886 GError **error)
887{
888 g_autoptr(FuDeviceLocker) locker = NULL;
889 locker = fu_device_locker_new (device, error);
890 if (locker == NULL)
891 return FALSE;
892 return fu_device_write_firmware (device, fw, flags, error);
893}
894
Richard Hughes7f677212019-10-05 16:19:40 +0100895static gboolean
896fu_plugin_device_read_firmware (FuPlugin *self, FuDevice *device, GError **error)
897{
898 g_autoptr(FuDeviceLocker) locker = NULL;
899 g_autoptr(GBytes) fw = NULL;
900 GChecksumType checksum_types[] = {
901 G_CHECKSUM_SHA1,
902 G_CHECKSUM_SHA256,
903 0 };
904 locker = fu_device_locker_new (device, error);
905 if (locker == NULL)
906 return FALSE;
907 if (!fu_device_detach (device, error))
908 return FALSE;
909 fw = fu_device_read_firmware (device, error);
910 if (fw == NULL) {
911 g_autoptr(GError) error_local = NULL;
912 if (!fu_device_attach (device, &error_local))
913 g_debug ("ignoring: %s", error_local->message);
914 return FALSE;
915 }
916 for (guint i = 0; checksum_types[i] != 0; i++) {
917 g_autofree gchar *hash = NULL;
918 hash = g_compute_checksum_for_bytes (checksum_types[i], fw);
919 fu_device_add_checksum (device, hash);
920 }
921 return fu_device_attach (device, error);
922}
923
Richard Hughesd0905142016-03-13 09:46:49 +0000924gboolean
Richard Hughes12724852018-09-04 13:53:44 +0100925fu_plugin_runner_startup (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +0000926{
Richard Hughes12724852018-09-04 13:53:44 +0100927 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +0000928 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +0000929 g_autoptr(GError) error_local = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +0000930
931 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +0000932 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +0000933 return TRUE;
934
Richard Hughes639da472018-01-06 22:35:04 +0000935 /* no object loaded */
936 if (priv->module == NULL)
937 return TRUE;
938
Richard Hughesd0905142016-03-13 09:46:49 +0000939 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +0000940 g_module_symbol (priv->module, "fu_plugin_startup", (gpointer *) &func);
941 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +0000942 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +0000943 g_debug ("performing startup() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +0000944 if (!func (self, &error_local)) {
945 if (error_local == NULL) {
946 g_critical ("unset error in plugin %s for startup()",
947 priv->name);
948 g_set_error_literal (&error_local,
949 FWUPD_ERROR,
950 FWUPD_ERROR_INTERNAL,
951 "unspecified error");
952 }
953 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
954 "failed to startup using %s: ",
955 priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +0000956 return FALSE;
957 }
958 return TRUE;
959}
960
961static gboolean
962fu_plugin_runner_offline_invalidate (GError **error)
963{
964 g_autoptr(GError) error_local = NULL;
965 g_autoptr(GFile) file1 = NULL;
966
967 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
968
969 file1 = g_file_new_for_path (FU_OFFLINE_TRIGGER_FILENAME);
970 if (!g_file_query_exists (file1, NULL))
971 return TRUE;
972 if (!g_file_delete (file1, NULL, &error_local)) {
973 g_set_error (error,
974 FWUPD_ERROR,
975 FWUPD_ERROR_INTERNAL,
976 "Cannot delete %s: %s",
977 FU_OFFLINE_TRIGGER_FILENAME,
978 error_local->message);
979 return FALSE;
980 }
981 return TRUE;
982}
983
984static gboolean
985fu_plugin_runner_offline_setup (GError **error)
986{
987 gint rc;
Richard Hughes484ee292019-03-22 16:10:50 +0000988 g_autofree gchar *filename = NULL;
Mario Limoncielloe1b4b202019-04-30 10:01:19 -0500989 g_autofree gchar *symlink_target = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG);
Richard Hughescff38bc2016-12-12 12:03:37 +0000990
991 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
992
Richard Hughes484ee292019-03-22 16:10:50 +0000993 /* does already exist */
994 filename = fu_common_realpath (FU_OFFLINE_TRIGGER_FILENAME, NULL);
995 if (g_strcmp0 (filename, symlink_target) == 0) {
996 g_debug ("%s already points to %s, skipping creation",
997 FU_OFFLINE_TRIGGER_FILENAME, symlink_target);
998 return TRUE;
999 }
1000
Richard Hughescff38bc2016-12-12 12:03:37 +00001001 /* create symlink for the systemd-system-update-generator */
Richard Hughes484ee292019-03-22 16:10:50 +00001002 rc = symlink (symlink_target, FU_OFFLINE_TRIGGER_FILENAME);
Richard Hughescff38bc2016-12-12 12:03:37 +00001003 if (rc < 0) {
1004 g_set_error (error,
1005 FWUPD_ERROR,
1006 FWUPD_ERROR_INTERNAL,
1007 "Failed to create symlink %s to %s: %s",
1008 FU_OFFLINE_TRIGGER_FILENAME,
1009 "/var/lib", strerror (errno));
Richard Hughesd0905142016-03-13 09:46:49 +00001010 return FALSE;
1011 }
1012 return TRUE;
1013}
1014
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001015static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001016fu_plugin_runner_device_generic (FuPlugin *self, FuDevice *device,
Richard Hughes4b303802019-10-04 13:22:51 +01001017 const gchar *symbol_name,
1018 FuPluginDeviceFunc device_func,
1019 GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001020{
Richard Hughes12724852018-09-04 13:53:44 +01001021 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001022 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001023 g_autoptr(GError) error_local = NULL;
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001024
1025 /* not enabled */
1026 if (!priv->enabled)
1027 return TRUE;
1028
Richard Hughesd3d96cc2017-11-14 11:34:33 +00001029 /* no object loaded */
1030 if (priv->module == NULL)
1031 return TRUE;
1032
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001033 /* optional */
1034 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
Richard Hughes4b303802019-10-04 13:22:51 +01001035 if (func == NULL) {
1036 if (device_func != NULL) {
1037 g_debug ("running superclassed %s() on %s",
1038 symbol_name + 10, priv->name);
1039 return device_func (self, device, error);
1040 }
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001041 return TRUE;
Richard Hughes4b303802019-10-04 13:22:51 +01001042 }
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001043 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001044 if (!func (self, device, &error_local)) {
1045 if (error_local == NULL) {
1046 g_critical ("unset error in plugin %s for %s()",
1047 priv->name, symbol_name + 10);
1048 g_set_error_literal (&error_local,
1049 FWUPD_ERROR,
1050 FWUPD_ERROR_INTERNAL,
1051 "unspecified error");
1052 }
1053 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1054 "failed to %s using %s: ",
1055 symbol_name + 10, priv->name);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001056 return FALSE;
1057 }
1058 return TRUE;
1059}
1060
Richard Hughesdbd8c762018-06-15 20:31:40 +01001061static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001062fu_plugin_runner_flagged_device_generic (FuPlugin *self, FwupdInstallFlags flags,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001063 FuDevice *device,
1064 const gchar *symbol_name, GError **error)
1065{
Richard Hughes12724852018-09-04 13:53:44 +01001066 FuPluginPrivate *priv = GET_PRIVATE (self);
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001067 FuPluginFlaggedDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001068 g_autoptr(GError) error_local = NULL;
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001069
1070 /* not enabled */
1071 if (!priv->enabled)
1072 return TRUE;
1073
1074 /* no object loaded */
1075 if (priv->module == NULL)
1076 return TRUE;
1077
1078 /* optional */
1079 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1080 if (func == NULL)
1081 return TRUE;
1082 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001083 if (!func (self, flags, device, &error_local)) {
1084 if (error_local == NULL) {
1085 g_critical ("unset error in plugin %s for %s()",
1086 priv->name, symbol_name + 10);
1087 g_set_error_literal (&error_local,
1088 FWUPD_ERROR,
1089 FWUPD_ERROR_INTERNAL,
1090 "unspecified error");
1091 }
1092 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1093 "failed to %s using %s: ",
1094 symbol_name + 10, priv->name);
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001095 return FALSE;
1096 }
1097 return TRUE;
1098
1099}
1100
1101static gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001102fu_plugin_runner_device_array_generic (FuPlugin *self, GPtrArray *devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001103 const gchar *symbol_name, GError **error)
1104{
Richard Hughes12724852018-09-04 13:53:44 +01001105 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesdbd8c762018-06-15 20:31:40 +01001106 FuPluginDeviceArrayFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001107 g_autoptr(GError) error_local = NULL;
Richard Hughesdbd8c762018-06-15 20:31:40 +01001108
1109 /* not enabled */
1110 if (!priv->enabled)
1111 return TRUE;
1112
1113 /* no object loaded */
1114 if (priv->module == NULL)
1115 return TRUE;
1116
1117 /* optional */
1118 g_module_symbol (priv->module, symbol_name, (gpointer *) &func);
1119 if (func == NULL)
1120 return TRUE;
1121 g_debug ("performing %s() on %s", symbol_name + 10, priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001122 if (!func (self, devices, &error_local)) {
1123 if (error_local == NULL) {
1124 g_critical ("unset error in plugin %s for %s()",
1125 priv->name, symbol_name + 10);
1126 g_set_error_literal (&error_local,
1127 FWUPD_ERROR,
1128 FWUPD_ERROR_INTERNAL,
1129 "unspecified error");
1130 }
1131 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1132 "failed to %s using %s: ",
1133 symbol_name + 10, priv->name);
Richard Hughesdbd8c762018-06-15 20:31:40 +01001134 return FALSE;
1135 }
1136 return TRUE;
1137}
1138
Richard Hughesd0905142016-03-13 09:46:49 +00001139gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001140fu_plugin_runner_coldplug (FuPlugin *self, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00001141{
Richard Hughes12724852018-09-04 13:53:44 +01001142 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001143 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001144 g_autoptr(GError) error_local = NULL;
Richard Hughesd0905142016-03-13 09:46:49 +00001145
1146 /* not enabled */
Richard Hughescff38bc2016-12-12 12:03:37 +00001147 if (!priv->enabled)
Richard Hughesd0905142016-03-13 09:46:49 +00001148 return TRUE;
1149
Richard Hughes639da472018-01-06 22:35:04 +00001150 /* no object loaded */
1151 if (priv->module == NULL)
1152 return TRUE;
1153
Richard Hughesd0905142016-03-13 09:46:49 +00001154 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00001155 g_module_symbol (priv->module, "fu_plugin_coldplug", (gpointer *) &func);
1156 if (func == NULL)
Richard Hughesd0905142016-03-13 09:46:49 +00001157 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001158 g_debug ("performing coldplug() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001159 if (!func (self, &error_local)) {
1160 if (error_local == NULL) {
1161 g_critical ("unset error in plugin %s for coldplug()",
1162 priv->name);
1163 g_set_error_literal (&error_local,
1164 FWUPD_ERROR,
1165 FWUPD_ERROR_INTERNAL,
1166 "unspecified error");
1167 }
1168 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1169 "failed to coldplug using %s: ", priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00001170 return FALSE;
1171 }
1172 return TRUE;
1173}
1174
Richard Hughes7b8b2022016-12-12 16:15:03 +00001175gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001176fu_plugin_runner_recoldplug (FuPlugin *self, GError **error)
Richard Hughes2de8f132018-01-17 09:12:02 +00001177{
Richard Hughes12724852018-09-04 13:53:44 +01001178 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes2de8f132018-01-17 09:12:02 +00001179 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001180 g_autoptr(GError) error_local = NULL;
Richard Hughes2de8f132018-01-17 09:12:02 +00001181
1182 /* not enabled */
1183 if (!priv->enabled)
1184 return TRUE;
1185
1186 /* no object loaded */
1187 if (priv->module == NULL)
1188 return TRUE;
1189
1190 /* optional */
1191 g_module_symbol (priv->module, "fu_plugin_recoldplug", (gpointer *) &func);
1192 if (func == NULL)
1193 return TRUE;
1194 g_debug ("performing recoldplug() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001195 if (!func (self, &error_local)) {
1196 if (error_local == NULL) {
1197 g_critical ("unset error in plugin %s for recoldplug()",
1198 priv->name);
1199 g_set_error_literal (&error_local,
1200 FWUPD_ERROR,
1201 FWUPD_ERROR_INTERNAL,
1202 "unspecified error");
1203 }
1204 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1205 "failed to recoldplug using %s: ",
1206 priv->name);
Richard Hughes2de8f132018-01-17 09:12:02 +00001207 return FALSE;
1208 }
1209 return TRUE;
1210}
1211
1212gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001213fu_plugin_runner_coldplug_prepare (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001214{
Richard Hughes12724852018-09-04 13:53:44 +01001215 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001216 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001217 g_autoptr(GError) error_local = NULL;
Richard Hughes46487c92017-01-07 21:26:34 +00001218
1219 /* not enabled */
1220 if (!priv->enabled)
1221 return TRUE;
1222
Richard Hughes639da472018-01-06 22:35:04 +00001223 /* no object loaded */
1224 if (priv->module == NULL)
1225 return TRUE;
1226
Richard Hughes46487c92017-01-07 21:26:34 +00001227 /* optional */
1228 g_module_symbol (priv->module, "fu_plugin_coldplug_prepare", (gpointer *) &func);
1229 if (func == NULL)
1230 return TRUE;
1231 g_debug ("performing coldplug_prepare() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001232 if (!func (self, &error_local)) {
1233 if (error_local == NULL) {
1234 g_critical ("unset error in plugin %s for coldplug_prepare()",
1235 priv->name);
1236 g_set_error_literal (&error_local,
1237 FWUPD_ERROR,
1238 FWUPD_ERROR_INTERNAL,
1239 "unspecified error");
1240 }
1241 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1242 "failed to coldplug_prepare using %s: ",
1243 priv->name);
Richard Hughes46487c92017-01-07 21:26:34 +00001244 return FALSE;
1245 }
1246 return TRUE;
1247}
1248
1249gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001250fu_plugin_runner_coldplug_cleanup (FuPlugin *self, GError **error)
Richard Hughes46487c92017-01-07 21:26:34 +00001251{
Richard Hughes12724852018-09-04 13:53:44 +01001252 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes46487c92017-01-07 21:26:34 +00001253 FuPluginStartupFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001254 g_autoptr(GError) error_local = NULL;
Richard Hughes46487c92017-01-07 21:26:34 +00001255
1256 /* not enabled */
1257 if (!priv->enabled)
1258 return TRUE;
1259
Richard Hughes639da472018-01-06 22:35:04 +00001260 /* no object loaded */
1261 if (priv->module == NULL)
1262 return TRUE;
1263
Richard Hughes46487c92017-01-07 21:26:34 +00001264 /* optional */
1265 g_module_symbol (priv->module, "fu_plugin_coldplug_cleanup", (gpointer *) &func);
1266 if (func == NULL)
1267 return TRUE;
1268 g_debug ("performing coldplug_cleanup() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001269 if (!func (self, &error_local)) {
1270 if (error_local == NULL) {
1271 g_critical ("unset error in plugin %s for coldplug_cleanup()",
1272 priv->name);
1273 g_set_error_literal (&error_local,
1274 FWUPD_ERROR,
1275 FWUPD_ERROR_INTERNAL,
1276 "unspecified error");
1277 }
1278 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1279 "failed to coldplug_cleanup using %s: ",
1280 priv->name);
Richard Hughes46487c92017-01-07 21:26:34 +00001281 return FALSE;
1282 }
1283 return TRUE;
1284}
1285
1286gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001287fu_plugin_runner_composite_prepare (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001288{
Richard Hughes12724852018-09-04 13:53:44 +01001289 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001290 "fu_plugin_composite_prepare",
1291 error);
1292}
1293
1294gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001295fu_plugin_runner_composite_cleanup (FuPlugin *self, GPtrArray *devices, GError **error)
Richard Hughesdbd8c762018-06-15 20:31:40 +01001296{
Richard Hughes12724852018-09-04 13:53:44 +01001297 return fu_plugin_runner_device_array_generic (self, devices,
Richard Hughesdbd8c762018-06-15 20:31:40 +01001298 "fu_plugin_composite_cleanup",
1299 error);
1300}
1301
1302gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001303fu_plugin_runner_update_prepare (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001304 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001305{
Richard Hughes12724852018-09-04 13:53:44 +01001306 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001307 "fu_plugin_update_prepare",
1308 error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001309}
1310
1311gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001312fu_plugin_runner_update_cleanup (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001313 GError **error)
Richard Hughes7b8b2022016-12-12 16:15:03 +00001314{
Richard Hughes12724852018-09-04 13:53:44 +01001315 return fu_plugin_runner_flagged_device_generic (self, flags, device,
Mario Limoncielloe3b1a3f2018-08-21 13:01:45 -05001316 "fu_plugin_update_cleanup",
1317 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001318}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001319
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001320gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001321fu_plugin_runner_update_attach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001322{
Richard Hughes12724852018-09-04 13:53:44 +01001323 return fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001324 "fu_plugin_update_attach",
1325 fu_plugin_device_attach,
1326 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001327}
Richard Hughes7b8b2022016-12-12 16:15:03 +00001328
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001329gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001330fu_plugin_runner_update_detach (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001331{
Richard Hughes12724852018-09-04 13:53:44 +01001332 return fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001333 "fu_plugin_update_detach",
1334 fu_plugin_device_detach,
1335 error);
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001336}
1337
1338gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001339fu_plugin_runner_update_reload (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughes0d7fdb32017-11-11 20:23:14 +00001340{
Richard Hughes42f33df2019-10-05 20:52:33 +01001341 FuPluginPrivate *priv = GET_PRIVATE (self);
1342 g_autoptr(FuDeviceLocker) locker = NULL;
1343
1344 /* not enabled */
1345 if (!priv->enabled)
1346 return TRUE;
1347
1348 /* no object loaded */
1349 locker = fu_device_locker_new (device, error);
1350 if (locker == NULL)
1351 return FALSE;
1352 return fu_device_reload (device, error);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001353}
1354
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001355/**
1356 * fu_plugin_add_udev_subsystem:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001357 * @self: a #FuPlugin
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001358 * @subsystem: a subsystem name, e.g. `pciport`
1359 *
1360 * Registers the udev subsystem to be watched by the daemon.
1361 *
1362 * Plugins can use this method only in fu_plugin_init()
1363 **/
1364void
Richard Hughes12724852018-09-04 13:53:44 +01001365fu_plugin_add_udev_subsystem (FuPlugin *self, const gchar *subsystem)
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001366{
Richard Hughes12724852018-09-04 13:53:44 +01001367 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001368 for (guint i = 0; i < priv->udev_subsystems->len; i++) {
1369 const gchar *subsystem_tmp = g_ptr_array_index (priv->udev_subsystems, i);
1370 if (g_strcmp0 (subsystem_tmp, subsystem) == 0)
1371 return;
1372 }
1373 g_debug ("added udev subsystem watch of %s", subsystem);
1374 g_ptr_array_add (priv->udev_subsystems, g_strdup (subsystem));
1375}
1376
Richard Hughes989acf12019-10-05 20:16:47 +01001377/**
1378 * fu_plugin_set_device_gtype:
1379 * @self: a #FuPlugin
1380 * @device_gtype: a #GType `FU_TYPE_DEVICE`
1381 *
1382 * Sets the device #GType which is used when creating devices.
1383 *
1384 * If this method is used then fu_plugin_usb_device_added() is not called, and
1385 * instead the object is created in the daemon for the plugin.
1386 *
1387 * Plugins can use this method only in fu_plugin_init()
1388 *
1389 * Since: 1.3.3
1390 **/
1391void
1392fu_plugin_set_device_gtype (FuPlugin *self, GType device_gtype)
1393{
1394 FuPluginPrivate *priv = GET_PRIVATE (self);
1395 priv->device_gtype = device_gtype;
1396}
1397
1398static gboolean
1399fu_plugin_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error)
1400{
1401 FuPluginPrivate *priv = GET_PRIVATE (self);
1402 g_autoptr(FuDevice) dev = NULL;
1403 g_autoptr(FuDeviceLocker) locker = NULL;
1404 dev = g_object_new (priv->device_gtype, NULL);
1405 fu_device_incorporate (FU_DEVICE (dev), FU_DEVICE (device));
1406 locker = fu_device_locker_new (dev, error);
1407 if (locker == NULL)
1408 return FALSE;
1409 fu_plugin_device_add (self, FU_DEVICE (dev));
1410 return TRUE;
1411}
1412
Richard Hughes104f6512017-11-24 11:44:57 +00001413gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001414fu_plugin_runner_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error)
Richard Hughes104f6512017-11-24 11:44:57 +00001415{
Richard Hughes12724852018-09-04 13:53:44 +01001416 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes104f6512017-11-24 11:44:57 +00001417 FuPluginUsbDeviceAddedFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001418 g_autoptr(GError) error_local = NULL;
Richard Hughes104f6512017-11-24 11:44:57 +00001419
1420 /* not enabled */
1421 if (!priv->enabled)
1422 return TRUE;
Richard Hughes639da472018-01-06 22:35:04 +00001423
1424 /* no object loaded */
Richard Hughes104f6512017-11-24 11:44:57 +00001425 if (priv->module == NULL)
1426 return TRUE;
1427
1428 /* optional */
1429 g_module_symbol (priv->module, "fu_plugin_usb_device_added", (gpointer *) &func);
Richard Hughes989acf12019-10-05 20:16:47 +01001430 if (func == NULL) {
1431 if (priv->device_gtype != G_TYPE_INVALID) {
1432 g_debug ("using generic usb_device_added() on %s", priv->name);
1433 return fu_plugin_usb_device_added (self, device, error);
1434 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001435 return TRUE;
Richard Hughes989acf12019-10-05 20:16:47 +01001436 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001437 g_debug ("performing usb_device_added() on %s", priv->name);
1438 if (!func (self, device, &error_local)) {
1439 if (error_local == NULL) {
1440 g_critical ("unset error in plugin %s for usb_device_added()",
1441 priv->name);
1442 g_set_error_literal (&error_local,
1443 FWUPD_ERROR,
1444 FWUPD_ERROR_INTERNAL,
1445 "unspecified error");
1446 }
1447 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1448 "failed to add device using on %s: ",
1449 priv->name);
1450 return FALSE;
Richard Hughes104f6512017-11-24 11:44:57 +00001451 }
1452 return TRUE;
1453}
1454
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001455gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001456fu_plugin_runner_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error)
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001457{
Richard Hughes12724852018-09-04 13:53:44 +01001458 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001459 FuPluginUdevDeviceAddedFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001460 g_autoptr(GError) error_local = NULL;
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001461
1462 /* not enabled */
1463 if (!priv->enabled)
1464 return TRUE;
1465
1466 /* no object loaded */
1467 if (priv->module == NULL)
1468 return TRUE;
1469
1470 /* optional */
1471 g_module_symbol (priv->module, "fu_plugin_udev_device_added", (gpointer *) &func);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001472 if (func == NULL)
1473 return TRUE;
1474 g_debug ("performing udev_device_added() on %s", priv->name);
1475 if (!func (self, device, &error_local)) {
1476 if (error_local == NULL) {
1477 g_critical ("unset error in plugin %s for udev_device_added()",
1478 priv->name);
1479 g_set_error_literal (&error_local,
1480 FWUPD_ERROR,
1481 FWUPD_ERROR_INTERNAL,
1482 "unspecified error");
1483 }
1484 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1485 "failed to add device using on %s: ",
1486 priv->name);
1487 return FALSE;
Richard Hughes9d6e0e72018-08-24 20:20:17 +01001488 }
1489 return TRUE;
1490}
1491
Richard Hughes5e952ce2019-08-26 11:09:46 +01001492gboolean
1493fu_plugin_runner_udev_device_changed (FuPlugin *self, FuUdevDevice *device, GError **error)
1494{
1495 FuPluginPrivate *priv = GET_PRIVATE (self);
1496 FuPluginUdevDeviceAddedFunc func = NULL;
1497 g_autoptr(GError) error_local = NULL;
1498
1499 /* not enabled */
1500 if (!priv->enabled)
1501 return TRUE;
1502
1503 /* no object loaded */
1504 if (priv->module == NULL)
1505 return TRUE;
1506
1507 /* optional */
1508 g_module_symbol (priv->module, "fu_plugin_udev_device_changed", (gpointer *) &func);
1509 if (func == NULL)
1510 return TRUE;
1511 g_debug ("performing udev_device_changed() on %s", priv->name);
1512 if (!func (self, device, &error_local)) {
1513 if (error_local == NULL) {
1514 g_critical ("unset error in plugin %s for udev_device_changed()",
1515 priv->name);
1516 g_set_error_literal (&error_local,
1517 FWUPD_ERROR,
1518 FWUPD_ERROR_INTERNAL,
1519 "unspecified error");
1520 }
1521 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1522 "failed to change device on %s: ",
1523 priv->name);
1524 return FALSE;
1525 }
1526 return TRUE;
1527}
1528
Richard Hughese1fd34d2017-08-24 14:19:51 +01001529void
Richard Hughes12724852018-09-04 13:53:44 +01001530fu_plugin_runner_device_removed (FuPlugin *self, FuDevice *device)
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001531{
1532 g_autoptr(GError) error_local= NULL;
1533
Richard Hughes12724852018-09-04 13:53:44 +01001534 if (!fu_plugin_runner_device_generic (self, device,
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001535 "fu_plugin_device_removed",
Richard Hughes4b303802019-10-04 13:22:51 +01001536 NULL,
Mario Limoncielloe260ead2018-09-01 09:19:24 -05001537 &error_local))
1538 g_warning ("%s", error_local->message);
1539}
1540
1541void
Richard Hughes12724852018-09-04 13:53:44 +01001542fu_plugin_runner_device_register (FuPlugin *self, FuDevice *device)
Richard Hughese1fd34d2017-08-24 14:19:51 +01001543{
Richard Hughes12724852018-09-04 13:53:44 +01001544 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughese1fd34d2017-08-24 14:19:51 +01001545 FuPluginDeviceRegisterFunc func = NULL;
1546
1547 /* not enabled */
1548 if (!priv->enabled)
1549 return;
Richard Hughes34834102017-11-21 21:55:00 +00001550 if (priv->module == NULL)
1551 return;
Richard Hughese1fd34d2017-08-24 14:19:51 +01001552
Mario Limonciello4910b242018-06-22 15:04:21 -05001553 /* don't notify plugins on their own devices */
Richard Hughes12724852018-09-04 13:53:44 +01001554 if (g_strcmp0 (fu_device_get_plugin (device), fu_plugin_get_name (self)) == 0)
Mario Limonciello4910b242018-06-22 15:04:21 -05001555 return;
1556
Richard Hughese1fd34d2017-08-24 14:19:51 +01001557 /* optional */
1558 g_module_symbol (priv->module, "fu_plugin_device_registered", (gpointer *) &func);
1559 if (func != NULL) {
Richard Hughes1bf7ff92018-08-24 20:21:35 +01001560 g_debug ("performing fu_plugin_device_registered() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01001561 func (self, device);
Richard Hughese1fd34d2017-08-24 14:19:51 +01001562 }
1563}
1564
Richard Hughesc6c312f2019-02-01 16:37:14 +00001565gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001566fu_plugin_runner_schedule_update (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +00001567 FuDevice *device,
Richard Hughes994b4d92019-03-25 14:28:30 +00001568 FwupdRelease *release,
Richard Hughescff38bc2016-12-12 12:03:37 +00001569 GBytes *blob_cab,
Richard Hughes5cbb5cf2019-04-26 16:48:03 +01001570 FwupdInstallFlags flags,
Richard Hughescff38bc2016-12-12 12:03:37 +00001571 GError **error)
1572{
Richard Hughes0a906262019-05-16 13:38:47 +01001573 gchar tmpname[] = {"XXXXXX.cab"};
Richard Hughescff38bc2016-12-12 12:03:37 +00001574 g_autofree gchar *dirname = NULL;
1575 g_autofree gchar *filename = NULL;
Richard Hughes780ef3f2018-01-12 16:20:31 +00001576 g_autoptr(FuHistory) history = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001577 g_autoptr(GFile) file = NULL;
1578
1579 /* id already exists */
Richard Hughes780ef3f2018-01-12 16:20:31 +00001580 history = fu_history_new ();
Richard Hughes5cbb5cf2019-04-26 16:48:03 +01001581 if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) {
1582 g_autoptr(FuDevice) res_tmp = NULL;
1583 res_tmp = fu_history_get_device_by_id (history, fu_device_get_id (device), NULL);
1584 if (res_tmp != NULL &&
1585 fu_device_get_update_state (res_tmp) == FWUPD_UPDATE_STATE_PENDING) {
1586 g_set_error (error,
1587 FWUPD_ERROR,
1588 FWUPD_ERROR_ALREADY_PENDING,
1589 "%s is already scheduled to be updated",
1590 fu_device_get_id (device));
1591 return FALSE;
1592 }
Richard Hughescff38bc2016-12-12 12:03:37 +00001593 }
1594
1595 /* create directory */
Richard Hughes4be17d12018-05-30 20:36:29 +01001596 dirname = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG);
Richard Hughescff38bc2016-12-12 12:03:37 +00001597 file = g_file_new_for_path (dirname);
1598 if (!g_file_query_exists (file, NULL)) {
1599 if (!g_file_make_directory_with_parents (file, NULL, error))
1600 return FALSE;
1601 }
1602
1603 /* get a random filename */
1604 for (guint i = 0; i < 6; i++)
1605 tmpname[i] = (gchar) g_random_int_range ('A', 'Z');
1606 filename = g_build_filename (dirname, tmpname, NULL);
1607
1608 /* just copy to the temp file */
Richard Hughes23135eb2017-11-30 21:01:25 +00001609 fu_device_set_status (device, FWUPD_STATUS_SCHEDULING);
Richard Hughescff38bc2016-12-12 12:03:37 +00001610 if (!g_file_set_contents (filename,
1611 g_bytes_get_data (blob_cab, NULL),
1612 (gssize) g_bytes_get_size (blob_cab),
1613 error))
1614 return FALSE;
1615
1616 /* schedule for next boot */
1617 g_debug ("schedule %s to be installed to %s on next boot",
1618 filename, fu_device_get_id (device));
Richard Hughes994b4d92019-03-25 14:28:30 +00001619 fwupd_release_set_filename (release, filename);
Richard Hughescff38bc2016-12-12 12:03:37 +00001620
1621 /* add to database */
Richard Hughes809abea2019-03-23 11:06:18 +00001622 fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT);
Richard Hughes3e90a582018-01-06 22:38:09 +00001623 fu_device_set_update_state (device, FWUPD_UPDATE_STATE_PENDING);
Richard Hughes994b4d92019-03-25 14:28:30 +00001624 if (!fu_history_add_device (history, device, release, error))
Richard Hughescff38bc2016-12-12 12:03:37 +00001625 return FALSE;
1626
1627 /* next boot we run offline */
Richard Hughesdb69c812019-03-22 16:10:15 +00001628 fu_device_set_progress (device, 100);
Richard Hughescff38bc2016-12-12 12:03:37 +00001629 return fu_plugin_runner_offline_setup (error);
1630}
1631
1632gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001633fu_plugin_runner_verify (FuPlugin *self,
Richard Hughescff38bc2016-12-12 12:03:37 +00001634 FuDevice *device,
1635 FuPluginVerifyFlags flags,
1636 GError **error)
1637{
Richard Hughes12724852018-09-04 13:53:44 +01001638 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001639 FuPluginVerifyFunc func = NULL;
Richard Hughesababbb72017-06-15 20:18:36 +01001640 GPtrArray *checksums;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001641 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001642
1643 /* not enabled */
1644 if (!priv->enabled)
1645 return TRUE;
1646
Richard Hughes639da472018-01-06 22:35:04 +00001647 /* no object loaded */
1648 if (priv->module == NULL)
1649 return TRUE;
1650
Richard Hughescff38bc2016-12-12 12:03:37 +00001651 /* optional */
1652 g_module_symbol (priv->module, "fu_plugin_verify", (gpointer *) &func);
Richard Hughes7f677212019-10-05 16:19:40 +01001653 if (func == NULL) {
1654 g_debug ("running superclassed read_firmware() on %s", priv->name);
1655 return fu_plugin_device_read_firmware (self, device, error);
1656 }
Richard Hughes1812fc72018-12-14 11:37:54 +00001657
1658 /* clear any existing verification checksums */
1659 checksums = fu_device_get_checksums (device);
1660 g_ptr_array_set_size (checksums, 0);
1661
Richard Hughesc9223be2019-03-18 08:46:42 +00001662 /* run additional detach */
1663 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01001664 "fu_plugin_update_detach",
Richard Hughes4b303802019-10-04 13:22:51 +01001665 fu_plugin_device_detach,
Richard Hughesc9223be2019-03-18 08:46:42 +00001666 error))
1667 return FALSE;
1668
Richard Hughes1812fc72018-12-14 11:37:54 +00001669 /* run vfunc */
Richard Hughescff38bc2016-12-12 12:03:37 +00001670 g_debug ("performing verify() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001671 if (!func (self, device, flags, &error_local)) {
Richard Hughesc9223be2019-03-18 08:46:42 +00001672 g_autoptr(GError) error_attach = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001673 if (error_local == NULL) {
1674 g_critical ("unset error in plugin %s for verify()",
1675 priv->name);
1676 g_set_error_literal (&error_local,
1677 FWUPD_ERROR,
1678 FWUPD_ERROR_INTERNAL,
1679 "unspecified error");
1680 }
1681 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1682 "failed to verify using %s: ",
1683 priv->name);
Richard Hughesc9223be2019-03-18 08:46:42 +00001684 /* make the device "work" again, but don't prefix the error */
1685 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01001686 "fu_plugin_update_attach",
Richard Hughes4b303802019-10-04 13:22:51 +01001687 fu_plugin_device_attach,
Richard Hughesc9223be2019-03-18 08:46:42 +00001688 &error_attach)) {
1689 g_warning ("failed to attach whilst aborting verify(): %s",
1690 error_attach->message);
1691 }
Richard Hughesd0905142016-03-13 09:46:49 +00001692 return FALSE;
1693 }
Richard Hughesc9223be2019-03-18 08:46:42 +00001694
1695 /* run optional attach */
1696 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes42f33df2019-10-05 20:52:33 +01001697 "fu_plugin_update_attach",
Richard Hughes4b303802019-10-04 13:22:51 +01001698 fu_plugin_device_attach,
Richard Hughesc9223be2019-03-18 08:46:42 +00001699 error))
1700 return FALSE;
1701
1702 /* success */
Richard Hughesd0905142016-03-13 09:46:49 +00001703 return TRUE;
1704}
1705
Richard Hughesd0905142016-03-13 09:46:49 +00001706gboolean
Mario Limonciello96a0dd52019-02-25 13:50:03 -06001707fu_plugin_runner_activate (FuPlugin *self, FuDevice *device, GError **error)
1708{
1709 guint64 flags;
1710
1711 /* final check */
1712 flags = fu_device_get_flags (device);
1713 if ((flags & FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION) == 0) {
1714 g_set_error (error,
1715 FWUPD_ERROR,
1716 FWUPD_ERROR_NOT_SUPPORTED,
1717 "Device %s does not need activation",
1718 fu_device_get_id (device));
1719 return FALSE;
1720 }
1721
1722 /* run vfunc */
1723 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001724 "fu_plugin_activate",
1725 fu_plugin_device_activate,
1726 error))
Mario Limonciello96a0dd52019-02-25 13:50:03 -06001727 return FALSE;
1728
1729 /* update with correct flags */
1730 fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION);
1731 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
1732 return TRUE;
1733}
1734
1735gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001736fu_plugin_runner_unlock (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughesd0905142016-03-13 09:46:49 +00001737{
Richard Hughescff38bc2016-12-12 12:03:37 +00001738 guint64 flags;
Richard Hughescff38bc2016-12-12 12:03:37 +00001739
1740 /* final check */
1741 flags = fu_device_get_flags (device);
1742 if ((flags & FWUPD_DEVICE_FLAG_LOCKED) == 0) {
1743 g_set_error (error,
1744 FWUPD_ERROR,
1745 FWUPD_ERROR_NOT_SUPPORTED,
1746 "Device %s is not locked",
1747 fu_device_get_id (device));
1748 return FALSE;
1749 }
1750
Richard Hughes9c4b5312017-11-14 11:34:53 +00001751 /* run vfunc */
Richard Hughes12724852018-09-04 13:53:44 +01001752 if (!fu_plugin_runner_device_generic (self, device,
Richard Hughes4b303802019-10-04 13:22:51 +01001753 "fu_plugin_unlock",
1754 NULL,
1755 error))
Richard Hughes9c4b5312017-11-14 11:34:53 +00001756 return FALSE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001757
1758 /* update with correct flags */
1759 flags = fu_device_get_flags (device);
1760 fu_device_set_flags (device, flags &= ~FWUPD_DEVICE_FLAG_LOCKED);
1761 fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
1762 return TRUE;
1763}
1764
1765gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001766fu_plugin_runner_update (FuPlugin *self,
Richard Hughesa785a1c2017-08-25 16:00:58 +01001767 FuDevice *device,
Richard Hughesa785a1c2017-08-25 16:00:58 +01001768 GBytes *blob_fw,
1769 FwupdInstallFlags flags,
1770 GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00001771{
Richard Hughes12724852018-09-04 13:53:44 +01001772 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughesa785a1c2017-08-25 16:00:58 +01001773 FuPluginUpdateFunc update_func;
Richard Hughes780ef3f2018-01-12 16:20:31 +00001774 g_autoptr(FuHistory) history = NULL;
Richard Hughes68982c62017-09-13 15:40:14 +01001775 g_autoptr(FuDevice) device_pending = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001776 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001777
1778 /* not enabled */
Richard Hughes41c15482018-02-01 22:07:21 +00001779 if (!priv->enabled) {
1780 g_debug ("plugin not enabled, skipping");
Richard Hughesd0905142016-03-13 09:46:49 +00001781 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00001782 }
Richard Hughesd0905142016-03-13 09:46:49 +00001783
Richard Hughes639da472018-01-06 22:35:04 +00001784 /* no object loaded */
Richard Hughes41c15482018-02-01 22:07:21 +00001785 if (priv->module == NULL) {
1786 g_debug ("module not enabled, skipping");
Richard Hughes639da472018-01-06 22:35:04 +00001787 return TRUE;
Richard Hughes41c15482018-02-01 22:07:21 +00001788 }
Richard Hughes639da472018-01-06 22:35:04 +00001789
Richard Hughesd0905142016-03-13 09:46:49 +00001790 /* optional */
Richard Hughesa785a1c2017-08-25 16:00:58 +01001791 g_module_symbol (priv->module, "fu_plugin_update", (gpointer *) &update_func);
1792 if (update_func == NULL) {
Richard Hughes4b303802019-10-04 13:22:51 +01001793 g_debug ("running superclassed write_firmware() on %s", priv->name);
1794 return fu_plugin_device_write_firmware (self, device, blob_fw, flags, error);
Richard Hughesa785a1c2017-08-25 16:00:58 +01001795 }
Richard Hughesd0905142016-03-13 09:46:49 +00001796
Richard Hughescff38bc2016-12-12 12:03:37 +00001797 /* cancel the pending action */
1798 if (!fu_plugin_runner_offline_invalidate (error))
1799 return FALSE;
1800
1801 /* online */
Richard Hughes780ef3f2018-01-12 16:20:31 +00001802 history = fu_history_new ();
Richard Hughes0b9d9962018-01-12 16:31:28 +00001803 device_pending = fu_history_get_device_by_id (history, fu_device_get_id (device), NULL);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001804 if (!update_func (self, device, blob_fw, flags, &error_local)) {
1805 if (error_local == NULL) {
1806 g_critical ("unset error in plugin %s for update()",
1807 priv->name);
1808 g_set_error_literal (&error_local,
Richard Hughes3c8ada32018-10-12 10:08:58 +01001809 FWUPD_ERROR,
1810 FWUPD_ERROR_INTERNAL,
1811 "unspecified error");
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001812 return FALSE;
Richard Hughes3c8ada32018-10-12 10:08:58 +01001813 }
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001814 fu_device_set_update_error (device, error_local->message);
1815 g_propagate_error (error, g_steal_pointer (&error_local));
Richard Hughescff38bc2016-12-12 12:03:37 +00001816 return FALSE;
1817 }
1818
Richard Hughesf556d372017-06-15 19:49:18 +01001819 /* no longer valid */
Richard Hughesf8039642019-01-16 12:22:22 +00001820 if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT) &&
1821 !fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) {
Richard Hughes08435162018-12-12 10:34:16 +00001822 GPtrArray *checksums = fu_device_get_checksums (device);
1823 g_ptr_array_set_size (checksums, 0);
1824 }
Richard Hughesf556d372017-06-15 19:49:18 +01001825
Richard Hughescff38bc2016-12-12 12:03:37 +00001826 /* cleanup */
Richard Hughes68982c62017-09-13 15:40:14 +01001827 if (device_pending != NULL) {
Richard Hughescff38bc2016-12-12 12:03:37 +00001828 const gchar *tmp;
Richard Hughesbc3a4e12018-01-06 22:41:47 +00001829 FwupdRelease *release;
Richard Hughescff38bc2016-12-12 12:03:37 +00001830
Richard Hughes780ef3f2018-01-12 16:20:31 +00001831 /* update history database */
Richard Hughesc0cd0232018-01-31 15:02:00 +00001832 fu_device_set_update_state (device, FWUPD_UPDATE_STATE_SUCCESS);
1833 if (!fu_history_modify_device (history, device,
1834 FU_HISTORY_FLAGS_MATCH_NEW_VERSION,
1835 error))
Richard Hughes0b9d9962018-01-12 16:31:28 +00001836 return FALSE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001837
1838 /* delete cab file */
Richard Hughesbc3a4e12018-01-06 22:41:47 +00001839 release = fu_device_get_release_default (device_pending);
1840 tmp = fwupd_release_get_filename (release);
Richard Hughescff38bc2016-12-12 12:03:37 +00001841 if (tmp != NULL && g_str_has_prefix (tmp, LIBEXECDIR)) {
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001842 g_autoptr(GError) error_delete = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001843 g_autoptr(GFile) file = NULL;
1844 file = g_file_new_for_path (tmp);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001845 if (!g_file_delete (file, NULL, &error_delete)) {
Richard Hughescff38bc2016-12-12 12:03:37 +00001846 g_set_error (error,
1847 FWUPD_ERROR,
1848 FWUPD_ERROR_INVALID_FILE,
1849 "Failed to delete %s: %s",
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001850 tmp, error_delete->message);
Richard Hughescff38bc2016-12-12 12:03:37 +00001851 return FALSE;
1852 }
1853 }
1854 }
Richard Hughesd0905142016-03-13 09:46:49 +00001855 return TRUE;
1856}
Richard Hughescff38bc2016-12-12 12:03:37 +00001857
1858gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001859fu_plugin_runner_clear_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00001860{
Richard Hughes12724852018-09-04 13:53:44 +01001861 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001862 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001863 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001864
1865 /* not enabled */
1866 if (!priv->enabled)
1867 return TRUE;
1868
Richard Hughes639da472018-01-06 22:35:04 +00001869 /* no object loaded */
1870 if (priv->module == NULL)
1871 return TRUE;
1872
Richard Hughes65e44ca2018-01-30 17:26:30 +00001873 /* optional */
1874 g_module_symbol (priv->module, "fu_plugin_get_results", (gpointer *) &func);
1875 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00001876 return TRUE;
Richard Hughes65e44ca2018-01-30 17:26:30 +00001877 g_debug ("performing clear_result() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001878 if (!func (self, device, &error_local)) {
1879 if (error_local == NULL) {
1880 g_critical ("unset error in plugin %s for clear_result()",
1881 priv->name);
1882 g_set_error_literal (&error_local,
1883 FWUPD_ERROR,
1884 FWUPD_ERROR_INTERNAL,
1885 "unspecified error");
1886 }
1887 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1888 "failed to clear_result using %s: ",
1889 priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00001890 return FALSE;
1891 }
Richard Hughes65e44ca2018-01-30 17:26:30 +00001892 return TRUE;
Richard Hughescff38bc2016-12-12 12:03:37 +00001893}
1894
1895gboolean
Richard Hughes12724852018-09-04 13:53:44 +01001896fu_plugin_runner_get_results (FuPlugin *self, FuDevice *device, GError **error)
Richard Hughescff38bc2016-12-12 12:03:37 +00001897{
Richard Hughes12724852018-09-04 13:53:44 +01001898 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughes7b8b2022016-12-12 16:15:03 +00001899 FuPluginDeviceFunc func = NULL;
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001900 g_autoptr(GError) error_local = NULL;
Richard Hughescff38bc2016-12-12 12:03:37 +00001901
1902 /* not enabled */
1903 if (!priv->enabled)
1904 return TRUE;
1905
Richard Hughes639da472018-01-06 22:35:04 +00001906 /* no object loaded */
1907 if (priv->module == NULL)
1908 return TRUE;
1909
Richard Hughes65e44ca2018-01-30 17:26:30 +00001910 /* optional */
Richard Hughescff38bc2016-12-12 12:03:37 +00001911 g_module_symbol (priv->module, "fu_plugin_get_results", (gpointer *) &func);
Richard Hughes65e44ca2018-01-30 17:26:30 +00001912 if (func == NULL)
Richard Hughescff38bc2016-12-12 12:03:37 +00001913 return TRUE;
Richard Hughes65e44ca2018-01-30 17:26:30 +00001914 g_debug ("performing get_results() on %s", priv->name);
Richard Hughescd2fb3e2018-11-29 19:58:09 +00001915 if (!func (self, device, &error_local)) {
1916 if (error_local == NULL) {
1917 g_critical ("unset error in plugin %s for get_results()",
1918 priv->name);
1919 g_set_error_literal (&error_local,
1920 FWUPD_ERROR,
1921 FWUPD_ERROR_INTERNAL,
1922 "unspecified error");
1923 }
1924 g_propagate_prefixed_error (error, g_steal_pointer (&error_local),
1925 "failed to get_results using %s: ",
1926 priv->name);
Richard Hughescff38bc2016-12-12 12:03:37 +00001927 return FALSE;
1928 }
Richard Hughescff38bc2016-12-12 12:03:37 +00001929 return TRUE;
1930}
1931
Richard Hughes08a37992017-09-12 12:57:43 +01001932/**
1933 * fu_plugin_get_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001934 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01001935 *
1936 * Gets the plugin order, where higher numbers are run after lower
1937 * numbers.
1938 *
1939 * Returns: the integer value
1940 **/
1941guint
Richard Hughes12724852018-09-04 13:53:44 +01001942fu_plugin_get_order (FuPlugin *self)
Richard Hughes08a37992017-09-12 12:57:43 +01001943{
Richard Hughes12724852018-09-04 13:53:44 +01001944 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01001945 return priv->order;
1946}
1947
1948/**
1949 * fu_plugin_set_order:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001950 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01001951 * @order: a integer value
1952 *
1953 * Sets the plugin order, where higher numbers are run after lower
1954 * numbers.
1955 **/
1956void
Richard Hughes12724852018-09-04 13:53:44 +01001957fu_plugin_set_order (FuPlugin *self, guint order)
Richard Hughes08a37992017-09-12 12:57:43 +01001958{
Richard Hughes12724852018-09-04 13:53:44 +01001959 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01001960 priv->order = order;
1961}
1962
1963/**
Richard Hughes81c427c2018-08-06 15:20:17 +01001964 * fu_plugin_get_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001965 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01001966 *
1967 * Gets the plugin priority, where higher numbers are better.
1968 *
1969 * Returns: the integer value
1970 **/
1971guint
Richard Hughes12724852018-09-04 13:53:44 +01001972fu_plugin_get_priority (FuPlugin *self)
Richard Hughes81c427c2018-08-06 15:20:17 +01001973{
Richard Hughes12724852018-09-04 13:53:44 +01001974 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01001975 return priv->priority;
1976}
1977
1978/**
1979 * fu_plugin_set_priority:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001980 * @self: a #FuPlugin
Richard Hughes81c427c2018-08-06 15:20:17 +01001981 * @priority: a integer value
1982 *
1983 * Sets the plugin priority, where higher numbers are better.
1984 **/
1985void
Richard Hughes12724852018-09-04 13:53:44 +01001986fu_plugin_set_priority (FuPlugin *self, guint priority)
Richard Hughes81c427c2018-08-06 15:20:17 +01001987{
Richard Hughes12724852018-09-04 13:53:44 +01001988 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes81c427c2018-08-06 15:20:17 +01001989 priv->priority = priority;
1990}
1991
1992/**
Richard Hughes08a37992017-09-12 12:57:43 +01001993 * fu_plugin_add_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01001994 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01001995 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
Richard Hughes4eada342017-10-03 21:20:32 +01001996 * @name: a plugin name, e.g. `upower`
Richard Hughes08a37992017-09-12 12:57:43 +01001997 *
1998 * If the plugin name is found, the rule will be used to sort the plugin list,
1999 * for example the plugin specified by @name will be ordered after this plugin
2000 * when %FU_PLUGIN_RULE_RUN_AFTER is used.
2001 *
2002 * NOTE: The depsolver is iterative and may not solve overly-complicated rules;
2003 * If depsolving fails then fwupd will not start.
2004 **/
2005void
Richard Hughes12724852018-09-04 13:53:44 +01002006fu_plugin_add_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes08a37992017-09-12 12:57:43 +01002007{
Richard Hughes12724852018-09-04 13:53:44 +01002008 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002009 g_ptr_array_add (priv->rules[rule], g_strdup (name));
Richard Hughes75b965d2018-11-15 13:51:21 +00002010 g_signal_emit (self, signals[SIGNAL_RULES_CHANGED], 0);
Richard Hughes08a37992017-09-12 12:57:43 +01002011}
2012
2013/**
2014 * fu_plugin_get_rules:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002015 * @self: a #FuPlugin
Richard Hughes08a37992017-09-12 12:57:43 +01002016 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
2017 *
2018 * Gets the plugin IDs that should be run after this plugin.
2019 *
2020 * Returns: (element-type utf8) (transfer none): the list of plugin names, e.g. ['appstream']
2021 **/
2022GPtrArray *
Richard Hughes12724852018-09-04 13:53:44 +01002023fu_plugin_get_rules (FuPlugin *self, FuPluginRule rule)
Richard Hughes08a37992017-09-12 12:57:43 +01002024{
Richard Hughes12724852018-09-04 13:53:44 +01002025 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes08a37992017-09-12 12:57:43 +01002026 return priv->rules[rule];
2027}
2028
Richard Hughes80b79bb2018-01-11 21:11:06 +00002029/**
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002030 * fu_plugin_has_rule:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002031 * @self: a #FuPlugin
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002032 * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
2033 * @name: a plugin name, e.g. `upower`
2034 *
Richard Hughes87fb9ff2018-06-28 12:55:59 +01002035 * Gets the plugin IDs that should be run after this plugin.
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002036 *
2037 * Returns: %TRUE if the name exists for the specific rule
2038 **/
2039gboolean
Richard Hughes12724852018-09-04 13:53:44 +01002040fu_plugin_has_rule (FuPlugin *self, FuPluginRule rule, const gchar *name)
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002041{
Richard Hughes12724852018-09-04 13:53:44 +01002042 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes5f3a56b2018-06-28 12:13:59 +01002043 for (guint i = 0; i < priv->rules[rule]->len; i++) {
2044 const gchar *tmp = g_ptr_array_index (priv->rules[rule], i);
2045 if (g_strcmp0 (tmp, name) == 0)
2046 return TRUE;
2047 }
2048 return FALSE;
2049}
2050
2051/**
Richard Hughes80b79bb2018-01-11 21:11:06 +00002052 * fu_plugin_add_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002053 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00002054 * @key: a string, e.g. `FwupdateVersion`
2055 * @value: a string, e.g. `10`
2056 *
2057 * Sets any additional metadata to be included in the firmware report to aid
2058 * debugging problems.
2059 *
2060 * Any data included here will be sent to the metadata server after user
2061 * confirmation.
2062 **/
2063void
Richard Hughes12724852018-09-04 13:53:44 +01002064fu_plugin_add_report_metadata (FuPlugin *self, const gchar *key, const gchar *value)
Richard Hughes80b79bb2018-01-11 21:11:06 +00002065{
Richard Hughes12724852018-09-04 13:53:44 +01002066 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002067 g_hash_table_insert (priv->report_metadata, g_strdup (key), g_strdup (value));
2068}
2069
2070/**
2071 * fu_plugin_get_report_metadata:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002072 * @self: a #FuPlugin
Richard Hughes80b79bb2018-01-11 21:11:06 +00002073 *
2074 * Returns the list of additional metadata to be added when filing a report.
2075 *
2076 * Returns: (transfer none): the map of report metadata
2077 **/
2078GHashTable *
Richard Hughes12724852018-09-04 13:53:44 +01002079fu_plugin_get_report_metadata (FuPlugin *self)
Richard Hughes80b79bb2018-01-11 21:11:06 +00002080{
Richard Hughes12724852018-09-04 13:53:44 +01002081 FuPluginPrivate *priv = fu_plugin_get_instance_private (self);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002082 return priv->report_metadata;
2083}
2084
Mario Limonciello963dc422018-02-27 14:26:58 -06002085/**
2086 * fu_plugin_get_config_value:
Richard Hughes2c0635a2018-09-04 14:52:46 +01002087 * @self: a #FuPlugin
Mario Limonciello963dc422018-02-27 14:26:58 -06002088 * @key: A settings key
2089 *
2090 * Return the value of a key if it's been configured
2091 *
2092 * Since: 1.0.6
2093 **/
2094gchar *
Richard Hughes12724852018-09-04 13:53:44 +01002095fu_plugin_get_config_value (FuPlugin *self, const gchar *key)
Mario Limonciello963dc422018-02-27 14:26:58 -06002096{
Richard Hughes4be17d12018-05-30 20:36:29 +01002097 g_autofree gchar *conf_dir = NULL;
Mario Limonciello963dc422018-02-27 14:26:58 -06002098 g_autofree gchar *conf_file = NULL;
2099 g_autofree gchar *conf_path = NULL;
2100 g_autoptr(GKeyFile) keyfile = NULL;
2101 const gchar *plugin_name;
2102
Richard Hughes4be17d12018-05-30 20:36:29 +01002103 conf_dir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR_PKG);
Richard Hughes12724852018-09-04 13:53:44 +01002104 plugin_name = fu_plugin_get_name (self);
Mario Limonciello963dc422018-02-27 14:26:58 -06002105 conf_file = g_strdup_printf ("%s.conf", plugin_name);
Richard Hughes4be17d12018-05-30 20:36:29 +01002106 conf_path = g_build_filename (conf_dir, conf_file, NULL);
Mario Limonciello963dc422018-02-27 14:26:58 -06002107 if (!g_file_test (conf_path, G_FILE_TEST_IS_REGULAR))
2108 return NULL;
2109 keyfile = g_key_file_new ();
2110 if (!g_key_file_load_from_file (keyfile, conf_path,
2111 G_KEY_FILE_NONE, NULL))
2112 return NULL;
2113 return g_key_file_get_string (keyfile, plugin_name, key, NULL);
2114}
2115
Richard Hughes8c71a3f2018-05-22 19:19:52 +01002116/**
2117 * fu_plugin_name_compare:
2118 * @plugin1: first #FuPlugin to compare.
2119 * @plugin2: second #FuPlugin to compare.
2120 *
2121 * Compares two plugins by their names.
2122 *
2123 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
2124 **/
2125gint
2126fu_plugin_name_compare (FuPlugin *plugin1, FuPlugin *plugin2)
2127{
2128 FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1);
2129 FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2);
2130 return g_strcmp0 (priv1->name, priv2->name);
2131}
2132
2133/**
2134 * fu_plugin_order_compare:
2135 * @plugin1: first #FuPlugin to compare.
2136 * @plugin2: second #FuPlugin to compare.
2137 *
2138 * Compares two plugins by their depsolved order.
2139 *
2140 * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2.
2141 **/
2142gint
2143fu_plugin_order_compare (FuPlugin *plugin1, FuPlugin *plugin2)
2144{
2145 FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1);
2146 FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2);
2147 if (priv1->order < priv2->order)
2148 return -1;
2149 if (priv1->order > priv2->order)
2150 return 1;
2151 return 0;
2152}
2153
Richard Hughescff38bc2016-12-12 12:03:37 +00002154static void
2155fu_plugin_class_init (FuPluginClass *klass)
2156{
2157 GObjectClass *object_class = G_OBJECT_CLASS (klass);
2158 object_class->finalize = fu_plugin_finalize;
2159 signals[SIGNAL_DEVICE_ADDED] =
2160 g_signal_new ("device-added",
2161 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2162 G_STRUCT_OFFSET (FuPluginClass, device_added),
2163 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2164 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
2165 signals[SIGNAL_DEVICE_REMOVED] =
2166 g_signal_new ("device-removed",
2167 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2168 G_STRUCT_OFFSET (FuPluginClass, device_removed),
2169 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2170 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughese1fd34d2017-08-24 14:19:51 +01002171 signals[SIGNAL_DEVICE_REGISTER] =
2172 g_signal_new ("device-register",
2173 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2174 G_STRUCT_OFFSET (FuPluginClass, device_register),
2175 NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2176 G_TYPE_NONE, 1, FU_TYPE_DEVICE);
Richard Hughes362d6d72017-01-07 21:42:14 +00002177 signals[SIGNAL_RECOLDPLUG] =
2178 g_signal_new ("recoldplug",
2179 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2180 G_STRUCT_OFFSET (FuPluginClass, recoldplug),
2181 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2182 G_TYPE_NONE, 0);
Richard Hughesb0829032017-01-10 09:27:08 +00002183 signals[SIGNAL_SET_COLDPLUG_DELAY] =
2184 g_signal_new ("set-coldplug-delay",
2185 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2186 G_STRUCT_OFFSET (FuPluginClass, set_coldplug_delay),
2187 NULL, NULL, g_cclosure_marshal_VOID__UINT,
2188 G_TYPE_NONE, 1, G_TYPE_UINT);
Richard Hughesaabdc372018-11-14 10:11:08 +00002189 signals[SIGNAL_CHECK_SUPPORTED] =
2190 g_signal_new ("check-supported",
2191 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2192 G_STRUCT_OFFSET (FuPluginClass, check_supported),
2193 NULL, NULL, g_cclosure_marshal_generic,
2194 G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
Richard Hughes75b965d2018-11-15 13:51:21 +00002195 signals[SIGNAL_RULES_CHANGED] =
2196 g_signal_new ("rules-changed",
2197 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2198 G_STRUCT_OFFSET (FuPluginClass, rules_changed),
2199 NULL, NULL, g_cclosure_marshal_VOID__VOID,
2200 G_TYPE_NONE, 0);
Richard Hughescff38bc2016-12-12 12:03:37 +00002201}
2202
2203static void
Richard Hughes12724852018-09-04 13:53:44 +01002204fu_plugin_init (FuPlugin *self)
Richard Hughescff38bc2016-12-12 12:03:37 +00002205{
Richard Hughes12724852018-09-04 13:53:44 +01002206 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002207 priv->enabled = TRUE;
Richard Hughesb1065422019-08-15 16:44:34 +01002208 priv->udev_subsystems = g_ptr_array_new_with_free_func (g_free);
Richard Hughescff38bc2016-12-12 12:03:37 +00002209 priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal,
2210 g_free, (GDestroyNotify) g_object_unref);
Richard Hughes161e9b52019-06-12 14:22:45 +01002211 g_rw_lock_init (&priv->devices_mutex);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002212 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 +01002213 for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++)
2214 priv->rules[i] = g_ptr_array_new_with_free_func (g_free);
Richard Hughescff38bc2016-12-12 12:03:37 +00002215}
2216
2217static void
2218fu_plugin_finalize (GObject *object)
2219{
Richard Hughes12724852018-09-04 13:53:44 +01002220 FuPlugin *self = FU_PLUGIN (object);
2221 FuPluginPrivate *priv = GET_PRIVATE (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002222 FuPluginInitFunc func = NULL;
2223
2224 /* optional */
2225 if (priv->module != NULL) {
2226 g_module_symbol (priv->module, "fu_plugin_destroy", (gpointer *) &func);
2227 if (func != NULL) {
2228 g_debug ("performing destroy() on %s", priv->name);
Richard Hughes12724852018-09-04 13:53:44 +01002229 func (self);
Richard Hughescff38bc2016-12-12 12:03:37 +00002230 }
2231 }
2232
Richard Hughes08a37992017-09-12 12:57:43 +01002233 for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++)
2234 g_ptr_array_unref (priv->rules[i]);
2235
Richard Hughescff38bc2016-12-12 12:03:37 +00002236 if (priv->usb_ctx != NULL)
2237 g_object_unref (priv->usb_ctx);
Richard Hughesb8f8db22017-04-25 15:56:00 +01002238 if (priv->hwids != NULL)
Richard Hughesd7704d42017-08-08 20:29:09 +01002239 g_object_unref (priv->hwids);
Richard Hughes9c028f02017-10-28 21:14:28 +01002240 if (priv->quirks != NULL)
2241 g_object_unref (priv->quirks);
Richard Hughes9d6e0e72018-08-24 20:20:17 +01002242 if (priv->udev_subsystems != NULL)
2243 g_ptr_array_unref (priv->udev_subsystems);
Richard Hughes49e5e052017-09-03 12:15:41 +01002244 if (priv->smbios != NULL)
2245 g_object_unref (priv->smbios);
Richard Hughes275d3b42018-04-20 16:40:37 +01002246 if (priv->runtime_versions != NULL)
2247 g_hash_table_unref (priv->runtime_versions);
Richard Hughes34e0dab2018-04-20 16:43:00 +01002248 if (priv->compile_versions != NULL)
2249 g_hash_table_unref (priv->compile_versions);
Richard Hughescff38bc2016-12-12 12:03:37 +00002250 g_hash_table_unref (priv->devices);
Richard Hughes80b79bb2018-01-11 21:11:06 +00002251 g_hash_table_unref (priv->report_metadata);
Richard Hughes161e9b52019-06-12 14:22:45 +01002252 g_rw_lock_clear (&priv->devices_mutex);
Richard Hughes84999302019-05-02 10:18:32 +01002253 g_free (priv->build_hash);
Richard Hughescff38bc2016-12-12 12:03:37 +00002254 g_free (priv->name);
2255 g_free (priv->data);
Mario Limonciello3f9a1c12018-06-06 14:06:40 -05002256 /* Must happen as the last step to avoid prematurely
2257 * freeing memory held by the plugin */
2258#ifndef RUNNING_ON_VALGRIND
2259 if (priv->module != NULL)
2260 g_module_close (priv->module);
2261#endif
Richard Hughescff38bc2016-12-12 12:03:37 +00002262
2263 G_OBJECT_CLASS (fu_plugin_parent_class)->finalize (object);
2264}
2265
2266FuPlugin *
2267fu_plugin_new (void)
2268{
Richard Hughes12724852018-09-04 13:53:44 +01002269 return FU_PLUGIN (g_object_new (FU_TYPE_PLUGIN, NULL));
Richard Hughescff38bc2016-12-12 12:03:37 +00002270}