Coverage Report

Created: 2025-08-24 07:10

/src/fwupd/libfwupdplugin/fu-common.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2017 Richard Hughes <richard@hughsie.com>
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 */
6
7
0
#define G_LOG_DOMAIN "FuCommon"
8
9
#include "config.h"
10
11
#ifdef HAVE_CPUID_H
12
#include <cpuid.h>
13
#endif
14
15
#include "fu-common-private.h"
16
#include "fu-firmware.h"
17
#include "fu-path.h"
18
#include "fu-string.h"
19
20
/**
21
 * fu_error_map_entry_to_gerror:
22
 * @value: the value to look up
23
 * @entries: the #FuErrorMapEntry map
24
 * @n_entries: number of @entries
25
 * @error: (nullable): optional return location for an error
26
 *
27
 * Sets the #GError from the integer value and the error map.
28
 *
29
 * Any entries with a error_code of `FWUPD_ERROR_LAST` will return success.
30
 *
31
 * Returns: boolean success
32
 *
33
 * Since: 2.0.13
34
 **/
35
gboolean
36
fu_error_map_entry_to_gerror(guint value,
37
           const FuErrorMapEntry entries[],
38
           guint n_entries,
39
           GError **error)
40
0
{
41
0
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
42
43
0
  for (guint i = 0; i < n_entries; i++) {
44
0
    const FuErrorMapEntry entry = entries[i];
45
0
    if (entry.value != value)
46
0
      continue;
47
0
    if (entry.code == FWUPD_ERROR_LAST)
48
0
      return TRUE;
49
0
    g_set_error(error,
50
0
          FWUPD_ERROR,
51
0
          entry.code,
52
0
          "%s [0x%x]",
53
0
          entry.message != NULL ? entry.message
54
0
              : fwupd_error_to_string(entry.value),
55
0
          entry.value);
56
0
    return FALSE;
57
0
  }
58
0
  g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "generic failure [0x%x]", value);
59
0
  return FALSE;
60
0
}
61
62
/**
63
 * fu_cpuid:
64
 * @leaf: the CPUID level, now called the 'leaf' by Intel
65
 * @eax: (out) (nullable): EAX register
66
 * @ebx: (out) (nullable): EBX register
67
 * @ecx: (out) (nullable): ECX register
68
 * @edx: (out) (nullable): EDX register
69
 * @error: (nullable): optional return location for an error
70
 *
71
 * Calls CPUID and returns the registers for the given leaf.
72
 *
73
 * Returns: %TRUE if the registers are set.
74
 *
75
 * Since: 1.8.2
76
 **/
77
gboolean
78
fu_cpuid(guint32 leaf, guint32 *eax, guint32 *ebx, guint32 *ecx, guint32 *edx, GError **error)
79
0
{
80
#ifdef HAVE_CPUID_H
81
  guint eax_tmp = 0;
82
  guint ebx_tmp = 0;
83
  guint ecx_tmp = 0;
84
  guint edx_tmp = 0;
85
86
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
87
88
  /* get vendor */
89
  __get_cpuid_count(leaf, 0x0, &eax_tmp, &ebx_tmp, &ecx_tmp, &edx_tmp);
90
  if (eax != NULL)
91
    *eax = eax_tmp;
92
  if (ebx != NULL)
93
    *ebx = ebx_tmp;
94
  if (ecx != NULL)
95
    *ecx = ecx_tmp;
96
  if (edx != NULL)
97
    *edx = edx_tmp;
98
  return TRUE;
99
#else
100
0
  g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "no <cpuid.h> support");
101
0
  return FALSE;
102
0
#endif
103
0
}
104
105
/**
106
 * fu_cpu_get_attrs:
107
 * @error: (nullable): optional return location for an error
108
 *
109
 * Gets attributes for the first CPU listed in `/proc/cpuinfo`.
110
 *
111
 * Returns: (element-type utf8 utf8) (transfer full): CPU attributes
112
 *
113
 * Since: 2.0.7
114
 **/
