Coverage Report

Created: 2026-01-17 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fwupd/libfwupdplugin/fu-common-linux.c
Line
Count
Source
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
#include <gio/gio.h>
12
#include <unistd.h>
13
14
#include "fu-common-private.h"
15
#include "fu-kernel.h"
16
#include "fu-path.h"
17
18
0
#define UDISKS_DBUS_PATH        "/org/freedesktop/UDisks2"
19
0
#define UDISKS_DBUS_MANAGER_PATH      "/org/freedesktop/UDisks2/Manager"
20
0
#define UDISKS_DBUS_MANAGER_INTERFACE "org.freedesktop.UDisks2.Manager"
21
22
0
#define UDISKS_METHOD_TIMEOUT 10000 /* ms */
23
24
/* required for udisks <= 2.1.7 */
25
static GPtrArray *
26
fu_common_get_block_devices_legacy(GError **error)
27
0
{
28
0
  g_autolist(GDBusObject) dbus_objects = NULL;
29
0
  g_autoptr(GDBusConnection) connection = NULL;
30
0
  g_autoptr(GDBusObjectManager) dbus_object_manager = NULL;
31
0
  g_autoptr(GPtrArray) devices =
32
0
      g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
33
34
0
  connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, error);
35
0
  if (connection == NULL) {
36
0
    g_prefix_error_literal(error, "failed to get system bus: ");
37
0
    return NULL;
38
0
  }
39
0
  dbus_object_manager =
40
0
      g_dbus_object_manager_client_new_sync(connection,
41
0
              G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
42
0
              UDISKS_DBUS_SERVICE,
43
0
              UDISKS_DBUS_PATH,
44
0
              NULL,
45
0
              NULL,
46
0
              NULL,
47
0
              NULL,
48
0
              error);
49
0
  if (dbus_object_manager == NULL)
50
0
    return NULL;
51
0
  dbus_objects = g_dbus_object_manager_get_objects(dbus_object_manager);
52
0
  for (GList *l = dbus_objects; l != NULL; l = l->next) {
53
0
    GDBusObject *dbus_object = G_DBUS_OBJECT(l->data);
54
0
    const gchar *obj = g_dbus_object_get_object_path(dbus_object);
55
0
    g_autoptr(GDBusInterface) dbus_iface_blk = NULL;
56
0
    g_autoptr(GDBusProxy) proxy_blk = NULL;
57
58
0
    dbus_iface_blk =
59
0
        g_dbus_object_get_interface(dbus_object, UDISKS_DBUS_INTERFACE_BLOCK);
60
0
    if (dbus_iface_blk == NULL) {
61
0
      g_debug("skipping %s as has no block interface", obj);
62
0
      continue;
63
0
    }
64
0
    proxy_blk = g_dbus_proxy_new_sync(connection,
65
0
              G_DBUS_PROXY_FLAGS_NONE,
66
0
              NULL,
67
0
              UDISKS_DBUS_SERVICE,
68
0
              obj,
69
0
              UDISKS_DBUS_INTERFACE_BLOCK,
70
0
              NULL,
71
0
              error);
72
0
    if (proxy_blk == NULL) {
73
0
      g_prefix_error(error, "failed to initialize d-bus proxy for %s: ", obj);
74
0
      return NULL;
75
0
    }
76
0
    g_ptr_array_add(devices, g_steal_pointer(&proxy_blk));
77
0
  }
78
79
  /* success */
80
0
  return g_steal_pointer(&devices);
81
0
}
82
83
GPtrArray *
84
fu_common_get_block_devices(GError **error)
85
0
{
86
0
  GVariantBuilder builder;
87
0
  const gchar *obj;
88
0
  g_autoptr(GError) error_local = NULL;
89
0
  g_autoptr(GVariant) output = NULL;
90
0
  g_autoptr(GDBusProxy) proxy = NULL;
91
0
  g_autoptr(GPtrArray) devices = NULL;
92
0
  g_autoptr(GVariantIter) obj_iter = NULL;
93
0
  g_autoptr(GDBusConnection) connection = NULL;
94
95
0
  connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, error);
96
0
  if (connection == NULL) {
97
0
    g_prefix_error_literal(error, "failed to get system bus: ");
98
0
    return NULL;
99
0
  }
