Coverage Report

Created: 2026-06-15 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fwupd/libfwupdplugin/fu-bios-settings.c
Line
Count
Source
1
/*
2
 * Copyright 2022 Mario Limonciello <mario.limonciello@amd.com>
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 */
6
7
0
#define G_LOG_DOMAIN "FuBiosSettings"
8
9
#include "config.h"
10
11
#include <glib/gi18n.h>
12
13
#include "fwupd-error.h"
14
15
#include "fu-bios-setting.h"
16
#include "fu-bios-settings-private.h"
17
#include "fu-common.h"
18
#include "fu-path.h"
19
#include "fu-string.h"
20
21
0
#define LENOVO_READ_ONLY_NEEDLE "[Status:ShowOnly]"
22
23
struct _FuBiosSettings {
24
  GObject parent_instance;
25
  FuPathStore *pstore;
26
  GHashTable *descriptions;
27
  GHashTable *read_only;
28
  GPtrArray *attrs;
29
};
30
31
static void
32
fu_bios_settings_codec_iface_init(FwupdCodecInterface *iface);
33
34
0
G_DEFINE_TYPE_WITH_CODE(FuBiosSettings,
35
0
      fu_bios_settings,
36
0
      G_TYPE_OBJECT,
37
0
      G_IMPLEMENT_INTERFACE(FWUPD_TYPE_CODEC, fu_bios_settings_codec_iface_init))
38
0
39
0
static void
40
0
fu_bios_settings_finalize(GObject *obj)
41
0
{
42
0
  FuBiosSettings *self = FU_BIOS_SETTINGS(obj);
43
0
  if (self->pstore != NULL)
44
0
    g_object_unref(self->pstore);
45
0
  g_ptr_array_unref(self->attrs);
46
0
  g_hash_table_unref(self->descriptions);
47
0
  g_hash_table_unref(self->read_only);
48
0
  G_OBJECT_CLASS(fu_bios_settings_parent_class)->finalize(obj);
49
0
}
50
51
static void
52
fu_bios_settings_class_init(FuBiosSettingsClass *klass)
53
0
{
54
0
  GObjectClass *object_class = G_OBJECT_CLASS(klass);
55
0
  object_class->finalize = fu_bios_settings_finalize;
56
0
}
57
58
static gboolean
59
fu_bios_setting_get_key(FwupdBiosSetting *attr, /* nocheck:name */
60
      const gchar *key,
61
      gchar **value_out,
62
      GError **error)
63
0
{
64
0
  g_autofree gchar *tmp = NULL;
65
66
0
  g_return_val_if_fail(FWUPD_IS_BIOS_SETTING(attr), FALSE);
67
0
  g_return_val_if_fail(&value_out != NULL, FALSE);
68
69
0
  tmp = g_build_filename(fwupd_bios_setting_get_path(attr), key, NULL);
70
0
  if (!g_file_get_contents(tmp, value_out, NULL, error)) {
71
0
    g_prefix_error(error, "failed to load %s: ", key);
72
0
    fwupd_error_convert(error);
73
0
    return FALSE;
74
0
  }
75
0
  g_strchomp(*value_out);
76
0
  return TRUE;
77
0
}
78
79
static gboolean
80
fu_bios_settings_set_description(FuBiosSettings *self, FwupdBiosSetting *attr, GError **error)
81
0
{
82
0
  g_autofree gchar *data = NULL;
83
0
  const gchar *value;
84
85
0
  g_return_val_if_fail(FWUPD_IS_BIOS_SETTING(attr), FALSE);
86
87
  /* try ID, then name, and then key */
88
0
  value = g_hash_table_lookup(self->descriptions, fwupd_bios_setting_get_id(attr));
89
0
  if (value != NULL) {
90
0
    fwupd_bios_setting_set_description(attr, value);
91
0
    return TRUE;
92
0
  }
93
0
  value = g_hash_table_lookup(self->descriptions, fwupd_bios_setting_get_name(attr));
94
0
  if (value != NULL) {
95
0
    fwupd_bios_setting_set_description(attr, value);
96
0
    return TRUE;
97
0
  }
98
0
  if (!fu_bios_setting_get_key(attr, "display_name", &data, error))
99
0
    return FALSE;
100
0
  fwupd_bios_setting_set_description(attr, data);
101
102
0
  return TRUE;
103
0
}
104
105
static guint64
106
fu_bios_setting_get_key_as_integer(FwupdBiosSetting *attr, /* nocheck:name */
107
           const gchar *key,
108
           GError **error)
