mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-04 19:11:07 +00:00
uefi: detect unmounted ESP partitions (Fixes: #1405)
Mount these while writing out updates. Leave them mounted when done (you gotta reboot anyway).
This commit is contained in:
parent
dc227c6037
commit
5bd649ef31
@ -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 */
|
||||
|
@ -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))
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
138
plugins/uefi/fu-uefi-udisks.c
Normal file
138
plugins/uefi/fu-uefi-udisks.c
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Mario Limonciello <mario.limonciello@dell.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#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);
|
||||
}
|
13
plugins/uefi/fu-uefi-udisks.h
Normal file
13
plugins/uefi/fu-uefi-udisks.h
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Mario Limonciello <mario.limonciello@dell.com>
|
||||
*
|
||||
* 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);
|
@ -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 : [
|
||||
|
Loading…
Reference in New Issue
Block a user