Coverage Report

Created: 2026-04-12 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fwupd/libfwupdplugin/fu-context.c
Line
Count
Source
1
/*
2
 * Copyright 2021 Richard Hughes <richard@hughsie.com>
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 */
6
7
0
#define G_LOG_DOMAIN "FuContext"
8
9
#include "config.h"
10
11
#include "fu-bios-settings-private.h"
12
#include "fu-common-private.h"
13
#include "fu-config-private.h"
14
#include "fu-context-helper.h"
15
#include "fu-context-private.h"
16
#include "fu-dummy-efivars.h"
17
#include "fu-efi-device-path-list.h"
18
#include "fu-efi-file-path-device-path.h"
19
#include "fu-efi-hard-drive-device-path.h"
20
#include "fu-fdt-firmware.h"
21
#include "fu-hwids-private.h"
22
#include "fu-path-store.h"
23
#include "fu-path.h"
24
#include "fu-pefile-firmware.h"
25
#include "fu-volume-locker.h"
26
#include "fu-volume-private.h"
27
28
/**
29
 * FuContext:
30
 *
31
 * A context that represents the shared system state. This object is shared
32
 * between the engine, the plugins and the devices.
33
 */
34
35
typedef struct {
36
  FuContextFlags flags;
37
  FuPathStore *pstore;
38
  FuHwids *hwids;
39
  FuConfig *config;
40
  FuSmbios *smbios;
41
  FuSmbiosChassisKind chassis_kind;
42
  FuQuirks *quirks;
43
  FuEfivars *efivars;
44
  GPtrArray *backends;
45
  GHashTable *runtime_versions;
46
  GHashTable *compile_versions;
47
  GHashTable *udev_subsystems; /* utf8:GPtrArray */
48
  GPtrArray *esp_volumes;
49
  GHashTable *firmware_gtypes; /* utf8:GType */
50
  GHashTable *hwid_flags;      /* str: */
51
  FuPowerState power_state;
52
  FuLidState lid_state;
53
  FuDisplayState display_state;
54
  guint battery_level;
55
  guint battery_threshold;
56
  FuBiosSettings *host_bios_settings;
57
  FuFirmware *fdt; /* optional */
58
  gchar *esp_location;
59
} FuContextPrivate;
60
61
enum { SIGNAL_SECURITY_CHANGED, SIGNAL_HOUSEKEEPING, SIGNAL_LAST };
62
63
enum {
64
  PROP_0,
65
  PROP_POWER_STATE,
66
  PROP_LID_STATE,
67
  PROP_DISPLAY_STATE,
68
  PROP_BATTERY_LEVEL,
69
  PROP_BATTERY_THRESHOLD,
70
  PROP_FLAGS,
71
  PROP_LAST
72
};
73
74
static guint signals[SIGNAL_LAST] = {0};
75
76
1.11k
G_DEFINE_TYPE_WITH_PRIVATE(FuContext, fu_context, G_TYPE_OBJECT)
77
1.11k
78
1.11k
#define GET_PRIVATE(o) (fu_context_get_instance_private(o))
79
80
static gboolean
81
fu_context_ensure_smbios_uefi_enabled(FuContext *self, GError **error)
82
0
{
83
0
  GBytes *bios_blob;
84
0
  g_autoptr(FuStructSmbiosBiosInformation) st = NULL;
85
0
  g_autoptr(GPtrArray) bios_tables = NULL;
86
87
0
  bios_tables = fu_context_get_smbios_data(self, 0, FU_SMBIOS_STRUCTURE_LENGTH_ANY, NULL);
88
0
  if (bios_tables == NULL) {
89
0
    const gchar *tmp = g_getenv("FWUPD_DELL_FAKE_SMBIOS");
90
0
    if (tmp != NULL)
91
0
      return TRUE;
92
0
    g_set_error_literal(error,
93
0
            FWUPD_ERROR,
94
0
            FWUPD_ERROR_NOT_SUPPORTED,
95
0
            "SMBIOS not supported");
96
0
    return FALSE;
97
0
  }
98
0
  bios_blob = g_ptr_array_index(bios_tables, 0);
99
100
0
  st = fu_struct_smbios_bios_information_parse_bytes(bios_blob, 0x0, error);
101
0
  if (st == NULL)
102
0
    return FALSE;
103
0
  if (fu_struct_smbios_bios_information_get_length(st) < 0x14) {
104
0
    g_set_error_literal(error,
105
0
            FWUPD_ERROR,
106
0
            FWUPD_ERROR_NOT_SUPPORTED,
107
0
            "SMBIOS 2.3 not supported");
108
0
    return FALSE;
109
0
  }
110
0
  if ((fu_struct_smbios_bios_information_get_characteristics_ext(st) &
111
0
       FU_SMBIOS_BIOS_CHARACTERISTICS_EXT_UEFI_SPECIFICATION_SUPPORTED) == 0) {
112
0
    g_set_error_literal(error,
113
0
            FWUPD_ERROR,
114
0
            FWUPD_ERROR_NOT_SUPPORTED,
115
0
            "System does not support UEFI mode");
116
0
    return FALSE;
117
0
  }
118
119
  /* success */
120
0
  fu_context_add_flag(self, FU_CONTEXT_FLAG_SMBIOS_UEFI_ENABLED);
121
0
  return TRUE;
122
0
}
123
124
static GFile *
125
fu_context_get_fdt_file(FuContext *self, GError **error)
126
0
{
127
0
  g_autofree gchar *fdtfn_local = NULL;
128
0
  g_autofree gchar *fdtfn_sys = NULL;
129
130
  /* look for override first, fall back to system value */
131
0
  fdtfn_local = fu_context_build_filename(self,
132
0
            error,
133
0
            FU_PATH_KIND_LOCALSTATEDIR_PKG,
134
0
            "system.dtb",
135
0
            NULL);
136
0
  if (fdtfn_local == NULL)
137
0
    return NULL;
138
0
  if (g_file_test(fdtfn_local, G_FILE_TEST_EXISTS))
139
0
    return g_file_new_for_path(fdtfn_local);
140
141
  /* actual hardware value */
142
0
  fdtfn_sys = fu_context_build_filename(self, error, FU_PATH_KIND_SYSFSDIR_FW, "fdt", NULL);
143
0
  if (fdtfn_sys == NULL)
144
0
    return NULL;
145
0
  if (g_file_test(fdtfn_sys, G_FILE_TEST_EXISTS))
146
0
    return g_file_new_for_path(fdtfn_sys);
147
148
  /* failed */
149
0
  g_set_error(error,
150
0
        FWUPD_ERROR,
151
0
        FWUPD_ERROR_NOT_SUPPORTED,
152
0
        "cannot find %s or override %s",
153
0
        fdtfn_sys,
154
0
        fdtfn_local);
155
0
  return NULL;
156
0
}
157
158
/**
159
 * fu_context_get_fdt:
160
 * @self: a #FuContext
161
 * @error: (nullable): optional return location for an error
162
 *
163
 * Gets and parses the system FDT, aka. the Flat Device Tree.
164
 *
165
 * The results are cached internally to the context, and subsequent calls to this function
166
 * returns the pre-parsed object.
167
 *
168
 * Returns: (transfer full): a #FuFdtFirmware, or %NULL
169
 *
170
 * Since: 1.8.10
171
 **/
172
FuFirmware *
173
fu_context_get_fdt(FuContext *self, GError **error)
174
0
{
175
0
  FuContextPrivate *priv = GET_PRIVATE(self);
176
177
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
178
0
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
179
180
  /* load if not already parsed */
181
0
  if (priv->fdt == NULL) {
182
0
    g_autoptr(FuFirmware) fdt_tmp = fu_fdt_firmware_new();
183
0
    g_autoptr(GFile) file = fu_context_get_fdt_file(self, error);
184
0
    if (file == NULL)
185
0
      return NULL;
186
0
    if (!fu_firmware_parse_file(fdt_tmp,
187
0
              file,
188
0
              FU_FIRMWARE_PARSE_FLAG_NO_SEARCH,
189
0
              error)) {
190
0
      g_prefix_error_literal(error, "failed to parse FDT: ");
191
0
      return NULL;
192
0
    }
193
0
    priv->fdt = g_steal_pointer(&fdt_tmp);
194
0
  }
195
196
  /* success */
197
0
  return g_object_ref(priv->fdt);
198
0
}
199
200
/**
201
 * fu_context_get_efivars:
202
 * @self: a #FuContext
203
 *
204
 * Gets the EFI variable store.
205
 *
206
 * Returns: (transfer none): a #FuEfivars
207
 *
208
 * Since: 2.0.0
209
 **/
210
FuEfivars *
211
fu_context_get_efivars(FuContext *self)
212
0
{
213
0
  FuContextPrivate *priv = GET_PRIVATE(self);
214
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
215
0
  return priv->efivars;
216
0
}
217
218
/**
219
 * fu_context_efivars_check_free_space:
220
 * @self: a #FuContext
221
 * @count: size in bytes
222
 * @error: (nullable): optional return location for an error
223
 *
224
 * Checks for a given amount of free space in the EFI NVRAM variable store.
225
 *
226
 * Returns: %TRUE for success
227
 *
228
 * Since: 2.0.12
229
 **/
230
gboolean
231
fu_context_efivars_check_free_space(FuContext *self, gsize count, GError **error)
232
0
{
233
0
  FuContextPrivate *priv = GET_PRIVATE(self);
234
0
  guint64 total;
235
236
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), FALSE);
237
0
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
238
239
  /* escape hatch */
240
0
  if (fu_context_has_flag(self, FU_CONTEXT_FLAG_IGNORE_EFIVARS_FREE_SPACE))
241
0
    return TRUE;
242
243
0
  total = fu_efivars_space_free(priv->efivars, error);
244
0
  if (total == G_MAXUINT64)
245
0
    return FALSE;
246
0
  if (total < count) {
247
0
    g_autofree gchar *countstr = g_format_size(count);
248
0
    g_autofree gchar *totalstr = g_format_size(total);
249
0
    g_set_error(error,
250
0
          FWUPD_ERROR,
251
0
          FWUPD_ERROR_BROKEN_SYSTEM,
252
0
          "Not enough efivarfs space, requested %s and got %s",
253
0
          countstr,
254
0
          totalstr);
255
0
    return FALSE;
256
0
  }
257
0
  return TRUE;
258
0
}
259
260
/**
261
 * fu_context_get_smbios:
262
 * @self: a #FuContext
263
 *
264
 * Gets the SMBIOS store.
265
 *
266
 * Returns: (transfer none): a #FuSmbios
267
 *
268
 * Since: 1.8.10
269
 **/
270
FuSmbios *
271
fu_context_get_smbios(FuContext *self)
272
0
{
273
0
  FuContextPrivate *priv = GET_PRIVATE(self);
274
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
275
0
  return priv->smbios;
276
0
}
277
278
/**
279
 * fu_context_set_smbios:
280
 * @self: a #FuContext
281
 * @smbios: a #FuSmbios
282
 *
283
 * Sets the SMBIOS store. This is only required by self test code.
284
 *
285
 * Since: 2.1.1
286
 **/
287
void
288
fu_context_set_smbios(FuContext *self, FuSmbios *smbios)
289
0
{
290
0
  FuContextPrivate *priv = GET_PRIVATE(self);
291
0
  g_return_if_fail(FU_IS_CONTEXT(self));
292
0
  g_return_if_fail(FU_IS_SMBIOS(smbios));
293
0
  g_set_object(&priv->smbios, smbios);
294
0
  fu_context_add_flag(self, FU_CONTEXT_FLAG_LOADED_HWINFO);
295
0
}
296
297
/**
298
 * fu_context_get_hwids:
299
 * @self: a #FuContext
300
 *
301
 * Gets the HWIDs store.
302
 *
303
 * Returns: (transfer none): a #FuHwids
304
 *
305
 * Since: 1.8.10
306
 **/
307
FuHwids *
308
fu_context_get_hwids(FuContext *self)
309
0
{
310
0
  FuContextPrivate *priv = GET_PRIVATE(self);
311
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
312
0
  return priv->hwids;
313
0
}
314
315
/**
316
 * fu_context_get_config:
317
 * @self: a #FuContext
318
 *
319
 * Gets the system config.
320
 *
321
 * Returns: (transfer none): a #FuHwids
322
 *
323
 * Since: 1.9.1
324
 **/
325
FuConfig *
326
fu_context_get_config(FuContext *self)
327
0
{
328
0
  FuContextPrivate *priv = GET_PRIVATE(self);
329
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
330
0
  return priv->config;
331
0
}
332
333
/**
334
 * fu_context_get_smbios_string:
335
 * @self: a #FuContext
336
 * @type: a SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
337
 * @length: expected length of the structure, or %FU_SMBIOS_STRUCTURE_LENGTH_ANY
338
 * @offset: a SMBIOS offset
339
 * @error: (nullable): optional return location for an error
340
 *
341
 * Gets a hardware SMBIOS string.
342
 *
343
 * The @type and @offset can be referenced from the DMTF SMBIOS specification:
344
 * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.1.1.pdf
345
 *
346
 * Returns: a string, or %NULL
347
 *
348
 * Since: 2.0.7
349
 **/
350
const gchar *
351
fu_context_get_smbios_string(FuContext *self,
352
           guint8 type,
353
           guint8 length,
354
           guint8 offset,
355
           GError **error)
356
0
{
357
0
  FuContextPrivate *priv = GET_PRIVATE(self);
358
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
359
0
  if (!fu_context_has_flag(self, FU_CONTEXT_FLAG_LOADED_HWINFO)) {
360
0
    g_critical("cannot use SMBIOS before calling ->load_hwinfo()");
361
0
    return NULL;
362
0
  }
363
0
  return fu_smbios_get_string(priv->smbios, type, length, offset, error);
364
0
}
365
366
/**
367
 * fu_context_get_smbios_data:
368
 * @self: a #FuContext
369
 * @type: a SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
370
 * @length: expected length of the structure, or %FU_SMBIOS_STRUCTURE_LENGTH_ANY
371
 * @error: (nullable): optional return location for an error
372
 *
373
 * Gets all hardware SMBIOS data for a specific type.
374
 *
375
 * Returns: (transfer container) (element-type GBytes): a #GBytes, or %NULL if not found
376
 *
377
 * Since: 2.0.7
378
 **/
379
GPtrArray *
380
fu_context_get_smbios_data(FuContext *self, guint8 type, guint8 length, GError **error)
381
0
{
382
0
  FuContextPrivate *priv = GET_PRIVATE(self);
383
384
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
385
386
  /* must be valid and non-zero length */
387
0
  if (!fu_context_has_flag(self, FU_CONTEXT_FLAG_LOADED_HWINFO)) {
388
0
    g_critical("cannot use SMBIOS before calling ->load_hwinfo()");
389
0
    g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "no data");
390
0
    return NULL;
391
0
  }
392
0
  return fu_smbios_get_data(priv->smbios, type, length, error);