109
0
{
110
0
  g_autofree gchar *str = NULL;
111
0
  guint64 tmp;
112
113
0
  if (!fu_bios_setting_get_key(attr, key, &str, error))
114
0
    return G_MAXUINT64;
115
0
  if (!fu_strtoull(str, &tmp, 0, G_MAXUINT64, FU_INTEGER_BASE_AUTO, error)) {
116
0
    g_prefix_error(error, "failed to convert %s to integer: ", key);
117
0
    return G_MAXUINT64;
118
0
  }
119
0
  return tmp;
120
0
}
121
122
static gboolean
123
fu_bios_setting_set_enumeration_attrs(FwupdBiosSetting *attr, GError **error) /* nocheck:name */
124
0
{
125
0
  const gchar *delimiters[] = {",", ";", NULL};
126
0
  g_autofree gchar *str = NULL;
127
128
0
  if (!fu_bios_setting_get_key(attr, "possible_values", &str, error))
129
0
    return FALSE;
130
0
  for (guint j = 0; delimiters[j] != NULL; j++) {
131
0
    g_auto(GStrv) vals = NULL;
132
0
    if (g_strrstr(str, delimiters[j]) == NULL)
133
0
      continue;
134
0
    vals = fu_strsplit(str, strlen(str), delimiters[j], -1);
135
0
    if (vals[0] != NULL)
136
0
      fwupd_bios_setting_set_kind(attr, FWUPD_BIOS_SETTING_KIND_ENUMERATION);
137
0
    for (guint i = 0; vals[i] != NULL && vals[i][0] != '\0'; i++)
138
0
      fwupd_bios_setting_add_possible_value(attr, vals[i]);
139
0
  }
140
0
  return TRUE;
141
0
}
142
143
static gboolean
144
fu_bios_setting_set_string_attrs(FwupdBiosSetting *attr, GError **error) /* nocheck:name */
145
0
{
146
0
  guint64 tmp;
147
148
0
  tmp = fu_bios_setting_get_key_as_integer(attr, "min_length", error);
149
0
  if (tmp == G_MAXUINT64)
150
0
    return FALSE;
151
0
  fwupd_bios_setting_set_lower_bound(attr, tmp);
152
0
  tmp = fu_bios_setting_get_key_as_integer(attr, "max_length", error);
153
0
  if (tmp == G_MAXUINT64)
154
0
    return FALSE;
155
0
  fwupd_bios_setting_set_upper_bound(attr, tmp);
156
0
  fwupd_bios_setting_set_kind(attr, FWUPD_BIOS_SETTING_KIND_STRING);
157
0
  return TRUE;
158
0
}
159
160
static gboolean
161
fu_bios_setting_set_integer_attrs(FwupdBiosSetting *attr, GError **error) /* nocheck:name */
162
0
{
163
0
  guint64 tmp;
164
165
0
  tmp = fu_bios_setting_get_key_as_integer(attr, "min_value", error);
166
0
  if (tmp == G_MAXUINT64)
167
0
    return FALSE;
168
0
  fwupd_bios_setting_set_lower_bound(attr, tmp);
169
0
  tmp = fu_bios_setting_get_key_as_integer(attr, "max_value", error);
170
0
  if (tmp == G_MAXUINT64)
171
0
    return FALSE;
172
0
  fwupd_bios_setting_set_upper_bound(attr, tmp);
173
0
  tmp = fu_bios_setting_get_key_as_integer(attr, "scalar_increment", error);
174
0
  if (tmp == G_MAXUINT64)
175
0
    return FALSE;
176
0
  fwupd_bios_setting_set_scalar_increment(attr, tmp);
177
0
  fwupd_bios_setting_set_kind(attr, FWUPD_BIOS_SETTING_KIND_INTEGER);
178
0
  return TRUE;
179
0
}
180
181
static gboolean
182
fu_bios_setting_set_current_value(FwupdBiosSetting *attr, GError **error) /* nocheck:name */
183
0
{
184
0
  g_autofree gchar *str = NULL;
185
186
0
  if (!fu_bios_setting_get_key(attr, "current_value", &str, error))
187
0
    return FALSE;
188
0
  fwupd_bios_setting_set_current_value(attr, str);
189
0
  return TRUE;
190
0
}
191
192
static void
193
fu_bios_settings_set_read_only(FuBiosSettings *self, FwupdBiosSetting *attr)
194
0
{
195
0
  const gchar *tmp;
196
0
  if (fwupd_bios_setting_get_kind(attr) == FWUPD_BIOS_SETTING_KIND_ENUMERATION) {
197
0
    const gchar *value =
198
0
        g_hash_table_lookup(self->read_only, fwupd_bios_setting_get_id(attr));
199
0
    if (g_strcmp0(value, fwupd_bios_setting_get_current_value(attr)) == 0)
200
0
      fwupd_bios_setting_set_read_only(attr, TRUE);
201
0
  }
202
0
  tmp = g_strrstr(fwupd_bios_setting_get_current_value(attr), LENOVO_READ_ONLY_NEEDLE);
203
0
  if (tmp != NULL)
204
0
    fwupd_bios_setting_set_read_only(attr, TRUE);
205
0
}
206
207
static gboolean
208
fu_bios_settings_set_type(FuBiosSettings *self, FwupdBiosSetting *attr, GError **error)
209
0
{
210
0
  gboolean kernel_bug = FALSE;
211
0
  g_autofree gchar *data = NULL;
212
0
  g_autoptr(GError) error_key = NULL;
213
0
  g_autoptr(GError) error_local = NULL;
214
215
0
  g_return_val_if_fail(FU_IS_BIOS_SETTINGS(self), FALSE);
216
0
  g_return_val_if_fail(FWUPD_IS_BIOS_SETTING(attr), FALSE);
217
218
0
  if (!fu_bios_setting_get_key(attr, "type", &data, &error_key)) {
219
0
    g_debug("%s", error_key->message);
220
0
    g_propagate_error(error, g_steal_pointer(&error_key));
221
0
    return FALSE;
222
0
  }
223
224
0
  if (g_strcmp0(data, "enumeration") == 0 || kernel_bug) {
225
0
    if (!fu_bios_setting_set_enumeration_attrs(attr, &error_local))
226
0
      g_debug("failed to add enumeration attrs: %s", error_local->message);
227
0
  } else if (g_strcmp0(data, "integer") == 0) {
228
0
    if (!fu_bios_setting_set_integer_attrs(attr, &error_local))
229
0
      g_debug("failed to add integer attrs: %s", error_local->message);
230
0
  } else if (g_strcmp0(data, "string") == 0) {
231
0
    if (!fu_bios_setting_set_string_attrs(attr, &error_local))
232
0
      g_debug("failed to add string attrs: %s", error_local->message);
233
0
  }
234
0
  return TRUE;
235
0
}
236
237
/* Special case attribute that is a file not a folder
238
 * https://github.com/torvalds/linux/blob/v5.18/Documentation/ABI/testing/sysfs-class-firmware-attributes#L300
239
 */
