Allow devices to save the old firmware to disk for recovery

This would also help, for example, to go back to the nonfree firmware when the
alternate firmware did not work as well as hoped. It would also allow flashing
the firmware using an SPI programmer if everything went very wrong indeed.
This commit is contained in:
Richard Hughes 2020-09-29 19:39:38 +01:00
parent 460c4b75fe
commit 1a61258239
4 changed files with 36 additions and 0 deletions

View File

@ -199,6 +199,8 @@ fwupd_device_flag_to_string (FwupdDeviceFlags device_flag)
return "skips-restart";
if (device_flag == FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES)
return "has-multiple-branches";
if (device_flag == FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL)
return "backup-before-install";
if (device_flag == FWUPD_DEVICE_FLAG_UNKNOWN)
return "unknown";
return NULL;
@ -299,6 +301,8 @@ fwupd_device_flag_from_string (const gchar *device_flag)
return FWUPD_DEVICE_FLAG_SKIPS_RESTART;
if (g_strcmp0 (device_flag, "has-multiple-branches") == 0)
return FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES;
if (g_strcmp0 (device_flag, "backup-before-install") == 0)
return FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL;
return FWUPD_DEVICE_FLAG_UNKNOWN;
}

View File

@ -127,6 +127,7 @@ typedef enum {
* @FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN: Device is updatable but should not be called by the client
* @FWUPD_DEVICE_FLAG_SKIPS_RESTART: Device relies upon activation or power cycle to load firmware
* @FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES: Device supports switching to a different stream of firmware
* @FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL: Device firmware should be saved before installing firmware
*
* The device flags.
**/
@ -171,6 +172,7 @@ typedef enum {
#define FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN (1llu << 37) /* Since: 1.4.1 */
#define FWUPD_DEVICE_FLAG_SKIPS_RESTART (1llu << 38) /* Since: 1.5.0 */
#define FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES (1llu << 39) /* Since: 1.5.0 */
#define FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL (1llu << 40) /* Since: 1.5.0 */
#define FWUPD_DEVICE_FLAG_UNKNOWN G_MAXUINT64 /* Since: 0.7.3 */
typedef guint64 FwupdDeviceFlags;

View File

@ -1052,6 +1052,32 @@ fu_plugin_device_write_firmware (FuPlugin *self, FuDevice *device,
locker = fu_device_locker_new (device, error);
if (locker == NULL)
return FALSE;
/* back the old firmware up to /var/lib/fwupd */
if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL)) {
g_autoptr(GBytes) fw_old = NULL;
g_autofree gchar *path = NULL;
g_autofree gchar *fn = NULL;
g_autofree gchar *localstatedir = NULL;
fw_old = fu_device_dump_firmware (device, error);
if (fw_old == NULL) {
g_prefix_error (error, "failed to backup old firmware: ");
return FALSE;
}
localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG);
fn = g_strdup_printf ("%s.bin", fu_device_get_version (device));
path = g_build_filename (localstatedir,
"backup",
fu_device_get_id (device),
fu_device_get_serial (device) != NULL ?
fu_device_get_serial (device) :
"default",
fn, NULL);
if (!fu_common_set_contents_bytes (path, fw_old, error))
return FALSE;
}
return fu_device_write_firmware (device, fw, flags, error);
}

View File

@ -1077,6 +1077,10 @@ fu_util_device_flag_to_string (guint64 device_flag)
/* TRANSLATORS: there is more than one supplier of the firmware */
return _("Device supports switching to a different branch of firmware");
}
if (device_flag == FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL) {
/* TRANSLATORS: save the old firmware to disk before installing the new one */
return _("Device will backup firmware before installing");
}
if (device_flag == FWUPD_DEVICE_FLAG_MD_SET_NAME) {
/* skip */
return NULL;