393
0
}
394
395
/**
396
 * fu_context_get_smbios_integer:
397
 * @self: a #FuContext
398
 * @type: a structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
399
 * @length: expected length of the structure, or %FU_SMBIOS_STRUCTURE_LENGTH_ANY
400
 * @offset: a structure offset
401
 * @error: (nullable): optional return location for an error
402
 *
403
 * Reads an integer value from the SMBIOS string table of a specific structure.
404
 *
405
 * The @type and @offset can be referenced from the DMTF SMBIOS specification:
406
 * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.1.1.pdf
407
 *
408
 * Returns: an integer, or %G_MAXUINT if invalid or not found
409
 *
410
 * Since: 2.0.7
411
 **/
412
guint
413
fu_context_get_smbios_integer(FuContext *self,
414
            guint8 type,
415
            guint8 length,
416
            guint8 offset,
417
            GError **error)
418
0
{
419
0
  FuContextPrivate *priv = GET_PRIVATE(self);
420
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), G_MAXUINT);
421
0
  if (!fu_context_has_flag(self, FU_CONTEXT_FLAG_LOADED_HWINFO)) {
422
0
    g_critical("cannot use SMBIOS before calling ->load_hwinfo()");
423
0
    return G_MAXUINT;
424
0
  }
425
0
  return fu_smbios_get_integer(priv->smbios, type, length, offset, error);
426
0
}
427
428
/**
429
 * fu_context_reload_bios_settings:
430
 * @self: a #FuContext
431
 * @error: (nullable): optional return location for an error
432
 *
433
 * Refreshes the list of firmware attributes on the system.
434
 *
435
 * Since: 1.8.4
436
 **/
437
gboolean
438
fu_context_reload_bios_settings(FuContext *self, GError **error)
439
0
{
440
0
  FuContextPrivate *priv = GET_PRIVATE(self);
441
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), FALSE);
442
0
  return fu_bios_settings_setup(priv->host_bios_settings, error);
443
0
}
444
445
/**
446
 * fu_context_get_bios_settings:
447
 * @self: a #FuContext
448
 *
449
 * Returns all the firmware attributes defined in the system.
450
 *
451
 * Returns: (transfer full): A #FuBiosSettings
452
 *
453
 * Since: 1.8.4
454
 **/
455
FuBiosSettings *
456
fu_context_get_bios_settings(FuContext *self)
457
0
{
458
0
  FuContextPrivate *priv = GET_PRIVATE(self);
459
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
460
0
  return g_object_ref(priv->host_bios_settings);
461
0
}
462
463
/**
464
 * fu_context_get_bios_setting:
465
 * @self: a #FuContext
466
 * @name: a BIOS setting title, e.g. `BootOrderLock`
467
 *
468
 * Finds out if a system supports a given BIOS setting.
469
 *
470
 * Returns: (transfer none): #FwupdBiosSetting if the attr exists.
471
 *
472
 * Since: 1.8.4
473
 **/
474
FwupdBiosSetting *
475
fu_context_get_bios_setting(FuContext *self, const gchar *name)
476
0
{
477
0
  FuContextPrivate *priv = GET_PRIVATE(self);
478
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
479
0
  g_return_val_if_fail(name != NULL, NULL);
480
0
  return fu_bios_settings_get_attr(priv->host_bios_settings, name);
481
0
}
482
483
/**
484
 * fu_context_get_bios_setting_pending_reboot:
485
 * @self: a #FuContext
486
 *
487
 * Determine if updates to BIOS settings are pending until next boot.
488
 *
489
 * Returns: %TRUE if updates are pending.
490
 *
491
 * Since: 1.8.4
492
 **/
493
gboolean
494
fu_context_get_bios_setting_pending_reboot(FuContext *self)
495
0
{
496
0
  FuContextPrivate *priv = GET_PRIVATE(self);
497
0
  gboolean ret;
498
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), FALSE);
499
0
  fu_bios_settings_get_pending_reboot(priv->host_bios_settings, &ret, NULL);
500
0
  return ret;
501
0
}
502
503
/**
504
 * fu_context_get_chassis_kind:
505
 * @self: a #FuContext
506
 *
507
 * Gets the chassis kind, if known.
508
 *
509
 * Returns: a #FuSmbiosChassisKind, e.g. %FU_SMBIOS_CHASSIS_KIND_LAPTOP
510
 *
511
 * Since: 1.8.10
512
 **/
513
FuSmbiosChassisKind
514
fu_context_get_chassis_kind(FuContext *self)
515
0
{
516
0
  FuContextPrivate *priv = GET_PRIVATE(self);
517
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), FALSE);
518
0
  return priv->chassis_kind;
519
0
}
520
521
/**
522
 * fu_context_set_chassis_kind:
523
 * @self: a #FuContext
524
 * @chassis_kind: a #FuSmbiosChassisKind, e.g. %FU_SMBIOS_CHASSIS_KIND_TABLET
525
 *
526
 * Sets the chassis kind.
527
 *
528
 * Since: 1.8.10
529
 **/
530
void
531
fu_context_set_chassis_kind(FuContext *self, FuSmbiosChassisKind chassis_kind)
532
0
{
533
0
  FuContextPrivate *priv = GET_PRIVATE(self);
534
0
  g_return_if_fail(FU_IS_CONTEXT(self));
535
0
  priv->chassis_kind = chassis_kind;
536
0
}
537
538
/**
539
 * fu_context_has_hwid_guid:
540
 * @self: a #FuContext
541
 * @guid: a GUID, e.g. `059eb22d-6dc7-59af-abd3-94bbe017f67c`
542
 *
543
 * Finds out if a hardware GUID exists.
544
 *
545
 * Returns: %TRUE if the GUID exists
546
 *
547
 * Since: 1.6.0
548
 **/
549
gboolean
550
fu_context_has_hwid_guid(FuContext *self, const gchar *guid)
551
0
{
552
0
  FuContextPrivate *priv = GET_PRIVATE(self);
553
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), FALSE);
554
0
  if (!fu_context_has_flag(self, FU_CONTEXT_FLAG_LOADED_HWINFO)) {
555
0
    g_critical("cannot use HWIDs before calling ->load_hwinfo()");
556
0
    return FALSE;
557
0
  }
558
0
  return fu_hwids_has_guid(priv->hwids, guid);
559
0
}
560
561
/**
562
 * fu_context_get_hwid_guids:
563
 * @self: a #FuContext
564
 *
565
 * Returns all the HWIDs defined in the system. All hardware IDs on a
566
 * specific system can be shown using the `fwupdmgr hwids` command.
567
 *
568
 * Returns: (transfer none) (element-type utf8): an array of GUIDs
569
 *
570
 * Since: 1.6.0
571
 **/
572
GPtrArray *
573
fu_context_get_hwid_guids(FuContext *self)
574
0
{
575
0
  FuContextPrivate *priv = GET_PRIVATE(self);
576
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
577
0
  if (!fu_context_has_flag(self, FU_CONTEXT_FLAG_LOADED_HWINFO)) {
578
0
    g_critical("cannot use HWIDs before calling ->load_hwinfo()");
579
0
    return NULL;
580
0
  }
581
0
  return fu_hwids_get_guids(priv->hwids);
582
0
}
583
584
/**
585
 * fu_context_get_hwid_value:
586
 * @self: a #FuContext
587
 * @key: a DMI ID, e.g. `BiosVersion`
588
 *
589
 * Gets the cached value for one specific key that is valid ASCII and suitable
590
 * for display.
591
 *
592
 * Returns: the string, e.g. `1.2.3`, or %NULL if not found
593
 *
594
 * Since: 1.6.0
595
 **/
596
const gchar *
597
fu_context_get_hwid_value(FuContext *self, const gchar *key)
598
0
{
599
0
  FuContextPrivate *priv = GET_PRIVATE(self);
600
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
601
0
  g_return_val_if_fail(key != NULL, NULL);
602
0
  if (!fu_context_has_flag(self, FU_CONTEXT_FLAG_LOADED_HWINFO)) {
603
0
    g_critical("cannot use HWIDs before calling ->load_hwinfo()");
604
0
    return NULL;
605
0
  }
606
0
  return fu_hwids_get_value(priv->hwids, key);
607
0
}
608
609
/**
610
 * fu_context_get_hwid_replace_value:
611
 * @self: a #FuContext
612
 * @keys: a key, e.g. `HardwareID-3` or %FU_HWIDS_KEY_PRODUCT_SKU
613
 * @error: (nullable): optional return location for an error
614
 *
615
 * Gets the replacement value for a specific key. All hardware IDs on a
616
 * specific system can be shown using the `fwupdmgr hwids` command.
617
 *
618
 * Returns: (transfer full): a string, or %NULL for error.
619
 *
620
 * Since: 1.6.0
621
 **/
622
gchar *
623
fu_context_get_hwid_replace_value(FuContext *self, const gchar *keys, GError **error)
624
0
{
625
0
  FuContextPrivate *priv = GET_PRIVATE(self);
626
627
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
628
0
  g_return_val_if_fail(keys != NULL, NULL);
629
0
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
630
631
0
  if (!fu_context_has_flag(self, FU_CONTEXT_FLAG_LOADED_HWINFO)) {
632
0
    g_critical("cannot use HWIDs before calling ->load_hwinfo()");
633
0
    g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "no data");
634
0
    return NULL;
635
0
  }
636
0
  return fu_hwids_get_replace_values(priv->hwids, keys, error);
637
0
}
638
639
/**
640
 * fu_context_add_runtime_version:
641
 * @self: a #FuContext
642
 * @component_id: an AppStream component id, e.g. `org.gnome.Software`
643
 * @version: a version string, e.g. `1.2.3`
644
 *
645
 * Sets a runtime version of a specific dependency.
646
 *
647
 * Since: 1.6.0
648
 **/
649
void
650
fu_context_add_runtime_version(FuContext *self, const gchar *component_id, const gchar *version)
651
0
{
652
0
  FuContextPrivate *priv = GET_PRIVATE(self);
653
654
0
  g_return_if_fail(FU_IS_CONTEXT(self));
655
0
  g_return_if_fail(component_id != NULL);
656
0
  g_return_if_fail(version != NULL);
657
658
0
  if (priv->runtime_versions == NULL)
659
0
    return;
660
0
  g_hash_table_insert(priv->runtime_versions, g_strdup(component_id), g_strdup(version));
661
0
}
662
663
/**
664
 * fu_context_get_runtime_version:
665
 * @self: a #FuContext
666
 * @component_id: an AppStream component id, e.g. `org.gnome.Software`
667
 *
668
 * Sets a runtime version of a specific dependency.
669
 *
670
 * Returns: a version string, e.g. `1.2.3`, or %NULL
671
 *
672
 * Since: 1.9.10
673
 **/
674
const gchar *
675
fu_context_get_runtime_version(FuContext *self, const gchar *component_id)
676
0
{
677
0
  FuContextPrivate *priv = GET_PRIVATE(self);
678
679
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
680
0
  g_return_val_if_fail(component_id != NULL, NULL);
681
682
0
  if (priv->runtime_versions == NULL)
683
0
    return NULL;
684
0
  return g_hash_table_lookup(priv->runtime_versions, component_id);
685
0
}
686
687
/**
688
 * fu_context_get_runtime_versions:
689
 * @self: a #FuContext
690
 *
691
 * Gets the runtime versions for the context.
692
 *
693
 * Returns: (transfer none) (element-type utf8 utf8): dictionary of versions
694
 *
695
 * Since: 1.9.10
696
 **/
697
GHashTable *
698
fu_context_get_runtime_versions(FuContext *self)
699
0
{
700
0
  FuContextPrivate *priv = GET_PRIVATE(self);
701
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
702
0
  return priv->runtime_versions;
703
0
}
704
705
/**
706
 * fu_context_add_compile_version:
707
 * @self: a #FuContext
708
 * @component_id: an AppStream component id, e.g. `org.gnome.Software`
709
 * @version: a version string, e.g. `1.2.3`
710
 *
711
 * Sets a compile-time version of a specific dependency.
712
 *
713
 * Since: 1.6.0
714
 **/
715
void
716
fu_context_add_compile_version(FuContext *self, const gchar *component_id, const gchar *version)
717
0
{
718
0
  FuContextPrivate *priv = GET_PRIVATE(self);
719
720
0
  g_return_if_fail(FU_IS_CONTEXT(self));
721
0
  g_return_if_fail(component_id != NULL);
722
0
  g_return_if_fail(version != NULL);
723
724
0
  if (priv->compile_versions == NULL)
725
0
    return;
726
0
  g_hash_table_insert(priv->compile_versions, g_strdup(component_id), g_strdup(version));
727
0
}
728
729
/**
730
 * fu_context_get_compile_versions:
731
 * @self: a #FuContext
732
 *
733
 * Gets the compile time versions for the context.
734
 *
735
 * Returns: (transfer none) (element-type utf8 utf8): dictionary of versions
736
 *
737
 * Since: 1.9.10
738
 **/
739
GHashTable *
740
fu_context_get_compile_versions(FuContext *self)
741
0
{
742
0
  FuContextPrivate *priv = GET_PRIVATE(self);
743
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
744
0
  return priv->compile_versions;
745
0
}
746
747
static gint
748
fu_context_udev_plugin_names_sort_cb(gconstpointer a, gconstpointer b)
749
0
{
750
0
  const gchar *str_a = *((const gchar **)a);
751
0
  const gchar *str_b = *((const gchar **)b);
752
0
  return g_strcmp0(str_a, str_b);
753
0
}
754
755
/**
756
 * fu_context_add_udev_subsystem:
757
 * @self: a #FuContext
758
 * @subsystem: a subsystem name, e.g. `pciport`, or `block:partition`
759
 * @plugin_name: (nullable): a plugin name, e.g. `iommu`
760
 *
761
 * Registers the udev subsystem to be watched by the daemon.
762
 *
763
 * Plugins can use this method only in fu_plugin_init()
764
 *
765
 * Since: 1.6.0
766
 **/
767
void
768
fu_context_add_udev_subsystem(FuContext *self, const gchar *subsystem, const gchar *plugin_name)
769
0
{
770
0
  FuContextPrivate *priv = GET_PRIVATE(self);
771
0
  GPtrArray *plugin_names;
772
0
  g_auto(GStrv) subsystem_devtype = NULL;
773
774
0
  g_return_if_fail(FU_IS_CONTEXT(self));
775
0
  g_return_if_fail(subsystem != NULL);
776
777
  /* add the base subsystem watch if passed a subsystem:devtype */
778
0
  subsystem_devtype = g_strsplit(subsystem, ":", 2);
779
0
  if (g_strv_length(subsystem_devtype) > 1)
780
0
    fu_context_add_udev_subsystem(self, subsystem_devtype[0], NULL);
781
782
  /* already exists */
783
0
  plugin_names = g_hash_table_lookup(priv->udev_subsystems, subsystem);
784
0
  if (plugin_names != NULL) {
785
0
    if (plugin_name != NULL) {
786
0
      for (guint i = 0; i < plugin_names->len; i++) {
787
0
        const gchar *tmp = g_ptr_array_index(plugin_names, i);
788
0
        if (g_strcmp0(tmp, plugin_name) == 0)
789
0
          return;
790
0
      }
791
0
      g_ptr_array_add(plugin_names, g_strdup(plugin_name));
792
0
      g_ptr_array_sort(plugin_names, fu_context_udev_plugin_names_sort_cb);
793
0
    }
794
0
    return;
795
0
  }
796
797
  /* add */
798
0
  plugin_names = g_ptr_array_new_with_free_func(g_free);
799
0
  if (plugin_name != NULL)
800
0
    g_ptr_array_add(plugin_names, g_strdup(plugin_name));
801
0
  g_hash_table_insert(priv->udev_subsystems,
802
0
          g_strdup(subsystem),
803
0
          g_steal_pointer(&plugin_names));
804
0
  if (plugin_name != NULL)
805
0
    g_info("added udev subsystem watch of %s for plugin %s", subsystem, plugin_name);
806
0
  else
807
0
    g_info("added udev subsystem watch of %s", subsystem);
808
0
}
809
810
/**
811
 * fu_context_get_plugin_names_for_udev_subsystem:
812
 * @self: a #FuContext
813
 * @subsystem: a subsystem name, e.g. `pciport`, or `block:partition`
814
 * @error: (nullable): optional return location for an error
815
 *
816
 * Gets the plugins which registered for a specific subsystem.
817
 *
818
 * Returns: (transfer container) (element-type utf8): List of plugin names
819
 *
820
 * Since: 1.9.3
821
 **/
