Coverage Report

Created: 2025-07-01 07:09

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