fu-plugin.c 76.4 KB
Newer Older
1
/*
2
 * Copyright (C) 2016 Richard Hughes <richard@hughsie.com>
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1+
5
6
 */

7
8
#define G_LOG_DOMAIN				"FuPlugin"

9
10
#include "config.h"

11
12
13
14
#include <fwupd.h>
#include <gmodule.h>
#include <errno.h>
#include <string.h>
15
#include <unistd.h>
16
#ifdef HAVE_VALGRIND
17
#include <valgrind.h>
18
#endif /* HAVE_VALGRIND */
19

20
#include "fu-device-private.h"
21
#include "fu-plugin-private.h"
22
#include "fu-mutex.h"
23

24
25
26
27
28
29
30
31
32
/**
 * SECTION:fu-plugin
 * @short_description: a daemon plugin
 *
 * An object that represents a plugin run by the daemon.
 *
 * See also: #FuDevice
 */

33
34
#define	FU_PLUGIN_COLDPLUG_DELAY_MAXIMUM	3000u	/* ms */

35
36
37
38
static void fu_plugin_finalize			 (GObject *object);

typedef struct {
	GModule			*module;
39
	guint			 order;
40
	guint			 priority;
41
	GPtrArray		*rules[FU_PLUGIN_RULE_LAST];
42
	GPtrArray		*devices;		/* (nullable) (element-type FuDevice) */
43
	gchar			*build_hash;
44
	FuHwids			*hwids;
45
	FuQuirks		*quirks;
46
	GHashTable		*runtime_versions;
47
	GHashTable		*compile_versions;
48
	GPtrArray		*udev_subsystems;
49
	FuSmbios		*smbios;
50
	GType			 device_gtype;
51
52
	GHashTable		*cache;			/* (nullable): platform_id:GObject */
	GRWLock			 cache_mutex;
53
	GHashTable		*report_metadata;	/* (nullable): key:value */
54
55
56
57
58
59
	FuPluginData		*data;
} FuPluginPrivate;

enum {
	SIGNAL_DEVICE_ADDED,
	SIGNAL_DEVICE_REMOVED,
60
	SIGNAL_DEVICE_REGISTER,
61
	SIGNAL_RULES_CHANGED,
62
	SIGNAL_RECOLDPLUG,
63
	SIGNAL_SET_COLDPLUG_DELAY,
64
	SIGNAL_CHECK_SUPPORTED,
65
	SIGNAL_ADD_FIRMWARE_GTYPE,
66
	SIGNAL_SECURITY_CHANGED,
67
68
69
70
71
	SIGNAL_LAST
};

static guint signals[SIGNAL_LAST] = { 0 };

72
G_DEFINE_TYPE_WITH_PRIVATE (FuPlugin, fu_plugin, FWUPD_TYPE_PLUGIN)
73
74
75
#define GET_PRIVATE(o) (fu_plugin_get_instance_private (o))

typedef const gchar	*(*FuPluginGetNameFunc)		(void);
76
77
typedef void		 (*FuPluginInitFunc)		(FuPlugin	*self);
typedef gboolean	 (*FuPluginStartupFunc)		(FuPlugin	*self,
78
							 GError		**error);
79
typedef void		 (*FuPluginDeviceRegisterFunc)	(FuPlugin	*self,
80
							 FuDevice	*device);
81
typedef gboolean	 (*FuPluginDeviceFunc)		(FuPlugin	*self,
82
83
							 FuDevice	*device,
							 GError		**error);
84
typedef gboolean	 (*FuPluginFlaggedDeviceFunc)	(FuPlugin	*self,
85
86
87
							 FwupdInstallFlags flags,
							 FuDevice	*device,
							 GError		**error);
88
typedef gboolean	 (*FuPluginDeviceArrayFunc)	(FuPlugin	*self,
89
90
							 GPtrArray	*devices,
							 GError		**error);
91
typedef gboolean	 (*FuPluginVerifyFunc)		(FuPlugin	*self,
92
93
94
							 FuDevice	*device,
							 FuPluginVerifyFlags flags,
							 GError		**error);
95
typedef gboolean	 (*FuPluginUpdateFunc)		(FuPlugin	*self,
96
97
98
99
							 FuDevice	*device,
							 GBytes		*blob_fw,
							 FwupdInstallFlags flags,
							 GError		**error);
100
101
typedef void		 (*FuPluginSecurityAttrsFunc)	(FuPlugin	*self,
							 FuSecurityAttrs *attrs);
102