822
GPtrArray *
823
fu_context_get_plugin_names_for_udev_subsystem(FuContext *self,
824
                 const gchar *subsystem,
825
                 GError **error)
826
0
{
827
0
  FuContextPrivate *priv = GET_PRIVATE(self);
828
0
  GPtrArray *plugin_names_tmp;
829
0
  g_auto(GStrv) subsystem_devtype = NULL;
830
0
  g_autoptr(GPtrArray) plugin_names = g_ptr_array_new_with_free_func(g_free);
831
832
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
833
0
  g_return_val_if_fail(subsystem != NULL, NULL);
834
835
  /* add the base subsystem first */
836
0
  subsystem_devtype = g_strsplit(subsystem, ":", 2);
837
0
  if (g_strv_length(subsystem_devtype) > 1) {
838
0
    plugin_names_tmp = g_hash_table_lookup(priv->udev_subsystems, subsystem_devtype[0]);
839
0
    if (plugin_names_tmp != NULL)
840
0
      g_ptr_array_extend(plugin_names,
841
0
             plugin_names_tmp,
842
0
             (GCopyFunc)g_strdup,
843
0
             NULL);
844
0
  }
845
846
  /* add the exact match */
847
0
  plugin_names_tmp = g_hash_table_lookup(priv->udev_subsystems, subsystem);
848
0
  if (plugin_names_tmp != NULL)
849
0
    g_ptr_array_extend(plugin_names, plugin_names_tmp, (GCopyFunc)g_strdup, NULL);
850
851
  /* no matches */
852
0
  if (plugin_names->len == 0) {
853
0
    g_set_error(error,
854
0
          FWUPD_ERROR,
855
0
          FWUPD_ERROR_NOT_FOUND,
856
0
          "no plugins registered for %s",
857
0
          subsystem);
858
0
    return NULL;
859
0
  }
860
861
  /* success */
862
0
  return g_steal_pointer(&plugin_names);
863
0
}
864
865
/**
866
 * fu_context_get_udev_subsystems:
867
 * @self: a #FuContext
868
 *
869
 * Gets the udev subsystems required by all plugins.
870
 *
871
 * Returns: (transfer container) (element-type utf8): List of subsystems
872
 *
873
 * Since: 1.6.0
874
 **/
875
GPtrArray *
876
fu_context_get_udev_subsystems(FuContext *self)
877
0
{
878
0
  FuContextPrivate *priv = GET_PRIVATE(self);
879
0
  g_autoptr(GList) keys = g_hash_table_get_keys(priv->udev_subsystems);
880
0
  g_autoptr(GPtrArray) subsystems = g_ptr_array_new_with_free_func(g_free);
881
882
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
883
884
0
  for (GList *l = keys; l != NULL; l = l->next) {
885
0
    const gchar *subsystem = (const gchar *)l->data;
886
0
    g_ptr_array_add(subsystems, g_strdup(subsystem));
887
0
  }
888
0
  return g_steal_pointer(&subsystems);
889
0
}
890
891
static gchar *
892
fu_context_convert_firmware_gtype_to_id(GType gtype)
893
0
{
894
0
  const gchar *gtype_name = g_type_name(gtype);
895
0
  gsize len = strlen(gtype_name);
896
0
  g_autoptr(GString) str = g_string_new(NULL);
897
898
  /* no format */
899
0
  if (g_strcmp0(gtype_name, "FuFirmware") == 0)
900
0
    return g_strdup("raw");
901
902
  /* not useful */
903
0
  if (g_str_has_suffix(gtype_name, "Firmware"))
904
0
    len -= 8;
905
906
  /* normal plugins */
907
0
  for (guint j = 2; j < len; j++) {
908
0
    gchar tmp = gtype_name[j];
909
0
    if (g_ascii_isupper(tmp)) {
910
0
      if (str->len > 0)
911
0
        g_string_append_c(str, '-');
912
0
      g_string_append_c(str, g_ascii_tolower(tmp));
913
0
    } else {
914
0
      g_string_append_c(str, tmp);
915
0
    }
916
0
  }
917
0
  if (str->len == 0)
918
0
    return NULL;
919
0
  return g_string_free(g_steal_pointer(&str), FALSE);
920
0
}
921
922
/**
923
 * fu_context_add_firmware_gtype:
924
 * @self: a #FuContext
925
 * @gtype: a #GType e.g. `FU_TYPE_FOO_FIRMWARE`
926
 *
927
 * Adds a firmware #GType which is used when creating devices.
928
 *
929
 * Plugins can use this method only in fu_plugin_init()
930
 *
931
 * Since: 2.1.1
932
 **/
933
void
934
fu_context_add_firmware_gtype(FuContext *self, GType gtype)
935
0
{
936
0
  FuContextPrivate *priv = GET_PRIVATE(self);
937
938
0
  g_return_if_fail(FU_IS_CONTEXT(self));
939
0
  g_return_if_fail(gtype != G_TYPE_INVALID);
940
941
0
  g_type_ensure(gtype);
942
0
  g_hash_table_insert(priv->firmware_gtypes,
943
0
          fu_context_convert_firmware_gtype_to_id(gtype),
944
0
          GSIZE_TO_POINTER(gtype));
945
0
}
946
947
/**
948
 * fu_context_get_firmware_gtype_by_id:
949
 * @self: a #FuContext
950
 * @id: an string describing the type, e.g. `ihex`
951
 *
952
 * Returns the #GType using the firmware @id.
953
 *
954
 * Returns: a #GType, or %G_TYPE_INVALID
955
 *
956
 * Since: 1.6.0
957
 **/
958
GType
959
fu_context_get_firmware_gtype_by_id(FuContext *self, const gchar *id)
960
0
{
961
0
  FuContextPrivate *priv = GET_PRIVATE(self);
962
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), G_TYPE_INVALID);
963
0
  g_return_val_if_fail(id != NULL, G_TYPE_INVALID);
964
0
  return GPOINTER_TO_SIZE(g_hash_table_lookup(priv->firmware_gtypes, id));
965
0
}
966
967
static gint
968
fu_context_gtypes_sort_cb(gconstpointer a, gconstpointer b)
969
0
{
970
0
  const gchar *stra = *((const gchar **)a);
971
0
  const gchar *strb = *((const gchar **)b);
972
0
  return g_strcmp0(stra, strb);
973
0
}
974
975
/**
976
 * fu_context_get_firmware_gtype_ids:
977
 * @self: a #FuContext
978
 *
979
 * Returns all the firmware #GType IDs.
980
 *
981
 * Returns: (transfer container) (element-type utf8): firmware IDs
982
 *
983
 * Since: 1.6.0
984
 **/
985
GPtrArray *
986
fu_context_get_firmware_gtype_ids(FuContext *self)
987
0
{
988
0
  FuContextPrivate *priv = GET_PRIVATE(self);
989
0
  GPtrArray *firmware_gtypes = g_ptr_array_new_with_free_func(g_free);
990
0
  g_autoptr(GList) keys = g_hash_table_get_keys(priv->firmware_gtypes);
991
992
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
993
994
0
  for (GList *l = keys; l != NULL; l = l->next) {
995
0
    const gchar *id = l->data;
996
0
    g_ptr_array_add(firmware_gtypes, g_strdup(id));
997
0
  }
998
0
  g_ptr_array_sort(firmware_gtypes, fu_context_gtypes_sort_cb);
999
0
  return firmware_gtypes;
1000
0
}
1001
1002
/**
1003
 * fu_context_get_firmware_gtypes:
1004
 * @self: a #FuContext
1005
 *
1006
 * Returns all the firmware #GType's.
1007
 *
1008
 * Returns: (transfer container) (element-type GType): Firmware types
1009
 *
1010
 * Since: 1.9.1
1011
 **/
1012
GArray *
1013
fu_context_get_firmware_gtypes(FuContext *self)
1014
0
{
1015
0
  FuContextPrivate *priv = GET_PRIVATE(self);
1016
0
  GArray *firmware_gtypes = g_array_new(FALSE, FALSE, sizeof(GType));
1017
0
  g_autoptr(GList) values = g_hash_table_get_values(priv->firmware_gtypes);
1018
1019
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
1020
1021
0
  for (GList *l = values; l != NULL; l = l->next) {
1022
0
    GType gtype = GPOINTER_TO_SIZE(l->data);
1023
0
    g_array_append_val(firmware_gtypes, gtype);
1024
0
  }
1025
0
  return firmware_gtypes;
1026
0
}
1027
1028
/**
1029
 * fu_context_add_quirk_key:
1030
 * @self: a #FuContext
1031
 * @key: a quirk string, e.g. `DfuVersion`
1032
 *
1033
 * Adds a possible quirk key. If added by a plugin it should be namespaced
1034
 * using the plugin name, where possible.
1035
 *
1036
 * Plugins can use this method only in fu_plugin_init()
1037
 *
1038
 * Since: 1.6.0
1039
 **/
1040
void
1041
fu_context_add_quirk_key(FuContext *self, const gchar *key)
1042
0
{
1043
0
  FuContextPrivate *priv = GET_PRIVATE(self);
1044
0
  g_return_if_fail(FU_IS_CONTEXT(self));
1045
0
  g_return_if_fail(key != NULL);
1046
0
  if (priv->quirks == NULL)
1047
0
    return;
1048
0
  fu_quirks_add_possible_key(priv->quirks, key);
1049
0
}
1050
1051
/**
1052
 * fu_context_lookup_quirk_by_id:
1053
 * @self: a #FuContext
1054
 * @guid: GUID to lookup
1055
 * @key: an ID to match the entry, e.g. `Summary`
1056
 *
1057
 * Looks up an entry in the hardware database using a string value.
1058
 *
1059
 * Returns: (transfer none): values from the database, or %NULL if not found
1060
 *
1061
 * Since: 1.6.0
1062
 **/
1063
const gchar *
1064
fu_context_lookup_quirk_by_id(FuContext *self, const gchar *guid, const gchar *key)
1065
0
{
1066
0
  FuContextPrivate *priv = GET_PRIVATE(self);
1067
1068
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
1069
0
  g_return_val_if_fail(guid != NULL, NULL);
1070
0
  g_return_val_if_fail(key != NULL, NULL);
1071
1072
  /* exact ID */
1073
0
  return fu_quirks_lookup_by_id(priv->quirks, guid, key);
1074
0
}
1075
1076
typedef struct {
1077
  FuContext *self; /* noref */
1078
  FuContextLookupIter iter_cb;
1079
  gpointer user_data;
1080
} FuContextQuirkLookupHelper;
1081
1082
static void
1083
fu_context_lookup_quirk_by_id_iter_cb(FuQuirks *self,
1084
              const gchar *key,
1085
              const gchar *value,
1086
              FuContextQuirkSource source,
1087
              gpointer user_data)
1088
0
{
1089
0
  FuContextQuirkLookupHelper *helper = (FuContextQuirkLookupHelper *)user_data;
1090
0
  helper->iter_cb(helper->self, key, value, source, helper->user_data);
1091
0
}
1092
1093
/**
1094
 * fu_context_lookup_quirk_by_id_iter:
1095
 * @self: a #FuContext
1096
 * @guid: GUID to lookup
1097
 * @key: (nullable): an ID to match the entry, e.g. `Name`, or %NULL for all keys
1098
 * @iter_cb: (scope call) (closure user_data): a function to call for each result
1099
 * @user_data: user data passed to @iter_cb
1100
 *
1101
 * Looks up all entries in the hardware database using a GUID value.
1102
 *
1103
 * Returns: %TRUE if the ID was found, and @iter was called
1104
 *
1105
 * Since: 1.6.0
1106
 **/
1107
gboolean
1108
fu_context_lookup_quirk_by_id_iter(FuContext *self,
1109
           const gchar *guid,
1110
           const gchar *key,
1111
           FuContextLookupIter iter_cb,
1112
           gpointer user_data)
1113
0
{
1114
0
  FuContextPrivate *priv = GET_PRIVATE(self);
1115
0
  FuContextQuirkLookupHelper helper = {
1116
0
      .self = self,
1117
0
      .iter_cb = iter_cb,
1118
0
      .user_data = user_data,
1119
0
  };
1120
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), FALSE);
1121
0
  g_return_val_if_fail(guid != NULL, FALSE);
1122
0
  g_return_val_if_fail(iter_cb != NULL, FALSE);
1123
0
  if (priv->flags & FU_CONTEXT_FLAG_NO_QUIRKS)
1124
0
    return TRUE;
1125
0
  return fu_quirks_lookup_by_id_iter(priv->quirks,
1126
0
             guid,
1127
0
             key,
1128
0
             fu_context_lookup_quirk_by_id_iter_cb,
1129
0
             &helper);
1130
0
}
1131
1132
/**
1133
 * fu_context_security_changed:
1134
 * @self: a #FuContext
1135
 *
1136
 * Informs the daemon that the HSI state may have changed.
1137
 *
1138
 * Since: 1.6.0
1139
 **/
1140
void
1141
fu_context_security_changed(FuContext *self)
1142
0
{
1143
0
  g_return_if_fail(FU_IS_CONTEXT(self));
1144
0
  g_signal_emit(self, signals[SIGNAL_SECURITY_CHANGED], 0);
1145
0
}
1146
1147
/**
1148
 * fu_context_housekeeping:
1149
 * @self: a #FuContext
1150
 *
1151
 * Performs any housekeeping maintenance when the daemon is idle.
1152
 *
1153
 * Since: 2.0.0
1154
 **/
