diff --git a/libfwupd/fwupd-enums.c b/libfwupd/fwupd-enums.c index 4edd8b9d9..ce23c3664 100644 --- a/libfwupd/fwupd-enums.c +++ b/libfwupd/fwupd-enums.c @@ -179,6 +179,8 @@ fwupd_device_flag_to_string (FwupdDeviceFlags device_flag) return "self-recovery"; if (device_flag == FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE) return "usable-during-update"; + if (device_flag == FWUPD_DEVICE_FLAG_VERSION_CHECK_REQUIRED) + return "version-check-required"; if (device_flag == FWUPD_DEVICE_FLAG_UNKNOWN) return "unknown"; return NULL; @@ -259,6 +261,8 @@ fwupd_device_flag_from_string (const gchar *device_flag) return FWUPD_DEVICE_FLAG_SELF_RECOVERY; if (g_strcmp0 (device_flag, "usable-during-update") == 0) return FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE; + if (g_strcmp0 (device_flag, "version-check-required") == 0) + return FWUPD_DEVICE_FLAG_VERSION_CHECK_REQUIRED; return FWUPD_DEVICE_FLAG_UNKNOWN; } diff --git a/libfwupd/fwupd-enums.h b/libfwupd/fwupd-enums.h index 97f5ea150..c68aba87e 100644 --- a/libfwupd/fwupd-enums.h +++ b/libfwupd/fwupd-enums.h @@ -97,6 +97,7 @@ typedef enum { * @FWUPD_DEVICE_FLAG_DUAL_IMAGE: Device update architecture uses A/B partitions for updates * @FWUPD_DEVICE_FLAG_SELF_RECOVERY: In flashing mode device will only accept intended payloads * @FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE: Device remains usable while fwupd flashes or schedules the update + * @FWUPD_DEVICE_FLAG_VERSION_CHECK_REQUIRED: All firmware updates for this device require a firmware version check * * The device flags. **/ @@ -131,6 +132,7 @@ typedef enum { #define FWUPD_DEVICE_FLAG_DUAL_IMAGE (1u << 27) /* Since: 1.3.3 */ #define FWUPD_DEVICE_FLAG_SELF_RECOVERY (1u << 28) /* Since: 1.3.3 */ #define FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE (1u << 29) /* Since: 1.3.3 */ +#define FWUPD_DEVICE_FLAG_VERSION_CHECK_REQUIRED (1u << 30) /* Since: 1.3.7 */ #define FWUPD_DEVICE_FLAG_UNKNOWN G_MAXUINT64 /* Since: 0.7.3 */ typedef guint64 FwupdDeviceFlags; diff --git a/src/fu-install-task.c b/src/fu-install-task.c index f3a042296..6d6ac321a 100644 --- a/src/fu-install-task.c +++ b/src/fu-install-task.c @@ -152,6 +152,35 @@ fu_install_task_check_verfmt (FuInstallTask *self, return TRUE; } +static gboolean +fu_install_task_check_requirements_version_check (FuInstallTask *self, GError **error) +{ + g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) reqs = NULL; + + reqs = xb_node_query (fu_install_task_get_component (self), + "requires/*", 0, &error_local); + if (reqs == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + error_local->message); + return FALSE; + } + for (guint i = 0; i < reqs->len; i++) { + XbNode *req = g_ptr_array_index (reqs, i); + if (g_strcmp0 (xb_node_get_element (req), "firmware") == 0 && + xb_node_get_text (req) == NULL) { + return TRUE; + } + } + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no firmware requirement"); + return FALSE; +} + /** * fu_install_task_check_requirements: * @self: A #FuInstallTask @@ -211,6 +240,14 @@ fu_install_task_check_requirements (FuInstallTask *self, return FALSE; } + /* device requries a version check */ + if (fu_device_has_flag (self->device, FWUPD_DEVICE_FLAG_VERSION_CHECK_REQUIRED)) { + if (!fu_install_task_check_requirements_version_check (self, error)) { + g_prefix_error (error, "device requires firmware with a version check: "); + return FALSE; + } + } + /* does the protocol match */ protocol = xb_node_query_text (self->component, "custom/value[@key='LVFS::UpdateProtocol']", diff --git a/src/fu-self-test.c b/src/fu-self-test.c index 37391a648..f48c0b360 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -225,6 +225,53 @@ fu_engine_requirements_missing_func (gconstpointer user_data) g_assert (!ret); } +static void +fu_engine_requirements_version_require_func (gconstpointer user_data) +{ + gboolean ret; + g_autoptr(FuDevice) device = fu_device_new (); + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuInstallTask) task = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo = NULL; + const gchar *xml = + "" + " " + " 12345678-1234-1234-1234-123456789012" + " " + " " + " " + " " + " " + ""; + + /* set up a dummy device */ + fu_device_set_version (device, "1.2.3", FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_set_version_bootloader (device, "4.5.6"); + fu_device_set_vendor_id (device, "FFFF"); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_VERSION_CHECK_REQUIRED); + fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012"); + + /* make the component require one thing */ + silo = xb_silo_new_from_xml (xml, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + component = xb_silo_query_first (silo, "component", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + + /* check this fails */ + task = fu_install_task_new (device, component); + ret = fu_engine_check_requirements (engine, task, + FWUPD_INSTALL_FLAG_NONE, + &error); + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED); + g_assert (g_str_has_prefix (error->message, "device requires firmware with a version check")); + g_assert (!ret); +} + static void fu_engine_requirements_unsupported_func (gconstpointer user_data) { @@ -439,6 +486,7 @@ fu_engine_requirements_device_func (gconstpointer user_data) fu_device_set_version_bootloader (device, "4.5.6"); fu_device_set_vendor_id (device, "FFFF"); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_VERSION_CHECK_REQUIRED); fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012"); /* make the component require three things */ @@ -2902,6 +2950,8 @@ main (int argc, char **argv) fu_engine_requirements_func); g_test_add_data_func ("/fwupd/engine{requirements-missing}", self, fu_engine_requirements_missing_func); + g_test_add_data_func ("/fwupd/engine{requirements-version-require}", self, + fu_engine_requirements_version_require_func); g_test_add_data_func ("/fwupd/engine{requirements-parent-device}", self, fu_engine_requirements_parent_device_func); g_test_add_data_func ("/fwupd/engine{requirements-not-child}", self, diff --git a/src/fu-util-common.c b/src/fu-util-common.c index 2fb819f4d..91313d8c3 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -1066,6 +1066,10 @@ fu_util_device_flag_to_string (guint64 device_flag) /* TRANSLATORS: Device remains usable during update */ return _("Device is usable for the duration of the update"); } + if (device_flag == FWUPD_DEVICE_FLAG_VERSION_CHECK_REQUIRED) { + /* TRANSLATORS: a version check is required for all firmware */ + return _("Device firmware is required to have a version check"); + } if (device_flag == FWUPD_DEVICE_FLAG_UNKNOWN) { return NULL; }