diff --git a/plugins/dell/fu-self-test.c b/plugins/dell/fu-self-test.c index 5a1a40915..869cbf1b4 100644 --- a/plugins/dell/fu-self-test.c +++ b/plugins/dell/fu-self-test.c @@ -491,6 +491,7 @@ main (int argc, char **argv) /* change behaviour */ sysfsdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); g_setenv ("FWUPD_UEFI_ESP_PATH", sysfsdir, TRUE); + g_setenv ("FWUPD_UEFI_TEST", "1", TRUE); g_setenv ("FWUPD_DELL_FAKE_SMBIOS", "1", FALSE); /* only critical and error are fatal */ diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index a804047ed..fec2ecf31 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -19,6 +19,7 @@ #include "fu-uefi-common.h" #include "fu-uefi-device.h" #include "fu-uefi-vars.h" +#include "fu-uefi-udisks.h" #ifndef HAVE_GIO_2_55_0 #pragma clang diagnostic push @@ -376,6 +377,7 @@ fu_plugin_update (FuPlugin *plugin, FwupdInstallFlags flags, GError **error) { + FuPluginData *data = fu_plugin_get_data (plugin); const gchar *str; guint32 flashes_left; g_autoptr(GError) error_splash = NULL; @@ -403,12 +405,24 @@ fu_plugin_update (FuPlugin *plugin, /* make sure that the ESP is mounted */ if (g_getenv ("FWUPD_UEFI_ESP_PATH") == NULL) { - if (!fu_plugin_uefi_esp_mounted (plugin, error)) + /* mount the partition somewhere */ + if (fu_uefi_udisks_objpath (data->esp_path)) { + g_autofree gchar *path = NULL; + path = fu_uefi_udisks_objpath_mount (data->esp_path, error); + if (path == NULL) + return FALSE; + g_debug ("Mounted ESP at %s", path); + g_free (data->esp_path); + data->esp_path = g_strdup (path); + } else if (!fu_plugin_uefi_esp_mounted (plugin, error)) { return FALSE; + } } /* perform the update */ g_debug ("Performing UEFI capsule update"); + if (data->esp_path != NULL) + fu_device_set_metadata (device, "EspPath", data->esp_path); fu_device_set_status (device, FWUPD_STATUS_SCHEDULING); if (!fu_plugin_uefi_update_splash (plugin, device, &error_splash)) { g_debug ("failed to upload UEFI UX capsule text: %s", @@ -559,6 +573,10 @@ fu_plugin_uefi_delete_old_capsules (FuPlugin *plugin, GError **error) g_autofree gchar *pattern = NULL; g_autoptr(GPtrArray) files = NULL; + /* can only do this if we're mounted */ + if (fu_uefi_udisks_objpath (data->esp_path)) + return TRUE; + /* delete any files matching the glob in the ESP */ files = fu_common_get_files_recursive (data->esp_path, error); if (files == NULL) @@ -677,16 +695,10 @@ fu_plugin_uefi_ensure_esp_path (FuPlugin *plugin, GError **error) g_ascii_strcasecmp (require_shim_for_sb, "true") == 0) data->require_shim_for_sb = TRUE; - /* try to guess from heuristics */ - data->esp_path = fu_uefi_guess_esp_path (); - if (data->esp_path == NULL) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_FILENAME, - "Unable to determine EFI system partition location, " - "See https://github.com/fwupd/fwupd/wiki/Determining-EFI-system-partition-location"); + /* try to guess from heuristics and partitions */ + data->esp_path = fu_uefi_guess_esp_path (error); + if (data->esp_path == NULL) return FALSE; - } /* check free space */ if (!fu_uefi_check_esp_free_space (data->esp_path, sz_reqd, error)) diff --git a/plugins/uefi/fu-uefi-bootmgr.c b/plugins/uefi/fu-uefi-bootmgr.c index 5d3ca98b0..89b412331 100644 --- a/plugins/uefi/fu-uefi-bootmgr.c +++ b/plugins/uefi/fu-uefi-bootmgr.c @@ -303,7 +303,7 @@ fu_uefi_bootmgr_bootnext (const gchar *esp_path, g_autofree gchar *target_app = NULL; /* skip for self tests */ - if (g_getenv ("FWUPD_UEFI_ESP_PATH") != NULL) + if (g_getenv ("FWUPD_UEFI_TEST") != NULL) return TRUE; /* if secure boot was turned on this might need to be installed separately */ diff --git a/plugins/uefi/fu-uefi-common.c b/plugins/uefi/fu-uefi-common.c index fa7df3ea8..8c0a64caf 100644 --- a/plugins/uefi/fu-uefi-common.c +++ b/plugins/uefi/fu-uefi-common.c @@ -13,6 +13,7 @@ #include "fu-common.h" #include "fu-uefi-common.h" #include "fu-uefi-vars.h" +#include "fu-uefi-udisks.h" #include "fwupd-common.h" #include "fwupd-error.h" @@ -277,6 +278,10 @@ fu_uefi_check_esp_free_space (const gchar *path, guint64 required, GError **erro g_autoptr(GFile) file = NULL; g_autoptr(GFileInfo) info = NULL; + /* skip the checks for unmounted disks */ + if (fu_uefi_udisks_objpath (path)) + return TRUE; + file = g_file_new_for_path (path); info = g_file_query_filesystem_info (file, G_FILE_ATTRIBUTE_FILESYSTEM_FREE, @@ -351,8 +356,45 @@ fu_uefi_check_esp_path (const gchar *path, GError **error) return TRUE; } +static gchar * +fu_uefi_probe_for_esp (GError **error) +{ + g_autoptr(GPtrArray) devices = NULL; + g_autofree gchar *found_esp = NULL; + + devices = fu_uefi_udisks_get_block_devices (error); + if (devices == NULL) + return FALSE; + for (guint i = 0; i < devices->len; i++) { + const gchar *obj = g_ptr_array_index (devices, i); + gboolean esp = fu_uefi_udisks_objpath_is_esp (obj); + g_debug ("block device %s, is_esp: %d", obj, esp); + if (!esp) + continue; + if (found_esp != NULL) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_FILENAME, + "Multiple EFI system partitions found, " + "See https://github.com/fwupd/fwupd/wiki/Determining-EFI-system-partition-location"); + return NULL; + } + found_esp = g_strdup (obj); + } + if (found_esp == NULL) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_FILENAME, + "Unable to determine EFI system partition location, " + "See https://github.com/fwupd/fwupd/wiki/Determining-EFI-system-partition-location"); + return NULL; + } + + return g_steal_pointer (&found_esp); +} + gchar * -fu_uefi_guess_esp_path (void) +fu_uefi_guess_esp_path (GError **error) { const gchar *paths[] = {"/boot/efi", "/boot", "/efi", NULL}; const gchar *path_tmp; @@ -362,16 +404,19 @@ fu_uefi_guess_esp_path (void) if (path_tmp != NULL) return g_strdup (path_tmp); + /* try to use known paths */ for (guint i = 0; paths[i] != NULL; i++) { - g_autoptr(GError) error = NULL; - if (!fu_uefi_check_esp_path (paths[i], &error)) { - g_debug ("ignoring ESP path: %s", error->message); + g_autoptr(GError) error_local = NULL; + if (!fu_uefi_check_esp_path (paths[i], &error_local)) { + g_debug ("ignoring ESP path: %s", error_local->message); continue; } return g_strdup (paths[i]); } - return NULL; + /* prove udisks2 */ + g_debug ("Using UDisks2 to probe for ESP"); + return fu_uefi_probe_for_esp (error); } gboolean diff --git a/plugins/uefi/fu-uefi-common.h b/plugins/uefi/fu-uefi-common.h index 535ac1837..7c9c92fac 100644 --- a/plugins/uefi/fu-uefi-common.h +++ b/plugins/uefi/fu-uefi-common.h @@ -72,7 +72,7 @@ gboolean fu_uefi_get_framebuffer_size (guint32 *width, guint32 *height, GError **error); gboolean fu_uefi_secure_boot_enabled (void); -gchar *fu_uefi_guess_esp_path (void); +gchar *fu_uefi_guess_esp_path (GError **error); gboolean fu_uefi_check_esp_path (const gchar *path, GError **error); gboolean fu_uefi_check_esp_free_space (const gchar *path, diff --git a/plugins/uefi/fu-uefi-device.c b/plugins/uefi/fu-uefi-device.c index 98b188ad4..e4e649a04 100644 --- a/plugins/uefi/fu-uefi-device.c +++ b/plugins/uefi/fu-uefi-device.c @@ -363,7 +363,7 @@ fu_uefi_device_write_update_info (FuUefiDevice *self, }; /* set the body as the device path */ - if (g_getenv ("FWUPD_UEFI_ESP_PATH") != NULL) { + if (g_getenv ("FWUPD_UEFI_TEST") != NULL) { g_debug ("not building device path, in tests...."); return TRUE; } diff --git a/plugins/uefi/fu-uefi-tool.c b/plugins/uefi/fu-uefi-tool.c index dbc92d13b..240451cb1 100644 --- a/plugins/uefi/fu-uefi-tool.c +++ b/plugins/uefi/fu-uefi-tool.c @@ -164,10 +164,11 @@ main (int argc, char *argv[]) return EXIT_FAILURE; } } else { - esp_path = fu_uefi_guess_esp_path (); + g_autoptr(GError) error_local = NULL; + esp_path = fu_uefi_guess_esp_path (&error_local); if (esp_path == NULL) { - g_printerr ("Unable to determine EFI system partition " - "location, override using --esp-path\n"); + g_printerr ("%s: override using --esp-path\n", + error_local->message); return EXIT_FAILURE; } } diff --git a/plugins/uefi/fu-uefi-udisks.c b/plugins/uefi/fu-uefi-udisks.c new file mode 100644 index 000000000..84ffa6ead --- /dev/null +++ b/plugins/uefi/fu-uefi-udisks.c @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2019 Mario Limonciello + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-uefi-udisks.h" +#include "fwupd-common.h" +#include "fwupd-error.h" + +#define UDISKS_DBUS_SERVICE "org.freedesktop.UDisks2" +#define UDISKS_DBUS_PATH "/org/freedesktop/UDisks2/Manager" +#define UDISKS_DBUS_MANAGER_INTERFACE "org.freedesktop.UDisks2.Manager" +#define UDISKS_DBUS_PART_INTERFACE "org.freedesktop.UDisks2.Partition" +#define UDISKS_DBUS_FILE_INTERFACE "org.freedesktop.UDisks2.Filesystem" +#define ESP_DISK_TYPE "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" + +gboolean +fu_uefi_udisks_objpath (const gchar *path) +{ + return g_str_has_prefix (path, "/org/freedesktop/UDisks2/"); +} + +static GDBusProxy * +fu_uefi_udisks_get_dbus_proxy (const gchar *path, const gchar *interface, + GError **error) +{ + g_autoptr(GDBusConnection) connection = NULL; + g_autoptr(GDBusProxy) proxy = NULL; + + connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); + if (connection == NULL) { + g_prefix_error (error, "failed to get bus: "); + return NULL; + } + proxy = g_dbus_proxy_new_sync (connection, + G_DBUS_PROXY_FLAGS_NONE, NULL, + UDISKS_DBUS_SERVICE, + path, + interface, + NULL, error); + if (proxy == NULL) { + g_prefix_error (error, "failed to find %s: ", UDISKS_DBUS_SERVICE); + return NULL; + } + return g_steal_pointer (&proxy); +} + + +GPtrArray * +fu_uefi_udisks_get_block_devices (GError **error) +{ + g_autoptr(GVariant) output = NULL; + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GPtrArray) devices = NULL; + g_autoptr(GVariantIter) iter = NULL; + GVariant *input; + GVariantBuilder builder; + const gchar *obj; + + proxy = fu_uefi_udisks_get_dbus_proxy (UDISKS_DBUS_PATH, + UDISKS_DBUS_MANAGER_INTERFACE, + error); + if (proxy == NULL) + return NULL; + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + input = g_variant_new ("(a{sv})", &builder); + output = g_dbus_proxy_call_sync (proxy, + "GetBlockDevices", g_variant_ref (input), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (output == NULL) + return FALSE; + devices = g_ptr_array_new_with_free_func (g_free); + g_variant_get (output, "(ao)", &iter); + while (g_variant_iter_next (iter, "o", &obj)) + g_ptr_array_add (devices, g_strdup (obj)); + + return g_steal_pointer (&devices); +} + +gboolean +fu_uefi_udisks_objpath_is_esp (const gchar *obj) +{ + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(GVariant) val = NULL; + const gchar *str; + + proxy = fu_uefi_udisks_get_dbus_proxy (obj, + UDISKS_DBUS_PART_INTERFACE, + &error_local); + if (proxy == NULL) { + g_warning ("Failed to initialize d-bus proxy: %s", + error_local->message); + return FALSE; + } + val = g_dbus_proxy_get_cached_property (proxy, "Type"); + if (val == NULL) + return FALSE; + + g_variant_get (val, "s", &str); + return g_strcmp0 (str, ESP_DISK_TYPE) == 0; +} + +gchar * +fu_uefi_udisks_objpath_mount (const gchar *path, GError **error) +{ + GVariant *input; + GVariantBuilder builder; + const gchar *str; + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GVariant) val = NULL; + + g_return_val_if_fail (fu_uefi_udisks_objpath (path), NULL); + + proxy = fu_uefi_udisks_get_dbus_proxy (path, + UDISKS_DBUS_FILE_INTERFACE, + error); + if (proxy == NULL) + return NULL; + + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + input = g_variant_new ("(a{sv})", &builder); + val = g_dbus_proxy_call_sync (proxy, + "Mount", input, + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (val == NULL) + return NULL; + g_variant_get (val, "(s)", &str); + + return g_strdup (str); +} diff --git a/plugins/uefi/fu-uefi-udisks.h b/plugins/uefi/fu-uefi-udisks.h new file mode 100644 index 000000000..46b08cb5e --- /dev/null +++ b/plugins/uefi/fu-uefi-udisks.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2019 Mario Limonciello + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +GPtrArray *fu_uefi_udisks_get_block_devices (GError **error); +gboolean fu_uefi_udisks_objpath (const gchar *path); +gboolean fu_uefi_udisks_objpath_is_esp (const gchar *obj); +gchar *fu_uefi_udisks_objpath_mount (const gchar *path, + GError **error); diff --git a/plugins/uefi/meson.build b/plugins/uefi/meson.build index e3d394318..45b18d7d3 100644 --- a/plugins/uefi/meson.build +++ b/plugins/uefi/meson.build @@ -23,6 +23,7 @@ shared_module('fu_plugin_uefi', 'fu-uefi-devpath.c', 'fu-uefi-pcrs.c', 'fu-uefi-update-info.c', + 'fu-uefi-udisks.c', 'fu-uefi-vars.c', ], include_directories : [ @@ -58,6 +59,7 @@ executable( 'fu-uefi-devpath.c', 'fu-uefi-pcrs.c', 'fu-uefi-update-info.c', + 'fu-uefi-udisks.c', 'fu-uefi-vars.c', ], include_directories : [ @@ -102,6 +104,7 @@ if get_option('tests') 'fu-uefi-pcrs.c', 'fu-uefi-update-info.c', 'fu-uefi-vars.c', + 'fu-uefi-udisks.c', 'fu-ucs2.c', ], include_directories : [