1155
void
1156
fu_context_housekeeping(FuContext *self)
1157
0
{
1158
0
  g_return_if_fail(FU_IS_CONTEXT(self));
1159
0
  g_signal_emit(self, signals[SIGNAL_HOUSEKEEPING], 0);
1160
0
}
1161
1162
typedef gboolean (*FuContextHwidsSetupFunc)(FuContext *self, FuHwids *hwids, GError **error);
1163
1164
static void
1165
fu_context_detect_full_disk_encryption(FuContext *self)
1166
0
{
1167
0
  FuContextPrivate *priv = GET_PRIVATE(self);
1168
0
  g_autoptr(GPtrArray) devices = NULL;
1169
0
  g_autoptr(GError) error_local = NULL;
1170
1171
0
  g_return_if_fail(FU_IS_CONTEXT(self));
1172
1173
0
  devices = fu_common_get_block_devices(&error_local);
1174
0
  if (devices == NULL) {
1175
0
    g_info("Failed to get block devices: %s", error_local->message);
1176
0
    return;
1177
0
  }
1178
1179
0
  for (guint i = 0; i < devices->len; i++) {
1180
0
    GDBusProxy *proxy = g_ptr_array_index(devices, i);
1181
0
    g_autoptr(GVariant) id_type = g_dbus_proxy_get_cached_property(proxy, "IdType");
1182
0
    g_autoptr(GVariant) device = g_dbus_proxy_get_cached_property(proxy, "Device");
1183
0
    g_autoptr(GVariant) id_label = g_dbus_proxy_get_cached_property(proxy, "IdLabel");
1184
0
    if (id_type != NULL && device != NULL &&
1185
0
        g_strcmp0(g_variant_get_string(id_type, NULL), "BitLocker") == 0)
1186
0
      priv->flags |= FU_CONTEXT_FLAG_FDE_BITLOCKER;
1187
1188
0
    if (id_type != NULL && id_label != NULL &&
1189
0
        g_strcmp0(g_variant_get_string(id_label, NULL), "ubuntu-data-enc") == 0 &&
1190
0
        g_strcmp0(g_variant_get_string(id_type, NULL), "crypto_LUKS") == 0) {
1191
0
      priv->flags |= FU_CONTEXT_FLAG_FDE_SNAPD;
1192
0
    }
1193
0
  }
1194
0
}
1195
1196
static void
1197
fu_context_hwid_quirk_cb(FuContext *self,
1198
       const gchar *key,
1199
       const gchar *value,
1200
       FuContextQuirkSource source,
1201
       gpointer user_data)
1202
0
{
1203
0
  FuContextPrivate *priv = GET_PRIVATE(self);
1204
0
  if (value != NULL) {
1205
0
    g_auto(GStrv) values = g_strsplit(value, ",", -1);
1206
0
    for (guint i = 0; values[i] != NULL; i++) {
1207
0
      const gchar *value_tmp = values[i];
1208
0
      if (g_str_has_prefix(value, "~")) {
1209
0
        g_hash_table_remove(priv->hwid_flags, value_tmp + 1);
1210
0
        continue;
1211
0
      }
1212
0
      g_hash_table_add(priv->hwid_flags, g_strdup(value_tmp));
1213
0
    }
1214
0
  }
1215
0
}
1216
1217
static void
1218
fu_context_detect_container(FuContext *self)
1219
0
{
1220
0
  gsize bufsz = 0;
1221
0
  g_autofree gchar *buf = NULL;
1222
1223
0
  if (!g_file_get_contents("/proc/1/cgroup", &buf, &bufsz, NULL))
1224
0
    return;
1225
0
  if (g_strstr_len(buf, (gssize)bufsz, "docker") != NULL) {
1226
0
    fu_context_add_flag(self, FU_CONTEXT_FLAG_IS_CONTAINER);
1227
0
    return;
1228
0
  }
1229
0
  if (g_strstr_len(buf, (gssize)bufsz, "lxc") != NULL) {
1230
0
    fu_context_add_flag(self, FU_CONTEXT_FLAG_IS_CONTAINER);
1231
0
    return;
1232
0
  }
1233
0
}
1234
1235
static void
1236
fu_context_detect_hypervisor_privileged(FuContext *self)
1237
0
{
1238
0
  g_autofree gchar *xen_privileged_fn = NULL;
1239
1240
  /* privileged xen can access most hardware */
1241
0
  xen_privileged_fn = fu_context_build_filename(self,
1242
0
                  NULL,
1243
0
                  FU_PATH_KIND_SYSFSDIR_FW_ATTRIB,
1244
0
                  "hypervisor",
1245
0
                  "start_flags",
1246
0
                  "privileged",
1247
0
                  NULL);
1248
0
  if (xen_privileged_fn == NULL)
1249
0
    return;
1250
0
  if (!g_file_test(xen_privileged_fn, G_FILE_TEST_EXISTS)) {
1251
0
    g_autofree gchar *contents = NULL;
1252
0
    if (g_file_get_contents(xen_privileged_fn, &contents, NULL, NULL)) {
1253
0
      if (g_strcmp0(contents, "1") == 0) {
1254
0
        fu_context_add_flag(self, FU_CONTEXT_FLAG_IS_HYPERVISOR_PRIVILEGED);
1255
0
        return;
1256
0
      }
1257
0
    }
1258
0
  }
1259
0
}
1260
1261
static void
1262
fu_context_detect_hypervisor(FuContext *self)
1263
0
{
1264
0
  FuContextPrivate *priv = GET_PRIVATE(self);
1265
0
  const gchar *flags;
1266
0
  g_autoptr(GHashTable) cpu_attrs = NULL;
1267
1268
0
  cpu_attrs = fu_cpu_get_attrs(priv->pstore, NULL);
1269
0
  if (cpu_attrs == NULL)
1270
0
    return;
1271
0
  flags = g_hash_table_lookup(cpu_attrs, "flags");
1272
0
  if (flags == NULL)
1273
0
    return;
1274
0
  if (g_strstr_len(flags, -1, "hypervisor") != NULL) {
1275
0
    fu_context_add_flag(self, FU_CONTEXT_FLAG_IS_HYPERVISOR);
1276
0
    fu_context_detect_hypervisor_privileged(self);
1277
0
    return;
1278
0
  }
1279
0
}
1280
1281
/**
1282
 * fu_context_load_hwinfo:
1283
 * @self: a #FuContext
1284
 * @progress: a #FuProgress
1285
 * @flags: a #FuContextHwidFlags, e.g. %FU_CONTEXT_HWID_FLAG_LOAD_SMBIOS
1286
 * @error: (nullable): optional return location for an error
1287
 *
1288
 * Loads all hardware information parts of the context.
1289
 *
1290
 * Returns: %TRUE for success
1291
 *
1292
 * Since: 1.8.10
1293
 **/
1294
gboolean
1295
fu_context_load_hwinfo(FuContext *self,
1296
           FuProgress *progress,
1297
           FuContextHwidFlags flags,
1298
           GError **error)
1299
0
{
1300
0
  FuContextPrivate *priv = GET_PRIVATE(self);
1301
0
  FuConfigLoadFlags config_load_flags = FU_CONFIG_LOAD_FLAG_NONE;
1302
0
  GPtrArray *guids;
1303
0
  const gchar *machine_kind = g_getenv("FWUPD_MACHINE_KIND");
1304
0
  g_autoptr(GError) error_hwids = NULL;
1305
0
  g_autoptr(GError) error_smbios = NULL;
1306
0
  g_autoptr(GError) error_bios_settings = NULL;
1307
0
  struct {
1308
0
    const gchar *name;
1309
0
    FuContextHwidFlags flag;
1310
0
    FuContextHwidsSetupFunc func;
1311
0
  } hwids_setup_map[] = {{"config", FU_CONTEXT_HWID_FLAG_LOAD_CONFIG, fu_hwids_config_setup},
1312
0
             {"smbios", FU_CONTEXT_HWID_FLAG_LOAD_SMBIOS, fu_hwids_smbios_setup},
1313
0
             {"fdt", FU_CONTEXT_HWID_FLAG_LOAD_FDT, fu_hwids_fdt_setup},
1314
0
             {"kenv", FU_CONTEXT_HWID_FLAG_LOAD_KENV, fu_hwids_kenv_setup},
1315
0
             {"dmi", FU_CONTEXT_HWID_FLAG_LOAD_DMI, fu_hwids_dmi_setup},
1316
0
             {"darwin", FU_CONTEXT_HWID_FLAG_LOAD_DARWIN, fu_hwids_darwin_setup},
1317
0
             {NULL, FU_CONTEXT_HWID_FLAG_NONE, NULL}};
1318
1319
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), FALSE);
1320
0
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
1321
1322
  /* progress */
1323
0
  fu_progress_set_id(progress, G_STRLOC);
1324
0
  fu_progress_add_step(progress, FWUPD_STATUS_LOADING, 1, "hwids-setup-funcs");
1325
0
  fu_progress_add_step(progress, FWUPD_STATUS_LOADING, 1, "hwids-setup");
1326
0
  fu_progress_add_step(progress, FWUPD_STATUS_LOADING, 3, "set-flags");
1327
0
  fu_progress_add_step(progress, FWUPD_STATUS_LOADING, 1, "detect-fde");
1328
0
  fu_progress_add_step(progress, FWUPD_STATUS_LOADING, 1, "detect-hypervisor-container");
1329
0
  fu_progress_add_step(progress, FWUPD_STATUS_LOADING, 93, "reload-bios-settings");
1330
1331
  /* required always */
1332
0
  if (flags & FU_CONTEXT_HWID_FLAG_WATCH_FILES)
1333
0
    config_load_flags |= FU_CONFIG_LOAD_FLAG_WATCH_FILES;
1334
0
  if (flags & FU_CONTEXT_HWID_FLAG_FIX_PERMISSIONS)
1335
0
    config_load_flags |= FU_CONFIG_LOAD_FLAG_FIX_PERMISSIONS;
1336
0
  if (!fu_config_load(priv->config, config_load_flags, error))
1337
0
    return FALSE;
1338
1339
  /* run all the HWID setup funcs */
1340
0
  for (guint i = 0; hwids_setup_map[i].name != NULL; i++) {
1341
0
    if ((flags & hwids_setup_map[i].flag) > 0) {
1342
0
      g_autoptr(GError) error_local = NULL;
1343
0
      if (!hwids_setup_map[i].func(self, priv->hwids, &error_local)) {
1344
0
        g_info("failed to load %s: %s",
1345
0
               hwids_setup_map[i].name,
1346
0
               error_local->message);
1347
0
        continue;
1348
0
      }
1349
0
    }
1350
0
  }
1351
0
  fu_context_add_flag(self, FU_CONTEXT_FLAG_LOADED_HWINFO);
1352
0
  fu_progress_step_done(progress);
1353
1354
0
  if (!fu_hwids_setup(priv->hwids, &error_hwids))
1355
0
    g_warning("Failed to load HWIDs: %s", error_hwids->message);
1356
0
  fu_progress_step_done(progress);
1357
1358
  /* does the system support UEFI mode? */
1359
0
  if (!fu_context_ensure_smbios_uefi_enabled(self, &error_smbios))
1360
0
    g_debug("%s", error_smbios->message);
1361
1362
  /* set the hwid flags */
1363
0
  guids = fu_context_get_hwid_guids(self);
1364
0
  for (guint i = 0; i < guids->len; i++) {
1365
0
    const gchar *guid = g_ptr_array_index(guids, i);
1366
0
    fu_context_lookup_quirk_by_id_iter(self,
1367
0
               guid,
1368
0
               FU_QUIRKS_FLAGS,
1369
0
               fu_context_hwid_quirk_cb,
1370
0
               NULL);
1371
0
  }
1372
0
  fu_progress_step_done(progress);
1373
1374
0
  fu_context_detect_full_disk_encryption(self);
1375
0
  fu_progress_step_done(progress);
1376
1377
  /* allow overriding for development */
1378
0
  if (machine_kind != NULL) {
1379
0
    if (g_strcmp0(machine_kind, "physical") == 0) {
1380
      /* nothing to do */
1381
0
    } else if (g_strcmp0(machine_kind, "container") == 0) {
1382
0
      fu_context_add_flag(self, FU_CONTEXT_FLAG_IS_CONTAINER);
1383
0
    } else if (g_strcmp0(machine_kind, "virtual") == 0) {
1384
0
      fu_context_add_flag(self, FU_CONTEXT_FLAG_IS_HYPERVISOR);
1385
0
    } else {
1386
0
      g_set_error(error,
1387
0
            FWUPD_ERROR,
1388
0
            FWUPD_ERROR_INVALID_DATA,
1389
0
            "invalid machine kind specified: %s",
1390
0
            machine_kind);
1391
0
      return FALSE;
1392
0
    }
1393
0
  } else {
1394
0
    fu_context_detect_hypervisor(self);
1395
0
    fu_context_detect_container(self);
1396
0
  }
1397
0
  fu_progress_step_done(progress);
1398
1399
0
  fu_context_add_udev_subsystem(self, "firmware-attributes", NULL);
1400
0
  if (!fu_context_reload_bios_settings(self, &error_bios_settings))
1401
0
    g_debug("%s", error_bios_settings->message);
1402
0
  fu_progress_step_done(progress);
1403
1404
  /* always */
1405
0
  return TRUE;
1406
0
}
1407
1408
/**
1409
 * fu_context_has_hwid_flag:
1410
 * @self: a #FuContext
1411
 * @flag: flag, e.g. `use-legacy-bootmgr-desc`
1412
 *
1413
 * Returns if a HwId custom flag exists, typically added from a DMI quirk.
1414
 *
1415
 * Returns: %TRUE if the flag exists
1416
 *
1417
 * Since: 1.7.2
1418
 **/
1419
gboolean
1420
fu_context_has_hwid_flag(FuContext *self, const gchar *flag)
1421
0
{
1422
0
  FuContextPrivate *priv = GET_PRIVATE(self);
1423
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), FALSE);
1424
0
  g_return_val_if_fail(flag != NULL, FALSE);
1425
0
  return g_hash_table_lookup(priv->hwid_flags, flag) != NULL;
1426
0
}
1427
1428
/**
1429
 * fu_context_load_quirks:
1430
 * @self: a #FuContext
1431
 * @flags: quirks load flags, e.g. %FU_QUIRKS_LOAD_FLAG_READONLY_FS
1432
 * @error: (nullable): optional return location for an error
1433
 *
1434
 * Loads all quirks into the context.
1435
 *
1436
 * Returns: %TRUE for success
1437
 *
1438
 * Since: 1.6.0
1439
 **/
1440
gboolean
1441
fu_context_load_quirks(FuContext *self, FuQuirksLoadFlags flags, GError **error)
1442
0
{
1443
0
  FuContextPrivate *priv = GET_PRIVATE(self);
1444
0
  g_autoptr(GError) error_local = NULL;
1445
1446
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), FALSE);
1447
0
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
1448
1449
  /* rebuild silo if required */
1450
0
  if (!fu_quirks_load(priv->quirks, flags, &error_local))
1451
0
    g_warning("Failed to load quirks: %s", error_local->message);
1452
1453
  /* always */
1454
0
  return TRUE;
1455
0
}
1456
1457
/**
1458
 * fu_context_get_power_state:
1459
 * @self: a #FuContext
1460
 *
1461
 * Gets if the system is on battery power, e.g. UPS or laptop battery.
1462
 *
1463
 * Returns: a power state, e.g. %FU_POWER_STATE_BATTERY_DISCHARGING
1464
 *
1465
 * Since: 1.8.11
1466
 **/