115
GHashTable *
116
fu_cpu_get_attrs(GError **error)
117
0
{
118
0
  gsize bufsz = 0;
119
0
  g_autofree gchar *buf = NULL;
120
0
  g_autofree gchar *procpath = fu_path_from_kind(FU_PATH_KIND_PROCFS);
121
0
  g_autofree gchar *fn = g_build_filename(procpath, "cpuinfo", NULL);
122
0
  g_autoptr(GHashTable) hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
123
124
0
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
125
126
0
  if (!g_file_get_contents(fn, &buf, &bufsz, error))
127
0
    return NULL;
128
0
  if (bufsz > 0) {
129
0
    g_auto(GStrv) lines = fu_strsplit(buf, bufsz, "\n", -1);
130
0
    for (guint i = 0; lines[i] != NULL; i++) {
131
0
      g_auto(GStrv) tokens = NULL;
132
0
      if (lines[i][0] == '\0')
133
0
        break;
134
0
      tokens = g_strsplit(lines[i], ": ", 2);
135
0
      for (guint j = 0; tokens[j] != NULL; j++) {
136
0
        g_hash_table_insert(hash,
137
0
                fu_strstrip(tokens[0]),
138
0
                g_strdup(tokens[1]));
139
0
      }
140
0
    }
141
0
  }
142
143
  /* success */
144
0
  return g_steal_pointer(&hash);
145
0
}
146
147
/**
148
 * fu_cpu_get_vendor:
149
 *
150
 * Uses CPUID to discover the CPU vendor.
151
 *
152
 * Returns: a CPU vendor, e.g. %FU_CPU_VENDOR_AMD if the vendor was AMD.
153
 *
154
 * Since: 1.8.2
155
 **/
156
FuCpuVendor
157
fu_cpu_get_vendor(void)
158
0
{
159
#ifdef HAVE_CPUID_H
160
  guint ebx = 0;
161
  guint ecx = 0;
162
  guint edx = 0;
163
164
  if (fu_cpuid(0x0, NULL, &ebx, &ecx, &edx, NULL)) {
165
    if (ebx == signature_INTEL_ebx && edx == signature_INTEL_edx &&
166
        ecx == signature_INTEL_ecx) {
167
      return FU_CPU_VENDOR_INTEL;
168
    }
169
    if (ebx == signature_AMD_ebx && edx == signature_AMD_edx &&
170
        ecx == signature_AMD_ecx) {
171
      return FU_CPU_VENDOR_AMD;
172
    }
173
  }
174
#endif
175
176
  /* failed */
177
0
  return FU_CPU_VENDOR_UNKNOWN;
178
0
}
179
180
/**
181
 * fu_common_get_memory_size:
182
 *
183
 * Returns the size of physical memory.
184
 *
185
 * Returns: bytes
186
 *
187
 * Since: 1.5.6
188
 **/
189
guint64
190
fu_common_get_memory_size(void)
191
0
{
192
0
  return fu_common_get_memory_size_impl();
193
0
}
194
195
/**
196
 * fu_common_get_kernel_cmdline:
197
 * @error: (nullable): optional return location for an error
198
 *
199
 * Returns the current kernel command line options.
200
 *
201
 * Returns: options as a string, or %NULL on error
202
 *
203
 * Since: 1.5.6
204
 **/
205
gchar *
206
fu_common_get_kernel_cmdline(GError **error)
207
0
{
208
0
  return fu_common_get_kernel_cmdline_impl(error);
209
0
}
210
211
/**
212
 * fu_common_get_olson_timezone_id:
213
 * @error: (nullable): optional return location for an error
214
 *
215
 * Gets the system Olson timezone ID, as used in the CLDR and ICU specifications.
216
 *
217
 * Returns: timezone string, e.g. `Europe/London` or %NULL on error
218
 *
219
 * Since: 1.9.7
220
 **/
221
gchar *
222
fu_common_get_olson_timezone_id(GError **error)
223
0
{
224
0
  return fu_common_get_olson_timezone_id_impl(error);
225
0
}
226
227
/**
228
 * fu_common_align_up:
229
 * @value: value to align
230
 * @alignment: align to this power of 2, where 0x1F is the maximum value of 2GB
231
 *
232
 * Align a value to a power of 2 boundary, where @alignment is the bit position
233
 * to align to. If @alignment is zero then @value is always returned unchanged.
234
 *
235
 * Returns: aligned value, which will be the same as @value if already aligned,
236
 *    or %G_MAXSIZE if the value would overflow
237
 *
238
 * Since: 1.6.0
239
 **/
240
gsize
241
fu_common_align_up(gsize value, guint8 alignment)
242
463k
{
243
463k
  gsize value_new;
244
463k
  gsize mask = (gsize)1 << alignment;
245
246
463k
  g_return_val_if_fail(alignment <= FU_FIRMWARE_ALIGNMENT_2G, G_MAXSIZE);
247
248
  /* no alignment required */
249
463k
  if ((value & (mask - 1)) == 0)
250
306k
    return value;
251
252
  /* increment up to the next alignment value */
253
157k
  value_new = value + mask;
254
157k
  value_new &= ~(mask - 1);
255
256
  /* overflow */
257
157k
  if (value_new < value)
258
0
    return G_MAXSIZE;
259
260
  /* success */
261
157k
  return value_new;
262
157k
}
263
264
/**
265
 * fu_power_state_is_ac:
266
 * @power_state: a power state, e.g. %FU_POWER_STATE_AC_FULLY_CHARGED
267
 *
268
 * Determines if the power state can be considered "on AC power".
269
 *
270
 * Returns: %TRUE for success
271
 *
272
 * Since: 1.8.11
273
 **/