240
static gboolean
241
fu_bios_settings_set_file_attributes(FuBiosSettings *self, FwupdBiosSetting *attr, GError **error)
242
0
{
243
0
  g_autofree gchar *value = NULL;
244
245
0
  if (g_strcmp0(fwupd_bios_setting_get_name(attr), FWUPD_BIOS_SETTING_PENDING_REBOOT) != 0) {
246
0
    g_set_error(error,
247
0
          FWUPD_ERROR,
248
0
          FWUPD_ERROR_NOT_SUPPORTED,
249
0
          "%s attribute is not supported",
250
0
          fwupd_bios_setting_get_name(attr));
251
0
    return FALSE;
252
0
  }
253
0
  if (!fu_bios_settings_set_description(self, attr, error))
254
0
    return FALSE;
255
0
  if (!fu_bios_setting_get_key(attr, NULL, &value, error))
256
0
    return FALSE;
257
0
  fwupd_bios_setting_set_current_value(attr, value);
258
0
  fwupd_bios_setting_set_read_only(attr, TRUE);
259
260
0
  return TRUE;
261
0
}
262
263
static gboolean
264
fu_bios_settings_set_folder_attributes(FuBiosSettings *self, FwupdBiosSetting *attr, GError **error)
265
0
{
266
0
  g_autoptr(GError) error_local = NULL;
267
268
0
  if (!fu_bios_settings_set_type(self, attr, error))
269
0
    return FALSE;
270
0
  if (!fu_bios_setting_set_current_value(attr, error))
271
0
    return FALSE;
272
0
  if (!fu_bios_settings_set_description(self, attr, &error_local))
273
0
    g_debug("%s", error_local->message);
274
0
  fu_bios_settings_set_read_only(self, attr);
275
0
  return TRUE;
276
0
}
277
278
void
279
fu_bios_settings_add_attribute(FuBiosSettings *self, FwupdBiosSetting *attr)
280
0
{
281
0
  g_return_if_fail(FU_IS_BIOS_SETTINGS(self));
282
0
  g_return_if_fail(FWUPD_IS_BIOS_SETTING(attr));
283
0
  g_ptr_array_add(self->attrs, g_object_ref(attr));
284
0
}
285
286
static gboolean
287
fu_bios_settings_populate_attribute(FuBiosSettings *self,
288
            const gchar *driver,
289
            const gchar *path,
290
            const gchar *name,
291
            GError **error)