100
0
  proxy = g_dbus_proxy_new_sync(connection,
101
0
              G_DBUS_PROXY_FLAGS_NONE,
102
0
              NULL,
103
0
              UDISKS_DBUS_SERVICE,
104
0
              UDISKS_DBUS_MANAGER_PATH,
105
0
              UDISKS_DBUS_MANAGER_INTERFACE,
106
0
              NULL,
107
0
              error);
108
0
  if (proxy == NULL) {
109
0
    g_prefix_error(error, "failed to find %s: ", UDISKS_DBUS_SERVICE);
110
0
    return NULL;
111
0
  }
112
113
0
  devices = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
114
0
  g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
115
0
  output = g_dbus_proxy_call_sync(proxy,
116
0
          "GetBlockDevices",
117
0
          g_variant_new("(a{sv})", &builder),
118
0
          G_DBUS_CALL_FLAGS_NONE,
119
0
          UDISKS_METHOD_TIMEOUT,
120
0
          NULL,
121
0
          &error_local);
122
0
  if (output == NULL) {
123
0
    if (g_error_matches(error_local, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD)) {
124
0
      g_debug("ignoring %s, trying fallback", error_local->message);
125
0
      return fu_common_get_block_devices_legacy(error);
126
0
    }
127
0
    g_dbus_error_strip_remote_error(error_local);
128
0
    g_propagate_prefixed_error(error,
129
0
             g_steal_pointer(&error_local),
130
0
             "failed to call %s.%s(): ",
131
0
             UDISKS_DBUS_MANAGER_INTERFACE,
132
0
             "GetBlockDevices");
133
0
    return NULL;
134
0
  }
135
136
0
  g_variant_get(output, "(ao)", &obj_iter);
137
0
  while (g_variant_iter_next(obj_iter, "&o", &obj)) {
138
0
    g_autoptr(GDBusProxy) proxy_blk = NULL;
139
0
    proxy_blk = g_dbus_proxy_new_sync(connection,
140
0
              G_DBUS_PROXY_FLAGS_NONE,
141
0
              NULL,
142
0
              UDISKS_DBUS_SERVICE,
143
0
              obj,
144
0
              UDISKS_DBUS_INTERFACE_BLOCK,
145
0
              NULL,
146
0
              error);
147
0
    if (proxy_blk == NULL) {
148
0
      g_prefix_error(error, "failed to initialize d-bus proxy for %s: ", obj);
149
0
      return NULL;
150
0
    }
151
0
    g_ptr_array_add(devices, g_steal_pointer(&proxy_blk));
152
0
  }
153
0
  return g_steal_pointer(&devices);