103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/**
 * fu_plugin_is_open:
 * @self: A #FuPlugin
 *
 * Determines if the plugin is opened
 *
 * Returns: TRUE for opened, FALSE for not
 *
 * Since: 1.3.5
 **/
gboolean
fu_plugin_is_open (FuPlugin *self)
{
	FuPluginPrivate *priv = GET_PRIVATE (self);
	return priv->module != NULL;
}

120
121
/**
 * fu_plugin_get_name:
122
 * @self: A #FuPlugin
123
124
125
126
127
128
129
 *
 * Gets the plugin name.
 *
 * Returns: a plugin name, or %NULL for unknown.
 *
 * Since: 0.8.0
 **/
130
const gchar *
131
fu_plugin_get_name (FuPlugin *self)
132
{
133
	g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
134
	return fwupd_plugin_get_name (FWUPD_PLUGIN (self));
135
}
136

137
138
139
140
141
142
143
144
145
/**
 * fu_plugin_set_name:
 * @self: A #FuPlugin
 * @name: A string
 *
 * Sets the plugin name.
 *
 * Since: 0.8.0
 **/
146
void
147
fu_plugin_set_name (FuPlugin *self, const gchar *name)
148
{
149
	g_return_if_fail (FU_IS_PLUGIN (self));
150
	fwupd_plugin_set_name (FWUPD_PLUGIN (self), name);
151
152
}

153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/**
 * fu_plugin_set_build_hash:
 * @self: A #FuPlugin
 * @build_hash: A checksum
 *
 * Sets the plugin build hash, typically a SHA256 checksum. All plugins must
 * set the correct checksum to avoid the daemon being marked as tainted.
 *
 * Since: 1.2.4
 **/
void
fu_plugin_set_build_hash (FuPlugin *self, const gchar *build_hash)
{
	FuPluginPrivate *priv = GET_PRIVATE (self);
	g_return_if_fail (FU_IS_PLUGIN (self));
	g_return_if_fail (build_hash != NULL);
169
170
171
172
173

	/* not changed */
	if (g_strcmp0 (priv->build_hash, build_hash) == 0)
		return;

174
175
176
177
	g_free (priv->build_hash);
	priv->build_hash = g_strdup (build_hash);
}

178
179
180
181
182
183
184
185
186
187
/**
 * fu_plugin_get_build_hash:
 * @self: A #FuPlugin
 *
 * Gets the build hash a plugin was generated with.
 *
 * Returns: (transfer none): a #gchar, or %NULL for unset.
 *
 * Since: 1.2.4
 **/
188
189
190
191
192
193
194
195
const gchar *
fu_plugin_get_build_hash (FuPlugin *self)
{
	FuPluginPrivate *priv = GET_PRIVATE (self);
	g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
	return priv->build_hash;
}

196
197
/**
 * fu_plugin_cache_lookup:
198
 * @self: A #FuPlugin
199
200
201
202
203
204
205
206
 * @id: the key
 *
 * Finds an object in the per-plugin cache.
 *
 * Returns: (transfer none): a #GObject, or %NULL for unfound.
 *
 * Since: 0.8.0
 **/
207
gpointer
208
fu_plugin_cache_lookup (FuPlugin *self, const gchar *id)
209
{
210
	FuPluginPrivate *priv = GET_PRIVATE (self);
211
	g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&priv->cache_mutex);
212
	g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
213
	g_return_val_if_fail (id != NULL, NULL);
214
	g_return_val_if_fail (locker != NULL, NULL);
215
	if (priv->cache == NULL)
216
		return NULL;
217
	return g_hash_table_lookup (priv->cache, id);
218
219
}

220
221
/**
 * fu_plugin_cache_add:
222
 * @self: A #FuPlugin
223
224
225
226
227
228
229
 * @id: the key
 * @dev: a #GObject, typically a #FuDevice
 *
 * Adds an object to the per-plugin cache.
 *
 * Since: 0.8.0
 **/
230
void
231
fu_plugin_cache_add (FuPlugin *self, const gchar *id, gpointer dev)
232
{
233
	FuPluginPrivate *priv = GET_PRIVATE (self);
234
	g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&priv->cache_mutex);
235
	g_return_if_fail (FU_IS_PLUGIN (self));
236
	g_return_if_fail (id != NULL);
237
	g_return_if_fail (locker != NULL);
238
239
240
241
242
	if (priv->cache == NULL) {
		priv->cache = g_hash_table_new_full (g_str_hash,
						     g_str_equal,
						     g_free,
						     (GDestroyNotify) g_object_unref);
243
	}