292
0
{
293
0
  g_autoptr(FwupdBiosSetting) attr = NULL;
294
0
  g_autofree gchar *id = NULL;
295
0
  g_autofree gchar *name_stripped = NULL;
296
297
0
  g_return_val_if_fail(FU_IS_BIOS_SETTINGS(self), FALSE);
298
0
  g_return_val_if_fail(name != NULL, FALSE);
299
0
  g_return_val_if_fail(path != NULL, FALSE);
300
0
  g_return_val_if_fail(driver != NULL, FALSE);
301
302
0
  attr = fu_bios_setting_new();
303
304
0
  name_stripped = g_strdup(name);
305
0
  g_strdelimit(name_stripped, " ", '_');
306
307
0
  id = g_strdup_printf("com.%s.%s", driver, name_stripped);
308
0
  fwupd_bios_setting_set_name(attr, name);
309
0
  fwupd_bios_setting_set_path(attr, path);
310
0
  fwupd_bios_setting_set_id(attr, id);
311
312
0
  if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
313
0
    fwupd_bios_setting_set_filename(attr, "current_value");
314
0
    if (!fu_bios_settings_set_folder_attributes(self, attr, error))
315
0
      return FALSE;
316
0
  } else {
317
0
    if (!fu_bios_settings_set_file_attributes(self, attr, error))
318
0
      return FALSE;
319
0
  }
320
321
0
  fu_bios_settings_add_attribute(self, attr);
322
0
  return TRUE;
