From 005bf9d0b4d2c9afbcc504eb7fb865dc3046d34f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 21 Jun 2021 18:05:32 +0100 Subject: [PATCH] Add support for soft-requirements that can be ignored with --force This allows OEMs to suggest that certain components are updated to specific versions, but allowing end-users to override this as required. --- src/fu-engine.c | 40 ++++++++++++++++++++++++++++++++++++++++ src/fu-self-test.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/src/fu-engine.c b/src/fu-engine.c index c1d579660..136466954 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -1645,6 +1645,28 @@ fu_engine_check_trust (FuInstallTask *task, GError **error) return TRUE; } +static gboolean +fu_engine_check_soft_requirement (FuEngine *self, + FuEngineRequest *request, + XbNode *req, + FuDevice *device, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(GError) error_local = NULL; + if (!fu_engine_check_requirement (self, request, req, device, + flags, &error_local)) { + if (flags & FWUPD_INSTALL_FLAG_FORCE) { + g_debug ("ignoring soft-requirement due to --force: %s", + error_local->message); + return TRUE; + } + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } + return TRUE; +} + gboolean fu_engine_check_requirements (FuEngine *self, FuEngineRequest *request, @@ -1679,6 +1701,24 @@ fu_engine_check_requirements (FuEngine *self, return FALSE; } + /* soft requirements */ + g_clear_error (&error_local); + reqs = xb_node_query (fu_install_task_get_component (task), + "suggests/*|recommends/*", 0, &error_local); + if (reqs != NULL) { + for (guint i = 0; i < reqs->len; i++) { + XbNode *req = g_ptr_array_index (reqs, i); + if (!fu_engine_check_soft_requirement (self, request, + req, device, + flags, error)) + return FALSE; + } + } else if (!g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) && + !g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) { + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } + return TRUE; } diff --git a/src/fu-self-test.c b/src/fu-self-test.c index fd7361e7a..10d2f7ce2 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -220,6 +220,43 @@ fu_engine_requirements_missing_func (gconstpointer user_data) g_assert (!ret); } +static void +fu_engine_requirements_soft_func (gconstpointer user_data) +{ + gboolean ret; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo = NULL; + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuEngineRequest) request = fu_engine_request_new (); + g_autoptr(FuInstallTask) task = NULL; + g_autoptr(GError) error = NULL; + const gchar *xml = + "" + " " + " not.going.to.exist" + " " + ""; + + /* set up a dummy version */ + fu_engine_add_runtime_version (engine, "org.test.dummy", "1.2.3"); + + /* 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 passes */ + task = fu_install_task_new (NULL, component); + ret = fu_engine_check_requirements (engine, request, task, + FWUPD_INSTALL_FLAG_FORCE, + &error); + g_assert_no_error (error); + g_assert (ret); +} + static void fu_engine_requirements_client_fail_func (gconstpointer user_data) { @@ -3289,6 +3326,8 @@ main (int argc, char **argv) fu_engine_downgrade_func); g_test_add_data_func ("/fwupd/engine{requirements-success}", self, fu_engine_requirements_func); + g_test_add_data_func ("/fwupd/engine{requirements-soft}", self, + fu_engine_requirements_soft_func); g_test_add_data_func ("/fwupd/engine{requirements-missing}", self, fu_engine_requirements_missing_func); g_test_add_data_func ("/fwupd/engine{requirements-client-fail}", self,