244
	g_hash_table_insert (priv->cache, g_strdup (id), g_object_ref (dev));
245
246
}

247
248
/**
 * fu_plugin_cache_remove:
249
 * @self: A #FuPlugin
250
251
252
253
254
255
 * @id: the key
 *
 * Removes an object from the per-plugin cache.
 *
 * Since: 0.8.0
 **/
256
void
257
fu_plugin_cache_remove (FuPlugin *self, const gchar *id)
258
{
259
	FuPluginPrivate *priv = GET_PRIVATE (self);
260
	g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&priv->cache_mutex);
261
	g_return_if_fail (FU_IS_PLUGIN (self));
262
	g_return_if_fail (id != NULL);
263
	g_return_if_fail (locker != NULL);
264
	if (priv->cache == NULL)
265
		return;
266
	g_hash_table_remove (priv->cache, id);
267
268
}

269
270
/**
 * fu_plugin_get_data:
271
 * @self: A #FuPlugin
272
 *
273
274
 * Gets the per-plugin allocated private data. This will return %NULL unless
 * fu_plugin_alloc_data() has been called by the plugin.
275
 *
276
 * Returns: (transfer none): a pointer to a structure, or %NULL for unset.
277
278
279
 *
 * Since: 0.8.0
 **/
280
FuPluginData *
281
fu_plugin_get_data (FuPlugin *self)
282
{
283
284
	FuPluginPrivate *priv = GET_PRIVATE (self);
	g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
285
286
287
	return priv->data;
}

288
/**
289
 * fu_plugin_alloc_data: (skip):
290
 * @self: A #FuPlugin
291
292
293
294
295
296
297
298
 * @data_sz: the size to allocate
 *
 * Allocates the per-plugin allocated private data.
 *
 * Returns: (transfer full): a pointer to a structure, or %NULL for unset.
 *
 * Since: 0.8.0
 **/
299
FuPluginData *
300
fu_plugin_alloc_data (FuPlugin *self, gsize data_sz)
301
{
302
303
	FuPluginPrivate *priv = GET_PRIVATE (self);
	g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
304
305
306
307
	if (priv->data != NULL) {
		g_critical ("fu_plugin_alloc_data() already used by plugin");
		return priv->data;
	}
308
309
	priv->data = g_malloc0 (data_sz);
	return priv->data;
310
311
}

312
313
/**
 * fu_plugin_get_usb_context:
314
 * @self: A #FuPlugin
315
 *
316
317
 * This used to get the shared USB context that all plugins can use; it now
 * returns %NULL;
318
319
320
321
322
 *
 * Returns: (transfer none): a #GUsbContext.
 *
 * Since: 0.8.0
 **/
323
GUsbContext *
324
fu_plugin_get_usb_context (FuPlugin *self)
325
{
326
	g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
327
	return NULL;
328
329
}

330
331
332
333
334
/**
 * fu_plugin_set_usb_context:
 * @self: A #FuPlugin
 * @usb_ctx: A #FGUsbContext
 *
335
 * This used to set the shared USB context for a plugin. It now does nothing.
336
337
338
 *
 * Since: 0.8.0
 **/
339
void
340
fu_plugin_set_usb_context (FuPlugin *self, GUsbContext *usb_ctx)
341
{
342
343
}

344
345
/**
 * fu_plugin_get_enabled:
346
 * @self: A #FuPlugin
347
 *
348
349
 * Returns if the plugin is enabled. Plugins may self-disable using
 * fu_plugin_set_enabled() or can be disabled by the daemon.
350
351
352
353
354
 *
 * Returns: %TRUE if the plugin is currently enabled.
 *
 * Since: 0.8.0
 **/
355
gboolean
356
fu_plugin_get_enabled (FuPlugin *self)
357
{
358
	g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
359
	return !fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED);
360
361
}

362
363
/**
 * fu_plugin_set_enabled:
364
 * @self: A #FuPlugin
365
366
367
368
369
370
 * @enabled: the enabled value
 *
 * Enables or disables a plugin. Plugins can self-disable at any point.
 *
 * Since: 0.8.0
 **/
371
void
372
fu_plugin_set_enabled (FuPlugin *self, gboolean enabled)
373
{
374
	g_return_if_fail (FU_IS_PLUGIN (self));
375
376
377
378
379
380
	if (enabled) {
		fwupd_plugin_remove_flag (FWUPD_PLUGIN (self),
					  FWUPD_PLUGIN_FLAG_DISABLED);
	} else {
		fu_plugin_add_flag (self, FWUPD_PLUGIN_FLAG_DISABLED);
	}
381
382
}