323
0
}
324
325
static void
326
fu_bios_settings_populate_descriptions(FuBiosSettings *self)
327
0
{
328
0
  g_return_if_fail(FU_IS_BIOS_SETTINGS(self));
329
330
0
  g_hash_table_insert(self->descriptions,
331
0
          g_strdup("pending_reboot"),
332
          /* TRANSLATORS: description of a BIOS setting */
333
0
          g_strdup(_("Settings will apply after system reboots")));
334
0
  g_hash_table_insert(self->descriptions,
335
0
          g_strdup("com.thinklmi.WindowsUEFIFirmwareUpdate"),
336
          /* TRANSLATORS: description of a BIOS setting */
337
0
          g_strdup(_("BIOS updates delivered via LVFS or Windows Update")));
338
0
}
339
340
static void
341
fu_bios_settings_populate_read_only(FuBiosSettings *self)
342
0
{
343
0
  g_return_if_fail(FU_IS_BIOS_SETTINGS(self));
344
345
0
  g_hash_table_insert(self->read_only,
346
0
          g_strdup("com.thinklmi.SecureBoot"),
347
0
          g_strdup(_("Enable")));
348
0
  g_hash_table_insert(self->read_only,
349
0
          g_strdup("com.dell-wmi-sysman.SecureBoot"),
350
0
          g_strdup(_("Enabled")));
351
0
}
352
353
static void
354
fu_bios_settings_combination_fixups(FuBiosSettings *self)
355
0
{
356
0
  FwupdBiosSetting *thinklmi_sb = fu_bios_settings_get_attr(self, "com.thinklmi.SecureBoot");
357
0
  FwupdBiosSetting *thinklmi_3rd =
358
0
      fu_bios_settings_get_attr(self, "com.thinklmi.Allow3rdPartyUEFICA");
359
360
0
  if (thinklmi_sb != NULL && thinklmi_3rd != NULL) {
361
0
    const gchar *val = fwupd_bios_setting_get_current_value(thinklmi_3rd);
362
0
    if (g_strcmp0(val, "Disable") == 0) {
363
0
      g_info("Disabling changing %s since %s is %s",
364
0
             fwupd_bios_setting_get_name(thinklmi_sb),
365
0
             fwupd_bios_setting_get_name(thinklmi_3rd),
366
0
             val);
367
0
      fwupd_bios_setting_set_read_only(thinklmi_sb, TRUE);
368
0
    }
369
0
  }
370
0
}
371
372
/**
373
 * fu_bios_settings_setup:
374
 * @self: a #FuBiosSettings
375
 *
376
 * Clears all attributes and re-initializes them.
377
 * Mostly used for the test suite, but could potentially be connected to udev
378
 * events for drivers being loaded or unloaded too.
379
 *
380
 * Since: 1.8.4
381
 **/