1467
FuPowerState
1468
fu_context_get_power_state(FuContext *self)
1469
0
{
1470
0
  FuContextPrivate *priv = GET_PRIVATE(self);
1471
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), FALSE);
1472
0
  return priv->power_state;
1473
0
}
1474
1475
/**
1476
 * fu_context_set_power_state:
1477
 * @self: a #FuContext
1478
 * @power_state: a power state, e.g. %FU_POWER_STATE_BATTERY_DISCHARGING
1479
 *
1480
 * Sets if the system is on battery power, e.g. UPS or laptop battery.
1481
 *
1482
 * Since: 1.8.11
1483
 **/
1484
void
1485
fu_context_set_power_state(FuContext *self, FuPowerState power_state)
1486
0
{
1487
0
  FuContextPrivate *priv = GET_PRIVATE(self);
1488
0
  g_return_if_fail(FU_IS_CONTEXT(self));
1489
0
  if (priv->power_state == power_state)
1490
0
    return;
1491
0
  priv->power_state = power_state;
1492
0
  g_info("power state now %s", fu_power_state_to_string(power_state));
1493
0
  g_object_notify(G_OBJECT(self), "power-state");
1494
0
}
1495
1496
/**
1497
 * fu_context_get_lid_state:
1498
 * @self: a #FuContext
1499
 *
1500
 * Gets the laptop lid state, if applicable.
1501
 *
1502
 * Returns: a lid state, e.g. %FU_LID_STATE_CLOSED
1503
 *
1504
 * Since: 1.7.4
1505
 **/
1506
FuLidState
1507
fu_context_get_lid_state(FuContext *self)
1508
0
{
1509
0
  FuContextPrivate *priv = GET_PRIVATE(self);
1510
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), FALSE);
1511
0
  return priv->lid_state;
1512
0
}
1513
1514
/**
1515
 * fu_context_set_lid_state:
1516
 * @self: a #FuContext
1517
 * @lid_state: a lid state, e.g. %FU_LID_STATE_CLOSED
1518
 *
1519
 * Sets the laptop lid state, if applicable.
1520
 *
1521
 * Since: 1.7.4
1522
 **/
1523
void
1524
fu_context_set_lid_state(FuContext *self, FuLidState lid_state)
1525
0
{
1526
0
  FuContextPrivate *priv = GET_PRIVATE(self);
1527
0
  g_return_if_fail(FU_IS_CONTEXT(self));
1528
0
  if (priv->lid_state == lid_state)
1529
0
    return;
1530
0
  priv->lid_state = lid_state;
1531
0
  g_info("lid state now %s", fu_lid_state_to_string(lid_state));
1532
0
  g_object_notify(G_OBJECT(self), "lid-state");
1533
0
}
1534
1535
/**
1536
 * fu_context_get_display_state:
1537
 * @self: a #FuContext
1538
 *
1539
 * Gets the display state, if applicable.
1540
 *
1541
 * Returns: a display state, e.g. %FU_DISPLAY_STATE_CONNECTED
1542
 *
1543
 * Since: 1.9.6
1544
 **/
1545
FuDisplayState
1546
fu_context_get_display_state(FuContext *self)
1547
0
{
1548
0
  FuContextPrivate *priv = GET_PRIVATE(self);
1549
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), FALSE);
1550
0
  return priv->display_state;
1551
0
}
1552
1553
/**
1554
 * fu_context_set_display_state:
1555
 * @self: a #FuContext
1556
 * @display_state: a display state, e.g. %FU_DISPLAY_STATE_CONNECTED
1557
 *
1558
 * Sets the display state, if applicable.
1559
 *
1560
 * Since: 1.9.6
1561
 **/
1562
void
1563
fu_context_set_display_state(FuContext *self, FuDisplayState display_state)
1564
0
{
1565
0
  FuContextPrivate *priv = GET_PRIVATE(self);
1566
0
  g_return_if_fail(FU_IS_CONTEXT(self));
1567
0
  if (priv->display_state == display_state)
1568
0
    return;
1569
0
  priv->display_state = display_state;
1570
0
  g_info("display-state now %s", fu_display_state_to_string(display_state));
1571
0
  g_object_notify(G_OBJECT(self), "display-state");
1572
0
}
1573
1574
/**
1575
 * fu_context_get_battery_level:
1576
 * @self: a #FuContext
1577
 *
1578
 * Gets the system battery level in percent.
1579
 *
1580
 * Returns: percentage value, or %FWUPD_BATTERY_LEVEL_INVALID for unknown
1581
 *
1582
 * Since: 1.6.0
1583
 **/
1584
guint
1585
fu_context_get_battery_level(FuContext *self)
1586
0
{
1587
0
  FuContextPrivate *priv = GET_PRIVATE(self);
1588
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), G_MAXUINT);
1589
0
  return priv->battery_level;
1590
0
}
1591
1592
/**
1593
 * fu_context_set_battery_level:
1594
 * @self: a #FuContext
1595
 * @battery_level: value
1596
 *
1597
 * Sets the system battery level in percent.
1598
 *
1599
 * Since: 1.6.0
1600
 **/
1601
void
1602
fu_context_set_battery_level(FuContext *self, guint battery_level)
1603
0
{
1604
0
  FuContextPrivate *priv = GET_PRIVATE(self);
1605
0
  g_return_if_fail(FU_IS_CONTEXT(self));
1606
0
  g_return_if_fail(battery_level <= FWUPD_BATTERY_LEVEL_INVALID);
1607
0
  if (priv->battery_level == battery_level)
1608
0
    return;
1609
0
  priv->battery_level = battery_level;
1610
0
  g_info("battery level now %u", battery_level);
1611
0
  g_object_notify(G_OBJECT(self), "battery-level");
1612
0
}
1613
1614
/**
1615
 * fu_context_get_battery_threshold:
1616
 * @self: a #FuContext
1617
 *
1618
 * Gets the system battery threshold in percent.
1619
 *
1620
 * Returns: percentage value, or %FWUPD_BATTERY_LEVEL_INVALID for unknown
1621
 *
1622
 * Since: 1.6.0
1623
 **/
1624
guint
1625
fu_context_get_battery_threshold(FuContext *self)
1626
0
{
1627
0
  FuContextPrivate *priv = GET_PRIVATE(self);
1628
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), G_MAXUINT);
1629
0
  return priv->battery_threshold;
1630
0
}
1631
1632
/**
1633
 * fu_context_set_battery_threshold:
1634
 * @self: a #FuContext
1635
 * @battery_threshold: value
1636
 *
1637
 * Sets the system battery threshold in percent.
1638
 *
1639
 * Since: 1.6.0
1640
 **/
1641
void
1642
fu_context_set_battery_threshold(FuContext *self, guint battery_threshold)
1643
0
{
1644
0
  FuContextPrivate *priv = GET_PRIVATE(self);
1645
0
  g_return_if_fail(FU_IS_CONTEXT(self));
1646
0
  g_return_if_fail(battery_threshold <= FWUPD_BATTERY_LEVEL_INVALID);
1647
0
  if (priv->battery_threshold == battery_threshold)
1648
0
    return;
1649
0
  priv->battery_threshold = battery_threshold;
1650
0
  g_info("battery threshold now %u", battery_threshold);
1651
0
  g_object_notify(G_OBJECT(self), "battery-threshold");
1652
0
}
1653
1654
/**
1655
 * fu_context_add_flag:
1656
 * @context: a #FuContext
1657
 * @flag: the context flag
1658
 *
1659
 * Adds a specific flag to the context.
1660
 *
1661
 * Since: 1.8.5
1662
 **/
1663
void
1664
fu_context_add_flag(FuContext *context, FuContextFlags flag)
1665
0
{
1666
0
  FuContextPrivate *priv = GET_PRIVATE(context);
1667
0
  g_return_if_fail(FU_IS_CONTEXT(context));
1668
0
  if (priv->flags & flag)
1669
0
    return;
1670
0
  priv->flags |= flag;
1671
0
  g_object_notify(G_OBJECT(context), "flags");
1672
0
}
1673
1674
/**
1675
 * fu_context_remove_flag:
1676
 * @context: a #FuContext
1677
 * @flag: the context flag
1678
 *
1679
 * Removes a specific flag from the context.
1680
 *
1681
 * Since: 1.8.10
1682
 **/
1683
void
1684
fu_context_remove_flag(FuContext *context, FuContextFlags flag)
1685
0
{
1686
0
  FuContextPrivate *priv = GET_PRIVATE(context);
1687
0
  g_return_if_fail(FU_IS_CONTEXT(context));
1688
0
  if ((priv->flags & flag) == 0)
1689
0
    return;
1690
0
  priv->flags &= ~flag;
1691
0
  g_object_notify(G_OBJECT(context), "flags");
1692
0
}
1693
1694
/**
1695
 * fu_context_has_flag:
1696
 * @context: a #FuContext
1697
 * @flag: the context flag
1698
 *
1699
 * Finds if the context has a specific flag.
1700
 *
1701
 * Returns: %TRUE if the flag is set
1702
 *
1703
 * Since: 1.8.5
1704
 **/
1705
gboolean
1706
fu_context_has_flag(FuContext *context, FuContextFlags flag)
1707
0
{
1708
0
  FuContextPrivate *priv = GET_PRIVATE(context);
1709
0
  g_return_val_if_fail(FU_IS_CONTEXT(context), FALSE);
1710
0
  return (priv->flags & flag) > 0;
1711
0
}
1712
1713
/**
1714
 * fu_context_add_esp_volume:
1715
 * @self: a #FuContext
1716
 * @volume: a #FuVolume
1717
 *
1718
 * Adds an ESP volume location.
1719
 *
1720
 * Since: 1.8.5
1721
 **/
1722
void
1723
fu_context_add_esp_volume(FuContext *self, FuVolume *volume)
1724
0
{
1725
0
  FuContextPrivate *priv = GET_PRIVATE(self);
1726
1727
0
  g_return_if_fail(FU_IS_CONTEXT(self));
1728
0
  g_return_if_fail(FU_IS_VOLUME(volume));
1729
1730
  /* check for dupes */
1731
0
  for (guint i = 0; i < priv->esp_volumes->len; i++) {
1732
0
    FuVolume *volume_tmp = g_ptr_array_index(priv->esp_volumes, i);
1733
0
    if (g_strcmp0(fu_volume_get_id(volume_tmp), fu_volume_get_id(volume)) == 0) {
1734
0
      g_debug("not adding duplicate volume %s", fu_volume_get_id(volume));
1735
0
      return;
1736
0
    }
1737
0
  }
1738
1739
  /* add */
1740
0
  g_ptr_array_add(priv->esp_volumes, g_object_ref(volume));
1741
0
}
1742
1743
/**
1744
 * fu_context_set_esp_location:
1745
 * @self: A #FuContext object.
1746
 * @location: The path to the preferred ESP.
1747
 *
1748
 * Sets the user's desired ESP (EFI System Partition) location for the given #FuContext.
1749
 */
1750
void
1751
fu_context_set_esp_location(FuContext *self, const gchar *location)
1752
0
{
1753
0
  FuContextPrivate *priv = GET_PRIVATE(self);
1754
0
  g_return_if_fail(FU_IS_CONTEXT(self));
1755
0
  g_return_if_fail(location != NULL);
1756
0
  g_free(priv->esp_location);
1757
0
  priv->esp_location = g_strdup(location);
1758
0
}
1759
1760
/**
1761
 * fu_context_get_esp_location:
1762
 * @self: The FuContext object.
1763
 *
1764
 * Retrieves the user's desired ESP (EFI System Partition) location for the given #FuContext
1765
 *
1766
 * Return: The preferred ESP location as a string.
1767
 */
1768
const gchar *
1769
fu_context_get_esp_location(FuContext *self)
1770
0
{
1771
0
  FuContextPrivate *priv = GET_PRIVATE(self);
1772
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
1773
0
  return priv->esp_location;
1774
0
}
1775
1776
/**
1777
 * fu_context_get_esp_volumes:
1778
 * @self: a #FuContext
1779
 * @error: (nullable): optional return location for an error
1780
 *
1781
 * Finds all volumes that could be an ESP.
1782
 *
1783
 * The volumes are cached and so subsequent calls to this function will be much faster.
1784
 *
1785
 * Returns: (transfer container) (element-type FuVolume): a #GPtrArray, or %NULL if no ESP was found
1786
 *
1787
 * Since: 1.8.5
1788
 **/