383
384
385
386
387
388
389
390
391
392
/**
 * fu_plugin_guess_name_from_fn:
 * @filename: filename to guess
 *
 * Tries to guess the name of the plugin from a filename
 *
 * Returns: (transfer full): the guessed name of the plugin
 *
 * Since: 1.0.8
 **/
393
394
395
396
397
398
399
400
401
402
403
404
405
gchar *
fu_plugin_guess_name_from_fn (const gchar *filename)
{
	const gchar *prefix = "libfu_plugin_";
	gchar *name;
	gchar *str = g_strstr_len (filename, -1, prefix);
	if (str == NULL)
		return NULL;
	name = g_strdup (str + strlen (prefix));
	g_strdelimit (name, ".", '\0');
	return name;
}

406
407
408
409
410
411
412
413
414
415
416
417
/**
 * fu_plugin_open:
 * @self: A #FuPlugin
 * @filename: The shared object filename to open
 * @error: A #GError or NULL
 *
 * Opens the plugin module
 *
 * Returns: TRUE for success, FALSE for fail
 *
 * Since: 0.8.0
 **/
418
gboolean
419
fu_plugin_open (FuPlugin *self, const gchar *filename, GError **error)
420
{
421
	FuPluginPrivate *priv = GET_PRIVATE (self);
422
423
	FuPluginInitFunc func = NULL;

424
425
426
427
	g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
	g_return_val_if_fail (filename != NULL, FALSE);
	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

428
429
430
431
432
	priv->module = g_module_open (filename, 0);
	if (priv->module == NULL) {
		g_set_error (error,
			     G_IO_ERROR,
			     G_IO_ERROR_FAILED,
433
434
			     "failed to open plugin %s: %s",
			     filename, g_module_error ());
435
436
		fu_plugin_add_flag (self, FWUPD_PLUGIN_FLAG_FAILED_OPEN);
		fu_plugin_add_flag (self, FWUPD_PLUGIN_FLAG_USER_WARNING);
437
438
439
440
		return FALSE;
	}

	/* set automatically */
441
442
443
444
	if (fu_plugin_get_name (self) == NULL) {
		g_autofree gchar *str = fu_plugin_guess_name_from_fn (filename);
		fu_plugin_set_name (self, str);
	}
445
446

	/* optional */
447
448
	g_module_symbol (priv->module, "fu_plugin_init", (gpointer *) &func);
	if (func != NULL) {
449
		g_debug ("init(%s)", filename);
450
		func (self);
451
452
	}

453
454
455
	return TRUE;
}

Richard Hughes's avatar
Richard Hughes committed
456
/* order of usefulness to the user */
457
458
459
460
461
462
463
464
static const gchar *
fu_plugin_build_device_update_error (FuPlugin *self)
{
	if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_NO_HARDWARE))
		return "Not updatable as required hardware was not found";
	if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_LEGACY_BIOS))
		return "Not updatable in legacy BIOS mode";
	if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED))
465
		return "Not updatable as UEFI capsule updates not enabled in firmware setup";
466
467
468
469
470
471
472
473
474
475
476
	if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_UNLOCK_REQUIRED))
		return "Not updatable as requires unlock";
	if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_EFIVAR_NOT_MOUNTED))
		return "Not updatable as efivarfs was not found";
	if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND))
		return "Not updatable as UEFI ESP partition not detected";
	if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_DISABLED))
		return "Not updatable as plugin was disabled";
	return NULL;
}

477
478
479
480
481
482
483
484
485
static void
fu_plugin_ensure_devices (FuPlugin *self)
{
	FuPluginPrivate *priv = GET_PRIVATE (self);
	if (priv->devices != NULL)
		return;
	priv->devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
}

486
487
/**
 * fu_plugin_device_add:
488
 * @self: A #FuPlugin
489
490
491
492
493
494
495
496
497
498
499
500
 * @device: A #FuDevice
 *
 * Asks the daemon to add a device to the exported list. If this device ID
 * has already been added by a different plugin then this request will be
 * ignored.
 *
 * Plugins should use fu_plugin_device_add_delay() if they are not capable of
 * actually flashing an image to the hardware so that higher-priority plugins
 * can add the device themselves.
 *
 * Since: 0.8.0
 **/