382
gboolean
383
fu_bios_settings_setup(FuBiosSettings *self, GError **error)
384
0
{
385
0
  guint count = 0;
386
0
  const gchar *sysfsfwdir = NULL;
387
0
  g_autoptr(GDir) class_dir = NULL;
388
0
  g_autoptr(GError) error_local = NULL;
389
390
0
  g_return_val_if_fail(FU_IS_BIOS_SETTINGS(self), FALSE);
391
392
0
  if (self->attrs->len > 0) {
393
0
    g_debug("re-initializing attributes");
394
0
    g_ptr_array_set_size(self->attrs, 0);
395
0
  }
396
0
  if (g_hash_table_size(self->descriptions) == 0)
397
0
    fu_bios_settings_populate_descriptions(self);
398
399
0
  if (g_hash_table_size(self->read_only) == 0)
400
0
    fu_bios_settings_populate_read_only(self);
401
402
0
  sysfsfwdir =
403
0
      fu_path_store_get_path(self->pstore, FU_PATH_KIND_SYSFSDIR_FW_ATTRIB, &error_local);
404
0
  if (sysfsfwdir == NULL) {
405
0
    g_debug("ignoring BIOS settings: %s", error_local->message);
406
0
    return TRUE;
407
0
  }
408
0
  class_dir = g_dir_open(sysfsfwdir, 0, error);
409
0
  if (class_dir == NULL) {
410
0
    fwupd_error_convert(error);
411
0
    return FALSE;
412
0
  }
413
0
  do {
414
0
    g_autofree gchar *path = NULL;
415
0
    g_autoptr(GDir) driver_dir = NULL;
416
0
    const gchar *driver = g_dir_read_name(class_dir);
417
0
    if (driver == NULL)
418
0
      break;
419
0
    path = g_build_filename(sysfsfwdir, driver, "attributes", NULL);
420
0
    if (!g_file_test(path, G_FILE_TEST_IS_DIR)) {
421
0
      g_debug("skipping non-directory %s", path);
422
0
      continue;
423
0
    }
424
0
    driver_dir = g_dir_open(path, 0, error);
425
0
    if (driver_dir == NULL) {
426
0
      fwupd_error_convert(error);
427
0
      return FALSE;
428
0
    }
429
0
    do {
430
0
      const gchar *name = g_dir_read_name(driver_dir);
431
0
      g_autofree gchar *full_path = NULL;
432
0
      g_autoptr(GError) error_loop = NULL;
433
0
      if (name == NULL)
434
0
        break;
435
0
      full_path = g_build_filename(path, name, NULL);
436
0
      if (!fu_bios_settings_populate_attribute(self,
437
0
                 driver,
438
0
                 full_path,
439
0
                 name,
440
0
                 &error_loop)) {
441
0
        g_debug("%s is not supported: %s", name, error_loop->message);
442
0
        continue;
443
0
      }
444
0
    } while (++count);
445
0
  } while (TRUE);
446
0
  g_info("loaded %u BIOS settings", count);
447
448
0
  fu_bios_settings_combination_fixups(self);
449
450
0
  return TRUE;
451
0
}
452
453
static void
454
fu_bios_settings_init(FuBiosSettings *self)
455
0
{
456
0
  self->attrs = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
457
0
  self->descriptions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
458
0
  self->read_only = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
459
0
}
460
461
/**
462
 * fu_bios_settings_get_attr:
463
 * @self: a #FuBiosSettings
464
 * @val: the attribute ID or name to check for
465
 *
466
 * Returns: (transfer none): the attribute with the given ID or name or NULL if it doesn't exist.
467
 *
468
 * Since: 1.8.4
469
 **/
470
FwupdBiosSetting *
471
fu_bios_settings_get_attr(FuBiosSettings *self, const gchar *val)
472
0
{
473
0
  g_return_val_if_fail(FU_IS_BIOS_SETTINGS(self), NULL);
474
0
  g_return_val_if_fail(val != NULL, NULL);
475
476
0
  for (guint i = 0; i < self->attrs->len; i++) {
477
0
    FwupdBiosSetting *attr = g_ptr_array_index(self->attrs, i);
478
0
    const gchar *tmp_id = fwupd_bios_setting_get_id(attr);
479
0
    const gchar *tmp_name = fwupd_bios_setting_get_name(attr);
480
0
    if (g_strcmp0(val, tmp_id) == 0 || g_strcmp0(val, tmp_name) == 0)
481
0
      return attr;
482
0
  }
483
0
  return NULL;
484
0
}
485
486
/**
487
 * fu_bios_settings_get_all:
488
 * @self: a #FuBiosSettings
489
 *
490
 * Gets all the attributes in the object.
491
 *
492
 * Returns: (transfer container) (element-type FwupdBiosSetting): attributes
493
 *
494
 * Since: 1.8.4
495
 **/
496
GPtrArray *
497
fu_bios_settings_get_all(FuBiosSettings *self)
498
0
{
499
0
  g_return_val_if_fail(FU_IS_BIOS_SETTINGS(self), NULL);
500
0
  return g_ptr_array_ref(self->attrs);
501
0
}
502
503
/**
504
 * fu_bios_settings_get_pending_reboot:
505
 * @self: a #FuBiosSettings
506
 * @result: (out): Whether a reboot is pending
507
 * @error: (nullable): optional return location for an error
508
 *
509
 * Determines if the system will apply changes to attributes upon reboot
510
 *
511
 * Since: 1.8.4
512
 **/
