Allow verifying the device image itself from fwupdtool

To debug flashing failures it's sometimes requried to get a SPI dump of the
hardware to analysis.

Add a debug-only command that lets us dump the device from the engine.
This commit is contained in:
Richard Hughes 2019-10-30 10:03:12 +00:00
parent 51a869a01d
commit a58510b246
4 changed files with 103 additions and 1 deletions

View File

@ -21,6 +21,7 @@ _fwupdtool_cmd_list=(
'smbios-dump'
'attach'
'detach'
'firmware-read'
'verify-update'
'watch'
)
@ -86,7 +87,7 @@ _fwupdtool()
esac
case $command in
get-details|install|install-blob)
get-details|install|install-blob|firmware-read)
#find files
if [[ "$prev" = "$command" ]]; then
_filedir

View File

@ -2082,6 +2082,35 @@ fu_engine_update (FuEngine *self,
return TRUE;
}
GBytes *
fu_engine_firmware_read (FuEngine *self,
FuDevice *device,
FwupdInstallFlags flags,
GError **error)
{
g_autoptr(FuDeviceLocker) locker = NULL;
g_autoptr(FuFirmware) firmware = NULL;
/* open, detach, read, attach, serialize */
locker = fu_device_locker_new (device, error);
if (locker == NULL)
return NULL;
if (!fu_device_detach (device, error))
return NULL;
firmware = fu_device_read_firmware (device, error);
if (firmware == NULL) {
g_autoptr(GError) error_local = NULL;
if (!fu_device_attach (device, &error_local)) {
g_warning ("failed to attach after read image failure: %s",
error_local->message);
}
return NULL;
}
if (!fu_device_attach (device, error))
return NULL;
return fu_firmware_write (firmware, error);
}
gboolean
fu_engine_install_blob (FuEngine *self,
FuDevice *device,

View File

@ -96,6 +96,10 @@ gboolean fu_engine_verify (FuEngine *self,
gboolean fu_engine_verify_update (FuEngine *self,
const gchar *device_id,
GError **error);
GBytes *fu_engine_firmware_read (FuEngine *self,
FuDevice *device,
FwupdInstallFlags flags,
GError **error);
gboolean fu_engine_modify_remote (FuEngine *self,
const gchar *remote_id,
const gchar *key,

View File

@ -39,6 +39,7 @@ typedef enum {
FU_UTIL_OPERATION_UNKNOWN,
FU_UTIL_OPERATION_UPDATE,
FU_UTIL_OPERATION_INSTALL,
FU_UTIL_OPERATION_READ,
FU_UTIL_OPERATION_LAST
} FuUtilOperation;
@ -558,6 +559,11 @@ fu_util_update_device_changed_cb (FwupdClient *client,
str = g_strdup_printf (_("Installing on %s…"),
fwupd_device_get_name (device));
fu_progressbar_set_title (priv->progressbar, str);
} else if (priv->current_operation == FU_UTIL_OPERATION_READ) {
/* TRANSLATORS: %1 is a device name */
str = g_strdup_printf (_("Reading from %s…"),
fwupd_device_get_name (device));
fu_progressbar_set_title (priv->progressbar, str);
} else {
g_warning ("no FuUtilOperation set");
}
@ -660,6 +666,62 @@ fu_util_install_blob (FuUtilPrivate *priv, gchar **values, GError **error)
return fu_util_prompt_complete (priv->completion_flags, TRUE, error);
}
static gboolean
fu_util_firmware_read (FuUtilPrivate *priv, gchar **values, GError **error)
{
g_autoptr(FuDevice) device = NULL;
g_autoptr(GBytes) blob_empty = g_bytes_new (NULL, 0);
g_autoptr(GBytes) blob_fw = NULL;
/* invalid args */
if (g_strv_length (values) == 0) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_ARGS,
"Invalid arguments");
return FALSE;
}
/* file already exists */
if ((priv->flags & FWUPD_INSTALL_FLAG_FORCE) == 0 &&
g_file_test (values[0], G_FILE_TEST_EXISTS)) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_ARGS,
"Filename already exists");
return FALSE;
}
/* write a zero lenth file to ensure the destination is writable to
* avoid failing at the end of a potentially lengthy operation */
if (!fu_common_set_contents_bytes (values[0], blob_empty, error))
return FALSE;
/* load engine */
if (!fu_util_start_engine (priv, FU_ENGINE_LOAD_FLAG_NONE, error))
return FALSE;
/* get device */
if (g_strv_length (values) >= 2) {
device = fu_engine_get_device (priv->engine, values[1], error);
if (device == NULL)
return FALSE;
} else {
device = fu_util_prompt_for_device (priv, error);
if (device == NULL)
return FALSE;
}
priv->current_operation = FU_UTIL_OPERATION_READ;
g_signal_connect (priv->engine, "device-changed",
G_CALLBACK (fu_util_update_device_changed_cb), priv);
/* dump firmware */
blob_fw = fu_engine_firmware_read (priv->engine, device, priv->flags, error);
if (blob_fw == NULL)
return FALSE;
return fu_common_set_contents_bytes (values[0], blob_fw, error);
}
static gint
fu_util_install_task_sort_cb (gconstpointer a, gconstpointer b)
{
@ -1685,6 +1747,12 @@ main (int argc, char *argv[])
/* TRANSLATORS: command description */
_("Update the stored metadata with current contents"),
fu_util_verify_update);
fu_util_cmd_array_add (cmd_array,
"firmware-read",
"FILENAME [DEVICE-ID]",
/* TRANSLATORS: command description */
_("Read a firmware blob from a device"),
fu_util_firmware_read);
fu_util_cmd_array_add (cmd_array,
"firmware-parse",
"FILENAME [FIRMWARE_TYPE]",