501
void
502
fu_plugin_device_add (FuPlugin *self, FuDevice *device)
503
{
504
	FuPluginPrivate *priv = GET_PRIVATE (self);
505
	GPtrArray *children;
506
	g_autoptr(GError) error = NULL;
507

508
	g_return_if_fail (FU_IS_PLUGIN (self));
509
510
	g_return_if_fail (FU_IS_DEVICE (device));

511
512
513
514
515
516
	/* ensure the device ID is set from the physical and logical IDs */
	if (!fu_device_ensure_id (device, &error)) {
		g_warning ("ignoring add: %s", error->message);
		return;
	}

517
518
519
520
	/* add to array */
	fu_plugin_ensure_devices (self);
	g_ptr_array_add (priv->devices, g_object_ref (device));

521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
	/* proxy to device where required */
	if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE)) {
		g_debug ("plugin %s has _CLEAR_UPDATABLE, so removing from %s",
			 fu_plugin_get_name (self),
			 fu_device_get_id (device));
		fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE);
	}
	if (fu_plugin_has_flag (self, FWUPD_PLUGIN_FLAG_USER_WARNING) &&
	    fu_device_get_update_error (device) == NULL) {
		const gchar *tmp = fu_plugin_build_device_update_error (self);
		g_debug ("setting %s update error to '%s' from %s",
			 fu_device_get_id (device), tmp, fu_plugin_get_name (self));
		fu_device_set_update_error (device, tmp);
	}

536
	g_debug ("emit added from %s: %s",
537
		 fu_plugin_get_name (self),
538
539
		 fu_device_get_id (device));
	fu_device_set_created (device, (guint64) g_get_real_time () / G_USEC_PER_SEC);
540
541
	fu_device_set_plugin (device, fu_plugin_get_name (self));
	g_signal_emit (self, signals[SIGNAL_DEVICE_ADDED], 0, device);
542

Richard Hughes's avatar
Richard Hughes committed
543
	/* add children if they have not already been added */
544
545
546
	children = fu_device_get_children (device);
	for (guint i = 0; i < children->len; i++) {
		FuDevice *child = g_ptr_array_index (children, i);
Richard Hughes's avatar
Richard Hughes committed
547
		if (fu_device_get_created (child) == 0)
548
			fu_plugin_device_add (self, child);
549
	}
550
551
}

552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
/**
 * fu_plugin_get_devices:
 * @self: A #FuPlugin
 *
 * Returns all devices added by the plugin using fu_plugin_device_add() and
 * not yet removed with fu_plugin_device_remove().
 *
 * Returns: (transfer none) (element-type FuDevice): devices
 *
 * Since: 1.5.6
 **/
GPtrArray *
fu_plugin_get_devices (FuPlugin *self)
{
	FuPluginPrivate *priv = GET_PRIVATE (self);
	g_return_val_if_fail (FU_IS_PLUGIN (self), NULL);
	fu_plugin_ensure_devices (self);
	return priv->devices;
}

572
573
/**
 * fu_plugin_device_register:
574
 * @self: A #FuPlugin
575
576
577
578
579
580
 * @device: A #FuDevice
 *
 * Registers the device with other plugins so they can set metadata.
 *
 * Plugins do not have to call this manually as this is done automatically
 * when using fu_plugin_device_add(). They may wish to use this manually
581
 * if for instance the coldplug should be ignored based on the metadata
582
583
584
585
586
 * set from other plugins.
 *
 * Since: 0.9.7
 **/
void
587
fu_plugin_device_register (FuPlugin *self, FuDevice *device)
588
{
589
590
	g_autoptr(GError) error = NULL;

591
	g_return_if_fail (FU_IS_PLUGIN (self));
592
593
	g_return_if_fail (FU_IS_DEVICE (device));

594
595
596
597
598
599
	/* ensure the device ID is set from the physical and logical IDs */
	if (!fu_device_ensure_id (device, &error)) {
		g_warning ("ignoring registration: %s", error->message);
		return;
	}

600
	g_debug ("emit device-register from %s: %s",
601
		 fu_plugin_get_name (self),
602
		 fu_device_get_id (device));
603
	g_signal_emit (self, signals[SIGNAL_DEVICE_REGISTER], 0, device);
604
605
}

606
/**
607
 * fu_plugin_device_remove:
608
 * @self: A #FuPlugin
609
610
611
612
613
614
 * @device: A #FuDevice
 *
 * Asks the daemon to remove a device from the exported list.
 *
 * Since: 0.8.0
 **/