513
gboolean
514
fu_bios_settings_get_pending_reboot(FuBiosSettings *self, gboolean *result, GError **error)
515
0
{
516
0
  FwupdBiosSetting *attr = NULL;
517
0
  g_autofree gchar *data = NULL;
518
0
  guint64 val = 0;
519
520
0
  g_return_val_if_fail(result != NULL, FALSE);
521
0
  g_return_val_if_fail(FU_IS_BIOS_SETTINGS(self), FALSE);
522
523
0
  for (guint i = 0; i < self->attrs->len; i++) {
524
0
    FwupdBiosSetting *attr_tmp = g_ptr_array_index(self->attrs, i);
525
0
    const gchar *tmp = fwupd_bios_setting_get_name(attr_tmp);
526
0
    if (g_strcmp0(tmp, FWUPD_BIOS_SETTING_PENDING_REBOOT) == 0) {
527
0
      attr = attr_tmp;
528
0
      break;
529
0
    }
530
0
  }
531
0
  if (attr == NULL) {
532
0
    g_set_error_literal(error,
533
0
            FWUPD_ERROR,
534
0
            FWUPD_ERROR_NOT_FOUND,
535
0
            "failed to find pending reboot attribute");
536
0
    return FALSE;
537
0
  }
538
539
  /* refresh/re-read */
540
0
  if (!fu_bios_setting_get_key(attr, NULL, &data, error))
541
0
    return FALSE;
542
0
  fwupd_bios_setting_set_current_value(attr, data);
543
0
  if (!fu_strtoull(data, &val, 0, G_MAXUINT32, FU_INTEGER_BASE_AUTO, error))
544
0
    return FALSE;
545
546
0
  *result = (val == 1);
547
548
0
  return TRUE;
549
0
}
550
551
static GVariant *
552
fu_bios_settings_to_variant(FwupdCodec *codec, FwupdCodecFlags flags)
553
0
{
554
0
  FuBiosSettings *self = FU_BIOS_SETTINGS(codec);
555
0
  GVariantBuilder builder;
556
557
0
  g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}"));
558
0
  for (guint i = 0; i < self->attrs->len; i++) {
559
0
    FwupdBiosSetting *bios_setting = g_ptr_array_index(self->attrs, i);
560
0
    GVariant *value = fwupd_codec_to_variant(FWUPD_CODEC(bios_setting), flags);
561
0
    g_variant_builder_add_value(&builder, value);
562
0
  }
563
0
  return g_variant_new("(aa{sv})", &builder);
564
0
}
565
566
static gboolean
567
fu_bios_settings_from_json(FwupdCodec *codec, FwupdJsonObject *json_obj, GError **error)
568
0
{
569
0
  FuBiosSettings *self = FU_BIOS_SETTINGS(codec);
570
0
  g_autoptr(FwupdJsonArray) json_arr = NULL;
571
572
  /* this has to exist */
573
0
  json_arr = fwupd_json_object_get_array(json_obj, "BiosSettings", error);
574
0
  if (json_arr == NULL)
575
0
    return FALSE;
576
0
  for (guint i = 0; i < fwupd_json_array_get_size(json_arr); i++) {
577
0
    g_autoptr(FwupdBiosSetting) attr = fwupd_bios_setting_new(NULL, NULL);
578
0
    g_autoptr(FwupdJsonObject) json_obj_tmp = NULL;
579
580
0
    json_obj_tmp = fwupd_json_array_get_object(json_arr, i, error);
581
0
    if (json_obj_tmp == NULL)
582
0
      return FALSE;
583
0
    if (!fwupd_codec_from_json(FWUPD_CODEC(attr), json_obj_tmp, error))
584
0
      return FALSE;
585
0
    g_ptr_array_add(self->attrs, g_steal_pointer(&attr));
586
0
  }
587
588
  /* success */
589
0
  return TRUE;
590
0
}
591
592
static void
593
fu_bios_settings_codec_iface_init(FwupdCodecInterface *iface)
594
0
{
595
0
  iface->to_variant = fu_bios_settings_to_variant;
596
0
  iface->from_json = fu_bios_settings_from_json;
597
0
}
598
599
/**
600
 * fu_bios_settings_to_hash_kv:
601
 * @self: A #FuBiosSettings
602
 *
603
 * Creates a #GHashTable with the name and current value of
604
 * all BIOS settings.
605
 *
606
 * Returns: (transfer full): name/value pairs
607
 * Since: 1.8.4
608
 **/
