Coverage Report

Created: 2025-10-10 07:05

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