615
void
616
fu_plugin_device_remove (FuPlugin *self, FuDevice *device)
617
{
618
619
	FuPluginPrivate *priv = GET_PRIVATE (self);

620
	g_return_if_fail (FU_IS_PLUGIN (self));
621
622
	g_return_if_fail (FU_IS_DEVICE (device));

623
624
625
626
	/* remove from array */
	if (priv->devices != NULL)
		g_ptr_array_remove (priv->devices, device);

627
	g_debug ("emit removed from %s: %s",
628
		 fu_plugin_get_name (self),
629
		 fu_device_get_id (device));
630
	g_signal_emit (self, signals[SIGNAL_DEVICE_REMOVED], 0, device);
631
632
}

633
/**
634
 * fu_plugin_request_recoldplug:
635
 * @self: A #FuPlugin
636
637
638
639
640
641
642
 *
 * Ask all the plugins to coldplug all devices, which will include the prepare()
 * and cleanup() phases. Duplicate devices added will be ignored.
 *
 * Since: 0.8.0
 **/
void
643
fu_plugin_request_recoldplug (FuPlugin *self)
644
{
645
646
	g_return_if_fail (FU_IS_PLUGIN (self));
	g_signal_emit (self, signals[SIGNAL_RECOLDPLUG], 0);
647
648
}

649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
/**
 * fu_plugin_security_changed:
 * @self: A #FuPlugin
 *
 * Informs the daemon that the HSI state may have changed.
 *
 * Since: 1.5.0
 **/
void
fu_plugin_security_changed (FuPlugin *self)
{
	g_return_if_fail (FU_IS_PLUGIN (self));
	g_signal_emit (self, signals[SIGNAL_SECURITY_CHANGED], 0);
}

664
665
/**
 * fu_plugin_check_hwid:
666
 * @self: A #FuPlugin
667
 * @hwid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
668
 *
669
 * Checks to see if a specific GUID exists. All hardware IDs on a
670
671
 * specific system can be shown using the `fwupdmgr hwids` command.
 *
672
673
 * Returns: %TRUE if the HwId is found on the system.
 *
674
675
676
 * Since: 0.9.1
 **/
gboolean
677
fu_plugin_check_hwid (FuPlugin *self, const gchar *hwid)
678
{
679
	FuPluginPrivate *priv = GET_PRIVATE (self);
680
681
	if (priv->hwids == NULL)
		return FALSE;
682
683
684
	return fu_hwids_has_guid (priv->hwids, hwid);
}

685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
/**
 * fu_plugin_get_hwid_replace_value:
 * @self: A #FuPlugin
 * @keys: A key, e.g. `HardwareID-3` or %FU_HWIDS_KEY_PRODUCT_SKU
 * @error: A #GError or %NULL
 *
 * Gets the replacement value for a specific key. All hardware IDs on a
 * specific system can be shown using the `fwupdmgr hwids` command.
 *
 * Returns: (transfer full): a string, or %NULL for error.
 *
 * Since: 1.3.3
 **/
gchar *
fu_plugin_get_hwid_replace_value (FuPlugin *self, const gchar *keys, GError **error)
{
	FuPluginPrivate *priv = GET_PRIVATE (self);
	if (priv->hwids == NULL)
		return NULL;

	return fu_hwids_get_replace_values (priv->hwids, keys, error);
}

708
709
/**
 * fu_plugin_get_hwids:
710
 * @self: A #FuPlugin
711
712
713
714
 *
 * Returns all the HWIDs defined in the system. All hardware IDs on a
 * specific system can be shown using the `fwupdmgr hwids` command.
 *
715
 * Returns: (transfer none) (element-type utf8): An array of GUIDs
716
717
718
719
 *
 * Since: 1.1.1
 **/
GPtrArray *
720
fu_plugin_get_hwids (FuPlugin *self)
721
{
722
	FuPluginPrivate *priv = GET_PRIVATE (self);
723
724
725
726
727
	if (priv->hwids == NULL)
		return NULL;
	return fu_hwids_get_guids (priv->hwids);
}

728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
/**
 * fu_plugin_has_custom_flag:
 * @self: A #FuPlugin
 * @flag: A custom text flag, specific to the plugin, e.g. `uefi-force-enable`
 *
 * Returns if a per-plugin HwId custom flag exists, typically added from a DMI quirk.
 *
 * Returns: %TRUE if the quirk entry exists
 *
 * Since: 1.3.1
 **/