1789
GPtrArray *
1790
fu_context_get_esp_volumes(FuContext *self, GError **error)
1791
0
{
1792
0
  FuContextPrivate *priv = GET_PRIVATE(self);
1793
0
  const gchar *path_tmp;
1794
0
  g_autoptr(GError) error_bdp = NULL;
1795
0
  g_autoptr(GError) error_esp = NULL;
1796
0
  g_autoptr(GPtrArray) volumes_bdp = NULL;
1797
0
  g_autoptr(GPtrArray) volumes_esp = NULL;
1798
1799
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
1800
0
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
1801
1802
  /* cached result */
1803
0
  if (priv->esp_volumes->len > 0)
1804
0
    return g_ptr_array_ref(priv->esp_volumes);
1805
1806
  /* for the test suite use local directory for ESP */
1807
0
  path_tmp = fu_context_get_path(self, FU_PATH_KIND_UEFI_ESP, NULL);
1808
0
  if (path_tmp != NULL) {
1809
0
    g_autoptr(FuVolume) vol = fu_volume_new_from_mount_path(path_tmp);
1810
0
    fu_volume_set_partition_kind(vol, FU_VOLUME_KIND_ESP);
1811
0
    fu_volume_set_partition_uuid(vol, "00000000-0000-0000-0000-000000000000");
1812
0
    fu_context_add_esp_volume(self, vol);
1813
0
    return g_ptr_array_ref(priv->esp_volumes);
1814
0
  }
1815
1816
  /* ESP */
1817
0
  volumes_esp = fu_volume_new_by_kind(FU_VOLUME_KIND_ESP, &error_esp);
1818
0
  if (volumes_esp == NULL) {
1819
0
    g_debug("%s", error_esp->message);
1820
0
  } else {
1821
0
    for (guint i = 0; i < volumes_esp->len; i++) {
1822
0
      FuVolume *vol = g_ptr_array_index(volumes_esp, i);
1823
0
      g_autofree gchar *type = fu_volume_get_id_type(vol);
1824
0
      if (g_strcmp0(type, "vfat") != 0)
1825
0
        continue;
1826
0
      fu_context_add_esp_volume(self, vol);
1827
0
    }
1828
0
  }
1829
1830
  /* BDP */
1831
0
  volumes_bdp = fu_volume_new_by_kind(FU_VOLUME_KIND_BDP, &error_bdp);
1832
0
  if (volumes_bdp == NULL) {
1833
0
    g_debug("%s", error_bdp->message);
1834
0
  } else {
1835
0
    for (guint i = 0; i < volumes_bdp->len; i++) {
1836
0
      FuVolume *vol = g_ptr_array_index(volumes_bdp, i);
1837
0
      g_autofree gchar *type = fu_volume_get_id_type(vol);
1838
0
      if (g_strcmp0(type, "vfat") != 0)
1839
0
        continue;
1840
0
      if (!fu_volume_is_internal(vol))
1841
0
        continue;
1842
0
      fu_context_add_esp_volume(self, vol);
1843
0
    }
1844
0
  }
1845
1846
  /* nothing found */
1847
0
  if (priv->esp_volumes->len == 0) {
1848
0
    g_autoptr(GPtrArray) devices = NULL;
1849
1850
    /* check if udisks2 is working */
1851
0
    devices = fu_common_get_block_devices(error);
1852
0
    if (devices == NULL)
1853
0
      return NULL;
1854
0
    g_set_error_literal(error,
1855
0
            FWUPD_ERROR,
1856
0
            FWUPD_ERROR_NOT_FOUND,
1857
0
            "No ESP or BDP found");
1858
0
    return NULL;
1859
0
  }
1860
1861
  /* success */
1862
0
  return g_ptr_array_ref(priv->esp_volumes);
1863
0
}
1864
1865
static gboolean
1866
fu_context_is_esp(FuVolume *esp)
1867
0
{
1868
0
  g_autofree gchar *mount_point = fu_volume_get_mount_point(esp);
1869
0
  g_autofree gchar *fn = NULL;
1870
0
  g_autofree gchar *fn2 = NULL;
1871
1872
0
  if (mount_point == NULL)
1873
0
    return FALSE;
1874
1875
0
  fn = g_build_filename(mount_point, "EFI", NULL);
1876
0
  fn2 = g_build_filename(mount_point, "efi", NULL);
1877
1878
0
  return g_file_test(fn, G_FILE_TEST_IS_DIR) || g_file_test(fn2, G_FILE_TEST_IS_DIR);
1879
0
}
1880
1881
static gboolean
1882
fu_context_is_esp_linux(FuVolume *esp, GError **error)
1883
0
{
1884
0
  const gchar *prefixes[] = {"grub", "shim", "systemd-boot", "zfsbootmenu", NULL};
1885
0
  g_autofree gchar *prefixes_str = NULL;
1886
0
  g_autofree gchar *mount_point = fu_volume_get_mount_point(esp);
1887
0
  g_autoptr(GPtrArray) files = NULL;
1888
1889
  /* look for any likely basenames */
1890
0
  if (mount_point == NULL) {
1891
0
    g_set_error_literal(error,
1892
0
            FWUPD_ERROR,
1893
0
            FWUPD_ERROR_NOT_SUPPORTED,
1894
0
            "no mountpoint for ESP");
1895
0
    return FALSE;
1896
0
  }
1897
0
  files = fu_path_get_files(mount_point, error);
1898
0
  if (files == NULL)
1899
0
    return FALSE;
1900
0
  for (guint i = 0; i < files->len; i++) {
1901
0
    const gchar *fn = g_ptr_array_index(files, i);
1902
0
    g_autofree gchar *basename = g_path_get_basename(fn);
1903
0
    g_autofree gchar *basename_lower = g_utf8_strdown(basename, -1);
1904
1905
0
    for (guint j = 0; prefixes[j] != NULL; j++) {
1906
0
      if (!g_str_has_prefix(basename_lower, prefixes[j]))
1907
0
        continue;
1908
0
      if (!g_str_has_suffix(basename_lower, ".efi"))
1909
0
        continue;
1910
0
      g_info("found %s which indicates a Linux ESP, using %s", fn, mount_point);
1911
0
      return TRUE;
1912
0
    }
1913
0
  }
1914
1915
  /* failed */
1916
0
  prefixes_str = g_strjoinv("|", (gchar **)prefixes);
1917
0
  g_set_error(error,
1918
0
        FWUPD_ERROR,
1919
0
        FWUPD_ERROR_NOT_FOUND,
1920
0
        "did not any files with prefix %s in %s",
1921
0
        prefixes_str,
1922
0
        mount_point);
1923
0
  return FALSE;
1924
0
}
1925
1926
static gint
1927
fu_context_sort_esp_score_cb(gconstpointer a, gconstpointer b, gpointer user_data)
1928
0
{
1929
0
  GHashTable *esp_scores = (GHashTable *)user_data;
1930
0
  guint esp1_score = GPOINTER_TO_UINT(g_hash_table_lookup(esp_scores, *((FuVolume **)a)));
1931
0
  guint esp2_score = GPOINTER_TO_UINT(g_hash_table_lookup(esp_scores, *((FuVolume **)b)));
1932
0
  if (esp1_score < esp2_score)
1933
0
    return 1;
1934
0
  if (esp1_score > esp2_score)
1935
0
    return -1;
1936
0
  return 0;
1937
0
}
1938
1939
/**
1940
 * fu_context_get_default_esp:
1941
 * @self: a #FuContext
1942
 * @error: (nullable): optional return location for an error
1943
 *
1944
 * Finds the volume that represents the ESP that plugins should nominally
1945
 * use for accessing storing data.
1946
 *
1947
 * Returns: (transfer full): a volume, or %NULL if no ESP was found
1948
 *
1949
 * Since: 2.0.0
1950
 **/
1951
FuVolume *
1952
fu_context_get_default_esp(FuContext *self, GError **error)
1953
0
{
1954
0
  FuContextPrivate *priv = GET_PRIVATE(self);
1955
0
  g_autoptr(GPtrArray) esp_volumes = NULL;
1956
0
  const gchar *user_esp_location = fu_context_get_esp_location(self);
1957
1958
  /* show which volumes we're choosing from */
1959
0
  esp_volumes = fu_context_get_esp_volumes(self, error);
1960
0
  if (esp_volumes == NULL)
1961
0
    return NULL;
1962
1963
  /* no mounting */
1964
0
  if (priv->flags & FU_CONTEXT_FLAG_INHIBIT_VOLUME_MOUNT) {
1965
0
    g_set_error_literal(error,
1966
0
            FWUPD_ERROR,
1967
0
            FWUPD_ERROR_NOT_SUPPORTED,
1968
0
            "cannot mount volume by policy");
1969
0
    return NULL;
1970
0
  }
1971
1972
  /* we found more than one: lets look for the best one */
1973
0
  if (esp_volumes->len > 1) {
1974
0
    g_autoptr(GString) str = g_string_new("more than one ESP possible:");
1975
0
    g_autoptr(GHashTable) esp_scores = g_hash_table_new(g_direct_hash, g_direct_equal);
1976
0
    for (guint i = 0; i < esp_volumes->len; i++) {
1977
0
      FuVolume *esp = g_ptr_array_index(esp_volumes, i);
1978
0
      guint score = 0;
1979
0
      g_autofree gchar *kind = NULL;
1980
0
      g_autoptr(FuVolumeLocker) locker = NULL;
1981
0
      g_autoptr(GError) error_local = NULL;
1982
1983
      /* ignore the volume completely if we cannot mount it */
1984
0
      locker = fu_volume_locker_new(esp, &error_local);
1985
0
      if (locker == NULL) {
1986
0
        g_warning("failed to mount ESP: %s", error_local->message);
1987
0
        continue;
1988
0
      }
1989
1990
      /* if user specified, make sure that it matches */
1991
0
      if (user_esp_location != NULL) {
1992
0
        g_autofree gchar *mount = fu_volume_get_mount_point(esp);
1993
0
        if (g_strcmp0(mount, user_esp_location) != 0) {
1994
0
          g_debug("skipping %s as it's not the user "
1995
0
            "specified ESP",
1996
0
            mount);
1997
0
          continue;
1998
0
        }
1999
0
      }
2000
2001
0
      if (!fu_context_is_esp(esp)) {
2002
0
        g_debug("not an ESP: %s", fu_volume_get_id(esp));
2003
0
        continue;
2004
0
      }
2005
2006
      /* big partitions are better than small partitions */
2007
0
      score += fu_volume_get_size(esp) / FU_MB;
2008
2009
      /* prefer partitions with the ESP flag set over msftdata */
2010
0
      kind = fu_volume_get_partition_kind(esp);
2011
0
      if (g_strcmp0(kind, FU_VOLUME_KIND_ESP) == 0)
2012
0
        score += 0x20000;
2013
2014
      /* prefer linux ESP */
2015
0
      if (!fu_context_is_esp_linux(esp, &error_local)) {
2016
0
        g_debug("not a Linux ESP: %s", error_local->message);
2017
0
      } else {
2018
0
        score += 64 * FU_KB;
2019
0
      }
2020
0
      g_hash_table_insert(esp_scores, (gpointer)esp, GUINT_TO_POINTER(score));
2021
0
    }
2022
2023
0
    if (g_hash_table_size(esp_scores) == 0) {
2024
0
      g_set_error_literal(error,
2025
0
              FWUPD_ERROR,
2026
0
              FWUPD_ERROR_NOT_SUPPORTED,
2027
0
              "no EFI system partition found");
2028
0
      return NULL;
2029
0
    }
2030
2031
0
    g_ptr_array_sort_with_data(esp_volumes, fu_context_sort_esp_score_cb, esp_scores);
2032
0
    for (guint i = 0; i < esp_volumes->len; i++) {
2033
0
      FuVolume *esp = g_ptr_array_index(esp_volumes, i);
2034
0
      guint score = GPOINTER_TO_UINT(g_hash_table_lookup(esp_scores, esp));
2035
0
      g_string_append_printf(str, "\n - 0x%x:\t%s", score, fu_volume_get_id(esp));
2036
0
    }
2037
0
    g_debug("%s", str->str);
2038
0
  }
2039
2040
0
  if (esp_volumes->len == 1) {
2041
0
    FuVolume *esp = g_ptr_array_index(esp_volumes, 0);
2042
0
    g_autoptr(FuVolumeLocker) locker = NULL;
2043
2044
    /* ensure it can be mounted */
2045
0
    locker = fu_volume_locker_new(esp, error);
2046
0
    if (locker == NULL)
2047
0
      return NULL;
2048
2049
    /* if user specified, does it match mountpoints ? */
2050
0
    if (user_esp_location != NULL) {
2051
0
      g_autofree gchar *mount = fu_volume_get_mount_point(esp);
2052
2053
0
      if (g_strcmp0(mount, user_esp_location) != 0) {
2054
0
        g_set_error(error,
2055
0
              FWUPD_ERROR,
2056
0
              FWUPD_ERROR_NOT_SUPPORTED,
2057
0
              "user specified ESP %s not found",
2058
0
              user_esp_location);
2059
0
        return NULL;
2060
0
      }
2061
0
    }
2062
0
  }
2063
2064
  /* "success" */
2065
0
  return g_object_ref(g_ptr_array_index(esp_volumes, 0));
2066
0
}
2067
2068
/**
2069
 * fu_context_get_esp_volume_by_hard_drive_device_path:
2070
 * @self: a #FuContext
2071
 * @dp: a #FuEfiHardDriveDevicePath
2072
 * @error: (nullable): optional return location for an error
2073
 *
2074
 * Gets a volume that matches the EFI device path
2075
 *
2076
 * Returns: (transfer full): a volume, or %NULL if it was not found
2077
 *
2078
 * Since: 2.0.0
2079
 **/
2080
FuVolume *
2081
fu_context_get_esp_volume_by_hard_drive_device_path(FuContext *self,
2082
                FuEfiHardDriveDevicePath *dp,
2083
                GError **error)
2084
0
{
2085
0
  g_autoptr(GPtrArray) volumes = NULL;
2086
2087
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
2088
0
  g_return_val_if_fail(FU_IS_EFI_HARD_DRIVE_DEVICE_PATH(dp), NULL);
2089
0
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
2090
2091
0
  volumes = fu_context_get_esp_volumes(self, error);
2092
0
  if (volumes == NULL)
2093
0
    return NULL;
2094
0
  for (guint i = 0; i < volumes->len; i++) {
2095
0
    FuVolume *volume = g_ptr_array_index(volumes, i);
2096
0
    g_autoptr(GError) error_local = NULL;
2097
0
    g_autoptr(FuEfiHardDriveDevicePath) dp_tmp = NULL;
2098
2099
0
    dp_tmp = fu_efi_hard_drive_device_path_new_from_volume(volume, &error_local);
2100
0
    if (dp_tmp == NULL) {
2101
0
      g_debug("%s", error_local->message);
2102
0
      continue;
2103
0
    }
2104
0
    if (!fu_efi_hard_drive_device_path_compare(dp, dp_tmp))
2105
0
      continue;
2106
0
    return g_object_ref(volume);
2107
0
  }
2108
2109
  /* failed */
2110
0
  g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "could not find EFI DP");
2111
0
  return NULL;
2112
0
}
2113
2114
static FuFirmware *
2115
fu_context_esp_load_pe_file(const gchar *filename, GError **error)
2116
0
{
2117
0
  g_autoptr(FuFirmware) firmware = fu_pefile_firmware_new();
2118
0
  g_autoptr(GFile) file = g_file_new_for_path(filename);
2119
0
  fu_firmware_set_filename(firmware, filename);
2120
0
  if (!fu_firmware_parse_file(firmware, file, FU_FIRMWARE_PARSE_FLAG_NONE, error)) {
2121
0
    g_prefix_error(error, "failed to load %s: ", filename);
2122
0
    return NULL;
2123
0
  }
2124
0
  return g_steal_pointer(&firmware);
2125
0
}
2126
2127
static gchar *
2128
fu_context_build_uefi_basename_for_arch(const gchar *app_name)
2129
0
{
2130
0
#if defined(__x86_64__)
2131
0
  return g_strdup_printf("%sx64.efi", app_name);
2132
0
#endif
2133
#if defined(__aarch64__)
2134
  return g_strdup_printf("%saa64.efi", app_name);
2135
#endif
2136
#if defined(__loongarch_lp64)
2137
  return g_strdup_printf("%sloongarch64.efi", app_name);
2138
#endif
2139
#if (defined(__riscv) && __riscv_xlen == 64)
2140
  return g_strdup_printf("%sriscv64.efi", app_name);
2141
#endif
2142
#if defined(__i386__) || defined(__i686__)
2143
  return g_strdup_printf("%sia32.efi", app_name);
2144
#endif
2145
#if defined(__arm__)
2146
  return g_strdup_printf("%sarm.efi", app_name);
2147
#endif
2148
0
  return NULL;
2149
0
}
2150
2151
static gboolean
2152
fu_context_get_esp_files_for_entry(FuContext *self,
2153
           FuEfiLoadOption *entry,
2154
           GPtrArray *files,
2155
           FuContextEspFileFlags flags,
2156
           GError **error)