609
GHashTable *
610
fu_bios_settings_to_hash_kv(FuBiosSettings *self)
611
0
{
612
0
  GHashTable *bios_settings = NULL;
613
614
0
  g_return_val_if_fail(self != NULL, NULL);
615
616
0
  bios_settings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
617
0
  for (guint i = 0; i < self->attrs->len; i++) {
618
0
    FwupdBiosSetting *item_setting = g_ptr_array_index(self->attrs, i);
619
0
    g_hash_table_insert(bios_settings,
620
0
            g_strdup(fwupd_bios_setting_get_id(item_setting)),
621
0
            g_strdup(fwupd_bios_setting_get_current_value(item_setting)));
622
0
  }
623
0
  return bios_settings;
624
0
}
625
626
/**
627
 * fu_bios_settings_is_supported:
628
 * @self: a #FuBiosSettings
629
 *
630
 * Determines if any BIOS settings are supported on this system.
631
 *
632
 * Returns: %TRUE if any BIOS settings are available, %FALSE otherwise
633
 *
634
 * Since: 2.1.1
635
 **/
636
gboolean
637
fu_bios_settings_is_supported(FuBiosSettings *self)
638
0
{
639
0
  g_return_val_if_fail(FU_IS_BIOS_SETTINGS(self), FALSE);
640
0
  return self->attrs->len > 0;
641
0
}
642
643
/**
644
 * fu_bios_settings_new:
645
 * @pstore: (nullable): a #FuPathStore
646
 *
647
 * Returns: #FuBiosSettings
648
 *
649
 * Since: 1.8.4
650
 **/
651
FuBiosSettings *
652
fu_bios_settings_new(FuPathStore *pstore)
653
0
{
654
0
  FuBiosSettings *self;
655
0
  g_return_val_if_fail(FU_IS_PATH_STORE(pstore) || pstore == NULL, NULL);
656
0
  self = g_object_new(FU_TYPE_FIRMWARE_ATTRS, NULL);
657
0
  if (pstore != NULL)
658
0
    self->pstore = g_object_ref(pstore);
659
0
  return self;
660
0
}
661
662
/**
663
 * fu_bios_settings_register_attr:
664
 * @self: a #FuBiosSettings
665
 * @attr: a #FwupdBiosSetting
666
 * @error: (nullable): optional return location for an error
667
 *
668
 * Registers a BIOS setting that was created by a plugin.
669
 * This is a public API for plugins to register custom BIOS settings.
670
 *
671
 * Returns: TRUE if the setting was registered successfully
672
 *
673
 * Since: 2.1.1
674
 **/
675
gboolean
676
fu_bios_settings_register_attr(FuBiosSettings *self, FwupdBiosSetting *attr, GError **error)
677
0
{
678
0
  g_return_val_if_fail(FU_IS_BIOS_SETTINGS(self), FALSE);
679
0
  g_return_val_if_fail(FWUPD_IS_BIOS_SETTING(attr), FALSE);
680
0
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
681
682
0
  if (fwupd_bios_setting_get_id(attr) == NULL) {
683
0
    g_set_error_literal(error,
684
0
            FWUPD_ERROR,
685
0
            FWUPD_ERROR_INVALID_DATA,
686
0
            "BIOS setting missing required id property");
687
0
    return FALSE;
688
0
  }
689
690
0
  if (fu_bios_settings_get_attr(self, fwupd_bios_setting_get_id(attr)) != NULL) {
691
0
    g_set_error(error,
692
0
          FWUPD_ERROR,
693
0
          FWUPD_ERROR_INVALID_DATA,
694
0
          "BIOS setting with id %s already exists",
695
0
          fwupd_bios_setting_get_id(attr));
696
0
    return FALSE;
697
0
  }
698
699
0
  fu_bios_settings_add_attribute(self, attr);
700
0
  return TRUE;
701
0
}