154
0
}
155
156
guint64
157
fu_common_get_memory_size_impl(void)
158
0
{
159
0
  glong phys_pages = sysconf(_SC_PHYS_PAGES);
160
0
  glong page_size = sysconf(_SC_PAGE_SIZE);
161
0
  if (phys_pages > 0 && page_size > 0)
162
0
    return (guint64)phys_pages * (guint64)page_size;
163
0
  return 0;
164
0
}
165
166
gchar *
167
fu_common_get_kernel_cmdline_impl(GError **error)
168
0
{
169
0
  GHashTableIter iter;
170
0
  gpointer key;
171
0
  gpointer value;
172
0
  g_autoptr(GHashTable) hash = NULL;
173
0
  g_autoptr(GString) cmdline_safe = g_string_new(NULL);
174
0
  const gchar *ignore[] = {
175
0
      "",
176
0
      "apparmor",
177
0
      "audit",
178
0
      "auto",
179
0
      "bluetooth.disable_ertm",
180
0
      "boot",
181
0
      "BOOT_IMAGE",
182
0
      "console",
183
0
      "crashkernel",
184
0
      "cryptdevice",
185
0
      "cryptkey",
186
0
      "dm",
187
0
      "earlycon",
188
0
      "earlyprintk",
189
0
      "ether",
190
0
      "init",
191
0
      "initrd",
192
0
      "ip",
193
0
      "LANG",
194
0
      "loglevel",
195
0
      "luks.key",
196
0
      "luks.name",
197
0
      "luks.options",
198
0
      "luks.uuid",
199
0
      "mitigations",
200
0
      "mount.usr",
201
0
      "mount.usrflags",
202
0
      "mount.usrfstype",
203
0
      "netdev",
204
0
      "netroot",
205
0
      "nfsaddrs",
206
0
      "nfs.nfs4_unique_id",
207
0
      "nfsroot",
208
0
      "noplymouth",
209
0
      "nowatchdog",
210
0
      "ostree",
211
0
      "preempt",
212
0
      "quiet",
213
0
      "rd.dm.uuid",
214
0
      "rd.luks.allow-discards",
215
0
      "rd.luks.key",
216
0
      "rd.luks.name",
217
0
      "rd.luks.options",
218
0
      "rd.luks.uuid",
219
0
      "rd.lvm.lv",
220
0
      "rd.lvm.vg",
221
0
      "rd.md.uuid",
222
0
      "rd.systemd.mask",
223
0
      "rd.systemd.wants",
224
0
      "resume",
225
0
      "resumeflags",
226
0
      "rhgb",
227
0
      "ro",
228
0
      "root",
229
0
      "rootflags",
230
0
      "rootfstype",
231
0
      "roothash",
232
0
      "rw",
233
0
      "security",
234
0
      "selinux",
235
0
      "showopts",
236
0
      "splash",
237
0
      "swap",
238
0
      "systemd.machine_id",
239
0
      "systemd.mask",
240
0
      "systemd.show_status",
241
0
      "systemd.unit",
242
0
      "systemd.verity_root_data",
243
0
      "systemd.verity_root_hash",
244
0
      "systemd.wants",
245
0
      "udev.log_priority",
246
0
      "verbose",
247
0
      "vt.handoff",
248
0
      "zfs",
249
0
      "zswap.enabled",
250
0
  };
251
252
  /* get a PII-safe kernel command line */
253
0
  hash = fu_kernel_get_cmdline(error);
254
0
  if (hash == NULL)
255
0
    return NULL;
256
0
  for (guint i = 0; i < G_N_ELEMENTS(ignore); i++)
257
0
    g_hash_table_remove(hash, ignore[i]);
258
0
  g_hash_table_iter_init(&iter, hash);
259
0
  while (g_hash_table_iter_next(&iter, &key, &value)) {
260
0
    if (cmdline_safe->len > 0)
261
0
      g_string_append(cmdline_safe, " ");
262
0
    if (value == NULL) {
263
0
      g_string_append(cmdline_safe, (gchar *)key);
264
0
      continue;
265
0
    }
266
0
    g_string_append_printf(cmdline_safe, "%s=%s", (gchar *)key, (gchar *)value);
267
0
  }
268
269
0
  return g_string_free(g_steal_pointer(&cmdline_safe), FALSE);
270
0
}
271
272
gchar *
273
fu_common_get_olson_timezone_id_impl(GError **error)
274
0
{
275
0
  g_autofree gchar *fn_localtime = fu_path_from_kind(FU_PATH_KIND_LOCALTIME);
276
0
  g_autoptr(GFile) file_localtime = g_file_new_for_path(fn_localtime);
277
278
  /* use the last two sections of the symlink target */
279
0
  g_debug("looking for timezone file %s", fn_localtime);
280
0
  if (g_file_query_file_type(file_localtime, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL) ==
281
0
      G_FILE_TYPE_SYMBOLIC_LINK) {
282
0
    const gchar *target;
283
0
    g_autoptr(GFileInfo) info = NULL;
284
285
0
    info = g_file_query_info(file_localtime,
286
0
           G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET,
287
0
           G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
288
0
           NULL,
289
0
           error);
290
0
    if (info == NULL)
291
0
      return NULL;
292
0
    target = g_file_info_get_symlink_target(info);
293
0
    if (target != NULL) {
294
0
      g_auto(GStrv) sections = g_strsplit(target, "/", -1);
295
0
      guint sections_len = g_strv_length(sections);
296
0
      if (sections_len < 2) {
297
0
        g_set_error(error,
298
0
              FWUPD_ERROR,
299
0
              FWUPD_ERROR_NOT_SUPPORTED,
300
0
              "invalid symlink target: %s",
301
0
              target);
302
0
        return NULL;
303
0
      }
304
0
      return g_strdup_printf("%s/%s",
305
0
                 sections[sections_len - 2],
306
0
                 sections[sections_len - 1]);
307
0
    }
308
0
  }
309
310
  /* failed */
311
0
  g_set_error_literal(error,
312
0
          FWUPD_ERROR,
313
0
          FWUPD_ERROR_NOT_SUPPORTED,
314
0
          "no timezone or localtime is available");
315
  return NULL;
316
0
}