274
gboolean
275
fu_power_state_is_ac(FuPowerState power_state)
276
0
{
277
0
  return power_state != FU_POWER_STATE_BATTERY;
278
0
}
279
280
/**
281
 * fu_error_convert:
282
 * @entries: the #FuErrorConvertEntry map
283
 * @n_entries: number of @entries
284
 * @perror: (nullable): A #GError, perhaps with domain #GIOError
285
 *
286
 * Convert the error to a #FwupdError, if required.
287
 *
288
 * Since: 2.0.14
289
 **/
290
gboolean
291
fu_error_convert(const FuErrorConvertEntry entries[], guint n_entries, GError **perror)
292
0
{
293
0
  GError *error = (perror != NULL) ? *perror : NULL;
294
295
  /* sanity check */
296
0
  if (error == NULL)
297
0
    return TRUE;
298
299
  /* convert GIOError and GFileError */
300
0
  fwupd_error_convert(perror);
301
0
  if (error->domain == FWUPD_ERROR)
302
0
    return FALSE;
303
0
  for (guint i = 0; i < n_entries; i++) {
304
0
    if (g_error_matches(error, entries[i].domain, entries[i].code)) {
305
0
      error->domain = FWUPD_ERROR;
306
0
      error->code = entries[i].error;
307
0
      return FALSE;
308
0
    }
309
0
  }
310
311
0
#ifndef SUPPORTED_BUILD
312
  /* fallback */
313
0
  g_critical("GError %s:%i was not converted to FwupdError",
314
0
       g_quark_to_string(error->domain),
315
0
       error->code);
316
0
#endif
317
0
  error->domain = FWUPD_ERROR;
318
0
  error->code = FWUPD_ERROR_INTERNAL;
319
0
  return FALSE;
320
0
}
321
322
/**
323
 * fu_xmlb_builder_insert_kv:
324
 * @bn: #XbBuilderNode
325
 * @key: string key
326
 * @value: string value
327
 *
328
 * Convenience function to add an XML node with a string value. If @value is %NULL
329
 * then no member is added.
330
 *
331
 * Since: 1.6.0
332
 **/
333
void
334
fu_xmlb_builder_insert_kv(XbBuilderNode *bn, const gchar *key, const gchar *value)
335
751k
{
336
751k
  if (value == NULL)
337
479k
    return;
338
272k
  xb_builder_node_insert_text(bn, key, value, NULL);
339
272k
}
340
341
/**
342
 * fu_xmlb_builder_insert_kx:
343
 * @bn: #XbBuilderNode
344
 * @key: string key
345
 * @value: integer value
346
 *
347
 * Convenience function to add an XML node with an integer value. If @value is 0
348
 * then no member is added.
349
 *
350
 * Since: 1.6.0
351
 **/
352
void
353
fu_xmlb_builder_insert_kx(XbBuilderNode *bn, const gchar *key, guint64 value)
354
1.20M
{
355
1.20M
  g_autofree gchar *value_hex = NULL;
356
1.20M
  if (value == 0)
357
865k
    return;
358
336k
  value_hex = g_strdup_printf("0x%x", (guint)value);
359
336k
  xb_builder_node_insert_text(bn, key, value_hex, NULL);
360
336k
}
361
362
/**
363
 * fu_xmlb_builder_insert_kb:
364
 * @bn: #XbBuilderNode
365
 * @key: string key
366
 * @value: boolean value
367
 *
368
 * Convenience function to add an XML node with a boolean value.
369
 *
370
 * Since: 1.6.0
371
 **/
372
void
373
fu_xmlb_builder_insert_kb(XbBuilderNode *bn, const gchar *key, gboolean value)
374
0
{
375
0
  xb_builder_node_insert_text(bn, key, value ? "true" : "false", NULL);
376
0
}
377
378
/**
379
 * fu_snap_is_in_snap:
380
 *
381
 * Check whether the current process is running inside a snap.
382
 *
383
 * Returns: TRUE if current process is running inside a snap.
384
 *
385
 * Since: 2.0.4
386
 **/
387
gboolean
388
fu_snap_is_in_snap(void)
389
0
{
390
0
  return getenv("SNAP") != NULL;
391
0
}