2157
0
{
2158
0
  FuContextPrivate *priv = GET_PRIVATE(self);
2159
0
  g_autofree gchar *dp_filename = NULL;
2160
0
  g_autofree gchar *filename = NULL;
2161
0
  g_autofree gchar *mount_point = NULL;
2162
0
  g_autofree gchar *shim_name = fu_context_build_uefi_basename_for_arch("shim");
2163
0
  g_autoptr(FuVolumeLocker) volume_locker = NULL;
2164
0
  g_autoptr(FuEfiFilePathDevicePath) dp_path = NULL;
2165
0
  g_autoptr(FuEfiHardDriveDevicePath) dp_hdd = NULL;
2166
0
  g_autoptr(FuFirmware) dp_list = NULL;
2167
0
  g_autoptr(FuVolume) volume = NULL;
2168
2169
  /* all entries should have a list */
2170
0
  dp_list =
2171
0
      fu_firmware_get_image_by_gtype(FU_FIRMWARE(entry), FU_TYPE_EFI_DEVICE_PATH_LIST, NULL);
2172
0
  if (dp_list == NULL)
2173
0
    return TRUE;
2174
2175
  /* HDD */
2176
0
  dp_hdd = FU_EFI_HARD_DRIVE_DEVICE_PATH(
2177
0
      fu_firmware_get_image_by_gtype(FU_FIRMWARE(dp_list),
2178
0
             FU_TYPE_EFI_HARD_DRIVE_DEVICE_PATH,
2179
0
             NULL));
2180
0
  if (dp_hdd == NULL)
2181
0
    return TRUE;
2182
2183
  /* FILE */
2184
0
  dp_path = FU_EFI_FILE_PATH_DEVICE_PATH(
2185
0
      fu_firmware_get_image_by_gtype(FU_FIRMWARE(dp_list),
2186
0
             FU_TYPE_EFI_FILE_PATH_DEVICE_PATH,
2187
0
             NULL));
2188
0
  if (dp_path == NULL)
2189
0
    return TRUE;
2190
2191
  /* can we match the volume? */
2192
0
  volume = fu_context_get_esp_volume_by_hard_drive_device_path(self, dp_hdd, error);
2193
0
  if (volume == NULL)
2194
0
    return FALSE;
2195
0
  if (priv->flags & FU_CONTEXT_FLAG_INHIBIT_VOLUME_MOUNT) {
2196
0
    g_set_error_literal(error,
2197
0
            FWUPD_ERROR,
2198
0
            FWUPD_ERROR_NOT_SUPPORTED,
2199
0
            "cannot mount volume by policy");
2200
0
    return FALSE;
2201
0
  }
2202
0
  volume_locker = fu_volume_locker_new(volume, error);
2203
0
  if (volume_locker == NULL)
2204
0
    return FALSE;
2205
0
  dp_filename = fu_efi_file_path_device_path_get_name(dp_path, error);
2206
0
  if (dp_filename == NULL)
2207
0
    return FALSE;
2208
2209
  /* the file itself */
2210
0
  mount_point = fu_volume_get_mount_point(volume);
2211
0
  filename = g_build_filename(mount_point, dp_filename, NULL);
2212
0
  g_debug("check for 1st stage bootloader: %s", filename);
2213
0
  if (flags & FU_CONTEXT_ESP_FILE_FLAG_INCLUDE_FIRST_STAGE) {
2214
0
    g_autoptr(FuFirmware) firmware = NULL;
2215
0
    g_autoptr(GError) error_local = NULL;
2216
2217
    /* ignore if the file cannot be loaded as a PE file */
2218
0
    firmware = fu_context_esp_load_pe_file(filename, &error_local);
2219
0
    if (firmware == NULL) {
2220
0
      if (g_error_matches(error_local, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED) ||
2221
0
          g_error_matches(error_local, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE)) {
2222
0
        g_debug("ignoring: %s", error_local->message);
2223
0
      } else {
2224
0
        g_propagate_error(error, g_steal_pointer(&error_local));
2225
0
        return FALSE;
2226
0
      }
2227
0
    } else {
2228
0
      fu_firmware_set_idx(firmware, fu_firmware_get_idx(FU_FIRMWARE(entry)));
2229
0
      g_ptr_array_add(files, g_steal_pointer(&firmware));
2230
0
    }
2231
0
  }
2232
2233
  /* the 2nd stage bootloader, typically grub */
2234
0
  if (flags & FU_CONTEXT_ESP_FILE_FLAG_INCLUDE_SECOND_STAGE &&
2235
0
      g_str_has_suffix(filename, shim_name)) {
2236
0
    g_autoptr(FuFirmware) firmware = NULL;
2237
0
    g_autoptr(GError) error_local = NULL;
2238
0
    g_autoptr(GString) filename2 = g_string_new(filename);
2239
0
    const gchar *path;
2240
2241
0
    path =
2242
0
        fu_efi_load_option_get_metadata(entry, FU_EFI_LOAD_OPTION_METADATA_PATH, NULL);
2243
0
    if (path != NULL) {
2244
0
      g_string_replace(filename2, shim_name, path, 1);
2245
0
    } else {
2246
0
      g_autofree gchar *grub_name =
2247
0
          fu_context_build_uefi_basename_for_arch("grub");
2248
0
      g_string_replace(filename2, shim_name, grub_name, 1);
2249
0
    }
2250
0
    g_debug("check for 2nd stage bootloader: %s", filename2->str);
2251
2252
    /* ignore if the file cannot be loaded as a PE file */
2253
0
    firmware = fu_context_esp_load_pe_file(filename2->str, &error_local);
2254
0
    if (firmware == NULL) {
2255
0
      if (g_error_matches(error_local, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED) ||
2256
0
          g_error_matches(error_local, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE)) {
2257
0
        g_debug("ignoring: %s", error_local->message);
2258
0
      } else {
2259
0
        g_propagate_error(error, g_steal_pointer(&error_local));
2260
0
        return FALSE;
2261
0
      }
2262
0
    } else {
2263
0
      fu_firmware_set_idx(firmware, fu_firmware_get_idx(FU_FIRMWARE(entry)));
2264
0
      g_ptr_array_add(files, g_steal_pointer(&firmware));
2265
0
    }
2266
0
  }
2267
2268
  /* revocations, typically for SBAT */
2269
0
  if (flags & FU_CONTEXT_ESP_FILE_FLAG_INCLUDE_REVOCATIONS &&
2270
0
      g_str_has_suffix(filename, shim_name)) {
2271
0
    g_autoptr(GString) filename2 = g_string_new(filename);
2272
0
    g_autoptr(FuFirmware) firmware = NULL;
2273
0
    g_autoptr(GError) error_local = NULL;
2274
2275
0
    g_string_replace(filename2, shim_name, "revocations.efi", 1);
2276
0
    g_debug("check for revocation: %s", filename2->str);
2277
2278
    /* ignore if the file cannot be loaded as a PE file */
2279
0
    firmware = fu_context_esp_load_pe_file(filename2->str, &error_local);
2280
0
    if (firmware == NULL) {
2281
0
      if (g_error_matches(error_local, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED) ||
2282
0
          g_error_matches(error_local, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE)) {
2283
0
        g_debug("ignoring: %s", error_local->message);
2284
0
      } else {
2285
0
        g_propagate_error(error, g_steal_pointer(&error_local));
2286
0
        return FALSE;
2287
0
      }
2288
0
    } else {
2289
0
      fu_firmware_set_idx(firmware, fu_firmware_get_idx(FU_FIRMWARE(entry)));
2290
0
      g_ptr_array_add(files, g_steal_pointer(&firmware));
2291
0
    }
2292
0
  }
2293
2294
  /* success */
2295
0
  return TRUE;
2296
0
}
2297
2298
/**
2299
 * fu_context_get_esp_files:
2300
 * @self: a #FuContext
2301
 * @flags: some #FuContextEspFileFlags, e.g. #FU_CONTEXT_ESP_FILE_FLAG_INCLUDE_FIRST_STAGE
2302
 * @error: #GError
2303
 *
2304
 * Gets the PE files for all the entries listed in `BootOrder`.
2305
 *
2306
 * Returns: (transfer full) (element-type FuPefileFirmware): PE firmware data
2307
 *
2308
 * Since: 2.0.0
2309
 **/
2310
GPtrArray *
2311
fu_context_get_esp_files(FuContext *self, FuContextEspFileFlags flags, GError **error)
2312
0
{
2313
0
  FuContextPrivate *priv = GET_PRIVATE(self);
2314
0
  g_autoptr(GPtrArray) entries = NULL;
2315
0
  g_autoptr(GPtrArray) files = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
2316
2317
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
2318
0
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
2319
2320
0
  entries = fu_efivars_get_boot_entries(priv->efivars, error);
2321
0
  if (entries == NULL)
2322
0
    return NULL;
2323
0
  for (guint i = 0; i < entries->len; i++) {
2324
0
    FuEfiLoadOption *entry = g_ptr_array_index(entries, i);
2325
0
    g_autoptr(GError) error_local = NULL;
2326
0
    if (!fu_context_get_esp_files_for_entry(self, entry, files, flags, &error_local)) {
2327
0
      if (g_error_matches(error_local, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND) ||
2328
0
          g_error_matches(error_local, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE)) {
2329
0
        g_debug("ignoring %s: %s",
2330
0
          fu_firmware_get_id(FU_FIRMWARE(entry)),
2331
0
          error_local->message);
2332
0
        continue;
2333
0
      }
2334
0
      g_propagate_error(error, g_steal_pointer(&error_local));
2335
0
      return NULL;
2336
0
    }
2337
0
  }
2338
2339
  /* success */
2340
0
  return g_steal_pointer(&files);
2341
0
}
2342
2343
/**
2344
 * fu_context_get_backends:
2345
 * @self: a #FuContext
2346
 *
2347
 * Gets all the possible backends used by all plugins.
2348
 *
2349
 * Returns: (transfer none) (element-type FuBackend): List of backends
2350
 *
2351
 * Since: 2.0.0
2352
 **/
2353
GPtrArray *
2354
fu_context_get_backends(FuContext *self)
2355
0
{
2356
0
  FuContextPrivate *priv = GET_PRIVATE(self);
2357
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
2358
0
  return priv->backends;
2359
0
}
2360
2361
/**
2362
 * fu_context_add_backend:
2363
 * @self: a #FuContext
2364
 * @backend: a #FuBackend
2365
 *
2366
 * Adds a backend to the context.
2367
 *
2368
 * Returns: (transfer full): a #FuBackend, or %NULL on error
2369
 *
2370
 * Since: 2.0.0
2371
 **/
2372
void
2373
fu_context_add_backend(FuContext *self, FuBackend *backend)
2374
0
{
2375
0
  FuContextPrivate *priv = GET_PRIVATE(self);
2376
0
  g_return_if_fail(FU_IS_CONTEXT(self));
2377
0
  g_return_if_fail(FU_IS_BACKEND(backend));
2378
0
  g_ptr_array_add(priv->backends, g_object_ref(backend));
2379
0
}
2380
2381
/**
2382
 * fu_context_get_backend_by_name:
2383
 * @self: a #FuContext
2384
 * @name: backend name, e.g. `udev` or `bluez`
2385
 * @error: (nullable): optional return location for an error
2386
 *
2387
 * Gets a specific backend added to the context.
2388
 *
2389
 * Returns: (transfer full): a #FuBackend, or %NULL on error
2390
 *
2391
 * Since: 2.0.0
2392
 **/
2393
FuBackend *
2394
fu_context_get_backend_by_name(FuContext *self, const gchar *name, GError **error)
2395
0
{
2396
0
  FuContextPrivate *priv = GET_PRIVATE(self);
2397
2398
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
2399
0
  g_return_val_if_fail(name != NULL, NULL);
2400
0
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
2401
2402
0
  for (guint i = 0; i < priv->backends->len; i++) {
2403
0
    FuBackend *backend = g_ptr_array_index(priv->backends, i);
2404
0
    if (g_strcmp0(fu_backend_get_name(backend), name) == 0)
2405
0
      return g_object_ref(backend);
2406
0
  }
2407
0
  g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "no backend with name %s", name);
2408
0
  return NULL;
2409
0
}
2410
2411
/* private */
2412
gboolean
2413
fu_context_has_backend(FuContext *self, const gchar *name)
2414
0
{
2415
0
  FuContextPrivate *priv = GET_PRIVATE(self);
2416
2417
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), FALSE);
2418
0
  g_return_val_if_fail(name != NULL, FALSE);
2419
2420
0
  for (guint i = 0; i < priv->backends->len; i++) {
2421
0
    FuBackend *backend = g_ptr_array_index(priv->backends, i);
2422
0
    if (g_strcmp0(fu_backend_get_name(backend), name) == 0)
2423
0
      return TRUE;
2424
0
  }
2425
0
  return FALSE;
2426
0
}
2427
2428
/* private */
2429
gpointer
2430
fu_context_get_data(FuContext *self, const gchar *key)
2431
0
{
2432
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
2433
0
  g_return_val_if_fail(key != NULL, NULL);
2434
0
  return g_object_get_data(G_OBJECT(self), key);
2435
0
}
2436
2437
/* private */
2438
void
2439
fu_context_set_data(FuContext *self, const gchar *key, gpointer data)
2440
0
{
2441
0
  g_return_if_fail(FU_IS_CONTEXT(self));
2442
0
  g_return_if_fail(key != NULL);
2443
0
  g_object_set_data(G_OBJECT(self), key, data);
2444
0
}
2445
2446
/**
2447
 * fu_context_get_path:
2448
 * @self: a #FuContext
2449
 * @kind: a #FuPathKind
2450
 * @error: (nullable): optional return location for an error
2451
 *
2452
 * Gets a well-known path.
2453
 *
2454
 * Returns: (transfer full): a #FuBackend, or %NULL on error
2455
 *
2456
 * Since: 2.1.1
2457
 **/
2458
const gchar *
2459
fu_context_get_path(FuContext *self, FuPathKind kind, GError **error)
2460
0
{
2461
0
  FuContextPrivate *priv = GET_PRIVATE(self);
2462
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
2463
0
  return fu_path_store_get_path(priv->pstore, kind, error);
2464
0
}
2465
2466
/**
2467
 * fu_context_build_filename:
2468
 * @self: a #FuContext
2469
 * @error: (nullable): optional return location for an error
2470
 * @kind: a #FuPathKind e.g. %FU_PATH_KIND_DATADIR_PKG
2471
 * @...: pairs of string key values, ending with %NULL
2472
 *
2473
 * Gets a fwupd-specific system path. These can be overridden with various
2474
 * environment variables, for instance %FWUPD_DATADIR.
2475
 *
2476
 * Returns: a system path, or %NULL if invalid
2477
 *
2478
 * Since: 2.1.1
2479
 **/
2480
gchar *
2481
fu_context_build_filename(FuContext *self, GError **error, FuPathKind kind, ...)
2482
0
{
2483
0
  FuContextPrivate *priv = GET_PRIVATE(self);
2484
0
  va_list args;
2485
0
  gchar *path;
2486
0
  const gchar *path_prefix = NULL;
2487
2488
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
2489
2490
0
  path_prefix = fu_path_store_get_path(priv->pstore, kind, error);
2491
0
  if (path_prefix == NULL)
2492
0
    return NULL;
2493
2494
0
  va_start(args, kind);
2495
0
  path = g_build_filename_valist(path_prefix, &args);
2496
0
  va_end(args);
2497
2498
0
  return path;
2499
0
}
2500
2501
/**
2502
 * fu_context_set_path:
2503
 * @self: a #FuContext
2504
 * @kind: a #FuPathKind
2505
 *
2506
 * Sets a well-known path.
2507
 *
2508
 * Since: 2.1.1
2509
 **/