gboolean
fu_plugin_has_custom_flag (FuPlugin *self, const gchar *flag)
{
	FuPluginPrivate *priv = GET_PRIVATE (self);
	GPtrArray *hwids = fu_plugin_get_hwids (self);

	g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE);
	g_return_val_if_fail (flag != NULL, FALSE);

	/* never set up, e.g. in tests */
	if (hwids == NULL)
		return FALSE;

	/* search each hwid */
	for (guint i = 0; i < hwids->len; i++) {
		const gchar *hwid = g_ptr_array_index (hwids, i);
		const gchar *value;
		g_autofree gchar *key = g_strdup_printf ("HwId=%s", hwid);

		/* does prefixed quirk exist */
		value = fu_quirks_lookup_by_id (priv->quirks, key, FU_QUIRKS_FLAGS);
		if (value != NULL) {
			g_auto(GStrv) quirks = g_strsplit (value, ",", -1);
			if (g_strv_contains ((const gchar * const *) quirks, flag))
				return TRUE;
		}
	}
	return FALSE;
}

769
770
/**
 * fu_plugin_check_supported:
771
 * @self: A #FuPlugin
772
 * @guid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234`
773
774
775
776
 *
 * Checks to see if a specific device GUID is supported, i.e. available in the
 * AppStream metadata.
 *
777
778
 * Returns: %TRUE if the device is supported.
 *
779
780
 * Since: 1.0.0
 **/
781
static gboolean
782
fu_plugin_check_supported (FuPlugin *self, const gchar *guid)
783
{
784
785
786
	gboolean retval = FALSE;
	g_signal_emit (self, signals[SIGNAL_CHECK_SUPPORTED], 0, guid, &retval);
	return retval;
787
788
}

789
790
/**
 * fu_plugin_get_dmi_value:
791
 * @self: A #FuPlugin
792
 * @dmi_id: A DMI ID, e.g. `BiosVersion`
793
794
795
 *
 * Gets a hardware DMI value.
 *
796
797
 * Returns: The string, or %NULL
 *
798
799
800
 * Since: 0.9.7
 **/
const gchar *
801
fu_plugin_get_dmi_value (FuPlugin *self, const gchar *dmi_id)
802
{
803
	FuPluginPrivate *priv = GET_PRIVATE (self);
804
	if (priv->hwids == NULL)
805
		return NULL;
806
	return fu_hwids_get_value (priv->hwids, dmi_id);
807
808
}

809
810
/**
 * fu_plugin_get_smbios_string:
811
 * @self: A #FuPlugin
812
813
814
815
816
817
818
819
 * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
 * @offset: A SMBIOS offset
 *
 * Gets a hardware SMBIOS string.
 *
 * The @type and @offset can be referenced from the DMTF SMBIOS specification:
 * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.1.1.pdf
 *
820
821
 * Returns: A string, or %NULL
 *
822
823
824
 * Since: 0.9.8
 **/
const gchar *
825
fu_plugin_get_smbios_string (FuPlugin *self, guint8 structure_type, guint8 offset)
826
{
827
	FuPluginPrivate *priv = GET_PRIVATE (self);
828
829
830
831
832
833
834
	if (priv->smbios == NULL)
		return NULL;
	return fu_smbios_get_string (priv->smbios, structure_type, offset, NULL);
}

/**
 * fu_plugin_get_smbios_data:
835
 * @self: A #FuPlugin
836
837
838
839
 * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
 *
 * Gets a hardware SMBIOS data.
 *
840
 * Returns: (transfer full): A #GBytes, or %NULL
841
 *
842
843
844
 * Since: 0.9.8
 **/
GBytes *
845
fu_plugin_get_smbios_data (FuPlugin *self, guint8 structure_type)
846
{
847
	FuPluginPrivate *priv = GET_PRIVATE (self);
848
849
850
851
852
	if (priv->smbios == NULL)
		return NULL;
	return fu_smbios_get_data (priv->smbios, structure_type, NULL);
}

853
854
855
856
857
858
859
860
861
/**
 * fu_plugin_set_hwids:
 * @self: A #FuPlugin
 * @hwids: A #FuHwids
 *
 * Sets the hwids for a plugin
 *
 * Since: 0.9.7
 **/
862
void
863
fu_plugin_set_hwids (FuPlugin *self, FuHwids *hwids)
864
{
865
	FuPluginPrivate *priv = GET_PRIVATE (self);
866
	g_set_object (&priv->hwids, hwids);
867
868
}

869
870
871
/**
 * fu_plugin_set_udev_subsystems:
 * @self: A #FuPlugin
872
 * @udev_subsystems: (element-type utf8): A #GPtrArray
873
874
875
876
877
 *
 * Sets the udev subsystems used by a plugin
 *
 * Since: 1.1.2
 **/