2510
void
2511
fu_context_set_path(FuContext *self, FuPathKind kind, const gchar *dirname)
2512
0
{
2513
0
  FuContextPrivate *priv = GET_PRIVATE(self);
2514
0
  g_return_if_fail(FU_IS_CONTEXT(self));
2515
0
  fu_path_store_set_path(priv->pstore, kind, dirname);
2516
0
}
2517
2518
/**
2519
 * fu_context_set_tmpdir:
2520
 * @self: a #FuContext
2521
 * @tmpdir: (not nullable): a #FuTemporaryDirectory
2522
 *
2523
 * Sets the @kind to a temporary path.
2524
 *
2525
 * Since: 2.1.1
2526
 **/
2527
void
2528
fu_context_set_tmpdir(FuContext *self, FuPathKind kind, FuTemporaryDirectory *tmpdir)
2529
0
{
2530
0
  FuContextPrivate *priv = GET_PRIVATE(self);
2531
0
  g_return_if_fail(FU_IS_CONTEXT(self));
2532
0
  g_return_if_fail(kind < FU_PATH_KIND_LAST);
2533
0
  g_return_if_fail(FU_IS_TEMPORARY_DIRECTORY(tmpdir));
2534
0
  fu_path_store_set_tmpdir(priv->pstore, kind, tmpdir);
2535
0
}
2536
2537
/**
2538
 * fu_context_get_path_store:
2539
 * @self: a #FuContext
2540
 *
2541
 * Gets the well-known path store.
2542
 *
2543
 * Returns: (transfer none): a #FuPathStore, or %NULL if not set
2544
 *
2545
 * Since: 2.1.1
2546
 **/
2547
FuPathStore *
2548
fu_context_get_path_store(FuContext *self)
2549
0
{
2550
0
  FuContextPrivate *priv = GET_PRIVATE(self);
2551
0
  g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
2552
0
  return priv->pstore;
2553
0
}
2554
2555
/**
2556
 * fu_context_load_path_store:
2557
 * @self: a #FuContext
2558
 *
2559
 * Loads the path store defaults and overrides.
2560
 *
2561
 * IMPORTANT: This should only be used for binaries, NEVER self tests!
2562
 *
2563
 * Since: 2.1.1
2564
 **/
2565
void
2566
fu_context_load_path_store(FuContext *self)
2567
0
{
2568
0
  FuContextPrivate *priv = GET_PRIVATE(self);
2569
0
  g_return_if_fail(FU_IS_CONTEXT(self));
2570
0
  fu_path_store_load_defaults(priv->pstore);
2571
0
  fu_path_store_load_from_env(priv->pstore);
2572
0
}
2573
2574
static void
2575
fu_context_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
2576
0
{
2577
0
  FuContext *self = FU_CONTEXT(object);
2578
0
  FuContextPrivate *priv = GET_PRIVATE(self);
2579
0
  switch (prop_id) {
2580
0
  case PROP_POWER_STATE:
2581
0
    g_value_set_uint(value, priv->power_state);
2582
0
    break;
2583
0
  case PROP_LID_STATE:
2584
0
    g_value_set_uint(value, priv->lid_state);
2585
0
    break;
2586
0
  case PROP_DISPLAY_STATE:
2587
0
    g_value_set_uint(value, priv->display_state);
2588
0
    break;
2589
0
  case PROP_BATTERY_LEVEL:
2590
0
    g_value_set_uint(value, priv->battery_level);
2591
0
    break;
2592
0
  case PROP_BATTERY_THRESHOLD:
2593
0
    g_value_set_uint(value, priv->battery_threshold);
2594
0
    break;
2595
0
  case PROP_FLAGS:
2596
0
    g_value_set_uint64(value, priv->flags);
2597
0
    break;
2598
0
  default:
2599
0
    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
2600
0
    break;
2601
0
  }
2602
0
}
2603
2604
static void
2605
fu_context_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
2606
0
{
2607
0
  FuContext *self = FU_CONTEXT(object);
2608
0
  FuContextPrivate *priv = GET_PRIVATE(self);
2609
0
  switch (prop_id) {
2610
0
  case PROP_POWER_STATE:
2611
0
    fu_context_set_power_state(self, g_value_get_uint(value));
2612
0
    break;
2613
0
  case PROP_LID_STATE:
2614
0
    fu_context_set_lid_state(self, g_value_get_uint(value));
2615
0
    break;
2616
0
  case PROP_DISPLAY_STATE:
2617
0
    fu_context_set_display_state(self, g_value_get_uint(value));
2618
0
    break;
2619
0
  case PROP_BATTERY_LEVEL:
2620
0
    fu_context_set_battery_level(self, g_value_get_uint(value));
2621
0
    break;
2622
0
  case PROP_BATTERY_THRESHOLD:
2623
0
    fu_context_set_battery_threshold(self, g_value_get_uint(value));
2624
0
    break;
2625
0
  case PROP_FLAGS:
2626
0
    priv->flags = g_value_get_uint64(value);
2627
0
    break;
2628
0
  default:
2629
0
    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
2630
0
    break;
2631
0
  }
2632
0
}
2633
2634
static void
2635
fu_context_dispose(GObject *object)
2636
0
{
2637
0
  FuContext *self = FU_CONTEXT(object);
2638
0
  FuContextPrivate *priv = GET_PRIVATE(self);
2639
0
  g_ptr_array_set_size(priv->backends, 0);
2640
0
  G_OBJECT_CLASS(fu_context_parent_class)->dispose(object);
2641
0
}
2642
2643
static void
2644
fu_context_finalize(GObject *object)
2645
0
{
2646
0
  FuContext *self = FU_CONTEXT(object);
2647
0
  FuContextPrivate *priv = GET_PRIVATE(self);
2648
2649
0
  if (priv->fdt != NULL)
2650
0
    g_object_unref(priv->fdt);
2651
0
  if (priv->efivars != NULL)
2652
0
    g_object_unref(priv->efivars);
2653
0
  g_free(priv->esp_location);
2654
0
  g_hash_table_unref(priv->runtime_versions);
2655
0
  g_hash_table_unref(priv->compile_versions);
2656
0
  g_object_unref(priv->pstore);
2657
0
  g_object_unref(priv->hwids);
2658
0
  g_object_unref(priv->config);
2659
0
  g_hash_table_unref(priv->hwid_flags);
2660
0
  g_object_unref(priv->quirks);
2661
0
  g_object_unref(priv->smbios);
2662
0
  g_object_unref(priv->host_bios_settings);
2663
0
  g_hash_table_unref(priv->firmware_gtypes);
2664
0
  g_hash_table_unref(priv->udev_subsystems);
2665
0
  g_ptr_array_unref(priv->esp_volumes);
2666
0
  g_ptr_array_unref(priv->backends);
2667
2668
0
  G_OBJECT_CLASS(fu_context_parent_class)->finalize(object);
2669
0
}
2670
2671
static void
2672
fu_context_constructed(GObject *obj)
2673
0
{
2674
0
  FuContext *self = FU_CONTEXT(obj);
2675
0
  FuContextPrivate *priv = GET_PRIVATE(self);
2676
0
  priv->efivars = (priv->flags & FU_CONTEXT_FLAG_DUMMY_EFIVARS) > 0
2677
0
          ? fu_dummy_efivars_new()
2678
0
          : fu_efivars_new(priv->pstore);
2679
2680
  /* chain up to parent */
2681
0
  G_OBJECT_CLASS(fu_context_parent_class)->constructed(obj);
2682
0
}
2683
2684
static void
2685
fu_context_class_init(FuContextClass *klass)
2686
0
{
2687
0
  GObjectClass *object_class = G_OBJECT_CLASS(klass);
2688
0
  GParamSpec *pspec;
2689
2690
0
  object_class->dispose = fu_context_dispose;
2691
0
  object_class->get_property = fu_context_get_property;
2692
0
  object_class->set_property = fu_context_set_property;
2693
0
  object_class->constructed = fu_context_constructed;
2694
2695
  /**
2696
   * FuContext:power-state:
2697
   *
2698
   * The system power state.
2699
   *
2700
   * Since: 1.8.11
2701
   */
2702
0
  pspec = g_param_spec_uint("power-state",
2703
0
          NULL,
2704
0
          NULL,
2705
0
          FU_POWER_STATE_UNKNOWN,
2706
0
          FU_POWER_STATE_LAST,
2707
0
          FU_POWER_STATE_UNKNOWN,
2708
0
          G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
2709
0
  g_object_class_install_property(object_class, PROP_POWER_STATE, pspec);
2710
2711
  /**
2712
   * FuContext:lid-state:
2713
   *
2714
   * The system lid state.
2715
   *
2716
   * Since: 1.7.4
2717
   */
2718
0
  pspec = g_param_spec_uint("lid-state",
2719
0
          NULL,
2720
0
          NULL,
2721
0
          FU_LID_STATE_UNKNOWN,
2722
0
          FU_LID_STATE_LAST,
2723
0
          FU_LID_STATE_UNKNOWN,
2724
0
          G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
2725
0
  g_object_class_install_property(object_class, PROP_LID_STATE, pspec);
2726
2727
  /**
2728
   * FuContext:display-state:
2729
   *
2730
   * The display state.
2731
   *
2732
   * Since: 1.9.6
2733
   */
2734
0
  pspec = g_param_spec_uint("display-state",
2735
0
          NULL,
2736
0
          NULL,
2737
0
          FU_DISPLAY_STATE_UNKNOWN,
2738
0
          FU_DISPLAY_STATE_LAST,
2739
0
          FU_DISPLAY_STATE_UNKNOWN,
2740
0
          G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
2741
0
  g_object_class_install_property(object_class, PROP_DISPLAY_STATE, pspec);
2742
2743
  /**
2744
   * FuContext:battery-level:
2745
   *
2746
   * The system battery level in percent.
2747
   *
2748
   * Since: 1.6.0
2749
   */
2750
0
  pspec = g_param_spec_uint("battery-level",
2751
0
          NULL,
2752
0
          NULL,
2753
0
          0,
2754
0
          FWUPD_BATTERY_LEVEL_INVALID,
2755
0
          FWUPD_BATTERY_LEVEL_INVALID,
2756
0
          G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
2757
0
  g_object_class_install_property(object_class, PROP_BATTERY_LEVEL, pspec);
2758
2759
  /**
2760
   * FuContext:battery-threshold:
2761
   *
2762
   * The system battery threshold in percent.
2763
   *
2764
   * Since: 1.6.0
2765
   */
2766
0
  pspec = g_param_spec_uint("battery-threshold",
2767
0
          NULL,
2768
0
          NULL,
2769
0
          0,
2770
0
          FWUPD_BATTERY_LEVEL_INVALID,
2771
0
          FWUPD_BATTERY_LEVEL_INVALID,
2772
0
          G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
2773
0
  g_object_class_install_property(object_class, PROP_BATTERY_THRESHOLD, pspec);
2774
2775
  /**
2776
   * FuContext:flags:
2777
   *
2778
   * The context flags.
2779
   *
2780
   * Since: 1.8.10
2781
   */
2782
0
  pspec = g_param_spec_uint64("flags",
2783
0
            NULL,
2784
0
            NULL,
2785
0
            FU_CONTEXT_FLAG_NONE,
2786
0
            G_MAXUINT64,
2787
0
            FU_CONTEXT_FLAG_NONE,
2788
0
            G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_NAME);
2789
0
  g_object_class_install_property(object_class, PROP_FLAGS, pspec);
2790
2791
  /**
2792
   * FuContext::security-changed:
2793
   * @self: the #FuContext instance that emitted the signal
2794
   *
2795
   * The ::security-changed signal is emitted when some system state has changed that could
2796
   * have affected the security level.
2797
   *
2798
   * Since: 1.6.0
2799
   **/
2800
0
  signals[SIGNAL_SECURITY_CHANGED] =
2801
0
      g_signal_new("security-changed",
2802
0
       G_TYPE_FROM_CLASS(object_class),
2803
0
       G_SIGNAL_RUN_LAST,
2804
0
       G_STRUCT_OFFSET(FuContextClass, security_changed),
2805
0
       NULL,
2806
0
       NULL,
2807
0
       g_cclosure_marshal_VOID__VOID,
2808
0
       G_TYPE_NONE,
2809
0
       0);
2810
  /**
2811
   * FuContext::housekeeping:
2812
   * @self: the #FuContext instance that emitted the signal
2813
   *
2814
   * The ::housekeeping signal is emitted when helper objects should do house-keeping actions
2815
   * when the daemon is idle.
2816
   *
2817
   * Since: 2.0.0
2818
   **/
2819
0
  signals[SIGNAL_HOUSEKEEPING] = g_signal_new("housekeeping",
2820
0
                G_TYPE_FROM_CLASS(object_class),
2821
0
                G_SIGNAL_RUN_LAST,
2822
0
                G_STRUCT_OFFSET(FuContextClass, housekeeping),
2823
0
                NULL,
2824
0
                NULL,
2825
0
                g_cclosure_marshal_VOID__VOID,
2826
0
                G_TYPE_NONE,
2827
0
                0);
2828
2829
0
  object_class->finalize = fu_context_finalize;
2830
0
}
2831
2832
static void
2833
fu_context_init(FuContext *self)
2834
0
{
2835
0
  FuContextPrivate *priv = GET_PRIVATE(self);
2836
0
  priv->chassis_kind = FU_SMBIOS_CHASSIS_KIND_UNKNOWN;
2837
0
  priv->battery_level = FWUPD_BATTERY_LEVEL_INVALID;
2838
0
  priv->battery_threshold = FWUPD_BATTERY_LEVEL_INVALID;
2839
0
  priv->pstore = fu_path_store_new();
2840
0
  priv->smbios = fu_smbios_new(priv->pstore);
2841
0
  priv->hwids = fu_hwids_new();
2842
0
  priv->config = fu_config_new(priv->pstore);
2843
0
  priv->hwid_flags = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
2844
0
  priv->udev_subsystems = g_hash_table_new_full(g_str_hash,
2845
0
                  g_str_equal,
2846
0
                  g_free,
2847
0
                  (GDestroyNotify)g_ptr_array_unref);
2848
0
  priv->firmware_gtypes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
2849
0
  priv->quirks = fu_quirks_new(self);
2850
0
  priv->host_bios_settings = fu_bios_settings_new(priv->pstore);
2851
0
  priv->esp_volumes = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
2852
0
  priv->runtime_versions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
2853
0
  priv->compile_versions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
2854
0
  priv->backends = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
2855
0
}
2856
2857
/* private */
2858
FuContext *
2859
fu_context_new_full(FuContextFlags flags)
2860
0
{
2861
0
  return FU_CONTEXT(g_object_new(FU_TYPE_CONTEXT, "flags", (guint64)flags, NULL));
2862
0
}
2863
2864
/**
2865
 * fu_context_new:
2866
 *
2867
 * Creates a new #FuContext
2868
 *
2869
 * Returns: (transfer full): the object
2870
 *
2871
 * Since: 1.6.0
2872
 **/
2873
FuContext *
2874
fu_context_new(void)
2875
0
{
2876
0
  return fu_context_new_full(FU_CONTEXT_FLAG_NONE);
2877
0
}