878
void
879
fu_plugin_set_udev_subsystems (FuPlugin *self, GPtrArray *udev_subsystems)
880
{
881
	FuPluginPrivate *priv = GET_PRIVATE (self);
882
883
884
885
886
	if (priv->udev_subsystems != NULL)
		g_ptr_array_unref (priv->udev_subsystems);
	priv->udev_subsystems = g_ptr_array_ref (udev_subsystems);
}

887
888
889
890
891
892
893
894
895
/**
 * fu_plugin_set_quirks:
 * @self: A #FuPlugin
 * @quirks: A #FuQuirks
 *
 * Sets the quirks for a plugin
 *
 * Since: 1.0.1
 **/
896
void
897
fu_plugin_set_quirks (FuPlugin *self, FuQuirks *quirks)
898
{
899
	FuPluginPrivate *priv = GET_PRIVATE (self);
900
901
902
903
904
	g_set_object (&priv->quirks, quirks);
}

/**
 * fu_plugin_get_quirks:
905
 * @self: A #FuPlugin
906
907
908
909
910
911
912
913
914
 *
 * Returns the hardware database object. This can be used to discover device
 * quirks or other device-specific settings.
 *
 * Returns: (transfer none): a #FuQuirks, or %NULL if not set
 *
 * Since: 1.0.1
 **/
FuQuirks *
915
fu_plugin_get_quirks (FuPlugin *self)
916
{
917
	FuPluginPrivate *priv = GET_PRIVATE (self);
918
919
920
	return priv->quirks;
}

921
922
923
924
925
926
927
928
929
/**
 * fu_plugin_set_runtime_versions:
 * @self: A #FuPlugin
 * @runtime_versions: A #GHashTables
 *
 * Sets the runtime versions for a plugin
 *
 * Since: 1.0.7
 **/
930
void
931
fu_plugin_set_runtime_versions (FuPlugin *self, GHashTable *runtime_versions)
932
{
933
	FuPluginPrivate *priv = GET_PRIVATE (self);
934
935
936
937
938
	priv->runtime_versions = g_hash_table_ref (runtime_versions);
}

/**
 * fu_plugin_add_runtime_version:
939
 * @self: A #FuPlugin
940
941
942
 * @component_id: An AppStream component id, e.g. "org.gnome.Software"
 * @version: A version string, e.g. "1.2.3"
 *
943
 * Sets a runtime version of a specific dependency.
944
945
946
947
 *
 * Since: 1.0.7
 **/
void
948
fu_plugin_add_runtime_version (FuPlugin *self,
949
950
951
			       const gchar *component_id,
			       const gchar *version)
{
952
	FuPluginPrivate *priv = GET_PRIVATE (self);
953
954
	if (priv->runtime_versions == NULL)
		return;
955
956
957
958
959
	g_hash_table_insert (priv->runtime_versions,
			     g_strdup (component_id),
			     g_strdup (version));
}

960
961
962
963
964
965
966
967
968
/**
 * fu_plugin_set_compile_versions:
 * @self: A #FuPlugin
 * @compile_versions: A #GHashTables
 *
 * Sets the compile time versions for a plugin
 *
 * Since: 1.0.7
 **/
969
void
970
fu_plugin_set_compile_versions (FuPlugin *self, GHashTable *compile_versions)
971
{
972
	FuPluginPrivate *priv = GET_PRIVATE (self);
973
974
975
976
977
	priv->compile_versions = g_hash_table_ref (compile_versions);
}

/**
 * fu_plugin_add_compile_version:
978
 * @self: A #FuPlugin
979
980
981
 * @component_id: An AppStream component id, e.g. "org.gnome.Software"
 * @version: A version string, e.g. "1.2.3"
 *
982
 * Sets a compile-time version of a specific dependency.
983
984
985
986
 *
 * Since: 1.0.7
 **/
void
987
fu_plugin_add_compile_version (FuPlugin *self,
988
989
990
			       const gchar *component_id,
			       const gchar *version)
{
991
	FuPluginPrivate *priv = GET_PRIVATE (self);
992
993
994
995
996
997
998
	if (priv->compile_versions == NULL)
		return;
	g_hash_table_insert (priv->compile_versions,
			     g_strdup (component_id),
			     g_strdup (version));
}

999
1000
/**
 * fu_plugin_lookup_quirk_by_id:
For faster browsing, not all history is shown. View entire blame